Solidity: abi.decode does not seem to be having correctly with memory

Created on 9 Oct 2020  路  2Comments  路  Source: ethereum/solidity

Description

abi.decode is (seemingly) not decoding correctly, at least for a bytes, in memory, of length 68 (i.e. byte4, bytes32, bytes32)

Environment

  • Compiler version: 0.6.12 and 0.7.3
  • Target EVM version (as per compiler settings): petersburg
  • Framework/IDE (e.g. Truffle or Remix): Truffle
  • EVM execution environment / backend / blockchain client: Ganache
  • Operating system: OSX Catalina 10.15.7 (19H2)

Steps to Reproduce

When I call myFunc below in this way:

const dataHex = '0x052f1ef000000000000000000000000000000000000000000000000000000000000000002c91ae39b411ab15cfdcf148a174f4aa7e922c8f9c050daa346a72c933a1a731';
const { receipt, logs } = await contractInstance.myFunc(callDataHex);




I get the following results:

// Try to decode first 4 bytes from left (works)

event Debug(bytes4);
function myFunc(bytes memory data) public {
    (bytes4 sig) = abi.decode(data, (bytes4));
    emit Debug(sig);
}

logs[0].args[0] is 0x052f1ef0



// Try to decode first 4 bytes and second 32 bytes from left (fails, gets first 4 bytes from left, then 32 bytes 4 away from the right)

event Debug(bytes4, byte32);
function myFunc(bytes memory data) public {
    (bytes4 sig, bytes32 thing_1) = abi.decode(data, (bytes4, bytes32));
    emit Debug(sig, thing_1);
}

logs[0].args[0] is 0x052f1ef0
logs[0].args[1] is 0x000000002c91ae39b411ab15cfdcf148a174f4aa7e922c8f9c050daa346a72c9



// Try to decode first 32 bytes and second 32 bytes from left (works)

event Debug(bytes32, byte32);
function myFunc(bytes memory data) public {
    (bytes32 thing_1, bytes32 thing_2) = abi.decode(data, (bytes32, bytes32));
    emit Debug(thing_1, thing_2);
}

logs[0].args[0] is 0x052f1ef000000000000000000000000000000000000000000000000000000000
logs[0].args[1] is 0x000000002c91ae39b411ab15cfdcf148a174f4aa7e922c8f9c050daa346a72c9



// Try to decode first 4 bytes, second 32 bytes, and third 32 bytes, from left (reverts)

event Debug(bytes4, byte32, bytes32);
function myFunc(bytes memory data) public {
    (bytes4 sig, bytes32 thing_1, bytes32 thing_2) = abi.decode(data, (bytes4, bytes32, bytes32));
    emit Debug(sig, thing_1, thing_2);
}

Error: Returned error: VM Exception while processing transaction: revert



// And just to make sure data is what I think it is:

event Debug(bytes);
function myFunc(bytes memory data) public {
    (bytes4 sig, bytes32 thing_1) = abi.decode(data, (bytes4));
    emit Debug(data);
}

logs[0].args[0] is 0x052f1ef000000000000000000000000000000000000000000000000000000000000000002c91ae39b411ab15cfdcf148a174f4aa7e922c8f9c050daa346a72c933a1a731



// Try to decode first 32 bytes, second 4 bytes, from left (reverts)

event Debug(byte32, bytes4);
function myFunc(bytes memory data) public {
    (bytes32 thing_1, bytes4 thing_2) = abi.decode(data, (bytes32, bytes4));
    emit Debug(thing_1, thing_2);
}

Error: Returned error: VM Exception while processing transaction: revert



However, this all works correct if data uses calldata as storage, instead of memory, in the function signature.

Most helpful comment

@deluca-mike From #9439:

abi.decode is the converse of abi.encode. From the fact that you are using bytes4 sig I assume that you are trying to do abi decoding and function selector decoding at the same time. This won't work because the abi encoding pads all types to 32 bytes, while the function selector is not padded.

If you change _data to bytes calldata, then you can use the following to decode: abi.decode(_data[4:], (bytes32, address, bytes32, bytes32));

So what you're seeing is how it's supposed to work currently, though we're considering adding abi.decodeWithSignature() to the language to better support your use case.

I'm going to close this as a duplicate not to split the discussion. Please feel free to post your comments in #9439 if you have something to add to the discussion.

All 2 comments

@deluca-mike From #9439:

abi.decode is the converse of abi.encode. From the fact that you are using bytes4 sig I assume that you are trying to do abi decoding and function selector decoding at the same time. This won't work because the abi encoding pads all types to 32 bytes, while the function selector is not padded.

If you change _data to bytes calldata, then you can use the following to decode: abi.decode(_data[4:], (bytes32, address, bytes32, bytes32));

So what you're seeing is how it's supposed to work currently, though we're considering adding abi.decodeWithSignature() to the language to better support your use case.

I'm going to close this as a duplicate not to split the discussion. Please feel free to post your comments in #9439 if you have something to add to the discussion.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

walter-weinmann picture walter-weinmann  路  4Comments

leviadam picture leviadam  路  4Comments

VoR0220 picture VoR0220  路  4Comments

chriseth picture chriseth  路  4Comments

kkagill picture kkagill  路  4Comments