EVM 연산 코드
개요
이 문서는 wolflo/evm-opcodes (새 탭에서 열림)의 EVM 참조 페이지를 업데이트한 버전입니다. 또한 황서 (새 탭에서 열림), Jello Paper (새 탭에서 열림), 그리고 고 이더리움 (geth) (새 탭에서 열림) 구현체에서도 내용을 발췌했습니다. 이 문서는 접근하기 쉬운 참조 자료로 작성되었지만, 특별히 엄밀하지는 않습니다. 정확성을 확신하고 모든 엣지 케이스를 파악하고 싶다면, Jello Paper나 클라이언트 구현체를 참고하는 것이 좋습니다.
대화형 참조 자료를 찾고 계신가요? evm.codes (새 탭에서 열림)를 확인해 보세요.
동적 가스 비용이 있는 연산에 대해서는 gas.md (새 탭에서 열림)를 참조하세요.
💡 간단한 팁: 전체 줄을 보려면 데스크톱에서 [shift] + 스크롤을 사용하여 가로로 스크롤하세요.
| 스택 | 이름 | 가스 | 초기 스택 | 결과 스택 | 메모리 / 스토리지 | 참고 |
|---|---|---|---|---|---|---|
| 00 | STOP | 0 | 실행 중지 | |||
| 01 | ADD | 3 | a, b | a + b | (u)int256 덧셈 모듈로 2**256 | |
| 02 | MUL | 5 | a, b | a * b | (u)int256 곱셈 모듈로 2**256 | |
| 03 | SUB | 3 | a, b | a - b | (u)int256 뺄셈 모듈로 2**256 | |
| 04 | DIV | 5 | a, b | a // b | uint256 나눗셈 | |
| 05 | SDIV | 5 | a, b | a // b | int256 나눗셈 | |
| 06 | MOD | 5 | a, b | a % b | uint256 나머지 | |
| 07 | SMOD | 5 | a, b | a % b | int256 나머지 | |
| 08 | ADDMOD | 8 | a, b, N | (a + b) % N | (u)int256 덧셈 모듈로 N | |
| 09 | MULMOD | 8 | a, b, N | (a * b) % N | (u)int256 곱셈 모듈로 N | |
| 0A | EXP | A1 (새 탭에서 열림) | a, b | a ** b | uint256 거듭제곱 모듈로 2**256 | |
| 0B | SIGNEXTEND | 5 | b, x | SIGNEXTEND(x, b) | (b+1) 바이트에서 32 바이트로 x를 부호 확장(sign extend) (새 탭에서 열림) | |
| 0C-0F | 유효하지 않음 | |||||
| 10 | LT | 3 | a, b | a < b | uint256 미만 | |
| 11 | GT | 3 | a, b | a > b | uint256 초과 | |
| 12 | SLT | 3 | a, b | a < b | int256 미만 | |
| 13 | SGT | 3 | a, b | a > b | int256 초과 | |
| 14 | EQ | 3 | a, b | a == b | (u)int256 같음 | |
| 15 | ISZERO | 3 | a | a == 0 | (u)int256 0인지 여부 | |
| 16 | AND | 3 | a, b | a && b | 비트 AND | |
| 17 | OR | 3 | a, b | a || b | 비트 OR | |
| 18 | XOR | 3 | a, b | a ^ b | 비트 XOR | |
| 19 | NOT | 3 | a | ~a | 비트 NOT | |
| 1A | BYTE | 3 | i, x | (x >> (248 - i * 8)) && 0xFF | 왼쪽에서부터 (u)int256 x의 i번째 바이트 | |
| 1B | SHL | 3 | shift, val | val << shift | 왼쪽 시프트 | |
| 1C | SHR | 3 | shift, val | val >> shift | 논리적 오른쪽 시프트 | |
| 1D | SAR | 3 | shift, val | val >> shift | 산술적 오른쪽 시프트 | |
| 1E-1F | 유효하지 않음 | |||||
| 20 | KECCAK256 | A2 (새 탭에서 열림) | ost, len | keccak256(mem[ost:ost+len-1]) | keccak256 | |
| 21-2F | 유효하지 않음 | |||||
| 30 | ADDRESS | 2 | . | address(this) | 실행 중인 컨트랙트의 주소 | |
| 31 | BALANCE | A5 (새 탭에서 열림) | addr | addr.balance | 잔액 (Wei 단위) | |
| 32 | ORIGIN | 2 | . | tx.origin | 트랜잭션을 시작한 주소 | |
| 33 | CALLER | 2 | . | msg.sender | msg 발신자의 주소 | |
| 34 | CALLVALUE | 2 | . | msg.value | msg 값 (Wei 단위) | |
| 35 | CALLDATALOAD | 3 | idx | msg.data[idx:idx+32] | 인덱스 idx의 msg 데이터에서 워드 읽기 | |
| 36 | CALLDATASIZE | 2 | . | len(msg.data) | msg 데이터의 길이 (바이트 단위) | |
| 37 | CALLDATACOPY | A3 (새 탭에서 열림) | dstOst, ost, len | . | mem[dstOst:dstOst+len-1] := msg.data[ost:ost+len-1] | msg 데이터 복사 |
| 38 | CODESIZE | 2 | . | len(this.code) | 실행 중인 컨트랙트 코드의 길이 (바이트 단위) | |
| 39 | CODECOPY | A3 (새 탭에서 열림) | dstOst, ost, len | . | mem[dstOst:dstOst+len-1] := this.code[ost:ost+len-1] | |
| 3A | GASPRICE | 2 | . | tx.gasprice | 트랜잭션의 가스 가격 (단위 가스당 Wei) ** (새 탭에서 열림) | |
| 3B | EXTCODESIZE | A5 (새 탭에서 열림) | addr | len(addr.code) | addr에 있는 코드의 크기 (바이트 단위) | |
| 3C | EXTCODECOPY | A4 (새 탭에서 열림) | addr, dstOst, ost, len | . | mem[dstOst:dstOst+len-1] := addr.code[ost:ost+len-1] | addr에서 코드 복사 |
| 3D | RETURNDATASIZE | 2 | . | size | 마지막 외부 호출에서 반환된 데이터의 크기 (바이트 단위) | |
| 3E | RETURNDATACOPY | A3 (새 탭에서 열림) | dstOst, ost, len | . | mem[dstOst:dstOst+len-1] := returndata[ost:ost+len-1] | 마지막 외부 호출에서 반환된 데이터 복사 |
| 3F | EXTCODEHASH | A5 (새 탭에서 열림) | addr | hash | hash = addr.exists ? keccak256(addr.code) : 0 | |
| 40 | BLOCKHASH | 20 | blockNum | blockHash(blockNum) | ||
| 41 | COINBASE | 2 | . | block.coinbase | 현재 블록 제안자의 주소 | |
| 42 | TIMESTAMP | 2 | . | block.timestamp | 현재 블록의 타임스탬프 | |
| 43 | NUMBER | 2 | . | block.number | 현재 블록의 번호 | |
| 44 | PREVRANDAO | 2 | . | randomness beacon | 무작위성 비콘 | |
| 45 | GASLIMIT | 2 | . | block.gaslimit | 현재 블록의 가스 한도 | |
| 46 | CHAINID | 2 | . | chain_id | 현재 체인 ID (새 탭에서 열림)를 스택에 푸시 | |
| 47 | SELFBALANCE | 5 | . | address(this).balance | 실행 중인 컨트랙트의 잔액 (Wei 단위) | |
| 48 | BASEFEE | 2 | . | block.basefee | 현재 블록의 기본 수수료 | |
| 49 | BLOBHASH | 3 | idx | tx.blob_versioned_hashes[idx] | EIP-4844 (새 탭에서 열림) | |
| 4A | BLOBBASEFEE | 2 | . | block.blobbasefee | 현재 블록의 블롭 기본 수수료 (EIP-7516 (새 탭에서 열림)) | |
| 4B-4F | 유효하지 않음 | |||||
| 50 | POP | 2 | _anon | . | 스택의 맨 위에서 항목을 제거하고 버림 | |
| 51 | MLOAD | 3* (새 탭에서 열림) | ost | mem[ost:ost+32] | 오프셋 ost의 메모리에서 워드 읽기 | |
| 52 | MSTORE | 3* (새 탭에서 열림) | ost, val | . | mem[ost:ost+32] := val | 메모리에 워드 쓰기 |
| 53 | MSTORE8 | 3* (새 탭에서 열림) | ost, val | . | mem[ost] := val && 0xFF | 메모리에 단일 바이트 쓰기 |
| 54 | SLOAD | A6 (새 탭에서 열림) | key | storage[key] | 스토리지에서 워드 읽기 | |
| 55 | SSTORE | A7 (새 탭에서 열림) | key, val | . | storage[key] := val | 스토리지에 워드 쓰기 |
| 56 | JUMP | 8 | dst | . | $pc := dst dst가 유효한 jumpdest인 경우에만 pc가 할당됨을 표시 | |
| 57 | JUMPI | 10 | dst, condition | . | $pc := condition ? dst : $pc + 1 | |
| 58 | PC | 2 | . | $pc | 프로그램 카운터 | |
| 59 | MSIZE | 2 | . | len(mem) | 현재 실행 컨텍스트의 메모리 크기 (바이트 단위) | |
| 5A | GAS | 2 | . | gasRemaining | ||
| 5B | JUMPDEST | 1 | 유효한 점프 목적지 표시 | 유효한 점프 목적지 (예: 푸시 데이터 내부에 있지 않은 점프 목적지) | ||
| 5C | TLOAD | 100 | key | tstorage[key] | 임시 스토리지에서 워드 읽기 (EIP-1153 (새 탭에서 열림)) | |
| 5D | TSTORE | 100 | key, val | . | tstorage[key] := val | 임시 스토리지에 워드 쓰기 (EIP-1153 (새 탭에서 열림)) |
| 5E | MCOPY | 3+3*words+A0 (새 탭에서 열림) | dstOst, ost, len | . | mem[dstOst] := mem[ost:ost+len] | 한 영역에서 다른 영역으로 메모리 복사 (EIP-5656 (새 탭에서 열림)) |
| 5F | PUSH0 | 2 | . | uint8 | 상수 값 0을 스택에 푸시 | |
| 60 | PUSH1 | 3 | . | uint8 | 1바이트 값을 스택에 푸시 | |
| 61 | PUSH2 | 3 | . | uint16 | 2바이트 값을 스택에 푸시 | |
| 62 | PUSH3 | 3 | . | uint24 | 3바이트 값을 스택에 푸시 | |
| 63 | PUSH4 | 3 | . | uint32 | 4바이트 값을 스택에 푸시 | |
| 64 | PUSH5 | 3 | . | uint40 | 5바이트 값을 스택에 푸시 | |
| 65 | PUSH6 | 3 | . | uint48 | 6바이트 값을 스택에 푸시 | |
| 66 | PUSH7 | 3 | . | uint56 | 7바이트 값을 스택에 푸시 | |
| 67 | PUSH8 | 3 | . | uint64 | 8바이트 값을 스택에 푸시 | |
| 68 | PUSH9 | 3 | . | uint72 | 9바이트 값을 스택에 푸시 | |
| 69 | PUSH10 | 3 | . | uint80 | 10바이트 값을 스택에 푸시 | |
| 6A | PUSH11 | 3 | . | uint88 | 11바이트 값을 스택에 푸시 | |
| 6B | PUSH12 | 3 | . | uint96 | 12바이트 값을 스택에 푸시 | |
| 6C | PUSH13 | 3 | . | uint104 | 13바이트 값을 스택에 푸시 | |
| 6D | PUSH14 | 3 | . | uint112 | 14바이트 값을 스택에 푸시 | |
| 6E | PUSH15 | 3 | . | uint120 | 15바이트 값을 스택에 푸시 | |
| 6F | PUSH16 | 3 | . | uint128 | 16바이트 값을 스택에 푸시 | |
| 70 | PUSH17 | 3 | . | uint136 | 17바이트 값을 스택에 푸시 | |
| 71 | PUSH18 | 3 | . | uint144 | 18바이트 값을 스택에 푸시 | |
| 72 | PUSH19 | 3 | . | uint152 | 19바이트 값을 스택에 푸시 | |
| 73 | PUSH20 | 3 | . | uint160 | 20바이트 값을 스택에 푸시 | |
| 74 | PUSH21 | 3 | . | uint168 | 21바이트 값을 스택에 푸시 | |
| 75 | PUSH22 | 3 | . | uint176 | 22바이트 값을 스택에 푸시 | |
| 76 | PUSH23 | 3 | . | uint184 | 23바이트 값을 스택에 푸시 | |
| 77 | PUSH24 | 3 | . | uint192 | 24바이트 값을 스택에 푸시 | |
| 78 | PUSH25 | 3 | . | uint200 | 25바이트 값을 스택에 푸시 | |
| 79 | PUSH26 | 3 | . | uint208 | 26바이트 값을 스택에 푸시 | |
| 7A | PUSH27 | 3 | . | uint216 | 27바이트 값을 스택에 푸시 | |
| 7B | PUSH28 | 3 | . | uint224 | 28바이트 값을 스택에 푸시 | |
| 7C | PUSH29 | 3 | . | uint232 | 29바이트 값을 스택에 푸시 | |
| 7D | PUSH30 | 3 | . | uint240 | 30바이트 값을 스택에 푸시 | |
| 7E | PUSH31 | 3 | . | uint248 | 31바이트 값을 스택에 푸시 | |
| 7F | PUSH32 | 3 | . | uint256 | 32바이트 값을 스택에 푸시 | |
| 80 | DUP1 | 3 | a | a, a | 스택의 1번째 값 복제 | |
| 81 | DUP2 | 3 | _, a | a, _, a | 스택의 2번째 값 복제 | |
| 82 | DUP3 | 3 | _, _, a | a, _, _, a | 스택의 3번째 값 복제 | |
| 83 | DUP4 | 3 | _, _, _, a | a, _, _, _, a | 스택의 4번째 값 복제 | |
| 84 | DUP5 | 3 | ..., a | a, ..., a | 스택의 5번째 값 복제 | |
| 85 | DUP6 | 3 | ..., a | a, ..., a | 스택의 6번째 값 복제 | |
| 86 | DUP7 | 3 | ..., a | a, ..., a | 스택의 7번째 값 복제 | |
| 87 | DUP8 | 3 | ..., a | a, ..., a | 스택의 8번째 값 복제 | |
| 88 | DUP9 | 3 | ..., a | a, ..., a | 스택의 9번째 값 복제 | |
| 89 | DUP10 | 3 | ..., a | a, ..., a | 스택의 10번째 값 복제 | |
| 8A | DUP11 | 3 | ..., a | a, ..., a | 스택의 11번째 값 복제 | |
| 8B | DUP12 | 3 | ..., a | a, ..., a | 스택의 12번째 값 복제 | |
| 8C | DUP13 | 3 | ..., a | a, ..., a | 스택의 13번째 값 복제 | |
| 8D | DUP14 | 3 | ..., a | a, ..., a | 스택의 14번째 값 복제 | |
| 8E | DUP15 | 3 | ..., a | a, ..., a | 스택의 15번째 값 복제 | |
| 8F | DUP16 | 3 | ..., a | a, ..., a | 스택의 16번째 값 복제 | |
| 90 | SWAP1 | 3 | a, b | b, a | ||
| 91 | SWAP2 | 3 | a, _, b | b, _, a | ||
| 92 | SWAP3 | 3 | a, _, _, b | b, _, _, a | ||
| 93 | SWAP4 | 3 | a, _, _, _, b | b, _, _, _, a | ||
| 94 | SWAP5 | 3 | a, ..., b | b, ..., a | ||
| 95 | SWAP6 | 3 | a, ..., b | b, ..., a | ||
| 96 | SWAP7 | 3 | a, ..., b | b, ..., a | ||
| 97 | SWAP8 | 3 | a, ..., b | b, ..., a | ||
| 98 | SWAP9 | 3 | a, ..., b | b, ..., a | ||
| 99 | SWAP10 | 3 | a, ..., b | b, ..., a | ||
| 9A | SWAP11 | 3 | a, ..., b | b, ..., a | ||
| 9B | SWAP12 | 3 | a, ..., b | b, ..., a | ||
| 9C | SWAP13 | 3 | a, ..., b | b, ..., a | ||
| 9D | SWAP14 | 3 | a, ..., b | b, ..., a | ||
| 9E | SWAP15 | 3 | a, ..., b | b, ..., a | ||
| 9F | SWAP16 | 3 | a, ..., b | b, ..., a | ||
| A0 | LOG0 | A8 (새 탭에서 열림) | ost, len | . | LOG0(memory[ost:ost+len-1]) | |
| A1 | LOG1 | A8 (새 탭에서 열림) | ost, len, topic0 | . | LOG1(memory[ost:ost+len-1], topic0) | |
| A2 | LOG2 | A8 (새 탭에서 열림) | ost, len, topic0, topic1 | . | LOG2(memory[ost:ost+len-1], topic0, topic1) | |
| A3 | LOG3 | A8 (새 탭에서 열림) | ost, len, topic0, topic1, topic2 | . | LOG3(memory[ost:ost+len-1], topic0, topic1, topic2) | |
| A4 | LOG4 | A8 (새 탭에서 열림) | ost, len, topic0, topic1, topic2, topic3 | . | LOG4(memory[ost:ost+len-1], topic0, topic1, topic2, topic3) | |
| A5-EF | 유효하지 않음 | |||||
| F0 | CREATE | A9 (새 탭에서 열림) | val, ost, len | addr | addr = keccak256(rlp([address(this), this.nonce])) | |
| F1 | CALL | AA (새 탭에서 열림) | gas, addr, val, argOst, argLen, retOst, retLen | success | mem[retOst:retOst+retLen-1] := returndata | |
| F2 | CALLCODE | AA (새 탭에서 열림) | gas, addr, val, argOst, argLen, retOst, retLen | success | mem[retOst:retOst+retLen-1] = returndata | DELEGATECALL과 동일하지만, 원래의 msg.sender와 msg.value를 전달하지 않음 |
| F3 | RETURN | 0* (새 탭에서 열림) | ost, len | . | return mem[ost:ost+len-1] | |
| F4 | DELEGATECALL | AA (새 탭에서 열림) | gas, addr, argOst, argLen, retOst, retLen | success | mem[retOst:retOst+retLen-1] := returndata | |
| F5 | CREATE2 | A9 (새 탭에서 열림) | val, ost, len, salt | addr | addr = keccak256(0xff ++ address(this) ++ salt ++ keccak256(mem[ost:ost+len-1]))[12:] | |
| F6-F9 | 유효하지 않음 | |||||
| FA | STATICCALL | AA (새 탭에서 열림) | gas, addr, argOst, argLen, retOst, retLen | success | mem[retOst:retOst+retLen-1] := returndata | |
| FB-FC | 유효하지 않음 | |||||
| FD | REVERT | 0* (새 탭에서 열림) | ost, len | . | revert(mem[ost:ost+len-1]) | |
| FE | INVALID | AF (새 탭에서 열림) | 지정된 유효하지 않은 연산 코드 - EIP-141 (새 탭에서 열림) | |||
| FF | SELFDESTRUCT | AB (새 탭에서 열림) | addr | . | 모든 ETH를 addr로 전송; 컨트랙트가 생성된 것과 동일한 트랜잭션에서 실행되는 경우 컨트랙트를 파기함 |