[루디움 렉쳐] 이더리움 베이직_kingyoungdae 학습 내용 정리 (이더리움 가상머신 EVM)

이더리움 가상머신(EVM)

코드를 실행할 수 있도록 특정 환경이 에뮬레이트된 이더리움 가상 머신(EVM)은 월드 컴퓨터인 이더리움 프로토콜의 핵심요소라고 할 수 있다. 이번 모듈에서 이더리움의 상태와 관련하여 EVM에 대해 자세히 알아보겠다.

1. 이더리움의 상태(State)와 EVM의 관계

이더리움 네트워크 상에서 트랜잭션이 발생하면 이에 대한 신뢰 여부를 참여자들에게 묻고 과반수가 합의할 경우 해당 트랜잭션은 처리된다. 이렇게 합의된 트랜잭션은 어카운트의 상태 전이를 가져오는데, 이더리움 플랫폼의 이해를 위해 먼저 상태 전이 과정에 대해 알아야 한다.

예를 들어, A의 계좌에는 20만원이 있다. B에게 10만원을 송금하려 하고 송금에 필요한 수수료는 1만원 이다. 이런 A의 송금 요청은 은행에 전달되고, 은행은 은행 원장의 A계좌에서 10만원과 수수료 1만원을 차감한 뒤 B의 계좌에 10만원을 더한다. 그 결과, A의 계좌 잔고는 9만원으로 줄고, B의 계좌 잔고엔 10만원이 더해진다.

이렇게 다른 사람의 계좌로 송금하는 것 같이 계좌의 상태 전이(state transition) 를 유발하는 행위를 트랜잭션이라 하고, 모든 변화와 관련된 정보를 은행의 원장에 기록하게 된다.

이더리움 또한 위의 예시처럼 상태 전이 과정을 기반으로 작동한다. 특정 시점의 현재 상태(S)가 상태 변이 함수(Y())에 의해 다른 상태(S’)로 전이되는 것을 말한다.

복사
Y(S, T)= S'

어카운트(account)는 이더리움에서 실행 주체이자 기본 단위로, 중복되지 않는 식별자로 특정 주소를 부여 받는다. 잔액이나 트랜잭션, 데이터 저장을 위한 저장공간을 가지고 있는데 이러한 모든 것을 어카운트 상태(state) 라고 하고, 이더리움의 전체 상태는 전체 어카운트의 상태를 말한다고 할 수 있다.

어카운트는 상태 변이 함수에 의해 전이된다. 상태 변이 함수는 송금같은 트랜잭션이 될 수도 있고, 스마트 컨트랙트가 될 수도 있다. 어카운트의 특정 시점의 한 상태는 단일 상태(single state) 로만 전이되는데, 만약 여러개의 상태로 전이된다면 사람들은 어떤 상태가 맞는지 합의할 수 없게 된다. 블록체인은 이런 변이 과정에 관련된 트랜잭션과 정보를 하나의 블록으로 구성하여 시간순으로 연결함으로써 단일 상태를 유지한다.

이런 이더리움의 상태 전이는 바이트 코드를 실행하는 스택 기반의 가상머신인 EVM에 의해 처리된다.

2. EVM 이란?

이미지 출처 : EVM Illustrated

이더리움 가상 머신(Ethereum Virtual Machine) 은 모든 이더리움 노드에서 일관되고 안전하게 코드를 실행할 수 있게 하는 탈중앙화된 가상 환경을 말한다. 어떤 OS에서든지 독립적인 환경을 만들어 이더리움 플랫폼 위에 프로그램을 실행시킬 수 있는 환경을 제공한다.

EVM은 단일 시간(블록타임)에 처리된 모든 트랜젝션은 바이트코드(bytecode)의 형태로 인풋 데이터가 저장이되는데 EVM은 해당 바이트 코드를 다음 블록 상태로 전이, 저장하기 위한 옵코드(Opcode)를 실행하는 데이터 영역을 가진다.

3. EVM 의 구조

이미지 출처 : Cyfrin, can the EVM read and write data?

EVM은 스택, 메모리, 스토리지, 일시적 스토리지, 콜 데이터, 프로그램 카운터, 코드의 데이터 영역으로 구성된다.

  • 스택(Stack)
    옵코드 기반 연산을 수행하는 영역이다. 256비트의 단어 크기로 동작하며 최대 크기는 1024개로 제한되어 있다. 1024개를 초과한 스택을 사용하면 예외가 발생되어 계약 실행이 종료된다.
  • 메모리(Memory)
    함수 호출이나 메모리 연산처럼 프로그램의 실행을 위해 임시로 사용되는 영역이다. 휘발성으로 호출이 발생할 때 초기화되어 계약 실행에 사용된다.
  • 스토리지(Storage)
    블록체인에 영구적으로 기록하기 위한 저장 공간이다. 이더리움의 모든 어카운트는 별도의 스토리지를 독자적으로 보유하고 있으며, 다른 어카운트의 스토리지에서 데이터를 읽어오거나 기록할 수 없다.
  • 콜 데이터(Call Data)
    트랜잭션을 요청했을 때 전송되는 데이터들의 기록 공간이다. 메모리와 동일한 방식으로 배치되고 동작한다.
  • 일시적 스토리지(Transient Storage)
    EIP-1153 업데이트에 따라 추가된 일시적 데이터 기록 공간으로 스토리지처럼 동작하지만 메모리처럼 트랜잭션이 끝나면 휘발된다. 스토리지의 가비스 비효율성으로 인한 재진입공격(Re-entrancy Guard) 방지와 같은 목적으로 제안, 도입되었다.
  • 프로그램 카운터(Program Counter)
    EVM에서 다음에 실행되어야 하는 프로그램의 번호를 표시한다. 이를 통해 스택과 메모리에서 다음 순서(Call next)를 정한다.
  • 코드(Code)
    EVM이 실행할 스마트 컨트랙트의 EVM명령어 목록을 보관할 때 사용된다.

데이터 구조를 정리한 표는 다음과 같다.

데이터 구조임시성수정 가능성삭제 시기데이터 크기

스토리지 아니오 영구 SSTORE당 32 바이트, 무제한
메모리 콜 콘텍스트 혹은 트랜잭션 종료시 MSTORE당 32 바이트, 무제한
스택 콜 콘텍스트 혹은 트랜잭션 종료시 슬롯(slot)당 32 바이트, 최대 1024개
일시적 스토리지 트랜잭션 종료시 TSTORE당 32 바이트, 무제한
콜 데이터 아니오 콜 콘텍스트 혹은 트랜잭션 종료시 무제한
코드 아니오 아니오 영구 EVM 실행별 컨트랙트 용량 제한에 따라 상이

4. EVM 의 실행

이더리움 스마트 컨트랙트는 주로 솔리디티(Solidity) 라는 언어로 작성된다. 작성된 코드는 컴파일러를 통해 기계가 이해할 수 있는 바이트 코드(Bytecode) 로 컴파일되고, 바이트코드는 수행할 명령어를 나타내는 부호인 연산코드(Opcode) 에 매칭되어 실행된다.

이미지 출처 : Cypherpunks Ethereum Book

위의 다이어그램을 통해 EVM의 아키텍처와 실행 흐름을 살펴볼 수 있다. 트랜잭션 호출자(caller)가 트랜잭션을 전송하면 EVM에서 실행을 위해 입력(input)트랜잭션을 수신하고 저장소를 업데이트 하는 동시에 스택에 인수를 저장한다. 그런 다음 스택과 스마트 컨트랙트의 바이트코드가 EVM에 실행되어 opcode를 통해 가스비(수수료)가 책정된다.

프로그래밍 언어 중 어떤 종류의 프로그램이라도 실행할 수 있다면 그 언어는 튜링 완전한 언어라고 부른다. 튜링 완전함에는 주의사항이 있는데 일부 프로그램이 영원이 실행될 수 있다는 점이다. 중요한 건 이 프로그램이 영원히 실행될지 정상 수행되어 종료될지 판별할 수 없다는 것이다. 프로그램이 실행되면 결과가 어떻게 될지 기다려야 하는데 만약 영원히 실행된다면 계속 기다려야 한다. 이것을 정지 문제(halting problem) 라고 부르며 이더리움의 큰 문제가 될 수 있다.

이처럼 네트워크에 무한 루프를 실행하는 코드가 사고에 의해서든 악의에 의해서든 실행된다면, 단일 스레드 머신처럼 동작하는 이더리움의 전체 네트워크를 사용할 수 없게 된다. 이러한 문제가 발생되지 않도록 이더리움은 가스(gas) 를 도입하여 해결하였다.

EVM은 스마트 컨트랙트가 EVM명령어를 실행하거나 데이터 저장 공간을 소비할 때마다 가스를 지급하도록 설계되어 있다. 미리 지정된 최대 계산량을 수행한 후에 실행이 종료되지 않으면 EVM에 의해 중단된다.

스마트 컨트랙트를 실행하는 트랜잭션을 요청할 때, 트랜잭션이 사용할 최대 가스량을 사용자가 지정하면, EVM은 스마트 컨트랙트의 EVM명령어를 실행할 때마다 가스를 차감해 나간다. 실행하다 가스가 0이 되면(run out of gas) 가스 없음(out of gas)으로 예외가 발생하여 작업이 종료된다.

5. 느낀점

이더리움 가상 머신(EVM)의 구조와 작동 방식이 매우 흥미로웠습니다. EVM이 트랜잭션을 처리하며 상태 전이를 관리하는 방식은 블록체인의 신뢰성과 효율성을 높이는 데 중요한 역할을 한다는 점이 인상적이고 또한, 가스를 통해 무한 루프 문제를 해결하는 접근 방식은 EVM의 안정성을 보장하는 핵심 요소라 생각합니다.