specs icon indicating copy to clipboard operation
specs copied to clipboard

feat: Store historical block hashes to `L1Block`

Open pegahcarter opened this issue 1 year ago • 12 comments
trafficstars

Is your feature request related to a problem? Please describe. When it comes to updating the L2, the L1Block is regularly called to update its' state values, including the L1 block hash. This hash is extremely valuable as a user can create a proof for any state of the L1 at the current block hash.

The issue arises when dealing with historical data. As we are only ever using the most-recent hash within L1Block, we are unable to prove L1 state at a historical point in time on-chain without deploying our own contract with manually-synced block hashes.

The value of a chain is derived by the value of its' state. Therefore, by having the ability to prove state at a particular time in the past, we open up cross-chain communication.

An example of what this can be used for is to prove L1 token voting power at a particular point in time.

Describe the solution you'd like Have a mapping with L1Block to store historical hashes. The most simple way I've seen it done is through a basic mapping.

pegahcarter avatar Mar 01 '24 17:03 pegahcarter

Previous work for this can be found here. We considered having a ring buffer instead of a mapping that grows forever. We decided to not merge this due to the inclusion of eip-4788 in the op stack. The proofs are larger when using 4788 but its still possible. I have been wondering if its a good idea to open a RIP that adds a precompile/predeploy for this functionality so that developers can have a more consistent experience between various L2s

tynes avatar Mar 01 '24 17:03 tynes

Do you have an idea of how much it would cost to post the updated mapping on L1 once we we're using blobs or no? Since blobs are pruned, my worry would be this additional overhead cost.

pegahcarter avatar Mar 01 '24 20:03 pegahcarter

Blobs have no impact on this because L2 outputs are not posted to L1, it is the L2 inputs that are posted to L1. Meaning L2 txs (inputs) are posted to L1, not the L2 state (outputs)

Your implementation will cause additional state growth for every L1 block forever. It may be a tradeoff you are willing to take, but generally core devs use ring buffers for these sorts of constructions so that the max storage usage is bounded

tynes avatar Mar 01 '24 21:03 tynes

Does changing state on L2 have the same impact on L1 as changing state on L1? Ie. adding new variables increases state vs. modifying existing state variables does not. I've been digging through the docs but can't seem to find a distinction between the two.

pegahcarter avatar Mar 01 '24 22:03 pegahcarter

The op stack batch submits inputs to L1, not state diffs. You can make as many modifications to L2 state as you want in a given L2 transaction and the batch size will be the same given the same sized tx that makes less modifications to L2 state

tynes avatar Mar 04 '24 23:03 tynes

Okay, that makes sense. What I'm asking is about the difference in:

  • modifying existing state variables
  • adding new state variables For a transaction on L2. Do new variables to the L2 increase L2 state but not L1 state?

pegahcarter avatar Mar 06 '24 18:03 pegahcarter

Adding new variable to L2 predeploys only increase L2 state

tynes avatar Mar 07 '24 17:03 tynes

IMO it's worth having a predeploy to provide some bridge back to L1 state.

pegahcarter avatar Mar 07 '24 18:03 pegahcarter

Previous work for this can be found here. We considered having a ring buffer instead of a mapping that grows forever. We decided to not merge this due to the inclusion of eip-4788 in the op stack. The proofs are larger when using 4788 but its still possible. I have been wondering if its a good idea to open a RIP that adds a precompile/predeploy for this functionality so that developers can have a more consistent experience between various L2s

https://github.com/Dedaub/audits/blob/main/Ethereum%20Foundation/EIP%204788%20Bytecode%20Audit.pdf

sambacha avatar Mar 12 '24 12:03 sambacha

Previous work for this can be found here. We considered having a ring buffer instead of a mapping that grows forever. We decided to not merge this due to the inclusion of eip-4788 in the op stack. The proofs are larger when using 4788 but its still possible. I have been wondering if its a good idea to open a RIP that adds a precompile/predeploy for this functionality so that developers can have a more consistent experience between various L2s

I vote for adding this feature since the cost is fixed and trivial, and the usage is much easier compared to eip-4788 :)

zhiqiangxu avatar Mar 23 '24 04:03 zhiqiangxu

@tynes IMO is the state bloat of a mapping storing every hash is worth it- otherwise, additional contracts will need to store historical block hashes and the additional redundancy may exceed storing the hash once in a single place.

It also doesn't make sense to skip block hashes (to save space) as oracles, for example, rely on different intervals and may need a specific block.

If we're storing block hashes, we should also store the timestamp associated with the hash.

pegahcarter avatar Mar 25 '24 16:03 pegahcarter

I think its worth pursuing this feature through the Rollup Improvement Process see https://github.com/ethereum/RIPs/issues/16

tynes avatar Mar 25 '24 16:03 tynes