This proposal introduces a new precompiled contract L1SLOAD
to L2s that can load storage slots from L1 given a contract address and storage keys. The motivation is to provide a convenient and trustless way for smart contracts deployed on an L2 chain to read storage values from L1. With the L1SLOAD
precompile, the developers don’t need to generate and submit MPT proofs themselves.
Being able to query L1 blocks from a precompile is great from the DevEx perspective and also from the end user perspective since it can bring new use cases with fast and cheap transactions.
I noticed that earlier versions of this proposal included the L1 block number as a parameter, but it has now been fixed to the latest block. While this precompile was primarily designed with keystores in mind, reintroducing the block number parameter could unlock additional use cases such as:
- Snapshots for token governance, whitelists and airdrops. For example: only if you were a holder in a specific time in the past you will be able to vote on a proposal or claim an airdrop
- ZK merkle inclusion proofs for cross-chain privacy applications. Proving that you have been part of an historic merkle tree can help saving gas because right now we have to store all historic roots in the contracts. So for example this can help saving gas if for example, you are building a L2 voting mechanism for L1 tokens holder, or a mixer where tokens are deposited in L1 and retrieved in L2.
- 100% on-chain DeFi data to feed financial algorithms. Access to historical block data can feed financial algorithms for DeFi applications. For instance, algorithms could be designed to react to specific market conditions, such as “sell if volatility decreases and price drops.” Projects like Maker and Aave are exploring stuff like this, for example the new Aave V4 proposal expressed the need to include different data points to their fuzzy interest rates.
I like the idea of reintroducing the block number and inviting new ways of saving gas fees. Any thoughts?
@FilosofiaCodigo great points! Was thinking the same about providing an optional L1 block number, and you brought up solid usecases.
Should be possible, assuming:
- as per RIP, you will need an archive L1 node for L2 node catch-up,
- the
L1SLOAD
precompile can receive an optional block number, if none was provided - fallback to default (i.e. take the latest L1 block known to the L2 sequencer), - a given L2 can choose to ignore a block height parameter if this is not an important feature to them and they want to avoid having to hold an archive node at all times,
- alternatively, have two different precompiles, e.g.
L1SLOAD
andL1SLOAD_at_block
with the second one being optional (or something similar).
For us it would be an important aspect of L1SLOAD
. This would make it more generic and would unlock more use cases, without compromising on much.
Happy to hear thoughts!
Hello everyone!
I’ve been reading through the RIP, and I have couple questions.
In the RIP it is stated:
Prerequisite 1: The L2 sequencer has access to an L1 node. Given that the sequencer needs to monitor deposit transactions from L1, it already embeds an L1 node inside (preferred) or has access to an L1 PRC endpoint.
The overhead to L2 sequencers from additional RPC latency
TheL1SLOAD
precompile introduces risks of additional RPC latency and intermittent RPC errors. Both risks can be mitigated by running a L1 node in the same cluster as the L2 sequencer. It is preferrable for a L2 operator to run their own L1 node instead of using third party to get better security and reliability. We will perform more benchmarks to quantify the latency overhead in such setting.
Q1
I could be missing something, but this prerequisite/overhead is not just for sequencers, it’s for any L2 node. Am I correct? (if so, IMHO, the RIP description should be updated so that mentions of “sequencer” is replaced with eg. “L2 node”).
Which ties to my next question/observation:
Q2
Assuming that I was correct, by making L1SLOAD
accept any block number, we would impose requirement of running full archive L1 node on any node which wants to participate in L2 (not just sequencers). Am I correct?
Q3
I’m not sure if this is actual problem in practice, ie. was it observed that indeed, most L2 nodes do run archive nodes either way, making this issue “non-issue”?
Hi @mralj, both your observations are correct. These were briefly discussed during RollCall #6 (slides: L1SLOAD @ RollCall #6 - Google Slides).
Currently for most rollups it’s possible to run an L2 node without connecting to an L1 node. In this case the node would need to trust the sequencer for any L1-derived info (most importantly deposit transactions), which is not ideal, but possible.
This is in contrast with this RIP. With L1SLOAD follower nodes must connect to an L1 node, since the sequencer has no standard way to relay the result of the L1 state reads to other nodes.
I think requiring L2 nodes to connect to an L1 full node is acceptable. But requiring them to connect to an L1 archive node (necessary during initial sync) might make it much more challenging to run a node.