Tech Lab3 min read

EVM 이해하기: 이더리움 가상 머신의 구조와 동작 원리

EVM은 이더리움에서 스마트 계약을 동일한 환경에서 실행하는 가상 머신입니다. 스택·바이트코드·가스 모델을 실제 예시와 함께 이해해 보세요.

#EVM#Ethereum#Solidity#EVM#Opcode#Gas#Model

독자는 이 글을 통해 EVM의 동작 원리와 가스 모델을 빠르게 이해하며, 스마트 계약 개발에서 흔한 혼동을 예시·표 기반으로 명확히 정리할 수 있습니다.

이더리움 네트워크와 EVM 계층 구조를 한눈에 보여주는 다이어그램

왜 가상 머신이 필요한가

하드웨어가 다른 환경에서 동일한 코드를 안정적으로 실행하려면 중간에 추상화 계층이 필요합니다. 가상 머신은 운영체제나 기기 차이를 숨기고, 프로그램을 격리된 환경에서 실행합니다. 이 덕분에 충돌을 줄이고 이식성을 높일 수 있습니다.

EVM 한 줄 정의

EVM(Ethereum Virtual Machine) 은 이더리움 블록체인 위에서 스마트 계약을 동일한 규칙으로 실행하는 가상의 CPU이자 런타임입니다. 특정 OS나 하드웨어에 종속되지 않으며, 컨트랙트는 어느 노드에서나 결정적으로 동일한 결과를 냅니다.

Solidity → 바이트코드 → 실행

스마트 계약은 보통 Solidity로 작성됩니다. 이 코드는 solcEVM 바이트코드로 컴파일되고, 클라이언트(예: Geth)를 통해 네트워크에 배포됩니다. 배포 후 노드의 EVM은 동일한 규칙으로 바이트코드를 해석·실행합니다.

  • 1단계: Solidity 소스 → solc → 바이트코드(및 ABI)
  • 2단계: 트랜잭션으로 컨트랙트 배포
  • 3단계: 호출 시 EVM이 바이트코드를 실행, 상태 변경 또는 값을 반환

팁: 배포 전 테스트넷에서 가스 소비를 측정하면 메인넷 비용 예측에 도움이 됩니다.

스택 기반 아키텍처 이해

EVM은 스택 머신입니다. 연산자는 스택에서 피연산자를 꺼내고 결과를 다시 스택에 넣습니다. 메모리·스토리지는 별도 영역으로 존재하며, 스토리지는 영속적이고 비용이 큽니다.

예제: 0x6001600101

  • 0x60(PUSH1): 다음 바이트를 스택에 푸시 → 0x01
  • 다시 0x60(PUSH1): 또 0x01 푸시 → 스택 [0x01, 0x01]
  • 0x01(ADD): 두 값을 더해 0x02 → 최종 스택 [0x02]

주의: 스택 깊이 초과(1024 제한)나 언더플로우는 즉시 예외를 유발합니다.

주요 Opcode와 가스

아래 표는 자주 언급되는 Opcode의 역할과 대략적 가스 비용을 정리한 것입니다. 네트워크 업그레이드에 따라 비용은 조정될 수 있습니다.

Opcode16진수 코드설명가스 비용(예시)
STOP0x00실행 중단0
ADD0x01스택 상단 두 값을 더함3
MUL0x02스택 상단 두 값을 곱함5
PUSH10x601바이트 상수를 스택에 푸시3
SSTORE0x55스토리지에 쓰기(영속)20000
JUMP0x56지정 위치로 무조건 점프8
CALL0xf1다른 컨트랙트 호출700+변동

팁: SSTORE는 비용이 매우 커서, 상태 쓰기를 최소화하는 설계(예: 배치 업데이트, 이벤트 로그 활용)가 필수입니다.

메모리·스토리지·콜데이터 구분

  • 메모리: 호출 동안 임시. 읽기/쓰기가 비교적 저렴.
  • 스토리지: 컨트랙트의 영속 상태. 쓰기는 비쌈.
  • 콜데이터: 호출 입력. 읽기 전용이며 가스가 가장 저렴.

이 구분을 이해하면 데이터 구조와 연산 위치를 최적화해 가스 절감이 가능합니다.

가스(Gas) 모델과 안전장치

EVM은 튜링 완전성을 가지지만, 무한 루프 등 자원 낭비를 막기 위해 가스 한도를 둡니다. 각 Opcode는 고정·가변 비용을 가지며, 가스가 소진되면 실행이 롤백됩니다.

트랜잭션은 가스 한도 내에서만 실행됩니다. 가스 부족은 상태를 되돌리며, 사용자는 낭비적 호출을 방지할 수 있습니다.

보안 격리(Sandboxing) 덕분에 잘못된 코드가 다른 컨트랙트나 노드에 직접적인 피해를 주지 못합니다. 또한 메시지 호출 경계가 있어 재진입 등 취약점은 패턴 차원에서 대비해야 합니다.

개발자가 꼭 체크할 사항

  1. 컴파일 산출물 관리: ABI·바이트코드를 모두 버전 태깅.
  2. 가스 예산: 함수 호출 전후 가스 소비를 측정·프로파일링.
  3. 스토리지 레이아웃: 구조체 패킹·슬롯 정렬로 쓰기 비용 절감.
  4. 실행 흐름 안전성: require·revert로 실패를 명시화.
  5. 외부 호출: 재진입 보호(체크·이펙트·인터랙션)와 pull 결제 패턴.

스택·메모리·스토리지 상호작용

다음으로 읽으면 좋은 자료

내부에서 제공하는 “EVM Opcode 심화 해설” 문서를 통해 실제 바이트코드 해석과 최적화 전략을 더 자세히 살펴보세요. (→ 타임스탬프 역사)

팁: 프로젝트 위키에 “가스 비용 표”와 “스토리지 레이아웃 도식”을 상시 업데이트하면 팀 온보딩이 빨라집니다.

참고 링크

다음으로 읽어볼 글