esaulpaugh / headlong

High-performance Contract ABI and RLP for Ethereum
Apache License 2.0
79 stars 20 forks source link

Variable length bytes error during log decoding #49

Closed tbuckley54 closed 1 year ago

tbuckley54 commented 1 year ago

When trying to decode the data for this log

{
    "logIndex": "0xae",
    "transactionIndex": "0x51",
    "transactionHash": "0xb304d3c6df4222f8d40722b37a88c6f9b25e0dfab931b7df67b7c6e58aa3e59c",
    "blockHash": "0x12dcda41bfeee8190410ac00ead9af24f14d9142e076fb22480a8be383c1bc50",
    "blockNumber": "0xc3757d",
    "address": "0x6758B7d441a9739b98552B373703d8d3d14f9e62",
    "data": "0x000000000000000000000000000000000000000000000034e2c0e23567d500000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100",
    "topics": [
      "0xe19260aff97b920c7df27010903aeb9c8d2be5d310a2c67824cf3f15396e4c16",
      "0x00000000000000000000000080dfb2ec0c6e1cc2425b47eff16c26e2ff8ca1c8",
      "0x000000000000000000000000d819e948b14ca6aad2b7ffd333ccdf732b129eed"
    ],
    "type": null
  }

using this abi

{
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "name": "value",
        "type": "uint256"
      },
      {
        "indexed": false,
        "name": "data",
        "type": "bytes"
      }
    ],
    "name": "Transfer",
    "type": "event"
  }

doing

val event        = Event.fromJson(abi)
 event.getNonIndexedParams
            .asInstanceOf[ABIType[Tuple]]
            .decode(ByteBuffer.wrap(FastHex.decode(log.data.stripLeadingHex)))

we see the error

tuple index 1: not enough bytes remaining: 1 < 32

doing

event.getNonIndexedParams.decode

yields a similar result

tuple index 1: unsigned val exceeds bit limit: 254 > 31

i would expect it to be just returning empty for the data bytes parameter instead, any suggestions?

esaulpaugh commented 1 year ago

000000000000000000000000000000000000000000000034e2c0e23567d50000 // uint256 0000000000000000000000000000000000000000000000000000000000000040 // bytes head (offset) 0000000000000000000000000000000000000000000000000000000000000001 // bytes length 00 // bytes data

That doesn't look like a valid encoding to me. The encoding of the data part of a bytes with length 1 should be 32 bytes long. But here, only 00 is given, which is one byte. There are supposed to be 31 padding bytes after that. All zeroes. If the creator of the data omitted the padding deliberately, I suggest adding the padding back to the data prior to decoding.

stripLeadingHex might be removing the leading zeroes as well. Leading and trailing zeroes must not be removed before decoding. Try FastHex.decode(str, 2, str.length() - 2) to ignore only the 0x prefix.

esaulpaugh commented 1 year ago

see #53

esaulpaugh commented 1 year ago

fixed https://github.com/esaulpaugh/headlong/releases/tag/v10.0.0