본문으로 바로가기

이더리움 스마트 컨트랙트를 작성후 컴파일하면 바이트코드로 컴파일된 결과물이 생성되고, 이러한 바이트코드가 이더리움 블록체 저장이 됩니다. 그리고 스마트컨트랙트의 특정 함수를 호출할경우, 해당 함수를 구분할수 있는 정보를 통해, 호출할 함수를 구분하여 호출하게 되는데, Function selector를 통해서 이러한 함수를 구분하게 됩니다.


먼저 트랜잭션 정보중에서 Input Data 필드의 정보를 가지고, 스마트 컨트랙트를 호출할때의 정보전달에 대해서 알아보도록 하겠습니다.


하기의 testnet의 트랜잭션을 예로 확인해보면 다음과 같습니다.


https://ropsten.etherscan.io/tx/0xaf4a217f6cc6f8c79530203372f3fbec160da83d1abe048625a390ba1705dd57



여기서 Input Data를 디폴트 View 로 확인시 위와같이 보여지게 됩니다. 해당 정보는 직관적으로 transfer 함수를 두개의 인자를 사용하여 호출하는것임을 알수 있습니다. 즉 함수를 호출할때는 4바이트의 MethodID와 각각 함수의 인자 갯수만큼의 32바이트 데이타가 추가되는 형태가 됨을 알수 있습니다. 


여기서 4바이트의 MethodID가 Function selector에 해당되며, 이 정보를 기반으로 바이트코드에서 함수를 구분하여 호출할 함수가 결정됩니다. 위의 트랜잭션에 포함된 transfer 함수호출정보를 기반으로 function selector를 계산하면 다음과 같습니다.


transfer(address _to, uint256 _value

   -> keccak256(‘transfer(address,uint256)’) = a9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b


위의 keccack256 연산은 인터넷 변환기를 사용하여 확인시 다음과 같이 확인할수 있으며, 첫 4바이트인 a9059cbb 가 MethodID인 0xa9059cbb 에 해당됩니다.



이와같이 4바이트의 Function selector와 각각 32바이트의 함수 Parameter로 구성된 Input Data의 형태는 같이 구성됩니다.


일반적으로 스마트컨트랙트에서 다른 컨트랙트의 함수를 호출할경우 다음 코드와 같은 형식으로 호출하게 되는데 이 형식이 바로 위에서 설명한 함수의 프로토타입을  keccak256 연산한 결과의 첫 4바이트를 취한 Function Selector를 사용하여 해당 함수를 호출하게 되는것임을 알수 있습니다.


contract ThatCallsSomeContract {
function callTheOtherContract(address _contractAddress) public {
require(_contractAddress.call(bytes4(keccak256("callMeMaybe()"))));
require(_contractAddress.delegatecall(bytes4(keccak256("callMeMaybe()"))));
SomeLib.calledSomeLibFun();
}
}