ethereum / eth-abi

Ethereum ABI utilities for python
MIT License
241 stars 268 forks source link

Ignore padding bytes #162

Closed Uxio0 closed 1 year ago

Uxio0 commented 2 years ago

What was wrong?

To have the same behaviour than Solidity, eth_abi should add an option to ignore padding bytes

Code that produced the error

from eth_abi import decode_single
to_decode = bytes.fromhex('0000000000000000000000ffdc5299b629ef24fdecfbb240c00fc79fabb9cf97')
decoded = decode_single('address', to_decode )

Full error output

NonEmptyPaddingBytes                      Traceback (most recent call last)
Input In [8], in <cell line: 3>()
      1 from eth_abi import decode_single
      2 to_decode = bytes.fromhex('0000000000000000000000ffdc5299b629ef24fdecfbb240c00fc79fabb9cf97')
----> 3 decoded = decode_single('address', to_decode )

File ~/.virtualenvs/gnosis-py/lib/python3.10/site-packages/eth_abi/codec.py:155, in ABIDecoder.decode_single(self, typ, data)
    152 decoder = self._registry.get_decoder(typ)
    153 stream = self.stream_class(data)
--> 155 return decoder(stream)

File ~/.virtualenvs/gnosis-py/lib/python3.10/site-packages/eth_abi/decoding.py:127, in BaseDecoder.__call__(self, stream)
    126 def __call__(self, stream: ContextFramesBytesIO) -> Any:
--> 127     return self.decode(stream)

File ~/.virtualenvs/gnosis-py/lib/python3.10/site-packages/eth_abi/decoding.py:201, in SingleDecoder.decode(self, stream)
    199 data, padding_bytes = self.split_data_and_padding(raw_data)
    200 value = self.decoder_fn(data)
--> 201 self.validate_padding_bytes(value, padding_bytes)
    203 return value

File ~/.virtualenvs/gnosis-py/lib/python3.10/site-packages/eth_abi/decoding.py:332, in FixedByteSizeDecoder.validate_padding_bytes(self, value, padding_bytes)
    329 padding_size = self.data_byte_size - value_byte_size
    331 if padding_bytes != b'\x00' * padding_size:
--> 332     raise NonEmptyPaddingBytes(
    333         "Padding bytes were not empty: {0}".format(repr(padding_bytes))
    334     )

NonEmptyPaddingBytes: Padding bytes were not empty: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff'

Expected Result

No errors, just ignore the non empty padding bytes (as Solidity does)

Environment

Python 3.10, eth-abi=2.1.1

How can it be fixed?

Workaround for this case

from eth_abi import decode_single
to_decode = bytes.fromhex('0000000000000000000000ffdc5299b629ef24fdecfbb240c00fc79fabb9cf97')
decoded = decode_single('address', b'\x00'*12 + to_decode[-20:])
fselmo commented 1 year ago

@Uxio0 I'd like to get a bit of clarity on this outstanding issue. I saw you were at least able to get around it for your library, which seems to be the best solution to me at the moment.

as Solidity does

I can't really reproduce this. Let me know if I'm missing anything.

function decode(bytes memory _bytes) external pure returns (address) {
    address _decoded = abi.decode(_bytes, (address));
    return _decoded;
}

Testing on remix...

Calling the above with 0x0000000000000000000000ffdc5299b629ef24fdecfbb240c00fc79fabb9cf97 reverts with "error": "Failed to decode output: Error: hex data is odd-length (argument=\"value\", value=\"0x0\", code=INVALID_ARGUMENT, version=bytes/5.7.0)".

Calling the above with 0x000000000000000000000000dc5299b629ef24fdecfbb240c00fc79fabb9cf97 does not revert and returns "0": "address: 0xdC5299b629Ef24fDECfBb240C00Fc79FAbB9cf97".

I think it's good to keep that kind of parity in the core library but I'm glad you can at least get around it. Again, let me know if I'm missing anything.

fselmo commented 1 year ago

Closing for now. Can't reproduce desired result in Solidity.

Uxio0 commented 11 months ago

Sorry for the late reply @fselmo , I was on holidays when you answered and totally missed this. Maybe I was wrong when I tested it on Solidity last year, but as the current behaviour is the same, I'm happy with it.

Thank you for taking the time to check this