無知

갈 길이 먼 공부 일기

기술 공부/블록체인

스마트 컨트랙트 (4-1) | 컨트랙트, 이더리움 가상머신

moozii 2022. 4. 12. 23:03

@Diagram adapted from Ethereum EVM illustrated https://ethereum.org/static/e8aca8381c7b3b40c44bf8882d4ab930/302a4/evm.png

 

1. 이더리움 스마트 컨트랙트의 개념

1-1. 계정

1-1-1. 계정의 종류 : 외부 소유 계정(EOA)와 계약 계정(Contract Account)가 존재한다.

 

1-1-2. EOA, 외부 소유 계정

- 일반적으로 사용자에 의해 관리된다. (사용자가 가지는 지갑으로 생각하면 된다)

- 프라이빗 키에 의해 관리된다. 

- EOA 계정이 스마트 컨트랙트와 통신하는 방법은 2가지.

(1) 신규 컨트랙트를 생성

(2) 이미 생성된 컨트랙트에 메시지를 전송

 

 

1-1-3. 계약 계정, 컨트랙트 어카운트

- 사용자가 아닌, 이더리움 가상 머신 위에서 동작하는 프로그램에 의해 관리된다

- 프라이빗 키가 없다

 

 

 

 

1-2. 개념

1-2-1. 닉자보가 스마트 컨트랙트를 주장한 이유

- 프로그램화된 계약은 자동 실행이 가능해 부정을 막을 수 있다

- 분쟁 해결 비용이 없다

 

1-2-2. 이더리움 상의 스마트 컨트랙트

- 이더리움이라는 컴퓨터에서 작동하는 프로그램이다. 

- 비탈릭 부테린: "Persistent Script"로 부르는 것이 더 기획 의도에 가깝다.

- 안드레아 안토노폴로스, 개빈 우드: "Immutable Computer Program"이다.

 

1-2-3. 스마트 컨트랙트의 특징

1-2-3-1. Immutable, 변경 불가능하다.

한번 배포되면 코드 변경이 불가능하다. 변경 후 새로이 배포하면 새로운 주소를 갖는 새로운 컨트랙트이다. 따라서 업그레이드나 디버깅 등이 어려운 코드이다.

 

1-2-3-2. Deterministic, 결정성을 가진다.

동일한 상태에서 시작하면 동일한 결과를 가진다. 실행 주체, 실행되는 노드와 무관하다.

 

 

 

 

1-3. 스마트 컨트랙트의 작동 방법

1-3-1. 고수준 언어로 컨트랙트가 작성됨 (i.e. Solidity)

1-3-2. 작성된 컨트랙트가 바이트코드로 컴파일됨.

 

1-3-3. 컴파일된 바이트코드가 이더리움으로 디플로이됨.

(Contract Creation Transaction) 이 트랜잭션에서 앞서 컴파일한 바이트코드를 전달함.

 

1-3-4. 이더리움 내에 컨트랙트로 생성이 됨.

(Contract Creation Transaction을 생성한 EOA 계정과 트랜잭션 순서를 표시하는 논스 값, 총 2가지로 구성됨.)

 

1-3-5. 이더리움 가상 머신 위에서 컨트랙트가 실행됨.

컨트랙트는 immutable하므로 변경되지 않음.

 

1-3-5-1. 컨트랙트 실행 조건

(1) EOA가 컨트랙트를 호출해서 실행

(2) 이미 실행된 컨트랙트가 호출해서 실행

즉, 컨트랙트는 스스로 실행될 수 없음.

 

1-3-6. 컨트렉트가 삭제됨. 

- 컨트랙트의 삭제는 해당 주소 내 프로그램과 상태 정보의 삭제임. 

- 그러나 해당 계정과 관련된 기록은 그대로 블록체인에 보존됨. 

 

 

 

 

1-4. 컨트랙트의 컴파일 결과

1-4-1. 바이트코드

object 항목이 이더리움으로 deploy되는 16진수 바이트코드이다.

 

1-4-2. ABI, Application Binary Interface

컨트랙트의 메소드가 어떤 arg를 받고 어떤 return 값을 반환하는지 정의한다.

컨트랙트 호출 시 인코딩 혹은 데이터 디코딩에 사용한다.

 

 

 

 

1-5. Remix Web IDE

앞선 스마트 컨트랙트 관련 내용을 직접 실습할 수 있는 IDE.

솔리디티 에디터 및 컴파일, 실행 등이 가능하다.

 

https://remix-project.org/

 

Remix - Ethereum IDE & community

DEPLOY & RUN TRANSACTIONS IN THE CLOUD

remix-project.org

 

https://remix.ethereum.org/

 

Remix - Ethereum IDE

 

remix.ethereum.org

 

 

 

 

 

 

2. EVM, 이더리움 가상머신

2-1. 개념

2-1-1. 정의 : 이더리움 바이트코드가 디플로이되고 실행되는 컴퓨테이션 엔진

- 이더리움 노드 내부에 실행되는 가상 머신

- 노드 들 간 Peer-to-Peer 방식으로 연결되어 독립적으로 실행되는 가상머신

- 독립 실행을 통해 효율성 대신 탈중앙화된 방식으로 위변조 방지 합의를 진행 

 

2-1-2. 속성

(1) Turing Complete하다, 튜링완전하다

- 계산 가능한 모든 문제를 풀 수 있다

- 어떤 프로그램도 실행 가능하다

 

(2) 유사-튜링완전하다

- 가스의 한도 안에서만 실행된다

- 무한히 실행되지 않는다

- 무한 동작 프로그램을 방지한다

 

(3) 스택 기반 구조를 가진다

- 메모리 상의 값이 스택에 저장된다.

 

(4) State-Machine, 상태 기계다

- 컨트랙트 코드를 실행해 이더리움 상태를 변경해 나간다

- EOA가 실행하는 트랜잭션으로 시작되는 Transaction-based state machine이다.

 

 

 

 

2-2. 구조

2-2-1. 개요

스택, 메모리, 스토리지, 프로그램 코드로 구성된다.

 

2-2-2. 스택

- 메모리 상의 값들이 저장되는 공간

 

2-2-3. 메모리

- 비영구적인 임시 값들이 저장되는 공간.

- 바이트 어레이로 구성된다.

 

2-2-4. 스토리지

- 이더리움의 상태를 저장하는 공간.

- 워드 어레이 형태로 구성되는 공간. 

- 비휘발성으로 일반 컴퓨터 하드디스크와 같다.

 

2-2-5. 프로그램 코드 영역

- 컨트랙트 코드를 저장하는 공간.

 

 

 

 

2-3. EVM 상태

2-3-1. 개요 

- 이더리움 상태는 World State와 Account State으로 구분된다.

 

2-3-2. 월드 상태, World State

- 이더리움 주소와 어카운트(계정)을 매핑한 상태.

- 새로운 어카운트가 생성되면 월드 상태가 변경된다.

 

2-3-3. 계정 상태, Account State

- 어카운트의 잔고(balance), 논스, 스토리지, 컨트랙트 코드 등 정보를 가진다.

- 프로그램 코드(컨트랙트 코드)는 immutable, 변경 불가능하다.

 

 

 

 

2-4. EVM 코드

2-4-1. 고수준 언어 코드

- 개발자가 작성한 코드. Solidity 등을 기반으로 한다.

 

2-4-2. EVM Instruction Set

- 이더리움 가상머신이 이해하는 명령어

- 고수준 언어 코드를 컴파일한 바이트코드 Instruction Set

Here given are the various exceptions to the state transition rules given in section 9 specified for each instruction, together with the additional instruction-specific definitions of J and C. For each instruction, also specified is α, the additional items placed on the stack and δ, the items removed from stack, as defined in section 9.

0s: Stop and Arithmetic Operations
10s: Comparison & Bitwise Logic Operations
20s: KECCAK256
30s: Environmental Information
40s: Block Information
50s: Stack, Memory, Storage and Flow Operations
60s & 70s: Push Operations
80s: Duplication Operation
90s: Exchange Operation
a0s: Logging Operations
f0s: System operations

[ETHEREUM: A SECURE DECENTRALISED GENERALISED TRANSACTION LEDGER]
BERLIN VERSION 934279c – 2022-04-07
DR. GAVIN WOOD
https://ethereum.github.io/yellowpaper/paper.pdf 

 

 

 

 

2-5. EVM의 실행

2-5-1. EOA의 스마트 컨트랙트 실행

- EOA가 컨트랙트를 생성하며 보내는 바이트코드를, deployment bytecode라 부른다

- deployment bytecode 코드의 실행 결과 = 새로 생성된 컨트랙트의 코드

 

2-5-2. EVM의 생성

2-5-3. EVM 내 프로그램 코드 영역에 컨트랙트 코드를 로드

2-5-4. EVM 내 스토리지에 어카운트 데이터를 저장

2-5-5. EVM 환경 변수로 Gas Supply를 설정

 

2-5-6. EVM 메모리 및 스택 기반 코드 실행

2-5-6-1. 코드 실행과 함께 가스 부족 여부를 확인

 

2-5-7-A. 가스가 부족한 경우

2-5-7-A-1. 코드 실행 중단. 트랜잭션 및 변경 정보 버림.

 

2-5-7-B. 가스가 충분한 경우

2-5-7-B-1. 코드 실행 성공

 

2-5-7-B-2. 코드 실행 결과를 이더리움 상태로 저장.

(1) 실행 결과 신규 어카운트 생성 시 월드 상태 매핑에 추가

(2) 실행 결과 개별 어카운트 상태를 업데이트

 

 

 

 

2-6. 바이트코드로의 컴파일 과정

#Initiation Code : 새로운 컨트랙트를 만드는 초기화 부분
PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT
JUMPDEST POP PUSH1 0xE6 DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID 

# Runtime Bytecode : 컨트랙트 코드로 저장되었다 호출시 실행되는 부분
PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x43 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29
0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV DUP1 PUSH4 0x60FE47B1 EQ
PUSH1 0x48 JUMPI DUP1 PUSH4 0x6D4CE63C EQ PUSH1 0x7F JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT
JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x53 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x7D
PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH1 0x68 JUMPI PUSH1 0x0 DUP1 REVERT
JUMPDEST DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP
POP POP PUSH1 0xA7 JUMP JUMPDEST STOP JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x8A JUMPI PUSH1 0x0
DUP1 REVERT JUMPDEST POP

 

위의 바이트 코드 중 런타임 바이트코드의 실행 과정을 살펴보자.

# 런타임 바이트코드의 첫 부분인 Dispatcher
PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x43 JUMPI 

>>> PUSH1 = 뒤에 오는 1바이트를 스택에 넣기
>>> PUSH1 0x80 = 0x80을 스택에 추가
>>> PUSH1 0x40 = 0x40을 스택에 추가
>>> MSTORE = Memory Store. 스택 내 두 값을 읽어 메모리에 저장.
>>> MSTORE with Stack [0x40, 0x80] = 메모리 0x40 주소에 0x80을 저장.

>>> PUSH1 0x40 = 0x40을 스택에 추가
>>> CALLDATASIZE : 현재 트랜잭션 데이터 크기를 구해 스택에 저장
>>> LT = Less-than. 스택 내 맨 위 값이 다음 값보다 작은지 비교.
>>> LT with Stack [Data_Size, 0x40] : 데이터 크기가 4보다 작은가 : 0 혹은 1을 스택에 저장
>>> 메소드 호출 시 메소드 해시 값이 앞 4바이트를 사용하므로 4보다 작으면 메소드 호출이 아님

>>> PUSH1 0x43 = 0x43을 스택에 추가
>>> JUMPI = Jump If. 조건에 따라 주어진 주소로 이동.
>>> 스택 값이 1일 경우(LT=True), 43번지로 이동
>>> 스택 값이 0일 경우(LT=False), 명령 무시하고 넘어감

>>> 43번지로 이동했을 경우 JUMPDEST PUSH1 0x0 DUP1 REVERT
>>> Revert 명령을 통해 트랜잭션 중단

>>> 넘어갔을 경우 아래를 실행

# 여기까지가 Dispatcher 끝



PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 
>>> PUSH1 0x0 = 0x0을 스택에 추가
>>> CALLDATASIZE : 현재 트랜잭션 데이터 크기를 읽음
>>> PUSH29 0x100000000000000000000000000000000000000000000000000000000 : 스택에 값 추가

SWAP1 DIV DUP1 PUSH4 0x60FE47B1 EQ
>>> SWAP1 : 스택 내 두 값의 위치를 변경
>>> DIV : 스택 내 두 값을 나누기 연산
>>> DIV 결과 트랜잭션 데이터 값 중 앞 4바이트를 구함
>>> DUP1 : 스택의 값을 복사해서 넣음
>>> PUSH4 0x60FE47B1 : 해당 4바이트 값을 스택에 추가
# 0x60FE47B1은 Set 메소드의 해시 값 앞 4바이트
>>> EQ : 스택 내 상위 2 값의 일치 여부 확인

PUSH1 0x48 JUMPI 
>>> PUSH1 0x48 = 0x48을 스택에 추가
>>> JUMPI = Jump If. 조건에 따라 주어진 주소로 이동.
>>> 스택 값이 1일 경우(EQ=True), 48번지로 이동
>>> 스택 값이 0일 경우(EQ=False), 명령 무시하고 넘어감

>>> 48번지로 이동했을 경우 JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x53 JUMPI
>>> 넘어갔을 경우 DUP1 PUSH4 0x6D4CE63C EQ PUSH1 0x7F JUMPI

...TO_BE_CONTINUED

 

 

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

 

Home | ethereum.org

Ethereum is a global, decentralized platform for money and new kinds of applications. On Ethereum, you can write code that controls money, and build applications accessible anywhere in the world.

ethereum.org