---
title: "Solidity 바이너리란 무엇인가?"
description: "Solidity 바이너리란 무엇이며 스마트 컨트랙트 코드를 최적화하는 데 어떻게 사용하는가"
---

# Solidity 바이너리란 무엇인가?

스마트 컨트랙트를 통해 Ethereum 블록체인에 게시되는 원시 데이터는 바이트코드, 즉 긴 16진수 문자열입니다. 개발자는 사람이 읽을 수 있는 [Solidity](https://www.alchemy.com/overviews/solidity) 코드로 스마트 컨트랙트를 작성하고 읽지만, 실제로 블록체인에 게시되는 것은 그 텍스트가 아닙니다.

마찬가지로, 스마트 컨트랙트에 대한 모든 "호출", 즉 스마트 컨트랙트가 공개한 외부에서 볼 수 있는 함수에 대한 요청은 원시 바이트코드, 즉 "바이너리" 형태로 이루어집니다.

다음과 같은 \(Solidity로 인코딩된\) 구조를 가진 스마트 컨트랙트가 [Ethereum mainnet](https://www.alchemy.com/rpc/ethereum)에 업로드되었다고 합시다:

사용자가 함수 baz를 매개변수 69와 true로 호출하려 한다고 합시다.

이 요청이 실제로 바이트코드로 전송되면 다음과 같은 모습입니다:

`0xcdcd77c000000000000000000000000000000000000000000000000000000000000000450`...

읽기 꽤 어렵죠?

이 글에서는 [Ethereum Virtual Machine](https://www.alchemy.com/overviews/what-is-the-ethereum-virtual-machine-evm)이 모든 것을 바이트코드로 인코딩하는 이유를 살펴보고, ABI가 무엇이며 어떻게 사용하는지 알아보고, 바이트코드를 다시 사람이 읽을 수 있는 [Solidity](https://www.alchemy.com/dapps/solidity)로 디컴파일하는 몇 가지 기본 도구를 소개합니다.

**참고:** 이 글의 예시는 공식 [Solidity ABI 문서](https://docs.soliditylang.org/en/v0.8.13/abi-spec.html)에서 가져온 것입니다.

## **Solidity는 왜 스마트 컨트랙트를 바이너리로 인코딩할까?**

Ethereum 블록체인에 데이터를 저장하는 것은 매우 비용이 많이 들고, 업로드되는 모든 바이트는 블록체인의 모든 풀 노드에 복제되어야 하므로, Solidity 코드를 업로드하는 것보다 원시 바이트코드를 쓰고 읽는 것이 비용 효율적입니다.

사람이 읽을 수 있는 코드를 파싱하고 저장하는 것은 데이터 비용이 자릿수 단위로 더 커질 수 있는데, mainnet에서 이미 스마트 컨트랙트 하나에 수천 달러가 들 수 있다는 점을 고려하면 이는 문제가 됩니다.

## **Solidity ABI란 무엇이며, 왜 스마트 컨트랙트를 읽으려면 ABI가 필요할까?**

스마트 컨트랙트는 게시될 때 Ethereum에 게시되기 전에 자동으로 바이트코드로 트랜스파일됩니다. 하지만 일단 네트워크에 게시된 후에는, 특정 개인이 해당 스마트 컨트랙트와 어떻게 상호작용해야 하는지 어떻게 알 수 있을까요? 긴 바이트코드 문자열을 보고 어떤 함수를 호출할 수 있는지 이해하는 것은 거의 불가능합니다.

[Application Binary Interface, 즉 ABI](https://www.alchemy.com/overviews/what-is-an-abi-of-a-smart-contract-examples-and-usage)가 그 해답입니다.

ABI는 특정 스마트 컨트랙트에 대해 어떤 호출이 가능하고 각 호출이 무엇을 반환하는지를 설명하는, 사람이 읽을 수 있는 공개 메서드 목록입니다.

ABI를 사용하면 스마트 컨트랙트 사용자는 바이트코드를 읽을 필요 없이, 호출을 바이트코드로 변환하여 스마트 컨트랙트와 상호작용할 수 있습니다.

ABI는 전통적인 Web2 아키텍처의 API\(Application Programming Interface\)와 매우 유사합니다. 하지만 주된 차이점은 **Solidity ABI는 바이너리로 인코딩된 스마트 컨트랙트 내의 메서드에 사용자가 접근할 수 있게 해주는** 반면, API는 온라인 서버 엔드포인트의 메서드에 사용자가 접근할 수 있게 해준다는 것입니다.

사람이 사용하고 읽도록 만들어졌기 때문에, 스마트 컨트랙트 개발자는 스마트 컨트랙트의 ABI를 블록체인에 게시하지 않습니다. 그렇게 하면 비용이 매우 많이 들기 때문입니다.

대신, ABI는 다음과 같은 방법으로 얻을 수 있습니다:

1. 스마트 컨트랙트 개발자가 공개한, 컨트랙트의 공개 소스 코드를 통해 ABI를 생성할 수 있습니다.
1. 스마트 컨트랙트가 Etherscan에서 검증된 경우, Etherscan의 컨트랙트 정보에서 얻을 수 있습니다.
1. 스마트 컨트랙트 바이트코드로부터 ABI를 리버스 엔지니어링할 수 있습니다\(권장하지 않음\).

ABI는 일반적으로 Solidity 스마트 컨트랙트의 공개 함수 선언을 JSON 형식으로 인코딩하여 게시됩니다.

다음 스마트 컨트랙트의 함수 정의를 살펴보겠습니다:

이에 대응하는 JSON 인코딩은 다음과 같습니다:

## **Solidity의 호출 데이터 바이너리를 해석하는 방법**

Solidity 바이너리를 직접 손으로 파싱해서 함수 호출을 역추적하는 것은 복잡하고 직관적이지 않으며 실수하기 쉬우므로 권장하지 않지만, 바이너리가 Solidity에서 어떻게 구성되는지 대략적으로 이해해두면 호출 데이터를 빠르게 훑어보거나 값을 다시 확인할 때 매우 유용합니다.

다음 섹션에서 이러한 변환 작업을 대부분 처리해주는 몇 가지 도구를 소개하겠습니다.

위의 예시를 다시 살펴보겠습니다.

사용자가 스마트 컨트랙트 내의 함수 **baz**를 매개변수 69와 true로 호출하려 한다고 합시다. 이 요청은 바이트코드로 다음과 같이 나타나며, 총 68바이트입니다:

`0xcdcd77c0000000000000000000000000000000000000000000000000000000000000004500`...

### 1. 호출 데이터의 처음 4바이트로 메서드 ID를 식별합니다.

이 경우 0xcdcd77c는 시그니처 baz\(uint32,bool\)의 ASCII 형태에 대한 Keccak 해시의 처음 4바이트를 구함으로써 메서드 **baz**를 식별합니다.

### 2. 다음 32바이트로 첫 번째 매개변수를 식별합니다

`0x00000000000000000000000000000000000000000000000000000000000000045`는 첫 번째 매개변수인 **69**를 식별하며, 이는 32바이트로 패딩된 uint32 값입니다. 패딩이란 실제 숫자 크기와 상관없이 전체 문자열이 \(이 경우\) 32바이트 길이가 되도록 0을 추가하는 것을 의미합니다.

`0x00000000000000000000000000000000000000000000000000000000000000045 `

### 3. 마지막 32바이트로 두 번째 매개변수를 식별합니다**

두 번째 매개변수는 **true**로, 32바이트로 패딩된 bool 값입니다:

`0x0000000000000000000000000000000000000000000000000000000000000001`

동적 타입을 포함하는 매개변수의 경우 인코딩이 다소 다르게 보이는데, address, bool, uint32 같은 정적 타입은 제자리에서 인코딩되는 반면 [동적 타입은 별도로 할당된 위치에 인코딩되기](https://docs.soliditylang.org/en/v0.8.13/abi-spec.html#use-of-dynamic-types) 때문입니다.

## **Solidity의 이벤트 데이터 바이너리는 어떻게 해석하나요?**

이벤트는 스마트 컨트랙트가 메서드 호출을 실행할 때 게시하는 로그이며, 이벤트는 바이너리 데이터로 게시됩니다.

이벤트는 매개변수를 받을 수 있으며, 이는 이벤트가 무엇을 출력할지 지정하는 데 도움이 됩니다. 이러한 매개변수는 인덱싱될 수 있는데, 이는 해당 인덱싱된 매개변수를 필터로 사용해 이벤트를 검색할 수 있게 된다는 의미입니다. 이러한 인덱싱된 매개변수는 Solidity 용어로 토픽\(topics\)이라고도 불립니다!

대략적으로, Solidity 이벤트는 다음과 같은 구조를 따릅니다:

- address: 컨트랙트의 주소
- topics\[n\]: 0~4개의 토픽, 즉 인덱싱된 매개변수
- 임의 길이의 바이너리 데이터로, ABI에 따라 파싱할 수 있습니다.

## **Solidity 바이너리를 디컴파일하려면 어떤 도구를 사용해야 할까?**

[EtherVM Decompiler](https://ethervm.io/decompile)와 [Panoramix decompiler](https://github.com/palkeo/panoramix)를 비롯하여 Solidity 바이너리를 더 읽기 쉬운 형태로 되돌리는 데 도움이 되는 다양한 EVM 디컴파일러가 있습니다.

이러한 EVM 디컴파일러가 원본 소스 코드를 완벽하게 복원해주지는 않지만\(바이너리 크기를 줄이기 위해 이름이나 다른 중요한 정보가 제거되었을 수 있습니다\), 허용된 ABI 요청에 대해 대략적으로 이해할 수 있게 해줍니다.
