2 분 소요

EVM


EVM은 이더리움 스마트 컨트랙트의 바이트 코드를 실행하는 32바이트 스택 기반의 실행환경이다. 이러한 스택 기반 환경은 저장 공간을 최대한 줄이기 위해 설계되었다.

이더리움의 각 노드는 EVM을 포함하고 있으며, EVM을 통해 컨트랙트의 바이트 코드를 Opcode로 변환 후 내부에서 실행한다.

EVM 동작

EVM 구조


EVM은 내부에 휘발성 메모리와 비휘발성 메모리로 구성되어 있고, 여기에 바이트 배열 형태로 스택 항목들을 저장한다. EVM은 프로그램 코드를 ROM에 저장하고 특별한 명령어를 통해 접근 가능하다.

주 구성 요소는 PC(Program Counter), 스택, 스토리지, 메모리 영역으로 구성된다.

2

스택

  • 스택은 연산에 필요한 데이터를 저장하기 위한 공간으로, 256bit의 크기들로 값들이 저장된다. 최대 스택의 크기는 1024개로 초과 시, 예외가 발생하여 컨트랙트 실행이 종료된다.
  • 내부 함수 또한, 일반적인 연산처럼 EVM 스택을 사용하도록 설계되었으며, 다른 컨트랙트의 메소드를 호출할 때 메시지 콜을 위한 스택을 사용하는데, 메시지 콜 스택의 크기도 1024이다.

메모리

  • 메모리는 휘발성 메모리이고 함수를 호출하거나 메모리 연산을 수행할 때 임시로 사용되는 영역으로, 이더리움에서 메시지 호출이 발생할 때마다 초기화된 메모리 영역이 컨트랙트에 제공된다.
  • 데이터를 읽는 것은 256bit 단위로 읽도록 제한되어있지만, 기록할 때는 8bit나 256bit 단위로 기록할 수 있다.

스토리지

  • 스토리지는 비휘발성 메모리로, key/value를 매핑하기 위한 구조이며, key와 value 모두 256bit의 크기를 사용한다.
  • 이더리움 어카운트는 별도의 스토리지를 독자적으로 보유하고 있으며, 다른 어카운트의 스토리지에 접근할 수 없게 설계되었다.

EVM 내부 동작


1

EVM은 위와 같이 동작하며, 맨 처음에는 메모리와 스택은 비어있으며, PC는 0이다.

EVM은 바이트 코드를 내부 Opcode로 치환하여 실행되며, Opcode의 PC를 증가시키면서, 최종적으로 오류가 나거나 STOP, RETURN, 실행 완료가 될 때까지 Opcode를 계속해서 실행해나간다.

트랜잭션을 반복적으로 실행하면서, 각 사이클에서는 시스템 상태와 머신 상태를 계산하고 머신 상태는 다음과 같다.

  • 사용 가능한 가스
  • PC
  • 메모리에 들어있는 값
  • 메모리에서 활성화된 단어의 수
  • 스택에 들어있는 값

EVM Gas


연산 수수료

EVM은 EVM 내부 동작과정에서와 같이 스택에서 POP하여 Opcode를 실행할 때마다 Gas가 남아있는지 확인한다.

여기서 Gas란 연산에 대한 수수료를 말하며, 이더리움의 트랜잭션에서 Gas Price와 Gas Limit를 볼 수 있는데, 여기서 Gas Price란 가스당 지불하려고 하는 이더의 양을 의미하며, Gwei단위를 사용하고 Gas Limit란 송신자가 지불하고자 하는 가스의 최대값이다.3

위 그림과 같이 실행 연산마다 Gas를 EVM에서는 부과하고 사용하지 않은 가스는 환불 받지만, 만약 Gas가 부족할 경우, 트랜잭션은 실행 중지가 되며, 실패한 트랜잭션에 대한 기록이 남기고, EVM은 연산을 이미 수행했기 때문에 Gas를 환불하지 않는다.

4

이 과정에서 채굴자는 이 Gas라는 수수료(보상)를 받으며, 따라서 송신자가 지불하고자 하는 가스 가격이 높을수록, 실제 연산에 드는 가스의 양이 많을 수록 많은 보상을 받을 수 있기 때문에 수수료가 높을수록 트랜잭션이 빨리 처리된다.

스토리지 수수료

EVM 동작과정에서 연산뿐만 아니라 스토리지를 사용할 때도 수수료를 내야 한다.

스토리지의 최종 수수료는 32바이트 단위에 비례하며, 스토리지 수수료는 일반적인 수수료와 다르게 이더리움의 상태 DB의 크기를 줄이기 위해 최대한 적게 유지할수록 인센티브를 부여한다.

이러한 이유로 만약 트랜잭션이 스토리지에 있는 특정 요소를 지우는 연산을 하면, 해당 연산을 수행하는 데에 대한 수수료는 면제하고, 저장 공간을 확보했기 때문에 기존에 요소를 스토리지에 추가했을 때 지불했던 가스를 환불받는다.

수수료를 지불하는 이유

이더리움은 튜링 완전 언어이기 때문에 반복문을 지원한다.

그러나 반복문은 무한 루프 문제가 일어날 수 있고, 이는 네트워크에 부하를 줄 수 있다.

따라서 수수료는 악의적인 공격으로부터 네트워크를 보호하기 위해 생겨났으며, 만약 의도치 않은 무한 루프 코드를 실행시키더라도 Gas Limit을 설정해두면 지정해둔 가스를 다 소모하기 전에 실행을 멈출 수 있다.

EVM 특징

  • 임시 저장소와 영구 저장소를 구분하여 임시 저장소에 저장된 값은 해당 인스턴스 안에서만 유효하고, 영구 저장소에 저장된 값은 해당 컨트랙트 전체에 유효하다.
  • EVM에서 바이트 코드를 실행하기 위해 스택, 메모리, 저장소가 있어야 하며, 저장소로는 LevelDB를 사용한다.
  • 4바이트와 8바이트 워드는 크기가 너무 작아 비효율적이라서 32바이트 워드를 지원한다.
  • 별도의 Opcode를 제공한다.
    • 모든 Opcode는 1바이트(2개의 16진수 문자)로 할당되고, 1바이트가 나타내는 의미는 다음 레퍼런스와 같다.
  • 메모리의 크기가 가변적이다.
  • 반복 호출 횟수를 1024로 제한하여 함수 반복 호출을 통한 공격으로 성능이 저하되거나 보안 문제가 발생하는 것을 방지하였다.