[Bytecode] 마스터링 바이트코드 (기본편)

드림보이즈·2025년 3월 26일
0

Smart Contract

목록 보기
3/11

학습 목표 : 바이트코드 완벽한 이해

1. Bytecode 개요

스마트 컨트랙트를 블록체인에 저장한다는 말은 무엇일까?
Solidity 코드를 파일 통으로 저장한다는 건가?
맞겠냐?

Solidity를 Compile한 Bytecode가 블록체인에 저장된다.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleContract {
    uint256 public value;

    function setValue(uint256 _value) public {
        value = _value;
    }
}

함수 하나, 전역 변수 하나 있는 Solidity 코드는

6080604052348015600e575f80fd5b506101268061001c5f395ff3fe6080604052348015600e575f80fd5b50600436106030575f3560e01c80633fa4f2451460345780635524107714604e575b5f80fd5b603a6066565b60405160459190608a565b60405180910390f35b606460048036038101906060919060ca565b606b565b005b5f5481565b805f8190555050565b5f819050919050565b6084816074565b82525050565b5f602082019050609b5f830184607d565b92915050565b5f80fd5b60ac816074565b811460b5575f80fd5b50565b5f8135905060c48160a5565b92915050565b5f6020828403121560dc5760db60a1565b5b5f60e78482850160b8565b9150509291505056fea264697066735822122064edc12fe43858226151c7aed89f37fe42ffada42c00c0840130e4a21391677b64736f6c634300081a0033

이렇게 바이트코드로 컴파일 된다.

그럼 저 바이트코드는 솔리디티 코드와 동일한 의미인가?

따로 다루겠지만, EVM은 그저 수동적인 기계일 뿐이다.
중요한 것은 바이트코드다.
외부에서 트랜잭션을 통해 특정 컨트랙트의 함수를 호출하든,
함수를 실행하든, 결국 저 바이트 코드 안에 어떤 명령을 해야할지 다 나와있다.
EVM은 그저 저 바이트코드를 읽으면서 매핑되는 명령을 차례차례 수행할 뿐이다. LIke 유미르.

다시 생각해보자. EVM은 멍청하다. 모든 동작은 ByteCode가 이끌어야 한다.
즉, 저 Bytecode는 저 Solidity 코드를 의미하는 것 뿐 아니라,

"전역변수로는 value가 있고, 함수는 1개 있는데, 그 함수의 바이트코드는 x번째 부터 시작해, 그걸 저장하면 돼 ~"

일일히 다 알려줘야 한다는 것이다.

그럼 실제로 위 바이트코드를 분석해보자.

2. Bytecode 구조

바이트코드는 실제로 3파트로 구분된다.

  • Creation code
  • Runtime code
  • Metadata

2-1. Creation code

608060405234801561001057600080fd5b5061012e806100206000396000f3 //Creation Code

이 부분은 컨트랙트를 배포시에 실행되고, 저장되지 않고 사라진다.
16진수니까 2글자가 1바이트, 2글자씩 묶어서 해당하는 Opcode를 살펴보면, 대충

60 80 PUSH1 0x80 메모리 위치 0x80 푸시
60 40 PUSH1 0x40 메모리 포인터 초기화 (프리메모리 위치)
52 MSTORE 메모리에 값 저장
34 CALLVALUE 트랜잭션으로 전송된 ETH 값 확인

이런식으로 해석이 된다.
다 필요없고, 가장 중요한 건,

함수 바이트코드가 어디부터 어디까지인지 알려줘서 저장, 생성자로 전역변수 있으면 저장

이다.

코드의 핵심이 뭐냐?

  • 함수
  • 변수

이게 전부다. 즉

함수 => Code

변수 => Storage

에 저장된다. 이게 전부다.

만약 누가 이 컨트랙트 주소로 어떤 함수를 호출했어.
그럼 EVM은 CA를 가지고 State DB에 가서, CodeHash, StorageRootHash를 찾고,
이걸로 실제 Code와 Storage를 가져올 수 있는거야. 뭔말알?

2-2. Runtime Code

실제로 Code에 저장되는 "함수" 부분이다.
런타임 부분은 다시 2파트로 나뉘는데,

  • Dispatcher
  • Function Bodies

복잡하지 않다. 너무나 당연한 구분이다.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleContract {
    uint256 public value;

    function setValue(uint256 _value) public {
        value = _value;
    }
    
    function getValue() returns (uint256) {
        return value
    }
}

이 컨트랙트는 함수가 2개다. 함수 2개가 Runtime Code에 저장이 될 것이다.
이제 사용자가 setValue를 호출하려고 한다. 어떻게 호출해야 되냐?

a. Dispatcher

함수 A 실행하는 분은 x부터 실행하세요~
함수 B 실행할 분은 y부터 실행하세요~

이렇게 알려주기 위한 부분이 앞부분의 Dispatcher다.
이를 위해 setValue를 호출할 사용자는 트랜잭션의 data에,

setValue(uint256) 를 Keccak256한 값의 4바이트인

55241077 + Parameter

를 넣는다.

그럼 Runtime의 앞부분인 Dispatcher가 data의 앞 4바이트를 읽고,

아 setValue 호출하시려는구나 ~ x번째 부터 읽으시면 되세요~

하고 해당 함수의 실제 로직 부분으로 바이트코드의 PC를 옮겨주는 것이다.

b. Function Bodies

위 컨트랙트라면 Set,Get의 실제 로직이 담긴 부분이다.

2-3. Metadata

Solidity 0.6.0 이상에선 기본적으로 IPFS, Swarm 해시가 메타데이터에 포함된다.
이 해시값은 소스코드, 빌드가 담긴 JSON 파일을 가르킨다.
실제로 IPFS에 직접 업로드는 되지 않고, 해시값만 포함한다.

마무리

이러면 바이트코드의 베이스 이해가 끝난 것이다.
잊지마라. 가장 핵심은

EVM은 바보.모든 세세한 동작을 바이트코드가 해줘잉

이다.
물론 Runtime 부분에는, 없는 함수를 실행했을 때 처리를 위한 Fallback 등이 포함되어 있지만,
그것은 심화에서, 아예 각각 명령어를 하나하나 뜯어보며 정확히 어떤 동작을 하는지 알아보자.

profile
시리즈 클릭하셔서 카테고리 별로 편하게 보세용

0개의 댓글