Ethereum:: ABI와 관련된 Q&A 정리
ABI (Application Binary Interface)
이더리움의 ABI에 대해 공부하면서 EthereumStackExchange 사이트를 정말 많이 이용하였습니다. 사이트를 돌아다니면서 ABI를 이해하는데 있어서 저에게 많은 도움이 되었던 질문 및 답변을 정리한 포스팅입니다.
Question: ABI는 어떻게 바이트 코드로 저장되는가?
0x25d8dcf2
와 같은 16진수 문자열의 정보만으로 컨트랙트 내의 함수를 어떻게 식별할 수 있을까? 함수 서명정보의 해시이다.
- Answer1:
메서드 ID를 가지고 컨트랙트의 바이트코드 안에 주소와 정확하게 연결시켜주는 작업을 하는 것이 컴파일러고, 컴파일러는 정확하게 동작하는 EVM 바이트코드를 생성할 것이다.
MethodID는 4바이트이기 때문에, 해시 충돌 (2개의 서로 다른 함수에서)이 가능하다. 솔리디티 컴파일러는 해시 충돌의 경우 에러를 반환하고 어떠한 바이트코드도 더이상 생산해내지 않는다.
EVM 컴파일러가 생성하는 바이트코드의 예시는 아래와 같다.
method_id = first 4 bytes of msg.data
if method_id == 0x25d8dcf2 jump to 0x11
if method_id == 0xaabbccdd jump to 0x22
if method_id == 0xffaaccee jump to 0x33
other code
0x11:
code for function with method id 0x25d8dcf2
0x22:
code for another function
0x33:
code for another function
ABI는 무엇이고 컨트랙트에 왜 필요한가?
Answer1
ABI는 보통 두 프로그램 모듈의 인터페이스 역할을 하고 그 중 하나는 종종 기계어 레벨에 있다. 인터페이스는 데이터를 기계 코드로 인코딩/디코딩 하기 위한 방법이다.
이더리움에서는 기본적으로 EVM에 솔리디티 컨트랙트 호출을 할 때 인코딩을 하거나, 트랜잭션들로부터 데이터를 읽는 방법이다.Answer2
ABI는 컨트랙트 내의 함수를 호출하거나 컨트랙트로부터 데이터를 얻는 방법이다. 이더리움 스마트 컨트랙트는 이더리움 블록체인에 배포된 바이트코드다. 컨트랙트 내에 여러 개의 함수가 있을 수 있을 것이다. ABI는 컨트랙트 내의 어떤 함수를 호출할지를 지정하는데 필요하며, 우리가 생각했던 대로 함수가 데이터를 리턴한다는 것을 보장하기 위해 반드시 필요하다.
Ethereum Contract ABI 에 등장한 예시를 살펴보면:
contract Foo {
function bar(real[2] xy) {}
function baz(uint32 x, bool y) returns (bool r) { r = x > 32 || y; }
function sam(bytes name, bool z, uint[] data) {}
}
만약 baz 함수를 69와 true를 매개변수로 호출했다고 가정해보자. 아래와 같이 총 68바이트의 데이터를 사용할 것이다. 메서드 식별자 4바이트, 32바이트로 감싸진 69라는 값, 32바이트로 감싸진 true값 이렇게 68바이트다.
0xcdcd77c0: the Method ID. This is derived as the first 4 bytes of the Keccak-256 hash of the ASCII form of the signature baz(uint32,bool). 0x0000000000000000000000000000000000000000000000000000000000000045: the first parameter, a uint32 value 69 padded to 32 bytes 0x0000000000000000000000000000000000000000000000000000000000000001: the second parameter - boolean true, padded to 32 bytes
위의 68바이트 데이터는 트랜잭션의 data
필드에 기술될 것이다: 관련 보안적인 이슈가 있으니 확인을 해보도록 하자. 보안 이슈. 해당 보안 이슈를 요약하자면 데이터 필드에 값을 넣을 때는 조심해야 한다는 것이다. 컨트랙트를 호출 시 데이터를 함께 보내는 과정에서 부작용이 발생할 수 있기 때문.
메서드 식별자를 추출할 때, 일반적으로 알려진 위험을 예방하려면 canonical types
가 반드시 사용되어야 한다. 예를 들어, uint
대신 uint256
을 사용하도록 한다.
솔리디티가 메서드 식별자를 계산할 때의 과정을 위 코드의 sam
메서드를 이용하여 예로 들어보면:
bytes4(sha3("sam(bytes, bool, uint256[])")
web3.js와 같은 고수준 라이브러리를 사용하다보면, 이런 디테일을 놓칠 수 있다. 여전히 이러한 고수준 라이브러리에서도 JSON형식의 ABI가 제공될 필요가 있다.
ABI는 코어 이더리움 프로토콜에 포함되지는 않는다. 누구나 자신의 컨트랙트에 대응되는 ABI를 만들어낼 수 있다. 물론 호출자는 해당 컨트랙트의 ABI를 알고 있어야 컨트랙트를 제대로 이용할 수 있다.
Answer3
Contract Definition: 전형적인 고수준 코드로 정의
Compiled Contract: 이더리움 가상 머신(EVM)에서 동작하기 위해 바이트 코드로 변환된 컨트랙트. 함수의 이름과 매개변수들이 컴파일 과정에서 해시된다. 그러므로 다른 계정이 함수를 호출하기 위해서는 함수 이름과 매개변수들을 알고 있어야 한다. ABI의 등장 이유
Application Binary Interface: 컨트랙트의 함수와 매개변수들을 JSON 형식으로 나타낸 리스트다. 스마트 컨트랙트의 함수를 이용하기 위해서는 ABI를 사용하여 함수의를 해시할 수 있어야 한다. 이렇게 하면 해당 함수를 호출하기 위해 필요한 EVM 바이트 코드를 생성할 수 있다. 그러고선 트랜잭션의 데이터 필드인 Td에 포함되고 EVM에 의해 해석(컨트랙트 주소에 맞춰 코드가 해석됨)된다.Answer4
think of "ABI" as an "API" at a low level.
따로 번역은 하지 않았지만.. 꼭 읽어보시는 걸 추천드립니다.
The API consists of a set of routines, objects, etc. that you can use in your code to access the functionality of that external component. An ABI is very similar. Think of it as the compiled version of an API (or as an API on the low level). as you know The contract are stored as bytecode in a binary form into the blockchain under a specific address. so you can accesses the binary data in the contract through the ABI which indicates to the caller the needed information (functions signatures and variables declarations) to encode a meaningful(understood by the VM) call to the bytecode(contract). The ABI defines the structures and methods that you will use to interact with binary contract (just like the API did), only on a lower level.
보너스: Function Selector란?
함수 호출시 발생하는 4바이트의 콜 데이터는 호출할 함수를 결정한다. 4바이트의 데이터는 Keccack256로 함수의 서명정보를 해시하여 빅 엔디안 방식으로 기술했을 시, 첫 번째 네 바이트를 일컫는다.
서명 정보는 기본적인 프로토타입에 대한 표현법으로 정의된다. 예로, 함수 이름과 매개변수들의 자료형이 있다. 매개변수의 자료형은 콤마로 구분되며 공백구분자는 인정되지 않는다.
리턴타입의 경우 함수 서명정보에 포함되지 않는다.