poanetwork / ex_abi

The Ethereum ABI Interface
GNU General Public License v3.0
61 stars 43 forks source link

Fix type decoder to use lazy stream instead of pre-allocated list #170

Closed fedor-ivn closed 4 months ago

fedor-ivn commented 5 months ago

Fixes https://github.com/blockscout/blockscout/issues/10292.

Consider the following code snippet which caused OOM errors on decoding arrays of tuples:

function_selectors = [
  %ABI.FunctionSelector{
    function: "swapExactTokensForTokens",
    method_id: <<42, 68, 63, 174>>,
    type: :function,
    inputs_indexed: nil,
    state_mutability: :non_payable,
    input_names: ["amountIn", "amountOutMin", "path", "to", "deadline"],
    types: [
      {:uint, 256},
      {:uint, 256},
      {:tuple, [array: {:uint, 256}, array: {:uint, 8}, array: :address]},
      :address,
      {:uint, 256}
    ],
    returns: [uint: 256],
    return_names: ["amountOut"]
  }
]

data =
  <<42, 68, 63, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 71, 248, 212, 138, 1, 180, 77, 243,
    255, 243, 93, 37, 138, 16, 163, 174, 220, 17, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 212, 153, 236, 108, 99, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 143, 154, 114, 216, 245, 100, 121, 144, 58, 227, 134, 132, 158, 41, 13, 73, 56,
    158, 65, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 25, 9, 44, 199, 203, 210, 9, 122, 227,
    21, 143, 114, 218, 72, 74, 200, 19, 183, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137, 134,
    203, 129, 146, 34, 242, 134, 159, 7, 202, 92, 60, 237, 11, 130, 38, 218, 44, 74, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 164, 168, 239, 101, 138, 224, 219, 204, 165, 88, 224, 178, 219, 217,
    229, 25, 37, 24, 13, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 1, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 245>>

ABI.find_and_decode(function_selectors, data)