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

feat(db): SyncDatabase for cross-chain state access #44

Merged
merged 37 commits into from
Oct 11, 2024

Conversation

CeciliaZ030
Copy link

@CeciliaZ030 CeciliaZ030 commented Sep 23, 2024

Overview

Screenshot 2024-10-02 at 2 53 41 AM

We modified Revm for cross-chain state access, namely, it reads any account/storage with ChainAddress = (ChainId, Address) and we need to support that when we start L2 nodes in ExEx Context.

Current Database & Provider

Screenshot 2024-10-02 at 2 53 23 AM

Revm

Need state provider associated with the current block to execute transactions, so the entire Revm crate abstracts over DB: revm::Database to provide this access. The struct implementation is typically a wrapper holding an in-memory cache state with underlying real database passed from Reth.

pub trait Database {
    /// The database error type.
    type Error;

    /// Get basic account information.
    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;

    /// Get account code by its hash.
    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error>;

    /// Get storage value of address at index.
    fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error>;

    /// Get block hash by block number.
    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error>;
}

Reth

Reth uses a ProviderFactory that holds unique references to an in-memory (mostly MDBX) DB and a StaticFileProvider: https://github.com/paradigmxyz/reth/tree/main/crates/static-file/static-file
The lowest level abstraction of Database in Reth represents operations on reading/writing data, which is different from that of Revm. Between the physical database and Revm state provider, Reth implemented many APIs to access blockchain data and they are mostly in StateProvider trait.

/// Main Database trait that can open read-only and read-write transactions.
///
/// Sealed trait which cannot be implemented by 3rd parties, exposed only for consumption.
pub trait Database: Send + Sync {
    /// Read-Only database transaction
    type TX: DbTx + Send + Sync + Debug + 'static;
    /// Read-Write database transaction
    type TXMut: DbTxMut + DbTx + TableImporter + Send + Sync + Debug + 'static;

    /// Create read only transaction.
    #[track_caller]
    fn tx(&self) -> Result<Self::TX, DatabaseError>;

    /// Create read write transaction only possible if database is open with write access.
    #[track_caller]
    fn tx_mut(&self) -> Result<Self::TXMut, DatabaseError>;
    ... ...
}

Cross-chain Database & Provider

We first modified Revm's Database trait to execute transactions against the targeted state root: taikoxyz/revm#17

pub trait SyncDatabase {
    /// The database error type.
    type Error;

    /// Get basic account information.
    fn basic(&mut self, address: ChainAddress) -> Result<Option<AccountInfo>, Self::Error>;

    /// Get account code by its hash.
    fn code_by_hash(&mut self, chain_id: u64, code_hash: B256) -> Result<Bytecode, Self::Error>;

    /// Get storage value of address at index.
    fn storage(&mut self, address: ChainAddress, index: U256) -> Result<U256, Self::Error>;

    /// Get block hash by block number.
    fn block_hash(&mut self, chain_id: u64, number: u64) -> Result<B256, Self::Error>;
}

For Reth, the cross-chain state provider should be implemented as a HashMap over some database trait, but the concrete type can be anything. Thus, performing type erasure with dyn trait object makes sense. We managed to preserve Reth's abstraction on its physical database and the building process of different generic Box< dyn StateProvider>. The main DB being pass into the executor is the following:

pub struct SyncStateProviderDatabase<DB>(pub HashMap<u64, StateProviderDatabase<DB>>);

This implements SyncDatabase and a modified blanket trait SyncEvmStateProvider which glue the old singleton database with EvmStateProvider and the synchronous database together:

impl<DB: EvmStateProvider> SyncEvmStateProvider for SyncStateProviderDatabase<DB> {
    fn basic_account(&self, address: ChainAddress) -> ProviderResult<Option<Account>> {
        if let Some(db) = self.get(&address.0) {
            db.0.basic_account(address.1)
        } else {
            Err(ProviderError::UnsupportedProvider)
        }
    }
    // ... other functions ...
}

We can start the sync DB compatible with the old code, and insert as many DB instances for multiple L2s in the ExEx context. Note that the CacheDB and state builder with WrapDatabaseRef are also available out of the box:

let state_provider = client.state_by_block_hash(parent_block.hash())?;

Screenshot 2024-10-02 at 8 20 20 PM

Dockerfile Outdated Show resolved Hide resolved
bin/reth/src/main.rs Outdated Show resolved Hide resolved
crates/cli/commands/src/stage/dump/execution.rs Outdated Show resolved Hide resolved
Comment on lines -39 to +42
<TransactionRequest as TransactionBuilder<Ethereum>>::set_blob_sidecar(&mut tx, sidecar);
<TransactionRequest as TransactionBuilder<Ethereum>>::set_max_fee_per_blob_gas(
<TransactionRequest as TransactionBuilder4844>::set_blob_sidecar(&mut tx, sidecar);
<TransactionRequest as TransactionBuilder<Ethereum>>::set_max_fee_per_gas(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this change do?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think it's from different ver of alloy, the old lines doesn't compile anymore

crates/ethereum/payload/src/lib.rs Outdated Show resolved Hide resolved
examples/custom-engine-types/src/main.rs Outdated Show resolved Hide resolved
examples/custom-evm/src/main.rs Outdated Show resolved Hide resolved
examples/custom-inspector/src/main.rs Show resolved Hide resolved
examples/stateful-precompile/src/main.rs Outdated Show resolved Hide resolved
@Brechtpd Brechtpd merged commit f304454 into gwyneth Oct 11, 2024
6 of 28 checks passed
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

Successfully merging this pull request may close these issues.

2 participants