streamingfast / substreams-rs

9 stars 3 forks source link

Implement simplified storage_changes access #17

Open abourget opened 1 year ago

abourget commented 1 year ago

Problem

storage_changes and keccak_preimages are powerful primitives in Firehose and Substreams data, that can avoid a huge percentage of eth calls in circulation, and even pick up data that isn't triggered by any log events on Ethereum.

However, accessing those storage changes require reverse interpretation of their keys. That's pretty opaque and can get quite annoying. With the AST, it's possible to know the storage slots, their offsets, and their types to know what technique to use to reverse the keys and interprete the data in the storage slots.

Proposed draft solution

An API like:


StructAccessor{slot: 3, name: "MyObject", fields: vec![
  Uint256Accessor{slot: 1, name: "field1"},
  Uint32Accessor{slot: 2, offset: 0, name: "field2"},
  Uint96Accessor{slot: 2, offset: 4, name: "field3"},
]}

let balance_accessor = MapAccessor<Address, Uint256>{slot: 1, name: "balances"};
let values_accessor = ListAccessor<Uint256>{slot: 1, name: "values"};

let key = balance_accessor.get_key("0x123123123123123");
let value = trx.storage_changes.filter(|el| el.key == key).first(); // is that even Rust? whatever

or something like that.

See https://gist.github.com/gane5h/5bf622cbaaf546d356994a4bec9f6798 for an example AST piece that details the storage layout. This can be extracted from artifacts left over the the solc compiler. This way, we could code gen the above structs. But we can start with non-codegen'd readers like the above, for the simple cases, when you know which field you want, its type (like a balance) and you can easily discover the slot it is at (by inspecting a few keccak and the keys in ERC20 transfers for instance)

Some reference to decoding storage: https://medium.com/coinmonks/decoding-the-memory-of-an-ethereum-contract-52c256f83f07

azf20 commented 1 year ago

Would this be Ethereum specific rather than core substreams?

maoueh commented 1 year ago

That is indeed Ethereum specific, so it will go in substreams-ethereum crate