Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Withdrawal proof cache #72

Open
onbjerg opened this issue Oct 24, 2024 · 6 comments
Open

Withdrawal proof cache #72

onbjerg opened this issue Oct 24, 2024 · 6 comments

Comments

@onbjerg
Copy link
Member

onbjerg commented Oct 24, 2024

Transferred over from paradigmxyz/alphanet#135

Motivation

To withdraw from an OP stack chain, a user needs to provide a proof on L1 that a withdrawal was included on-chain on L2. To do this, eth_getProof is called to prove a storage slot on the withdrawal contract against an output root.

On Reth, eth_getProof is really expensive due to no historical tries being stored. To prove at an old block, old state is reconstructed in-memory using changesets. The further back you go, the more expensive this operation is, which is why it is [restricted] in Reth.

We could increase this maximum, but it would likely be too impractical to run a node with the resources necessary to actually compute historical proofs on a 1s blocktime chain with activity, gigagas or not.

To solve this, we are going to build an ExEx.

Proposed solution

We will build an ExEx that computes withdrawal proofs and caches them in a separate database. The eth_getProof RPC method is replaced with one that first checks this cache, and thereafter computes a historical proof as usual with the normal constraints on how far back you can go.

The ExEx will look for any new withdrawals and store these. Then, every time an output root is posted on L1, non-proven withdrawals are proven and the resulting proof is stored in the cache.

@onbjerg
Copy link
Member Author

onbjerg commented Oct 24, 2024

Comment by @rkrasiuk on paradigmxyz/alphanet#135

After internal discussion, it seems like we can introduce a satisfactory workaround to avoid the headache of managing additional cache/state. Per @onbjerg's investigation, the only fields from eth_getProof response needed for withdrawals are storage_root and storage_proofs. Since the rest of the state is not needed, we can simply compute the storage proof and corresponding root and expose that through new eth_getStorageProof RPC endpoint. This endpoint can have much more lax limitations on historical state loading.

Here's a plan for implementing this:

  1. Extend StorageRootProvider with new storage_proof method
fn storage_proof(&self, address: Address, slot: B256) -> ProviderResult<StorageProof>;
  1. Extend EthApi new RPC endpoint eth_get_storage_proof
pub struct StorageProofResponse {
  root: B256,
  proof: EIP1186StorageProof,
}


#[method = "getStorageProof"]
async fn get_storage_proof(&self, address: Address, slot: JsonStorageKey, block_number: Option<BlockId>) -> RpcResult<StorageProofResponse>;
  1. Modify the relevant OP stack component to call eth_getStorageProof instead

@0xurb
Copy link
Contributor

0xurb commented Oct 24, 2024

As it is non-standard API, shouldn't it be on ExEx extended RPC modules? Or just another namespace (not eth_)?

@onbjerg
Copy link
Member Author

onbjerg commented Oct 24, 2024

We'd need to override eth_getProof in some capacity, maybe with a fallback to the default behavior if we're not proving on the withdrawal contract. The reason it needs to be eth_getProof is that everything uses that for proving withdrawals, incl. bridges, the optimism sdk and so on, and it would just be a huge task to fork all of that.

@loocapro
Copy link

loocapro commented Oct 25, 2024

May I take this?

@0xurb
Copy link
Contributor

0xurb commented Oct 27, 2024

Looks like the first step was merged on Reth?

For ExEx, would it be ( in your mind ) store data based on relay message calls to L2_CROSS_DOMAIN_MESSENGER?
If so, I have some samples for this.

@mahmudsudo
Copy link
Contributor

Can I contribute to this issue ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants