⚙️챕터 5

5장 · EVM과 Gas

스마트 컨트랙트가 생겼다. 코드를 블록체인에 올리고, 수천 개의 노드가 실행한다. 그런데 문제가 하나 있었다. 노드마다 OS가 달랐다. 리눅스, 윈도우, Mac. 같은 코드도 결과가 달라질 수 있다. 수천 개의 노드가 서로 다른 결과를 갖고 어떻게 합의하나?

이 챕터의 질문

서로 다른 수천 대의 컴퓨터에서, 어디서 실행해도 똑같은 결과를 내려면 어떻게 해야 할까?

EVM: OS 위에 올라가는 표준 번역기

해결책은 OS와 코드 사이에 표준 레이어를 하나 끼워 넣는 거예요.

EVM(Ethereum Virtual Machine) 은 OS 위에 올라가는 얇은 가상 컴퓨터예요. 스마트 컨트랙트 코드는 EVM 위에서만 실행돼요. EVM 내부 동작이 완전히 규격화되어 있어서, 어떤 OS에서 EVM을 돌리든 입력이 같으면 출력이 반드시 같아요.

같은 바이트코드6001600201 (1+2)EVM완전히 규격화된 실행Linux결과: 3EVM완전히 규격화된 실행Windows결과: 3EVM완전히 규격화된 실행macOS결과: 3수천 개의 노드가 같은 결과를 갖는다 → 합의가 가능해진다
EVM: OS와 코드 사이의 표준 레이어. 입력이 같으면 어디서든 출력이 같다

EVM 내부 구조: 휘발성과 비휘발성

EVM이 코드를 실행하는 동안 쓰는 메모리는 두 종류예요. 계산할 때 잠깐 쓰고 버리는 것과, 블록체인에 영구적으로 남는 것이에요.

휘발성: 실행 중에만 존재

  • Stack: 계산기 화면이에요. 1+2=3을 계산할 때 1, 2를 올려놓고 ADD 연산하면 3이 나오는 공간. 트랜잭션이 끝나면 사라져요.
  • Calldata: 함수를 호출할 때 넘겨주는 인자값을 잠깐 보관하는 곳이에요.
  • Memory: 실행 중 중간 결과를 임시로 저장하는 공간이에요.

비휘발성: 블록체인에 영구 저장

  • Storage: 컨트랙트의 상태가 저장되는 곳이에요. ERC-20 토큰에서 "철수 잔액 100"이라는 정보가 여기 있어요. 트랜잭션이 끝나도 남아 있어요.
  • Code: 배포된 컨트랙트의 바이트코드가 저장되는 곳이에요. 한 번 배포하면 변경 불가예요.
EVM휘발성: 실행 중에만 존재Stack계산기 화면Calldata함수 인자Memory임시 저장트랜잭션이 끝나면 사라진다 → 저렴 (3 Gas)비휘발성: 블록체인에 영구 저장Storage컨트랙트 상태 (잔액 등)Code배포된 바이트코드모든 노드가 영원히 보관 → 비쌈 (20,000 Gas)잠깐 쓰고 버리는 것 vs 전 세계 노드가 계속 들고 있어야 하는 것
EVM의 두 메모리 영역. 이 구분이 OPcode별 Gas 비용 차이의 핵심이다

코드가 실행되는 과정: OPcode

Solidity로 작성한 코드는 컴파일러를 거쳐 바이트코드가 돼요. EVM은 이 바이트코드를 OPcode 단위로 쪼개서 하나씩 실행해요.

예를 들어 1+2를 계산하는 코드는 이렇게 변환돼요.

Solidity:  1 + 2
Bytecode:  6001600201
OPcode:    PUSH1 1 → PUSH1 2 → ADD
결과:      Stack에 3이 남는다

OPcode는 ADD, PUSH, STORE 같은 기본 연산 단위예요. EVM은 이 OPcode들을 순서대로 실행해요.

Gas: 연료비이자 보호막

EVM이 생기자 새로운 위협이 등장했어요.

// 이런 코드를 배포하면?
while(true) {
    // 영원히 실행
}

무한루프를 가진 컨트랙트를 실행하면 노드가 영원히 멈춰요. 악의적인 공격자가 네트워크 전체를 마비시킬 수 있어요.

해결책이 Gas예요. 모든 OPcode 실행에 Gas 비용을 매겨요. 트랜잭션을 보낼 때 Gas 한도를 설정하고, 한도를 초과하면 실행이 강제 종료(revert)돼요. 무한루프는 Gas를 다 소모하는 순간 멈춰요.

Gas는 동시에 검증자 수수료이기도 해요. 트랜잭션을 블록에 담아주는 노드가 Gas fee를 받아요.

OPcode별 Gas 비용: 왜 이렇게 차이가 나나

왜 어떤 연산은 싸고 어떤 연산은 비쌀까요? 이유가 바로 휘발성/비휘발성 구분에 있어요. Stack 연산은 잠깐 계산하고 끝이지만, Storage에 뭔가를 쓰면 전 세계 모든 노드가 그 값을 영구적으로 저장해야 해요. 블록체인이 존재하는 한 계속 들고 있어야 하거든요. 그 부담이 Gas 비용에 반영된 거예요.

ADD덧셈3 GasPUSH스택에 값 추가3 GasMSTORE메모리(휘발성) 저장3 GasSSTOREStorage(영구) 저장20,000 Gas약 6,700배 차이 ↓휘발성 연산은 잠깐 계산하고 끝, 영구 저장은 블록체인이 존재하는 한 계속 부담
SSTORE가 ADD보다 약 6,700배 비싼 이유: 모든 노드가 그 값을 영원히 저장해야 하기 때문

Gas fee 계산

Gas fee는 Gas 사용량 × (Base Fee + Priority Fee) 로 계산돼요. Gas가 부족하면 실행이 취소(revert)되고 상태는 원래대로 돌아가요. 단, 소모된 Gas는 돌려주지 않아요. 실행을 시도한 비용이니까요.

💡 예전 자료에서 "Gas Price"를 본다면: 경매 시대의 흔적

2021년 EIP-1559 업그레이드 전에는 Gas fee = 사용량 × Gas Price 하나였고, Gas Price를 높게 부른 순서대로 처리되는 경매 방식이었어요. 혼잡할 때 수수료가 예측 불가능하게 치솟고, 필요 이상으로 과다 지불하는 문제가 커서 지금의 기본요금+팁 구조로 바뀌었어요. 오래된 블로그나 문서에서 "Gas Price를 높여라"라는 표현을 보면 이 옛 방식 이야기예요.

핵심 요약

개념역할
EVMOS 위의 표준 실행환경. 어디서나 동일한 결과 보장
OPcodeEVM이 실행하는 기본 연산 단위
휘발성 (Stack/Calldata/Memory)실행 중에만 존재. 트랜잭션 끝나면 사라짐
비휘발성 (Storage/Code)블록체인에 영구 저장
Gas연산 비용 단위. 무한루프 차단 + 검증자 수수료
Gas feeGas 사용량 × (Base Fee + Priority Fee)
revertGas 부족 시 실행 취소. 상태 원복. 소모된 Gas는 미반환

마무리

EVM 덕분에 스마트 컨트랙트를 어디서든 같은 결과로 실행할 수 있게 됐어요. 챕터 1부터 5까지, 블록체인은 하나의 문제를 풀었더니 새로운 문제가 생기고, 그걸 풀며 다음 기술이 태어나는 흐름이었어요.

다음 챕터의 질문

여기까지 배운 개념들이 실제로 돌아가고 있다는 걸 내 눈으로 직접 확인하려면?

6장에서 수조 원이 오가는 실제 컨트랙트를 Etherscan으로 직접 열어볼게요.

📚 참고자료 보기