이더리움과 EVM

FeelSoo·2022년 8월 2일
1
post-thumbnail

이더리움은 블록체인 기술을 활용해 단순 암호화폐 거래를 하는 것에 그치지 않

고 누구든지 Dapp을 개발할 수 있는 환경을 제공한다.


개발자들이 Dapp을 만들 수 있도록 Solidity 라는 프로그래밍 언어를

제공하였으며, 이더리움 네트워크에 올라간 솔리디티 코드는 EVM

( Ethereum Virtual Machine )을 통해 실행된다.


즉, 비트코인과의 가장 큰 대조점은 해당 메인넷을 기반으로 하는 Dapp 개발

가능 여부이다. 비트코인 같은 경우 암호화폐 거래만 가능한 반면 이더리움은

둘 다 가능하다.


그렇다면 Virtual Machine은 무엇일까?

쉽게 말하면 말 그대로 가상머신, 가짜 컴퓨터이다.

우리가 짠 코드가 Mac OS, Windows OS, Linux OS 등 운영체제마다

다르게 동작하면 어떻게 될까?

각 운영체제에 맞게 코드를 수정해야 할 것이고, 이러한 작업은 너무 번거로울

것이다.

Virtual Machine은 OS 혹은 하드웨어 스펙과 종류에 관계없이 동일한 코드

동작을 실행하게 만들어주는 Software이다.


EVM, Ethereum Virtual Machine은 이더리움 가상 머신, 즉 이더리움

코드를 어떤 하드웨어에서든지 동일하게 실행시킬 수 있는 환경을 제공한다.

이더리움의 각 노드는 EVM을 포함하고 있다. 이 말은 즉슨, 모든 이더리움 네

트워크 참여자의 컴퓨터는 EVM을 갖게 된다.

위에서 언급했듯이 Dapp은 Solidity라는 프로그래밍 언어로 작성되고,

솔리디티로 작성된 Dapp을 이더리움 네트워크에 배포해야 한다.

하지만 솔리디티는 고급 언어이기에 EVM ( 컴퓨터 ) 이 이해하기 어렵다.

때문에 solc를 이용해 컴파일하여 EVM이 읽을 수 있는 바이트코드 형태로 만든

후 이 바이트코드를 Geth를 이용해 이더리움 네트워크에 배포한다.

블록체인에 저장된 바이트코드 형태의 Dapp은 EVM에서 실행하게 되며, EVM에서

바이트코드를 Opcode로 변환하여 실행된다.

즉,

솔리디티 코드 작성 > ByteCode ( from Compile) > Opcode 흐름이다.

다음으로 EVM의 내부 동작 구조를 확인해보자.


상태머신

이더리움 블록체인은 거래에 기반을 둔 상태 머신 ( Transaction-Based State Machine ) 이다.

https://ethereum.org/en/developers/docs/evm/

상태 머신이란 일련의 입력 ( 트랜잭션 ) 을 읽고, 그 입력을 기반으로 새로운 상태로 전환하는 것을 의미한다.

Genesis State에서 시작하여 트랜잭션이 실행되면, 다음 상태로 전환, 더이상 트랜잭션이 들어오지 않은 마지막 상태가 바로 이더리움 블록의 현재 상태이다.

이더리움 블록에는 수천 개의 트랜잭션이 담겨있고 이 블록은 직전에 생성된 블록과 이어져있다.



EOA와 CA

이더리움에는 EOA(External Owned Account)와 CA(Contract Account)라는 두 종류의 계정이 있다.

두 계정 모두 주소로 식별되며, 동일한 크기의 주소 공간을 가진다.

EVM은 이 160bit 길이의 주소들을 처리한다.


EOA와 CA 모두 잔액(Balance), 논스(Nonce), 스토리지(Storage), 컨트랙트 코드(Contract Code)로 구성되어 있다.

  • Balance: 계정의 현재 이더 잔고

  • Nonce: EOA의 경우, 해당 EOA로부터 보내진 트랜잭션의 숫자. CA의 경우, 해당 CA로부터 생성된 컨트랙트의 숫자를 의미함

  • StorageRoot: 머클 패트리샤 트리의 루트 노드를 해싱한 값

  • Contract Code: EVM이 실행할 코드의 해싱된 값. EOA에는 코드를 저장할 수 없기 때문에 비어있다.


    EOA의 주소는 상응하는 Private Key를 가지고 있지만, CA는 Private Key가 없다.

또한 CA는 스스로 새로운 트랜잭션을 만들 수 없으며, CA는 EOA나 다른 CA에게서 받은 트랜잭션에 대한 응답에 대해서만 트랜잭션을 만들 수 있다.

따라서 이더리움 블록체인에서 일어나는 모든 액션은 항상 EOA에서 만든 트랜잭션에서부터 시작된다.


전역 상태

이더리움의 전역 상태는 계정 주소와 계정 상태를 매핑한 것으로 구성되어 있다.

이 매핑은 머클 패트리샤 트리 ( Merkle Patricia Tree ) 형태로 저장되어 있다.

머클 트리는 이진 트리의 한 종류로 다음의 특징을 갖고 있다.

  • 트리 맨 아래에 있는 노드들은 데이터를 가지고 있다.

  • 부모 노드는 두 자식 노드를 모아 해싱한 값을 가진다. 맨 위의 루트 노드도 자식 노드의 해싱한 값이다.

트리 맨 아레에 있는 데이터는 저장하려는 데이터를 청크(Chunk)로 분할한 다음, 각 청크를 두개씩 모아 해시를 취하여 부모 노드를 만든다.

그렇게 하나의 루트 노드가 만들어질때까지 동일한 과정을 반복한다.


이더리움의 블록 헤더에는 세 개의 머클 트리 구조의 루트 노드의 해시값이 저장되어 있다.

  1. 상태 트리(State Tree): 트랜잭션과 연관된 계정의 상태 정보 저장

  2. 트랜잭션 트리(Transaction Tree): 현재 블록의 트랜잭션 정보 저장

  3. 영수증 트리(Receipt Tree): 현재 블록의 거래 영수증 정보 저장

부모 노드는 자식 노드의 해싱 값이기에 단방향 함수인 해시의 특성상 자식 노드의 값이 조금이라도 바뀌면 부모 노드의 값도 바뀐다.

따라서 머클 패트리샤 트리에서 변조가 시도되면 그 즉시 발견된다.

따라서 루트 노드는 데이터에 대한 보안 ID처럼 사용될 수 있다.

또한 블록 헤더는 상태, 트랜잭션, 영수증 트리의 루트 노드 값을 가지고 있기 때문에 네트워크의 노드들은 모든 상태를 저장하고 있지 않더라도
이더리움의 상태 일부분을 검증할 수 있다.



트랜잭션과 메시지

우리는 이더리움이 트랜잭션 기반 상태 머신이라는 것을 알게 되었다. 다시 말해, 이더리움의 전역 상태를 하나의 상태에서 다음 상태로 이동시킨다는 것이다.

기본적으로 트랜잭션은 EOA에서 생성되고, 일련의 과정을 거쳐 블록체인에 올라간 암호화 서명된 명령어의 집합이다.

그 외의 트랜잭션은 메시지 호출(Message Call)과 컨트랙트 생성(Contract Creations) 두 종류로 나뉜다.

이더리움의 모든 트랜잭션은 항상 EOA에서 만들어지고 블록체인에 올라간다.
즉, 트랜잭션은 외부 세계를 이더리움 내부의 상태로 연결해주는 다리와 같다.

그리고 연결의 창구가 바로 CA라고 할 수 있다.

그렇다고 해서 CA가 다른 CA와 전혀 연관 없다는 것은 아니다. 이더리움 전역 상태에 있는 CA는 메시지나 내부 트랜잭션을 통해 다른 CA와 상호작용 할 수 있다.

메시지와 내부 트랜잭션은 일반적인 트랜잭션과 비슷하지만, EOA에서 생성되지 않으며, 오로지 CA에게서만 생성된다.

또한 일반적인 트랜잭션과는 다르게, 메시지와 내부 트랜잭션은 EVM에만 존재하는 가상 객체이다.

한 CA가 다른 CA에 내부 트랜잭션을 보내면, 수신하는 CA에 있는 관련 코드가 실행된다.



CA 생성

트랜잭션의 두 종류 중 컨트랙트 생성(Contract-Creating) 트랜잭션을 알아보자.

새로운 CA를 만들기 위해서는 먼저 특별한 공식을 이용해 새로운 계정의 주소를 정의해야 한다. 그리고 다음의 과정을 통해 새로운 CA를 만들 수 있다.

  • 논스를 0으로 설정한다.
  • 송신자가 CA 생성 트랜잭션에 이더를 함께 보낸 경우, 이를 CA의 잔금(Balance)으로 설정한다.
  • 잔금에서 Value 만큼을 제외한다.
  • CA의 스토리지를 빈 값으로 초기화한다.
  • CA의 코드를 빈 문자열의 해시값으로 초기화한다.

한번 계정을 초기화하고 나면, 트랜잭션에서 보낸 init 코드를 사용해 새로운 CA를 생성할 수 있다.

이 init 코드가 실행되는 동안에는 다양한 일이 발생한다.

계약 생성자에 따라 CA의 스토리지를 업데이트하거나, 다른 CA를 새롭게 생성하거나, 다른 메시지 호출을 만들 수 있다.




계약을 초기화하는 이 init 코드를 실행할 때는 가스를 사용한다.

트랜잭션은 남아있는 가스보다 더 많은 가스를 소비할 수 없기 때문에, 만약 남아있는 가스를 다 사용한 경우 OOG(Out-of-Gas) 예외처리와 함께 코드 실행이 종료된다.

OOG로 인한 트랜잭션 종료가 발생하면 상태는 트랜잭션 실행 이전 상태로 돌아간다.




이더리움에서는 트랜잭션에 있는 연산을 수행할 때마다 비용을 청구하는데, 이 비용의 단위를 가스(Gas)라고 한다.

트랜잭션을 보낼 때는 코드에 수행되는 만큼의 가스를 함께 보내야 한다.




트랜잭션이 실패해도 트랜잭션 송신자는 소진된 가스를 환불받을 수 없다.
그러나 송신자가 트랜잭션과 함께 이더 값을 보낸 경우, 이더는 환불된다.




init 코드가 성공적으로 실행되면, 마지막으로 CA 코드에 대한 비용이 지불된다.

이 비용은 스토리지 비용이며, 생성된 CA 코드의 크기에 비례한다.

만약 CA 코드에 대한 비용을 지불할 가스가 남아있지 않은 경우, 트랜잭션은 OOG 예외와 함께 중단된다.

예외 없이 트랜잭션 생성이 완료된 경우, 미사용된 가스는 송신자에게 환불되고, 변경된 상태가 저장된다.



메시지 호출(Message Call)

메시지 호출을 실행하는 것은 CA 생성과 비슷하지만, 몇가지 다른 점이 있다.

새 계정이 생성되지 않기 때문에 메시지 호출 실행에는 init 코드가 포함되지 않는다.

그러나 입력 데이터를 가지고 있을 수는 있다.

메시지 호출은 한번 실행되면 출력 데이터를 포함한 추가적인 요소들을 가지게 될 수도 있는데, 이 추가 요소들은 뒤에 이어질 다른 실행에 필요한 데이터이다.

CA 생성과 마찬가지로, 메시지 호출을 실행할 때 가스가 부족하거나, 트랜잭션이 잘못되어 종료되는 경우(예를 들어, 스택 오버플로우가 발생하거나, jump 실행의 결과가 올바르지 않거나, 잘못된 명령어를 사용하는 경우) 사용된 가스는 환불되지 않는다.

남은 가스는 모두 소비되며, 상태는 직전 상태로 돌아간다.



트랜잭션 실행 모델과 EVM

트랜잭션 처리를 실제로 처리하는 프로토콜은 EVM입니다. EVM의 구성 요소를 하나씩 살펴보자.

  • 스택
    EVM은 비트코인 스크립트와 마찬가지로, 스택 기반 아키텍쳐를 가지고 있다. EVM 내에는 하나의 빈 스택이 있으며, 스택에 들어가는 요소의 크기는 256bit이며, 스택의 최대 크기는 1024bit이다.

  • 메모리
    EVM은 메모리를 가지고 있으며, 메모리에서는 Word-Address 형식의 바이트 배열로 데이터를 저장한다. 메모리는 휘발성이기 때문에, 프로그램이 종료되면 메모리에 들어있는 데이터는 사라진다.

  • 스토리지
    메모리와 다르게, 스토리지는 비휘발성이며 시스템 상태에 따라 유지된다. EVM은 특정한 명령어로만 접근할 수 있는 가상 ROM이라는 공간에 프로그램 코드를 분리해서 저장해둔다.

EVM이 솔리디티 코드를 컴파일한 바이트코드를 받으면 실행이 시작된다.

맨 처음에는 메모리와 스택은 비어있으며, 프로그램 카운터(연산 실행 횟수)는 0 이다.

PC(Program Counter): 0
Stack: []
Memory: []
Storage: {}

EVM은 트랜잭션을 반복적으로 실행하며, 각 사이클에서 시스템 상태(이더리움의 전역 상태)와 머신 상태(Machine State)를 계산한다.

머신 상태는 다음과 같이 구성된다.

  • 사용 가능한 가스
  • 프로그램 카운터
  • 메모리에 들어있는 값
  • 메모리에서 활성화된 단어의 수
  • 스택에 들어있는 값

코드가 실행되면서 스택에 있는 요소들은 왼쪽에서부터 순서대로 추가되거나 제거되며, 남은 가스에서 적절한 양의 가스가 제거되고, 프로그램 카운터가 올라간다.

매 사이클이 끝날 때 다음과 같은 세가지 케이스가 발생할 수 있다.

  1. EVM이 예외 상황을 만나 중지되고, 변경사항은 폐기된다.
    ( 가스 부족, 명령어가 잘못된 경우, 스택에 잘못된 요소가 들어간 경우,
    스택에 있는 요소가 1024 bit를 넘는 경우 등 )

  2. 다음 사이클을 돌아야 하는 경우

  3. 머신이 프로세스 실행을 끝낸 경우


머신이 정상적으로 실행을 마치면, 결과적으로 발생한 상태와 남아있는 가스, 발생한 세부 상태, 결과값을 생성한다.
profile
세상은 넓고 배울건 많다

0개의 댓글