1

As documented in various places, the function selector is computed as the first four bytes of the keccak256 hash of the function header, which consists of the function name followed by the list of canonical argument types.

Is this function selector computed differently if the function is defined in a library instead of in a contract? The following example seems to indicate that (even though I haven't found any specification of this behaviour).

Function with struct parameter in contract

The selector of function F is computed as the first four bytes of the hash of F((address)), which is 0xa0b61132, as expected.

# cat c.sol
pragma solidity 0.5.12;
pragma experimental ABIEncoderV2;
contract C {
  struct S {address a;}
  function F(S calldata) external pure returns (uint256) {return 0;}
}
# solc --asm c.sol
...
    tag_1:
        /* "c.sol":58:173  contract C {... */
      pop
      jumpi(tag_2, lt(calldatasize, 0x04))
      shr(0xe0, calldataload(0x00))
      dup1
      0xa0b61132 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
      eq
      tag_3
      jumpi
...

Function with struct parameter in library

The selector of function F is computed as 0xe2a2daa1, which is unexpected.

# cat l.sol
pragma solidity 0.5.12;
pragma experimental ABIEncoderV2;
library L {
  struct S {address a;}
  function F(S calldata) external pure returns (uint256) {return 0;}
}
# solc --asm l.sol
...
sub_0: assembly {
        /* "l.sol":58:172  library L {... */
      eq(address, deployTimeAddress())
      mstore(0x40, 0x80)
      jumpi(tag_1, lt(calldatasize, 0x04))
      shr(0xe0, calldataload(0x00))
      dup1
      0xe2a2daa1 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
      eq
      tag_2
      jumpi
...

Which method is used to compute the selector for functions in libraries? What is the rationale for doing it differently from contracts?

  • 1
    I can't tell you why this is the case, but it seems the second selector comes from hashing F(L.S). (The first selector is from F((address)).) – user19510 Oct 9 '19 at 1:25
  • @smarx: It's pretty obvious why this is the case then. Library code is typically embedded into a contract which uses the library. At this point, how would you differentiate between two functions of an identical signature (function name + function parameter types), when one is implemented in the contract and the other in the library? – goodvibration Oct 9 '19 at 6:20
  • The library and the contract are at different addresses, so that's not a problem. My guess would be that web3.js and other libraries (which need to be able to call functions on the contract) had support for structs only as nameless tuples? Really not sure. – user19510 Oct 9 '19 at 7:17
  • 2
    I didn't find any documentation, just a couple comments in the Solidity compiler code that hinted at it. – user19510 Oct 9 '19 at 14:54
  • 1
    @smarx: I believe that the answer is in github.com/ethereum/solidity/blob/develop/libsolidity/codegen/… (or you can simply post it as a question to chriseth). – goodvibration Oct 10 '19 at 8:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.