diff --git a/.github/workflows/nightly_build_push.yml b/.github/workflows/nightly_build_push.yml index 486b307bc..1337e7d1c 100644 --- a/.github/workflows/nightly_build_push.yml +++ b/.github/workflows/nightly_build_push.yml @@ -35,7 +35,7 @@ jobs: - name: Build Project run: | - cargo build --features short-prefix + cargo build --features testing - name: Copy binary to build-push/nightly run: | diff --git a/Cargo.lock b/Cargo.lock index bfeea3fc1..97bb9f42c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1994,6 +1994,7 @@ dependencies = [ "secp256k1", "serde", "serde_json", + "sha2", "sov-modules-api", "sov-prover-storage-manager", "sov-rollup-interface", diff --git a/Makefile b/Makefile index c925c1375..0225ab27d 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ EF_TESTS_URL := https://github.com/chainwayxyz/ef-tests/archive/develop.tar.gz EF_TESTS_DIR := crates/evm/ethereum-tests CITREA_E2E_TEST_BINARY := $(CURDIR)/target/debug/citrea PARALLEL_PROOF_LIMIT := 1 -TEST_FEATURES := --features short-prefix +TEST_FEATURES := --features testing BATCH_OUT_PATH := resources/guests/risc0/ LIGHT_OUT_PATH := resources/guests/risc0/ diff --git a/bin/citrea/Cargo.toml b/bin/citrea/Cargo.toml index 50f380264..f78e815a9 100644 --- a/bin/citrea/Cargo.toml +++ b/bin/citrea/Cargo.toml @@ -102,7 +102,7 @@ sp1-helper = { version = "3.0.0", default-features = false } [features] default = [] # Deviate from convention by making the "native" feature active by default. This aligns with how this package is meant to be used (as a binary first, library second). -bench = ["hex"] +testing = ["citrea-primitives/testing", "citrea-risc0/testing", "sov-rollup-interface/testing"] [[bin]] name = "citrea" diff --git a/bin/citrea/src/rollup/mod.rs b/bin/citrea/src/rollup/mod.rs index 9a31b6944..e4a64ecd9 100644 --- a/bin/citrea/src/rollup/mod.rs +++ b/bin/citrea/src/rollup/mod.rs @@ -13,7 +13,7 @@ use jsonrpsee::RpcModule; use sov_db::ledger_db::migrations::LedgerDBMigrator; use sov_db::ledger_db::{LedgerDB, SharedLedgerOps}; use sov_db::rocks_db_config::RocksdbConfig; -use sov_db::schema::types::BatchNumber; +use sov_db::schema::types::SoftConfirmationNumber; use sov_modules_api::Spec; use sov_modules_rollup_blueprint::RollupBlueprint; use sov_modules_stf_blueprint::{Runtime as RuntimeTrait, StfBlueprint}; @@ -123,7 +123,7 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { .get_head_soft_confirmation() .map_err(|e| anyhow!("Failed to get head soft confirmation: {}", e))? .map(|(l2_height, _)| l2_height) - .unwrap_or(BatchNumber(0)); + .unwrap_or(SoftConfirmationNumber(0)); let mut fork_manager = ForkManager::new(get_forks(), current_l2_height.0); fork_manager.register_handler(Box::new(ledger_db.clone())); @@ -254,7 +254,7 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { .get_head_soft_confirmation() .map_err(|e| anyhow!("Failed to get head soft confirmation: {}", e))? .map(|(l2_height, _)| l2_height) - .unwrap_or(BatchNumber(0)); + .unwrap_or(SoftConfirmationNumber(0)); let mut fork_manager = ForkManager::new(get_forks(), current_l2_height.0); fork_manager.register_handler(Box::new(ledger_db.clone())); @@ -382,12 +382,11 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { let elfs_by_spec = self.get_batch_proof_elfs(); let current_l2_height = ledger_db - .get_head_soft_confirmation() + .get_head_soft_confirmation_height() .map_err(|e| anyhow!("Failed to get head soft confirmation: {}", e))? - .map(|(l2_height, _)| l2_height) - .unwrap_or(BatchNumber(0)); + .unwrap_or(0); - let mut fork_manager = ForkManager::new(get_forks(), current_l2_height.0); + let mut fork_manager = ForkManager::new(get_forks(), current_l2_height); fork_manager.register_handler(Box::new(ledger_db.clone())); let runner = CitreaBatchProver::new( @@ -475,7 +474,7 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { .get_head_soft_confirmation() .map_err(|e| anyhow!("Failed to get head soft confirmation: {}", e))? .map(|(l2_height, _)| l2_height) - .unwrap_or(BatchNumber(0)); + .unwrap_or(SoftConfirmationNumber(0)); let mut fork_manager = ForkManager::new(get_forks(), current_l2_height.0); fork_manager.register_handler(Box::new(ledger_db.clone())); diff --git a/bin/citrea/tests/bitcoin_e2e/batch_prover_test.rs b/bin/citrea/tests/bitcoin_e2e/batch_prover_test.rs index f70757632..cd0797981 100644 --- a/bin/citrea/tests/bitcoin_e2e/batch_prover_test.rs +++ b/bin/citrea/tests/bitcoin_e2e/batch_prover_test.rs @@ -291,7 +291,7 @@ impl TestCase for SkipPreprovenCommitmentsTest { // Wait for the full node to see all process verify and store all batch proofs full_node.wait_for_l1_height(finalized_height, None).await?; - let proofs = wait_for_zkproofs(full_node, finalized_height, None) + let proofs = wait_for_zkproofs(full_node, finalized_height, Some(Duration::from_secs(600))) .await .unwrap(); diff --git a/bin/citrea/tests/e2e/sequencer_behaviour.rs b/bin/citrea/tests/e2e/sequencer_behaviour.rs index 73f0754fd..34b2a91f6 100644 --- a/bin/citrea/tests/e2e/sequencer_behaviour.rs +++ b/bin/citrea/tests/e2e/sequencer_behaviour.rs @@ -425,7 +425,7 @@ async fn test_gas_limit_too_high() { assert_eq!(block_from_sequencer.header.hash, block.header.hash); seq_test_client.send_publish_batch_request().await; - wait_for_l2_block(&full_node_test_client, 2, None).await; + wait_for_l2_block(&full_node_test_client, 2, Some(Duration::from_secs(60))).await; let block = full_node_test_client .eth_get_block_by_number(Some(BlockNumberOrTag::Latest)) diff --git a/crates/batch-prover/src/da_block_handler.rs b/crates/batch-prover/src/da_block_handler.rs index 7ce464588..98b399aba 100644 --- a/crates/batch-prover/src/da_block_handler.rs +++ b/crates/batch-prover/src/da_block_handler.rs @@ -17,7 +17,7 @@ use rand::Rng; use serde::de::DeserializeOwned; use serde::Serialize; use sov_db::ledger_db::BatchProverLedgerOps; -use sov_db::schema::types::{BatchNumber, SlotNumber}; +use sov_db::schema::types::{SlotNumber, SoftConfirmationNumber}; use sov_modules_api::{DaSpec, StateDiff, Zkvm}; use sov_rollup_interface::da::{BlockHeaderTrait, SequencerCommitment}; use sov_rollup_interface::services::da::{DaService, SlotData}; @@ -365,9 +365,9 @@ pub(crate) async fn get_batch_proof_circuit_input_from_commitments< let mut witnesses = vec![]; let start_l2 = sequencer_commitment.l2_start_block_number; let end_l2 = sequencer_commitment.l2_end_block_number; - let soft_confirmations_in_commitment = match ledger_db - .get_soft_confirmation_range(&(BatchNumber(start_l2)..=BatchNumber(end_l2))) - { + let soft_confirmations_in_commitment = match ledger_db.get_soft_confirmation_range( + &(SoftConfirmationNumber(start_l2)..=SoftConfirmationNumber(end_l2)), + ) { Ok(soft_confirmations) => soft_confirmations, Err(e) => { return Err(anyhow!( @@ -450,14 +450,13 @@ pub(crate) fn break_sequencer_commitments_into_groups( for l2_height in sequencer_commitment.l2_start_block_number..=sequencer_commitment.l2_end_block_number { - let state_diff = - ledger_db - .get_l2_state_diff(BatchNumber(l2_height))? - .ok_or(anyhow!( - "Could not find state diff for L2 range {}-{}", - sequencer_commitment.l2_start_block_number, - sequencer_commitment.l2_end_block_number - ))?; + let state_diff = ledger_db + .get_l2_state_diff(SoftConfirmationNumber(l2_height))? + .ok_or(anyhow!( + "Could not find state diff for L2 range {}-{}", + sequencer_commitment.l2_start_block_number, + sequencer_commitment.l2_end_block_number + ))?; sequencer_commitment_state_diff = merge_state_diffs(sequencer_commitment_state_diff, state_diff); } diff --git a/crates/batch-prover/src/proving.rs b/crates/batch-prover/src/proving.rs index ba0054991..8c2e580dd 100644 --- a/crates/batch-prover/src/proving.rs +++ b/crates/batch-prover/src/proving.rs @@ -11,7 +11,7 @@ use citrea_primitives::forks::fork_from_block_number; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use sov_db::ledger_db::BatchProverLedgerOps; -use sov_db::schema::types::{BatchNumber, StoredBatchProof, StoredBatchProofOutput}; +use sov_db::schema::types::{SoftConfirmationNumber, StoredBatchProof, StoredBatchProofOutput}; use sov_modules_api::{BatchProofCircuitOutput, BlobReaderTrait, SlotData, SpecId, Zkvm}; use sov_rollup_interface::da::{BlockHeaderTrait, DaNamespace, DaSpec, SequencerCommitment}; use sov_rollup_interface::rpc::SoftConfirmationStatus; @@ -164,7 +164,7 @@ where .expect("There should be a state root"); let initial_batch_hash = ledger - .get_soft_confirmation_by_number(&BatchNumber(first_l2_height_of_l1)) + .get_soft_confirmation_by_number(&SoftConfirmationNumber(first_l2_height_of_l1)) .map_err(|e| { L1ProcessingError::Other(format!("Error getting initial batch hash: {:?}", e)) })? @@ -388,7 +388,10 @@ pub(crate) fn save_commitments( let l2_end_height = sequencer_commitment.l2_end_block_number; for i in l2_start_height..=l2_end_height { ledger_db - .put_soft_confirmation_status(BatchNumber(i), SoftConfirmationStatus::Proven) + .put_soft_confirmation_status( + SoftConfirmationNumber(i), + SoftConfirmationStatus::Proven, + ) .unwrap_or_else(|_| { panic!( "Failed to put soft confirmation status in the ledger db {}", diff --git a/crates/batch-prover/src/runner.rs b/crates/batch-prover/src/runner.rs index ff1e3b175..f6171cc32 100644 --- a/crates/batch-prover/src/runner.rs +++ b/crates/batch-prover/src/runner.rs @@ -19,7 +19,7 @@ use jsonrpsee::http_client::{HttpClient, HttpClientBuilder}; use jsonrpsee::server::{BatchRequestConfig, ServerBuilder}; use jsonrpsee::RpcModule; use sov_db::ledger_db::BatchProverLedgerOps; -use sov_db::schema::types::{BatchNumber, SlotNumber}; +use sov_db::schema::types::{SlotNumber, SoftConfirmationNumber}; use sov_ledger_rpc::LedgerRpcClient; use sov_modules_api::{Context, SignedSoftConfirmation, SlotData, Spec}; use sov_modules_stf_blueprint::{Runtime, StfBlueprint}; @@ -130,12 +130,8 @@ where } }; - // Start the main rollup loop - let item_numbers = ledger_db.get_next_items_numbers(); - let last_soft_confirmation_processed_before_shutdown = - item_numbers.soft_confirmation_number; // Last L1/L2 height before shutdown. - let start_l2_height = last_soft_confirmation_processed_before_shutdown; + let start_l2_height = ledger_db.get_head_soft_confirmation_height()?.unwrap_or(0) + 1; Ok(Self { start_l2_height, @@ -446,8 +442,10 @@ where } // Save state diff to ledger DB - self.ledger_db - .set_l2_state_diff(BatchNumber(l2_height), soft_confirmation_result.state_diff)?; + self.ledger_db.set_l2_state_diff( + SoftConfirmationNumber(l2_height), + soft_confirmation_result.state_diff, + )?; // Save witnesses data to ledger db self.ledger_db.set_l2_witness( @@ -472,7 +470,7 @@ where self.ledger_db.extend_l2_range_of_l1_slot( SlotNumber(current_l1_block.header().height()), - BatchNumber(l2_height), + SoftConfirmationNumber(l2_height), )?; // Register this new block with the fork manager to active diff --git a/crates/common/src/rpc/mod.rs b/crates/common/src/rpc/mod.rs index 26fed170b..d34eab3fe 100644 --- a/crates/common/src/rpc/mod.rs +++ b/crates/common/src/rpc/mod.rs @@ -11,7 +11,7 @@ use jsonrpsee::types::error::{INTERNAL_ERROR_CODE, INTERNAL_ERROR_MSG}; use jsonrpsee::types::{ErrorObjectOwned, Request}; use jsonrpsee::{MethodResponse, RpcModule}; use sov_db::ledger_db::{LedgerDB, SharedLedgerOps}; -use sov_db::schema::types::BatchNumber; +use sov_db::schema::types::SoftConfirmationNumber; use tower_http::cors::{Any, CorsLayer}; // Exit early if head_batch_num is below this threshold @@ -33,7 +33,7 @@ pub fn register_healthcheck_rpc( ) }; - let Some((BatchNumber(head_batch_num), _)) = ledger_db + let Some((SoftConfirmationNumber(head_batch_num), _)) = ledger_db .get_head_soft_confirmation() .map_err(|err| error(&format!("Failed to get head soft batch: {}", err)))? else { @@ -47,7 +47,8 @@ pub fn register_healthcheck_rpc( let soft_batches = ledger_db .get_soft_confirmation_range( - &(BatchNumber(head_batch_num - 1)..=BatchNumber(head_batch_num)), + &(SoftConfirmationNumber(head_batch_num - 1) + ..=SoftConfirmationNumber(head_batch_num)), ) .map_err(|err| error(&format!("Failed to get soft batch range: {}", err)))?; @@ -58,7 +59,7 @@ pub fn register_healthcheck_rpc( .get_head_soft_confirmation() .map_err(|err| error(&format!("Failed to get head soft batch: {}", err)))? .unwrap(); - if new_head_batch_num > BatchNumber(head_batch_num) { + if new_head_batch_num > SoftConfirmationNumber(head_batch_num) { Ok::<(), ErrorObjectOwned>(()) } else { Err(error("Block number is not increasing")) diff --git a/crates/common/src/utils.rs b/crates/common/src/utils.rs index 2a35866b6..88b757633 100644 --- a/crates/common/src/utils.rs +++ b/crates/common/src/utils.rs @@ -1,7 +1,7 @@ use std::collections::{HashMap, HashSet}; use sov_db::ledger_db::SharedLedgerOps; -use sov_db::schema::types::BatchNumber; +use sov_db::schema::types::SoftConfirmationNumber; use sov_modules_api::{Context, Spec}; use sov_rollup_interface::da::{DaSpec, SequencerCommitment}; use sov_rollup_interface::digest::Digest; @@ -53,8 +53,9 @@ fn filter_out_commitments_by_status( visited_l2_ranges.insert(current_range); // Check if the commitment was previously finalized. - let Some(status) = ledger_db - .get_soft_confirmation_status(BatchNumber(sequencer_commitment.l2_end_block_number))? + let Some(status) = ledger_db.get_soft_confirmation_status(SoftConfirmationNumber( + sequencer_commitment.l2_end_block_number, + ))? else { filtered.push(sequencer_commitment.clone()); continue; @@ -76,7 +77,8 @@ pub fn check_l2_range_exists( last_l2_height_of_l1: u64, ) -> bool { if let Ok(range) = ledger_db.get_soft_confirmation_range( - &(BatchNumber(first_l2_height_of_l1)..=BatchNumber(last_l2_height_of_l1)), + &(SoftConfirmationNumber(first_l2_height_of_l1) + ..=SoftConfirmationNumber(last_l2_height_of_l1)), ) { if (range.len() as u64) >= (last_l2_height_of_l1 - first_l2_height_of_l1 + 1) { return true; diff --git a/crates/evm/Cargo.toml b/crates/evm/Cargo.toml index 51f8ad5fe..8a7e43a30 100644 --- a/crates/evm/Cargo.toml +++ b/crates/evm/Cargo.toml @@ -49,7 +49,7 @@ reth-rpc-eth-types = { workspace = true, optional = true } reth-rpc-server-types = { workspace = true, optional = true } reth-rpc-types-compat = { workspace = true, optional = true } reth-transaction-pool = { workspace = true, optional = true } -revm = { workspace = true, features = ["secp256k1"] } +revm = { workspace = true, default-features = false, features = ["secp256k1"] } revm-inspectors = { workspace = true, optional = true } secp256k1 = { workspace = true, optional = true } @@ -64,7 +64,8 @@ rayon = { workspace = true } reth-chainspec = { workspace = true } reth-db = { workspace = true } reth-errors = { workspace = true } -revm = { workspace = true, features = ["optional_block_gas_limit", "optional_eip3607", "optional_no_base_fee", "secp256k1"] } +revm = { workspace = true, default-features = false, features = ["optional_block_gas_limit", "optional_eip3607", "optional_no_base_fee", "secp256k1"] } +sha2 = { workspace = true } sov-modules-api = { path = "../sovereign-sdk/module-system/sov-modules-api", features = ["macros"] } sov-prover-storage-manager = { path = "../sovereign-sdk/full-node/sov-prover-storage-manager", features = ["test-utils"] } sov-rollup-interface = { path = "../sovereign-sdk/rollup-interface", features = ["testing"] } @@ -84,6 +85,7 @@ native = [ "reth-rpc-eth-api", "reth-rpc-server-types", "reth-rpc-types-compat", + "revm/serde", "reth-transaction-pool", "revm-inspectors", "reth-provider", diff --git a/crates/evm/src/call.rs b/crates/evm/src/call.rs index 5dc5e4b61..1d6dcb99e 100644 --- a/crates/evm/src/call.rs +++ b/crates/evm/src/call.rs @@ -5,6 +5,7 @@ use revm::primitives::{BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}; use sov_modules_api::prelude::*; use sov_modules_api::{native_error, CallResponse, SoftConfirmationModuleCallError, WorkingSet}; +use crate::conversions::ConversionError; use crate::evm::db::EvmDb; use crate::evm::executor::{self}; use crate::evm::handler::{CitreaExternal, CitreaExternalExt}; @@ -131,14 +132,11 @@ impl Evm { ) -> Result { // use of `self.block_env` is allowed here - // TODO: should not include non deserilizable transactions let users_txs: Vec = txs .into_iter() - .filter_map(|tx| match tx.try_into() { - Ok(tx) => Some(tx), - Err(_) => None, - }) - .collect(); + .map(|tx| tx.try_into()) + .collect::, ConversionError>>() + .map_err(|_| SoftConfirmationModuleCallError::EvmTxNotSerializable)?; let cfg = self.cfg.get(working_set).expect("Evm config must be set"); let active_evm_spec = citrea_spec_id_to_evm_spec_id(context.active_spec()); diff --git a/crates/evm/src/evm/handler.rs b/crates/evm/src/evm/handler.rs index 16fa41639..a323e3110 100644 --- a/crates/evm/src/evm/handler.rs +++ b/crates/evm/src/evm/handler.rs @@ -8,13 +8,14 @@ use revm::handler::register::{EvmHandler, HandleRegisters}; #[cfg(feature = "native")] use revm::interpreter::{CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter}; use revm::interpreter::{Gas, InstructionResult}; +use revm::precompile::u64_to_address; #[cfg(feature = "native")] use revm::primitives::Log; use revm::primitives::{ spec_to_generic, Address, EVMError, Env, HandlerCfg, InvalidTransaction, ResultAndState, Spec, SpecId, B256, U256, }; -use revm::{Context, Database, FrameResult, InnerEvmContext, JournalEntry}; +use revm::{Context, ContextPrecompiles, Database, FrameResult, InnerEvmContext, JournalEntry}; #[cfg(feature = "native")] use revm::{EvmContext, Inspector}; use sov_modules_api::{native_debug, native_error, native_warn}; @@ -290,7 +291,7 @@ where // validation.env = validation.tx_against_state = Arc::new(CitreaHandler::::validate_tx_against_state); - // pre_execution.load_accounts = + pre_execution.load_precompiles = Arc::new(CitreaHandler::::load_precompiles); // pre_execution.load_accounts = pre_execution.deduct_caller = Arc::new(CitreaHandler::::deduct_caller); // execution.last_frame_return = @@ -314,6 +315,22 @@ struct CitreaHandler { } impl CitreaHandler { + fn load_precompiles() -> ContextPrecompiles { + fn our_precompiles() -> ContextPrecompiles { + let mut precompiles = revm::handler::mainnet::load_precompiles::(); + + if SPEC::enabled(SpecId::CANCUN) { + precompiles + .to_mut() + .remove(&u64_to_address(0x0A)) + .expect("after cancun point eval should be removed"); + } + + precompiles + } + + our_precompiles::() + } fn validate_tx_against_state( context: &mut Context, ) -> Result<(), EVMError> { diff --git a/crates/evm/src/evm/test_data/KZGPointEvaluationCaller.abi b/crates/evm/src/evm/test_data/KZGPointEvaluationCaller.abi new file mode 100644 index 000000000..f5bbbc1ef --- /dev/null +++ b/crates/evm/src/evm/test_data/KZGPointEvaluationCaller.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"bytes","name":"input","type":"bytes"}],"name":"verifyPointEvaluation","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/crates/evm/src/evm/test_data/KZGPointEvaluationCaller.bin b/crates/evm/src/evm/test_data/KZGPointEvaluationCaller.bin new file mode 100644 index 000000000..6afea8cd5 --- /dev/null +++ b/crates/evm/src/evm/test_data/KZGPointEvaluationCaller.bin @@ -0,0 +1 @@ +6080604052348015600e575f5ffd5b506103208061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c806325a05f401461002d575b5f5ffd5b610047600480360381019061004291906101a0565b61005d565b6040516100549190610205565b60405180910390f35b5f60c083839050146100a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161009b90610278565b60405180910390fd5b6060600a73ffffffffffffffffffffffffffffffffffffffff1684846040516100ce9291906102d2565b5f60405180830381855afa9150503d805f8114610106576040519150601f19603f3d011682016040523d82523d5f602084013e61010b565b606091505b5080925081935050505f815114610120575f5ffd5b60408101515f5581610130575f5ffd5b5092915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f8401126101605761015f61013f565b5b8235905067ffffffffffffffff81111561017d5761017c610143565b5b60208301915083600182028301111561019957610198610147565b5b9250929050565b5f5f602083850312156101b6576101b5610137565b5b5f83013567ffffffffffffffff8111156101d3576101d261013b565b5b6101df8582860161014b565b92509250509250929050565b5f8115159050919050565b6101ff816101eb565b82525050565b5f6020820190506102185f8301846101f6565b92915050565b5f82825260208201905092915050565b7f496e76616c696420696e7075742073697a6500000000000000000000000000005f82015250565b5f61026260128361021e565b915061026d8261022e565b602082019050919050565b5f6020820190508181035f83015261028f81610256565b9050919050565b5f81905092915050565b828183375f83830152505050565b5f6102b98385610296565b93506102c68385846102a0565b82840190509392505050565b5f6102de8284866102ae565b9150819050939250505056fea264697066735822122052f3d3eafaae24a10a4cb029d517a2fc7b949c9ee79750ca303d13aba9fb158264736f6c634300081b0033 \ No newline at end of file diff --git a/crates/evm/src/evm/test_data/KZGPointEvaluationCaller.sol b/crates/evm/src/evm/test_data/KZGPointEvaluationCaller.sol new file mode 100644 index 000000000..970b75635 --- /dev/null +++ b/crates/evm/src/evm/test_data/KZGPointEvaluationCaller.sol @@ -0,0 +1,21 @@ + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; + +contract KZGPointEvaluationCaller { + /// @notice Calls the 0x0A precompile to perform point evaluation + /// @param input A 192-byte input representing the polynomial versioned hash, commitment, point, and proof + function verifyPointEvaluation( + bytes calldata input // 192 bytes + ) external returns (bool success) { + require(input.length == 192, "Invalid input size"); + bytes memory out; + (success, out) = address(10).staticcall(input); + require(out.length == 0); + // Write the 32 bytes of out to first storage slot + assembly { + sstore(0, mload(add(out, 64))) + } + require(success); + } +} \ No newline at end of file diff --git a/crates/evm/src/smart_contracts/kzg_point_evaluation_caller.rs b/crates/evm/src/smart_contracts/kzg_point_evaluation_caller.rs new file mode 100644 index 000000000..551e56b43 --- /dev/null +++ b/crates/evm/src/smart_contracts/kzg_point_evaluation_caller.rs @@ -0,0 +1,49 @@ +use alloy_primitives::Bytes; +use alloy_sol_types::{sol, SolCall}; + +use super::TestContract; + +// KZGPointEvaluationCallerContract wrapper. +sol! { + #[sol(abi)] + KZGPointEvaluationCaller, + "./src/evm/test_data/KZGPointEvaluationCaller.abi" +} + +/// KZGPointEvaluationContract wrapper. +pub struct KZGPointEvaluationCallerContract { + bytecode: Vec, +} + +impl Default for KZGPointEvaluationCallerContract { + fn default() -> Self { + let bytecode = { + let bytecode_hex = + include_str!("../../../evm/src/evm/test_data/KZGPointEvaluationCaller.bin"); + hex::decode(bytecode_hex).unwrap() + }; + + Self { bytecode } + } +} + +impl TestContract for KZGPointEvaluationCallerContract { + fn byte_code(&self) -> Vec { + self.byte_code() + } +} + +impl KZGPointEvaluationCallerContract { + /// KZGPointEvaluation bytecode. + pub fn byte_code(&self) -> Vec { + self.bytecode.clone() + } + + /// Claims the gift. + pub fn call_kzg_point_evaluation( + &self, + input: Bytes, // 192 bytes + ) -> Vec { + KZGPointEvaluationCaller::verifyPointEvaluationCall { input }.abi_encode() + } +} diff --git a/crates/evm/src/smart_contracts/mod.rs b/crates/evm/src/smart_contracts/mod.rs index d32c43648..d35dee325 100644 --- a/crates/evm/src/smart_contracts/mod.rs +++ b/crates/evm/src/smart_contracts/mod.rs @@ -6,6 +6,7 @@ mod caller_contract; mod coinbase_contract; mod hive_contract; mod infinite_loop_contract; +mod kzg_point_evaluation_caller; mod logs_contract; mod mcopy_contract; mod payable_contract; @@ -20,6 +21,7 @@ pub use caller_contract::CallerContract; pub use coinbase_contract::CoinbaseContract; pub use hive_contract::HiveContract; pub use infinite_loop_contract::InfiniteLoopContract; +pub use kzg_point_evaluation_caller::KZGPointEvaluationCallerContract; pub use logs_contract::{AnotherLogEvent, LogEvent, LogsContract}; pub use mcopy_contract::McopyContract; pub use payable_contract::SimplePayableContract; diff --git a/crates/evm/src/tests/fork_tests.rs b/crates/evm/src/tests/fork_tests.rs index 07051b6af..f117f5b8c 100644 --- a/crates/evm/src/tests/fork_tests.rs +++ b/crates/evm/src/tests/fork_tests.rs @@ -1,7 +1,9 @@ use std::str::FromStr; +use std::thread::sleep; -use alloy_primitives::{address, keccak256, Address, TxKind}; +use alloy_primitives::{address, keccak256, Address, Bytes, TxKind}; use revm::primitives::U256; +use sha2::Digest; use sov_modules_api::default_context::DefaultContext; use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::utils::generate_address; @@ -11,17 +13,19 @@ use sov_rollup_interface::spec::SpecId as SovSpecId; use crate::call::CallMessage; use crate::evm::DbAccount; use crate::smart_contracts::{ - BlobBaseFeeContract, McopyContract, SelfdestructingConstructorContract, - TransientStorageContract, + BlobBaseFeeContract, KZGPointEvaluationCallerContract, McopyContract, SelfDestructorContract, + SelfdestructingConstructorContract, SimpleStorageContract, TransientStorageContract, }; use crate::tests::test_signer::TestSigner; -use crate::tests::utils::{create_contract_message, get_evm, get_evm_config}; +use crate::tests::utils::{create_contract_message, get_evm, get_evm_config, set_arg_message}; use crate::RlpEvmTransaction; type C = DefaultContext; use super::call_tests::send_money_to_contract_message; use super::utils::create_contract_message_with_bytecode; +const VERSIONED_HASH_VERSION_KZG: u8 = 1; + fn claim_gift_from_transient_storage_contract_transaction( contract_addr: Address, dev_signer: &TestSigner, @@ -56,6 +60,23 @@ fn store_blob_base_fee_transaction( .unwrap() } +fn call_kzg_point_evaluation_transaction( + contract_addr: Address, + dev_signer: &TestSigner, + nonce: u64, + input: Bytes, +) -> RlpEvmTransaction { + let contract = KZGPointEvaluationCallerContract::default(); + dev_signer + .sign_default_transaction( + TxKind::Call(contract_addr), + contract.call_kzg_point_evaluation(input), + nonce, + 0, + ) + .unwrap() +} + #[test] fn test_cancun_transient_storage_activation() { let (config, dev_signer, contract_addr) = @@ -234,7 +255,6 @@ fn test_cancun_mcopy_activation() { timestamp: 0, }; - // Deploy transient storage contract let sender_address = generate_address::("sender"); evm.begin_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); { @@ -436,7 +456,6 @@ fn test_blob_base_fee_should_return_1() { timestamp: 0, }; - // Deploy transient storage contract let sender_address = generate_address::("sender"); evm.begin_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); { @@ -535,3 +554,292 @@ fn test_blob_base_fee_should_return_1() { assert_eq!(storage_value, U256::from(1)); } + +#[test] +fn test_kzg_point_eval_should_revert() { + let (config, dev_signer, contract_addr) = + get_evm_config(U256::from_str("100000000000000000000").unwrap(), None); + + let (mut evm, mut working_set) = get_evm(&config); + let l1_fee_rate = 0; + let mut l2_height = 2; + + let soft_confirmation_info = HookSoftConfirmationInfo { + l2_height, + da_slot_hash: [5u8; 32], + da_slot_height: 1, + da_slot_txs_commitment: [42u8; 32], + pre_state_root: [10u8; 32].to_vec(), + current_spec: SovSpecId::Fork1, + pub_key: vec![], + deposit_data: vec![], + l1_fee_rate, + timestamp: 0, + }; + + let sender_address = generate_address::("sender"); + evm.begin_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + { + let context = C::new(sender_address, l2_height, SovSpecId::Fork1, l1_fee_rate); + + let deploy_message = + create_contract_message(&dev_signer, 0, KZGPointEvaluationCallerContract::default()); + + evm.call( + CallMessage { + txs: vec![deploy_message], + }, + &context, + &mut working_set, + ) + .unwrap(); + } + evm.end_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + evm.finalize_hook(&[99u8; 32].into(), &mut working_set.accessory_state()); + + l2_height += 1; + + // Implementation taken from https://eips.ethereum.org/EIPS/eip-4844#point-evaluation-precompile + fn kzg_to_versioned_hash(commitment: Bytes) -> Bytes { + let mut commitment_hash = sha2::Sha256::digest(commitment).to_vec(); + commitment_hash[0] = VERSIONED_HASH_VERSION_KZG; + Bytes::from(commitment_hash) + } + + // data is taken from: https://github.com/ethereum/c-kzg-4844/tree/main/tests/verify_kzg_proof/kzg-mainnet/verify_kzg_proof_case_correct_proof_d0992bc0387790a4 + let commitment= Bytes::from_str("8f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7").unwrap(); + let versioned_hash = kzg_to_versioned_hash(commitment.clone()); + let z = Bytes::from_str("5eb7004fe57383e6c88b99d839937fddf3f99279353aaf8d5c9a75f91ce33c62") + .unwrap(); + let y = Bytes::from_str("4882cf0609af8c7cd4c256e63a35838c95a9ebbf6122540ab344b42fd66d32e1") + .unwrap(); + let proof = Bytes::from_str("0x987ea6df69bbe97c23e0dd948cf2d4490824ba7fea5af812721b2393354b0810a9dba2c231ea7ae30f26c412c7ea6e3a").unwrap(); + + // The data is encoded as follows: versioned_hash | z | y | commitment | proof | with z and y being padded 32 byte big endian values + // ref: https://eips.ethereum.org/EIPS/eip-4844#point-evaluation-precompile + let mut input = vec![]; + input.extend_from_slice(&versioned_hash); + input.extend_from_slice(&z); + input.extend_from_slice(&y); + input.extend_from_slice(&commitment); + input.extend_from_slice(&proof); + + evm.begin_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + { + let context = C::new(sender_address, l2_height, SovSpecId::Fork1, l1_fee_rate); + + let deploy_message = call_kzg_point_evaluation_transaction( + contract_addr, + &dev_signer, + 1, + Bytes::from(input), + ); + + evm.call( + CallMessage { + txs: vec![deploy_message], + }, + &context, + &mut working_set, + ) + .unwrap(); + } + evm.end_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + evm.finalize_hook(&[99u8; 32].into(), &mut working_set.accessory_state()); + + // expect this call to fail because we do not have the kzg feature of revm enabled on fork1 + let receipts: Vec<_> = evm + .receipts + .iter(&mut working_set.accessory_state()) + .collect(); + + let db_account = DbAccount::new(contract_addr); + let storage_value = db_account + .storage + .get(&U256::ZERO, &mut working_set) + .unwrap(); + assert_ne!( + storage_value, + // expected if point eval precompile was enabled + U256::from_str( + "52435875175126190479447740508185965837690552500527637822603658699938581184513" + ) + .unwrap() + ); + assert!(receipts.last().unwrap().receipt.success); +} + +#[test] +fn test_offchain_contract_storage_evm() { + let (config, dev_signer, contract_addr) = + get_evm_config(U256::from_str("100000000000000000000").unwrap(), None); + + let (mut evm, mut working_set) = get_evm(&config); + let l1_fee_rate = 0; + let mut l2_height = 2; + + // Deployed a contract in genesis fork + let soft_confirmation_info = HookSoftConfirmationInfo { + l2_height, + da_slot_hash: [5u8; 32], + da_slot_height: 1, + da_slot_txs_commitment: [42u8; 32], + pre_state_root: [10u8; 32].to_vec(), + current_spec: SovSpecId::Genesis, + pub_key: vec![], + deposit_data: vec![], + l1_fee_rate, + timestamp: 0, + }; + + let sender_address = generate_address::("sender"); + evm.begin_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + { + let context = C::new(sender_address, l2_height, SovSpecId::Genesis, l1_fee_rate); + + let deploy_message = + create_contract_message(&dev_signer, 0, SimpleStorageContract::default()); + + evm.call( + CallMessage { + txs: vec![deploy_message], + }, + &context, + &mut working_set, + ) + .unwrap(); + } + evm.end_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + evm.finalize_hook(&[99u8; 32].into(), &mut working_set.accessory_state()); + + l2_height += 1; + + sleep(std::time::Duration::from_secs(2)); + + //try to get it from offchain storage and expect it to not exist + let contract_info = evm.accounts.get(&contract_addr, &mut working_set); + let code_hash = contract_info.unwrap().code_hash.unwrap(); + + let offchain_code = evm + .offchain_code + .get(&code_hash, &mut working_set.offchain_state()); + + assert!(offchain_code.is_none()); + + // activate fork and then try to get it from offchain storage and expect it to exist + // Deployed a contract in genesis fork + let soft_confirmation_info = HookSoftConfirmationInfo { + l2_height, + da_slot_hash: [5u8; 32], + da_slot_height: 1, + da_slot_txs_commitment: [42u8; 32], + pre_state_root: [10u8; 32].to_vec(), + current_spec: SovSpecId::Fork1, + pub_key: vec![], + deposit_data: vec![], + l1_fee_rate, + timestamp: 0, + }; + evm.begin_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + evm.end_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + evm.finalize_hook(&[99u8; 32].into(), &mut working_set.accessory_state()); + sleep(std::time::Duration::from_secs(2)); + l2_height += 1; + + let offchain_code = evm + .offchain_code + .get(&code_hash, &mut working_set.offchain_state()); + + assert!(offchain_code.is_none()); + + let evm_code = evm.code.get(&code_hash, &mut working_set).unwrap(); + + let code = evm + .get_code( + contract_addr, + Some(alloy_eips::BlockId::Number( + alloy_eips::BlockNumberOrTag::Latest, + )), + &mut working_set, + ) + .unwrap(); + + assert_eq!(code, evm_code.original_bytes()); + + // Deploy contract in fork1 + evm.begin_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + { + let context = C::new(sender_address, l2_height, SovSpecId::Fork1, l1_fee_rate); + + let deploy_message = + create_contract_message(&dev_signer, 1, SelfDestructorContract::default()); + + evm.call( + CallMessage { + txs: vec![deploy_message], + }, + &context, + &mut working_set, + ) + .unwrap(); + } + evm.end_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + evm.finalize_hook(&[99u8; 32].into(), &mut working_set.accessory_state()); + l2_height += 1; + + let new_contract_address = address!("d26ff5586e488e65d86bcc3f0fe31551e381a596"); + + let contract_info = evm.accounts.get(&new_contract_address, &mut working_set); + let code_hash = contract_info.unwrap().code_hash.unwrap(); + + let offchain_code = evm + .offchain_code + .get(&code_hash, &mut working_set.offchain_state()); + + assert!(offchain_code.is_some()); + + let evm_code = evm.code.get(&code_hash, &mut working_set); + assert!(evm_code.is_none()); + + // make tx on the contract that was deployed before fork1 and see that you can read it from offchain storage afterwards + let soft_confirmation_info = HookSoftConfirmationInfo { + l2_height, + da_slot_hash: [5u8; 32], + da_slot_height: 1, + da_slot_txs_commitment: [42u8; 32], + pre_state_root: [10u8; 32].to_vec(), + current_spec: SovSpecId::Fork1, + pub_key: vec![], + deposit_data: vec![], + l1_fee_rate, + timestamp: 0, + }; + + evm.begin_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + { + let context = C::new(sender_address, l2_height, SovSpecId::Fork1, l1_fee_rate); + + let call_message = set_arg_message(contract_addr, &dev_signer, 2, 99); + + evm.call( + CallMessage { + txs: vec![call_message], + }, + &context, + &mut working_set, + ) + .unwrap(); + } + evm.end_soft_confirmation_hook(&soft_confirmation_info, &mut working_set); + evm.finalize_hook(&[99u8; 32].into(), &mut working_set.accessory_state()); + + // Now I should be able to read the contract from offchain storage + let contract_info = evm.accounts.get(&contract_addr, &mut working_set); + let code_hash = contract_info.unwrap().code_hash.unwrap(); + + let offchain_code = evm + .offchain_code + .get(&code_hash, &mut working_set.offchain_state()); + + assert!(offchain_code.is_some()); +} diff --git a/crates/fullnode/src/da_block_handler.rs b/crates/fullnode/src/da_block_handler.rs index 78ce4a08f..cb7cd7eee 100644 --- a/crates/fullnode/src/da_block_handler.rs +++ b/crates/fullnode/src/da_block_handler.rs @@ -17,7 +17,7 @@ use serde::de::DeserializeOwned; use serde::Serialize; use sov_db::ledger_db::NodeLedgerOps; use sov_db::schema::types::{ - BatchNumber, SlotNumber, StoredBatchProofOutput, StoredSoftConfirmation, + SlotNumber, SoftConfirmationNumber, StoredBatchProofOutput, StoredSoftConfirmation, }; use sov_modules_api::{Context, Zkvm}; use sov_rollup_interface::da::{BlockHeaderTrait, SequencerCommitment}; @@ -237,7 +237,7 @@ where // and compare the root with the one from the ledger let stored_soft_confirmations: Vec = self.ledger_db.get_soft_confirmation_range( - &(BatchNumber(start_l2_height)..=BatchNumber(end_l2_height)), + &(SoftConfirmationNumber(start_l2_height)..=SoftConfirmationNumber(end_l2_height)), )?; // Make sure that the number of stored soft confirmations is equal to the range's length. @@ -278,11 +278,13 @@ where )?; for i in start_l2_height..=end_l2_height { - self.ledger_db - .put_soft_confirmation_status(BatchNumber(i), SoftConfirmationStatus::Finalized)?; + self.ledger_db.put_soft_confirmation_status( + SoftConfirmationNumber(i), + SoftConfirmationStatus::Finalized, + )?; } self.ledger_db - .set_last_commitment_l2_height(BatchNumber(end_l2_height))?; + .set_last_commitment_l2_height(SoftConfirmationNumber(end_l2_height))?; Ok(()) } @@ -408,8 +410,10 @@ where let l2_start_height = commitment.l2_start_block_number; let l2_end_height = commitment.l2_end_block_number; for i in l2_start_height..=l2_end_height { - self.ledger_db - .put_soft_confirmation_status(BatchNumber(i), SoftConfirmationStatus::Proven)?; + self.ledger_db.put_soft_confirmation_status( + SoftConfirmationNumber(i), + SoftConfirmationStatus::Proven, + )?; } } // store in ledger db diff --git a/crates/fullnode/src/runner.rs b/crates/fullnode/src/runner.rs index 550201674..2eafe51f6 100644 --- a/crates/fullnode/src/runner.rs +++ b/crates/fullnode/src/runner.rs @@ -19,7 +19,7 @@ use jsonrpsee::http_client::{HttpClient, HttpClientBuilder}; use jsonrpsee::server::{BatchRequestConfig, RpcServiceBuilder, ServerBuilder}; use jsonrpsee::RpcModule; use sov_db::ledger_db::NodeLedgerOps; -use sov_db::schema::types::{BatchNumber, SlotNumber}; +use sov_db::schema::types::{SlotNumber, SoftConfirmationNumber}; use sov_ledger_rpc::LedgerRpcClient; use sov_modules_api::{Context, SignedSoftConfirmation, Spec}; use sov_modules_stf_blueprint::{Runtime, StfBlueprint}; @@ -125,7 +125,7 @@ where } }; - let start_l2_height = ledger_db.get_next_items_numbers().soft_confirmation_number; + let start_l2_height = ledger_db.get_head_soft_confirmation_height()?.unwrap_or(0) + 1; info!("Starting L2 height: {}", start_l2_height); @@ -293,7 +293,7 @@ where self.ledger_db.extend_l2_range_of_l1_slot( SlotNumber(current_l1_block.header().height()), - BatchNumber(l2_height), + SoftConfirmationNumber(l2_height), )?; // Register this new block with the fork manager to active diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 5adf7c5d8..5ddaa3cb2 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -19,5 +19,4 @@ brotli = { workspace = true } sov-rollup-interface = { path = "../sovereign-sdk/rollup-interface", features = ["testing"] } [features] -testing = ["short-prefix"] -short-prefix = [] +testing = ["sov-rollup-interface/testing"] diff --git a/crates/primitives/src/constants.rs b/crates/primitives/src/constants.rs index 276685f7b..8db31fbfa 100644 --- a/crates/primitives/src/constants.rs +++ b/crates/primitives/src/constants.rs @@ -1,13 +1,13 @@ /// Prefix for the reveal transaction ids - batch proof namespace. -#[cfg(feature = "short-prefix")] +#[cfg(feature = "testing")] pub const TO_BATCH_PROOF_PREFIX: &[u8] = &[1]; -#[cfg(not(feature = "short-prefix"))] +#[cfg(not(feature = "testing"))] pub const TO_BATCH_PROOF_PREFIX: &[u8] = &[1, 1]; /// Prefix for the reveal transaction ids - light client namespace. -#[cfg(feature = "short-prefix")] +#[cfg(feature = "testing")] pub const TO_LIGHT_CLIENT_PREFIX: &[u8] = &[2]; -#[cfg(not(feature = "short-prefix"))] +#[cfg(not(feature = "testing"))] pub const TO_LIGHT_CLIENT_PREFIX: &[u8] = &[2, 2]; pub const TEST_PRIVATE_KEY: &str = diff --git a/crates/sequencer/src/commitment/controller.rs b/crates/sequencer/src/commitment/controller.rs index 6fb4e8fd6..6452a1c85 100644 --- a/crates/sequencer/src/commitment/controller.rs +++ b/crates/sequencer/src/commitment/controller.rs @@ -4,7 +4,7 @@ use citrea_common::utils::merge_state_diffs; use citrea_primitives::compression::compress_blob; use citrea_primitives::MAX_TXBODY_SIZE; use sov_db::ledger_db::SequencerLedgerOps; -use sov_db::schema::types::BatchNumber; +use sov_db::schema::types::SoftConfirmationNumber; use sov_modules_api::StateDiff; use tracing::{debug, warn}; @@ -46,14 +46,14 @@ where let last_finalized_l2_height = self .ledger_db .get_last_commitment_l2_height()? - .unwrap_or(BatchNumber(0)); + .unwrap_or(SoftConfirmationNumber(0)); let last_pending_l2_height = self .ledger_db .get_pending_commitments_l2_range()? .iter() .map(|(_, end)| *end) .max() - .unwrap_or(BatchNumber(0)); + .unwrap_or(SoftConfirmationNumber(0)); let last_committed_l2_height = cmp::max(last_finalized_l2_height, last_pending_l2_height); // If block state diff is empty, it is certain that state diff threshold won't be exceeded. @@ -97,7 +97,7 @@ where fn check_min_soft_confirmations( &self, - last_committed_l2_height: BatchNumber, + last_committed_l2_height: SoftConfirmationNumber, current_l2_height: u64, ) -> Option { // If the last commitment made is on par with the head @@ -121,13 +121,13 @@ where debug!("Enough soft confirmations to submit commitment"); Some(CommitmentInfo { - l2_height_range: BatchNumber(l2_start)..=BatchNumber(l2_end), + l2_height_range: SoftConfirmationNumber(l2_start)..=SoftConfirmationNumber(l2_end), }) } fn check_state_diff_threshold( &self, - last_committed_l2_height: BatchNumber, + last_committed_l2_height: SoftConfirmationNumber, current_l2_height: u64, state_diff: &StateDiff, ) -> Option { @@ -157,7 +157,7 @@ where debug!("Enough state diff size to submit commitment"); Some(CommitmentInfo { - l2_height_range: BatchNumber(l2_start)..=BatchNumber(l2_end), + l2_height_range: SoftConfirmationNumber(l2_start)..=SoftConfirmationNumber(l2_end), }) } diff --git a/crates/sequencer/src/commitment/mod.rs b/crates/sequencer/src/commitment/mod.rs index 62622486d..57bbdf7b5 100644 --- a/crates/sequencer/src/commitment/mod.rs +++ b/crates/sequencer/src/commitment/mod.rs @@ -9,7 +9,7 @@ use parking_lot::RwLock; use rs_merkle::algorithms::Sha256; use rs_merkle::MerkleTree; use sov_db::ledger_db::SequencerLedgerOps; -use sov_db::schema::types::{BatchNumber, SlotNumber}; +use sov_db::schema::types::{SlotNumber, SoftConfirmationNumber}; use sov_modules_api::StateDiff; use sov_rollup_interface::da::{BlockHeaderTrait, DaData, SequencerCommitment}; use sov_rollup_interface::services::da::{DaService, SenderWithNotifier}; @@ -26,7 +26,7 @@ mod controller; #[derive(Clone, Debug)] pub struct CommitmentInfo { /// L2 heights to commit - pub l2_height_range: RangeInclusive, + pub l2_height_range: RangeInclusive, } pub struct CommitmentService diff --git a/crates/sequencer/src/runner.rs b/crates/sequencer/src/runner.rs index 985884a9a..43b98966a 100644 --- a/crates/sequencer/src/runner.rs +++ b/crates/sequencer/src/runner.rs @@ -30,7 +30,7 @@ use reth_transaction_pool::{ use sov_accounts::Accounts; use sov_accounts::Response::{AccountEmpty, AccountExists}; use sov_db::ledger_db::SequencerLedgerOps; -use sov_db::schema::types::{BatchNumber, SlotNumber}; +use sov_db::schema::types::{SlotNumber, SoftConfirmationNumber}; use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::transaction::Transaction; use sov_modules_api::{ @@ -358,6 +358,7 @@ where working_set_to_discard = working_set.revert().to_revertable(); continue; }, + sov_modules_api::SoftConfirmationModuleCallError::EvmTxNotSerializable => panic!("Fed a non-serializable tx"), // we don't call the rule enforcer in the sequencer -- yet at least sov_modules_api::SoftConfirmationModuleCallError::RuleEnforcerUnauthorized => unreachable!(), }, @@ -580,7 +581,7 @@ where // connect L1 and L2 height self.ledger_db.extend_l2_range_of_l1_slot( SlotNumber(da_block.header().height()), - BatchNumber(l2_height), + SoftConfirmationNumber(l2_height), )?; // Register this new block with the fork manager to active diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/mod.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/mod.rs index 1163a5f2b..44cf8453a 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/mod.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/mod.rs @@ -1,5 +1,5 @@ use std::path::Path; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use serde::de::DeserializeOwned; use serde::Serialize; @@ -14,16 +14,16 @@ use crate::rocks_db_config::RocksdbConfig; #[cfg(test)] use crate::schema::tables::TestTableNew; use crate::schema::tables::{ - BatchByNumber, CommitmentsByNumber, ExecutedMigrations, L2GenesisStateRoot, L2RangeByL1Height, - L2Witness, LastPrunedBlock, LastSequencerCommitmentSent, LastStateDiff, - LightClientProofBySlotNumber, MempoolTxs, PendingProvingSessions, - PendingSequencerCommitmentL2Range, ProofsBySlotNumberV2, ProverLastScannedSlot, - ProverStateDiffs, SlotByHash, SlotByNumber, SoftConfirmationByHash, SoftConfirmationByNumber, - SoftConfirmationStatus, VerifiedBatchProofsBySlotNumber, LEDGER_TABLES, + CommitmentsByNumber, ExecutedMigrations, L2GenesisStateRoot, L2RangeByL1Height, L2Witness, + LastPrunedBlock, LastSequencerCommitmentSent, LastStateDiff, LightClientProofBySlotNumber, + MempoolTxs, PendingProvingSessions, PendingSequencerCommitmentL2Range, ProofsBySlotNumberV2, + ProverLastScannedSlot, ProverStateDiffs, SlotByHash, SoftConfirmationByHash, + SoftConfirmationByNumber, SoftConfirmationStatus, VerifiedBatchProofsBySlotNumber, + LEDGER_TABLES, }; use crate::schema::types::{ - BatchNumber, L2HeightRange, SlotNumber, StoredBatchProof, StoredBatchProofOutput, - StoredLightClientProof, StoredLightClientProofOutput, StoredSlot, StoredSoftConfirmation, + L2HeightRange, SlotNumber, SoftConfirmationNumber, StoredBatchProof, StoredBatchProofOutput, + StoredLightClientProof, StoredLightClientProofOutput, StoredSoftConfirmation, StoredTransaction, StoredVerifiedProof, }; @@ -46,19 +46,6 @@ pub struct LedgerDB { /// The database which stores the committed ledger. Uses an optimized layout which /// requires transactions to be executed before being committed. pub(crate) db: Arc, - pub(crate) next_item_numbers: Arc>, -} - -/// A SlotNumber, BatchNumber, TxNumber, and EventNumber which are grouped together, typically representing -/// the respective heights at the start or end of slot processing. -#[derive(Default, Clone, Debug)] -pub struct ItemNumbers { - /// The slot number - pub slot_number: u64, - /// The soft confirmation number - pub soft_confirmation_number: u64, - /// The batch number - pub batch_number: u64, } impl LedgerDB { @@ -75,18 +62,8 @@ impl LedgerDB { .unwrap_or_else(|| LEDGER_TABLES.iter().map(|e| e.to_string()).collect()); let inner = DB::open(path, "ledger-db", tables, &raw_options)?; - let next_item_numbers = ItemNumbers { - slot_number: Self::last_version_written(&inner, SlotByNumber)?.unwrap_or_default() + 1, - soft_confirmation_number: Self::last_version_written(&inner, SoftConfirmationByNumber)? - .unwrap_or_default() - + 1, - batch_number: Self::last_version_written(&inner, BatchByNumber)?.unwrap_or_default() - + 1, - }; - Ok(Self { db: Arc::new(inner), - next_item_numbers: Arc::new(Mutex::new(next_item_numbers)), }) } @@ -161,7 +138,7 @@ impl SharedLedgerOps for LedgerDB { fn put_soft_confirmation( &self, batch: &StoredSoftConfirmation, - batch_number: &BatchNumber, + batch_number: &SoftConfirmationNumber, schema_batch: &mut SchemaBatch, ) -> Result<(), anyhow::Error> { schema_batch.put::(batch_number, batch)?; @@ -175,15 +152,6 @@ impl SharedLedgerOps for LedgerDB { soft_confirmation_receipt: SoftConfirmationReceipt, tx_bodies: Option>>, ) -> Result<(), anyhow::Error> { - // Create a scope to ensure that the lock is released before we commit to the db - let mut current_item_numbers = { - let mut next_item_numbers = self.next_item_numbers.lock().unwrap(); - let item_numbers = next_item_numbers.clone(); - next_item_numbers.soft_confirmation_number += 1; - item_numbers - // The lock is released here - }; - let mut schema_batch = SchemaBatch::new(); let tx_bodies = if let Some(tx_bodies) = tx_bodies { @@ -201,11 +169,12 @@ impl SharedLedgerOps for LedgerDB { body: tx_body, }) .collect(); + let l2_height = soft_confirmation_receipt.l2_height; // Insert soft confirmation let soft_confirmation_to_store = StoredSoftConfirmation { da_slot_height: soft_confirmation_receipt.da_slot_height, - l2_height: current_item_numbers.soft_confirmation_number, + l2_height, da_slot_hash: soft_confirmation_receipt.da_slot_hash.into(), da_slot_txs_commitment: soft_confirmation_receipt.da_slot_txs_commitment.into(), hash: soft_confirmation_receipt.hash, @@ -220,10 +189,9 @@ impl SharedLedgerOps for LedgerDB { }; self.put_soft_confirmation( &soft_confirmation_to_store, - &BatchNumber(current_item_numbers.soft_confirmation_number), + &SoftConfirmationNumber(l2_height), &mut schema_batch, )?; - current_item_numbers.soft_confirmation_number += 1; self.db.write_schemas(schema_batch)?; @@ -235,7 +203,7 @@ impl SharedLedgerOps for LedgerDB { fn extend_l2_range_of_l1_slot( &self, l1_height: SlotNumber, - l2_height: BatchNumber, + l2_height: SoftConfirmationNumber, ) -> Result<(), anyhow::Error> { let current_range = self.db.get::(&l1_height)?; @@ -252,24 +220,6 @@ impl SharedLedgerOps for LedgerDB { Ok(()) } - /// Get the next slot, block, transaction numbers - #[instrument(level = "trace", skip(self), ret)] - fn get_next_items_numbers(&self) -> ItemNumbers { - self.next_item_numbers.lock().unwrap().clone() - } - - /// Gets all slots with numbers `range.start` to `range.end`. If `range.end` is outside - /// the range of the database, the result will smaller than the requested range. - /// Note that this method blindly preallocates for the requested range, so it should not be exposed - /// directly via rpc. - #[instrument(level = "trace", skip(self), err)] - fn _get_slot_range( - &self, - range: &std::ops::Range, - ) -> Result, anyhow::Error> { - self.get_data_range::(range) - } - /// Gets l1 height of l1 hash #[instrument(level = "trace", skip(self), err, ret)] fn get_state_diff(&self) -> Result { @@ -294,7 +244,7 @@ impl SharedLedgerOps for LedgerDB { #[instrument(level = "trace", skip(self), err, ret)] fn put_soft_confirmation_status( &self, - height: BatchNumber, + height: SoftConfirmationNumber, status: sov_rollup_interface::rpc::SoftConfirmationStatus, ) -> Result<(), anyhow::Error> { let mut schema_batch = SchemaBatch::new(); @@ -309,7 +259,7 @@ impl SharedLedgerOps for LedgerDB { #[instrument(level = "trace", skip(self), err, ret)] fn get_soft_confirmation_status( &self, - height: BatchNumber, + height: SoftConfirmationNumber, ) -> Result, anyhow::Error> { let status = self.db.get::(&height)?; @@ -369,7 +319,7 @@ impl SharedLedgerOps for LedgerDB { .transpose() } else { self.db - .get::(&BatchNumber(l2_height))? + .get::(&SoftConfirmationNumber(l2_height))? .map(|soft_confirmation| { bincode::deserialize(&soft_confirmation.state_root).map_err(Into::into) }) @@ -381,7 +331,7 @@ impl SharedLedgerOps for LedgerDB { #[instrument(level = "trace", skip(self), err)] fn get_head_soft_confirmation( &self, - ) -> anyhow::Result> { + ) -> anyhow::Result> { let mut iter = self.db.iter::()?; iter.seek_to_last(); @@ -392,6 +342,11 @@ impl SharedLedgerOps for LedgerDB { } } + fn get_head_soft_confirmation_height(&self) -> anyhow::Result> { + let head_l2_height = Self::last_version_written(&self.db, SoftConfirmationByNumber)?; + Ok(head_l2_height) + } + /// Gets all soft confirmations with numbers `range.start` to `range.end`. If `range.end` is outside /// the range of the database, the result will smaller than the requested range. /// Note that this method blindly preallocates for the requested range, so it should not be exposed @@ -399,10 +354,10 @@ impl SharedLedgerOps for LedgerDB { #[instrument(level = "trace", skip(self), err)] fn get_soft_confirmation_range( &self, - range: &std::ops::RangeInclusive, + range: &std::ops::RangeInclusive, ) -> Result, anyhow::Error> { let start = *range.start(); - let end = BatchNumber(range.end().0 + 1); + let end = SoftConfirmationNumber(range.end().0 + 1); self.get_data_range::(&(start..end)) } @@ -410,7 +365,7 @@ impl SharedLedgerOps for LedgerDB { #[instrument(level = "trace", skip(self), err)] fn get_soft_confirmation_by_number( &self, - number: &BatchNumber, + number: &SoftConfirmationNumber, ) -> Result, anyhow::Error> { self.db.get::(number) } @@ -418,7 +373,7 @@ impl SharedLedgerOps for LedgerDB { /// Get the most recent committed batch /// Returns L2 height. #[instrument(level = "trace", skip(self), err, ret)] - fn get_last_commitment_l2_height(&self) -> anyhow::Result> { + fn get_last_commitment_l2_height(&self) -> anyhow::Result> { self.db.get::(&()) } @@ -426,7 +381,10 @@ impl SharedLedgerOps for LedgerDB { /// For a sequencer, the last commitment height is set when the block is produced. /// For a full node the last commitment is set when a commitment is read from a finalized DA layer block. #[instrument(level = "trace", skip(self), err, ret)] - fn set_last_commitment_l2_height(&self, l2_height: BatchNumber) -> Result<(), anyhow::Error> { + fn set_last_commitment_l2_height( + &self, + l2_height: SoftConfirmationNumber, + ) -> Result<(), anyhow::Error> { let mut schema_batch = SchemaBatch::new(); schema_batch.put::(&(), &l2_height)?; @@ -521,7 +479,9 @@ impl BatchProverLedgerOps for LedgerDB { &self, l2_height: u64, ) -> anyhow::Result> { - let buf = self.db.get::(&BatchNumber(l2_height))?; + let buf = self + .db + .get::(&SoftConfirmationNumber(l2_height))?; if let Some((state_buf, offchain_buf)) = buf { let state_witness = bincode::deserialize(&state_buf)?; let offchain_witness = bincode::deserialize(&offchain_buf)?; @@ -579,7 +539,10 @@ impl BatchProverLedgerOps for LedgerDB { let state_buf = bincode::serialize(state_witness)?; let offchain_buf = bincode::serialize(offchain_witness)?; let mut schema_batch = SchemaBatch::new(); - schema_batch.put::(&BatchNumber(l2_height), &(state_buf, offchain_buf))?; + schema_batch.put::( + &SoftConfirmationNumber(l2_height), + &(state_buf, offchain_buf), + )?; self.db.write_schemas(schema_batch)?; @@ -588,7 +551,7 @@ impl BatchProverLedgerOps for LedgerDB { fn set_l2_state_diff( &self, - l2_height: BatchNumber, + l2_height: SoftConfirmationNumber, state_diff: StateDiff, ) -> anyhow::Result<()> { let mut schema_batch = SchemaBatch::new(); @@ -599,7 +562,10 @@ impl BatchProverLedgerOps for LedgerDB { Ok(()) } - fn get_l2_state_diff(&self, l2_height: BatchNumber) -> anyhow::Result> { + fn get_l2_state_diff( + &self, + l2_height: SoftConfirmationNumber, + ) -> anyhow::Result> { self.db.get::(&l2_height) } @@ -661,32 +627,6 @@ impl ProvingServiceLedgerOps for LedgerDB { } impl SequencerLedgerOps for LedgerDB { - /// Put slots - #[instrument(level = "trace", skip(self, schema_batch), err, ret)] - fn put_slot( - &self, - slot: &StoredSlot, - slot_number: &SlotNumber, - schema_batch: &mut SchemaBatch, - ) -> Result<(), anyhow::Error> { - schema_batch.put::(slot_number, slot)?; - schema_batch.put::(&slot.hash, slot_number) - } - - /// Used by the sequencer to record that it has committed to soft confirmations on a given L2 height - #[instrument(level = "trace", skip(self), err, ret)] - fn set_last_sequencer_commitment_l2_height( - &self, - l2_height: BatchNumber, - ) -> Result<(), anyhow::Error> { - let mut schema_batch = SchemaBatch::new(); - - schema_batch.put::(&(), &l2_height)?; - self.db.write_schemas(schema_batch)?; - - Ok(()) - } - /// Gets all pending commitments' l2 ranges. /// Returns start-end L2 heights. #[instrument(level = "trace", skip(self), err)] @@ -808,19 +748,6 @@ impl NodeLedgerOps for LedgerDB { } } - /// Get the most recent committed slot, if any - #[instrument(level = "trace", skip(self), err)] - fn get_head_slot(&self) -> anyhow::Result> { - let mut iter = self.db.iter::()?; - iter.seek_to_last(); - - match iter.next() { - Some(Ok(item)) => Ok(Some(item.into_tuple())), - Some(Err(e)) => Err(e), - _ => Ok(None), - } - } - /// Gets the commitments in the da slot with given height if any #[instrument(level = "trace", skip(self), err)] fn get_commitments_on_da_slot( diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/rpc.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/rpc.rs index e287dae5e..cfd306517 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/rpc.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/rpc.rs @@ -8,7 +8,7 @@ use crate::schema::tables::{ CommitmentsByNumber, SlotByHash, SoftConfirmationByHash, SoftConfirmationByNumber, SoftConfirmationStatus, VerifiedBatchProofsBySlotNumber, }; -use crate::schema::types::{BatchNumber, SlotNumber}; +use crate::schema::types::{SlotNumber, SoftConfirmationNumber}; /// The maximum number of batches that can be requested in a single RPC range query const MAX_BATCHES_PER_REQUEST: u64 = 20; @@ -94,7 +94,7 @@ impl LedgerRpcProvider for LedgerDB { ) -> Result { if self .db - .get::(&BatchNumber(l2_height)) + .get::(&SoftConfirmationNumber(l2_height)) .ok() .flatten() .is_none() @@ -107,7 +107,7 @@ impl LedgerRpcProvider for LedgerDB { let status = self .db - .get::(&BatchNumber(l2_height))?; + .get::(&SoftConfirmationNumber(l2_height))?; match status { Some(status) => Ok(status), @@ -196,19 +196,22 @@ impl LedgerRpcProvider for LedgerDB { fn get_head_soft_confirmation( &self, ) -> Result, anyhow::Error> { - let next_ids = self.get_next_items_numbers(); + let head_l2_height = + Self::last_version_written(&self.db, SoftConfirmationByNumber)?.unwrap_or(0); - if let Some(stored_soft_confirmation) = self.db.get::( - &BatchNumber(next_ids.soft_confirmation_number.saturating_sub(1)), - )? { + if let Some(stored_soft_confirmation) = self + .db + .get::(&SoftConfirmationNumber(head_l2_height))? + { return Ok(Some(stored_soft_confirmation.try_into()?)); } Ok(None) } fn get_head_soft_confirmation_height(&self) -> Result { - let next_ids = self.get_next_items_numbers(); - Ok(next_ids.soft_confirmation_number.saturating_sub(1)) + let head_l2_height = + Self::last_version_written(&self.db, SoftConfirmationByNumber)?.unwrap_or(0); + Ok(head_l2_height) } } @@ -216,10 +219,10 @@ impl LedgerDB { fn resolve_soft_confirmation_identifier( &self, batch_id: &SoftConfirmationIdentifier, - ) -> Result, anyhow::Error> { + ) -> Result, anyhow::Error> { match batch_id { SoftConfirmationIdentifier::Hash(hash) => self.db.get::(hash), - SoftConfirmationIdentifier::Number(num) => Ok(Some(BatchNumber(*num))), + SoftConfirmationIdentifier::Number(num) => Ok(Some(SoftConfirmationNumber(*num))), } } } diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/traits.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/traits.rs index befd64c1a..1f7e0438d 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/traits.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/ledger_db/traits.rs @@ -8,10 +8,9 @@ use sov_rollup_interface::stf::{SoftConfirmationReceipt, StateDiff}; use sov_rollup_interface::zk::Proof; use sov_schema_db::SchemaBatch; -use super::ItemNumbers; use crate::schema::types::{ - BatchNumber, L2HeightRange, SlotNumber, StoredBatchProof, StoredBatchProofOutput, - StoredLightClientProof, StoredLightClientProofOutput, StoredSlot, StoredSoftConfirmation, + L2HeightRange, SlotNumber, SoftConfirmationNumber, StoredBatchProof, StoredBatchProofOutput, + StoredLightClientProof, StoredLightClientProofOutput, StoredSoftConfirmation, }; /// Shared ledger operations @@ -23,7 +22,7 @@ pub trait SharedLedgerOps { fn put_soft_confirmation( &self, batch: &StoredSoftConfirmation, - batch_number: &BatchNumber, + batch_number: &SoftConfirmationNumber, schema_batch: &mut SchemaBatch, ) -> Result<()>; @@ -39,18 +38,9 @@ pub trait SharedLedgerOps { fn extend_l2_range_of_l1_slot( &self, l1_height: SlotNumber, - l2_height: BatchNumber, + l2_height: SoftConfirmationNumber, ) -> Result<()>; - /// Get the next slot, block, transaction numbers - fn get_next_items_numbers(&self) -> ItemNumbers; - - /// Gets all slots with numbers `range.start` to `range.end`. If `range.end` is outside - /// the range of the database, the result will smaller than the requested range. - /// Note that this method blindly preallocates for the requested range, so it should not be exposed - /// directly via rpc. - fn _get_slot_range(&self, range: &std::ops::Range) -> Result>; - /// Gets l1 height of l1 hash fn get_state_diff(&self) -> Result; @@ -63,14 +53,14 @@ pub trait SharedLedgerOps { /// Saves a soft confirmation status for a given L1 height fn put_soft_confirmation_status( &self, - height: BatchNumber, + height: SoftConfirmationNumber, status: sov_rollup_interface::rpc::SoftConfirmationStatus, ) -> Result<()>; /// Returns a soft confirmation status for a given L1 height fn get_soft_confirmation_status( &self, - height: BatchNumber, + height: SoftConfirmationNumber, ) -> Result>; /// Gets the commitments in the da slot with given height if any @@ -94,7 +84,12 @@ pub trait SharedLedgerOps { ) -> anyhow::Result>; /// Get the most recent committed soft confirmation, if any - fn get_head_soft_confirmation(&self) -> Result>; + fn get_head_soft_confirmation( + &self, + ) -> Result>; + + /// Get the most recent committed soft confirmation height, if any + fn get_head_soft_confirmation_height(&self) -> Result>; /// Gets all soft confirmations with numbers `range.start` to `range.end`. If `range.end` is outside /// the range of the database, the result will smaller than the requested range. @@ -102,22 +97,22 @@ pub trait SharedLedgerOps { /// directly via rpc. fn get_soft_confirmation_range( &self, - range: &std::ops::RangeInclusive, + range: &std::ops::RangeInclusive, ) -> Result>; /// Gets all soft confirmations by numbers fn get_soft_confirmation_by_number( &self, - number: &BatchNumber, + number: &SoftConfirmationNumber, ) -> Result>; /// Used by the sequencer to record that it has committed to soft confirmations on a given L2 height - fn set_last_commitment_l2_height(&self, l2_height: BatchNumber) -> Result<()>; + fn set_last_commitment_l2_height(&self, l2_height: SoftConfirmationNumber) -> Result<()>; /// Get the most recent committed batch /// Returns L2 height. - fn get_last_commitment_l2_height(&self) -> anyhow::Result>; + fn get_last_commitment_l2_height(&self) -> anyhow::Result>; /// Get the last scanned slot fn get_last_scanned_l1_height(&self) -> Result>; @@ -148,9 +143,6 @@ pub trait NodeLedgerOps: SharedLedgerOps { output: StoredBatchProofOutput, ) -> Result<()>; - /// Get the most recent committed slot, if any - fn get_head_slot(&self) -> Result>; - /// Gets the commitments in the da slot with given height if any fn get_commitments_on_da_slot(&self, height: u64) -> Result>>; } @@ -185,10 +177,14 @@ pub trait BatchProverLedgerOps: SharedLedgerOps + Send + Sync { ) -> Result<()>; /// Save a specific L2 range state diff - fn set_l2_state_diff(&self, l2_height: BatchNumber, state_diff: StateDiff) -> Result<()>; + fn set_l2_state_diff( + &self, + l2_height: SoftConfirmationNumber, + state_diff: StateDiff, + ) -> Result<()>; /// Returns an L2 state diff - fn get_l2_state_diff(&self, l2_height: BatchNumber) -> Result>; + fn get_l2_state_diff(&self, l2_height: SoftConfirmationNumber) -> Result>; /// Clears all pending proving sessions fn clear_pending_proving_sessions(&self) -> Result<()>; @@ -228,17 +224,6 @@ pub trait ProvingServiceLedgerOps: BatchProverLedgerOps + SharedLedgerOps + Send /// Sequencer ledger operations pub trait SequencerLedgerOps: SharedLedgerOps { - /// Put slots - fn put_slot( - &self, - slot: &StoredSlot, - slot_number: &SlotNumber, - schema_batch: &mut SchemaBatch, - ) -> Result<()>; - - /// Used by the sequencer to record that it has committed to soft confirmations on a given L2 height - fn set_last_sequencer_commitment_l2_height(&self, l2_height: BatchNumber) -> Result<()>; - /// Gets all pending commitments' l2 ranges. /// Returns start-end L2 heights. fn get_pending_commitments_l2_range(&self) -> Result>; diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs index e19f4bfe5..f8d1554c0 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs @@ -1,18 +1,5 @@ //! This module defines the following tables: //! -//! -//! Slot Tables: -//! - `SlotNumber -> StoredSlot` -//! - `SlotNumber -> Vec` -//! -//! Batch Tables: -//! - `BatchNumber -> StoredBatch` -//! - `BatchHash -> BatchNumber` -//! -//! Tx Tables: -//! - `TxNumber -> (TxHash,Tx)` -//! - `TxHash -> TxNumber` -//! //! JMT Tables: //! - `KeyHash -> Key` //! - `(Key, Version) -> JmtValue` @@ -31,8 +18,8 @@ use sov_schema_db::schema::{KeyDecoder, KeyEncoder, ValueCodec}; use sov_schema_db::{CodecError, SeekKeyEncoder}; use super::types::{ - AccessoryKey, AccessoryStateValue, BatchNumber, DbHash, JmtValue, L2HeightRange, SlotNumber, - StateKey, StoredBatch, StoredBatchProof, StoredLightClientProof, StoredSlot, + AccessoryKey, AccessoryStateValue, DbHash, JmtValue, L2HeightRange, SlotNumber, + SoftConfirmationNumber, StateKey, StoredBatchProof, StoredLightClientProof, StoredSoftConfirmation, StoredVerifiedProof, }; @@ -48,7 +35,6 @@ pub const STATE_TABLES: &[&str] = &[ /// transaction, events, receipts, etc. pub const LEDGER_TABLES: &[&str] = &[ ExecutedMigrations::table_name(), - SlotByNumber::table_name(), SlotByHash::table_name(), SoftConfirmationByNumber::table_name(), SoftConfirmationByHash::table_name(), @@ -60,7 +46,6 @@ pub const LEDGER_TABLES: &[&str] = &[ PendingSequencerCommitmentL2Range::table_name(), LastSequencerCommitmentSent::table_name(), ProverLastScannedSlot::table_name(), - BatchByNumber::table_name(), SoftConfirmationStatus::table_name(), CommitmentsByNumber::table_name(), ProofsBySlotNumber::table_name(), @@ -232,11 +217,6 @@ define_table_with_seek_key_codec!( (LastStateDiff) () => StateDiff ); -define_table_with_seek_key_codec!( - /// The primary source for slot data - (SlotByNumber) SlotNumber => StoredSlot -); - define_table_with_default_codec!( /// A "secondary index" for slot data by hash (SlotByHash) DbHash => SlotNumber @@ -249,12 +229,12 @@ define_table_with_default_codec!( define_table_with_seek_key_codec!( /// The primary source for soft confirmation data - (SoftConfirmationByNumber) BatchNumber => StoredSoftConfirmation + (SoftConfirmationByNumber) SoftConfirmationNumber => StoredSoftConfirmation ); define_table_with_default_codec!( /// A "secondary index" for soft confirmation data by hash - (SoftConfirmationByHash) DbHash => BatchNumber + (SoftConfirmationByHash) DbHash => SoftConfirmationNumber ); define_table_with_default_codec!( @@ -264,7 +244,7 @@ define_table_with_default_codec!( define_table_with_default_codec!( /// The primary source of state & offchain witnesses by L2 height - (L2Witness) BatchNumber => (Vec, Vec) + (L2Witness) SoftConfirmationNumber => (Vec, Vec) ); define_table_with_default_codec!( @@ -279,7 +259,7 @@ define_table_with_default_codec!( define_table_with_seek_key_codec!( /// Sequencer uses this table to store the last commitment it sent - (LastSequencerCommitmentSent) () => BatchNumber + (LastSequencerCommitmentSent) () => SoftConfirmationNumber ); define_table_with_seek_key_codec!( @@ -290,14 +270,9 @@ define_table_with_seek_key_codec!( (ProverLastScannedSlot) () => SlotNumber ); -define_table_with_seek_key_codec!( - /// The primary source for batch data - (BatchByNumber) BatchNumber => StoredBatch -); - define_table_with_default_codec!( /// Check whether a block is finalized - (SoftConfirmationStatus) BatchNumber => sov_rollup_interface::rpc::SoftConfirmationStatus + (SoftConfirmationStatus) SoftConfirmationNumber => sov_rollup_interface::rpc::SoftConfirmationStatus ); define_table_without_codec!( @@ -338,7 +313,7 @@ define_table_with_default_codec!( define_table_with_default_codec!( /// L2 height to state diff for prover - (ProverStateDiffs) BatchNumber => StateDiff + (ProverStateDiffs) SoftConfirmationNumber => StateDiff ); define_table_with_seek_key_codec!( diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/schema/types.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/schema/types.rs index 447757588..8071efd15 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/schema/types.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/schema/types.rs @@ -1,12 +1,10 @@ use std::fmt::Debug; -use std::marker::PhantomData; use std::sync::Arc; use borsh::{BorshDeserialize, BorshSerialize}; -use serde::de::DeserializeOwned; use sov_rollup_interface::rpc::{ BatchProofOutputRpcResponse, BatchProofResponse, HexTx, LightClientProofOutputRpcResponse, - LightClientProofResponse, SoftConfirmationResponse, TxResponse, VerifiedBatchProofResponse, + LightClientProofResponse, SoftConfirmationResponse, VerifiedBatchProofResponse, }; use sov_rollup_interface::soft_confirmation::SignedSoftConfirmation; use sov_rollup_interface::zk::{BatchProofInfo, CumulativeStateDiff, Proof}; @@ -57,18 +55,6 @@ pub type DbHash = [u8; 32]; pub type JmtValue = Option>; pub(crate) type StateKey = Vec; -/// The on-disk format of a slot. Specifies the batches contained in the slot -/// and the hash of the da block. TODO(@preston-evans98): add any additional data -/// required to reconstruct the da block proof. -#[derive(Debug, PartialEq, BorshDeserialize, BorshSerialize)] -pub struct StoredSlot { - /// The slot's hash, as reported by the DA layer. - pub hash: DbHash, - /// Any extra data which the rollup decides to store relating to this slot. - pub extra_data: DbBytes, - /// The range of batches which occurred in this slot. - pub batches: std::ops::Range, -} /// The on-disk format for a light client proof output #[derive(Debug, PartialEq, BorshDeserialize, BorshSerialize)] pub struct StoredLightClientProofOutput { @@ -286,7 +272,7 @@ where /// The range of L2 heights (soft confirmations) for a given L1 block /// (start, end) inclusive -pub type L2HeightRange = (BatchNumber, BatchNumber); +pub type L2HeightRange = (SoftConfirmationNumber, SoftConfirmationNumber); impl TryFrom for SoftConfirmationResponse { type Error = anyhow::Error; @@ -319,16 +305,6 @@ impl TryFrom for SoftConfirmationResponse { } } -/// The on-disk format for a batch. Stores the hash and identifies the range of transactions -/// included in the batch. -#[derive(Debug, PartialEq, BorshDeserialize, BorshSerialize)] -pub struct StoredBatch { - /// The hash of the batch, as reported by the DA layer. - pub hash: DbHash, - /// The range of transactions which occurred in this batch. - pub txs: std::ops::Range, -} - /// The on-disk format of a transaction. Includes the txhash, the serialized tx data, /// and identifies the events emitted by this transaction #[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone)] @@ -339,17 +315,6 @@ pub struct StoredTransaction { pub body: Option>, } -impl TryFrom for TxResponse { - type Error = anyhow::Error; - fn try_from(value: StoredTransaction) -> Result { - Ok(Self { - hash: value.hash, - body: value.body.map(HexTx::from), - phantom_data: PhantomData, - }) - } -} - macro_rules! u64_wrapper { ($name:ident) => { /// A typed wrapper around u64 implementing `Encode` and `Decode` @@ -378,6 +343,4 @@ macro_rules! u64_wrapper { } u64_wrapper!(SlotNumber); -u64_wrapper!(BatchNumber); -u64_wrapper!(TxNumber); -u64_wrapper!(EventNumber); +u64_wrapper!(SoftConfirmationNumber); diff --git a/crates/sovereign-sdk/rollup-interface/Cargo.toml b/crates/sovereign-sdk/rollup-interface/Cargo.toml index 476aa8a1f..c216d1c74 100644 --- a/crates/sovereign-sdk/rollup-interface/Cargo.toml +++ b/crates/sovereign-sdk/rollup-interface/Cargo.toml @@ -34,7 +34,7 @@ serde_json = { workspace = true } [features] default = ["std"] native = ["std", "tokio", "futures", "tracing"] -testing = ["native"] +testing = [] std = [ "anyhow/default", "borsh/default", diff --git a/crates/sovereign-sdk/rollup-interface/src/network.rs b/crates/sovereign-sdk/rollup-interface/src/network.rs index 4cbcba6bc..c66c77dc4 100644 --- a/crates/sovereign-sdk/rollup-interface/src/network.rs +++ b/crates/sovereign-sdk/rollup-interface/src/network.rs @@ -21,6 +21,7 @@ impl Display for Network { } impl Network { + /// Constant function to get the Network from &str pub const fn const_from_str(s: &str) -> Option { match s.as_bytes() { b"mainnet" => Some(Network::Mainnet), diff --git a/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs b/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs index 3a3c4afbb..b885e9f82 100644 --- a/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs +++ b/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs @@ -6,7 +6,6 @@ extern crate alloc; use alloc::collections::BTreeMap; use alloc::string::String; use alloc::vec::Vec; -use core::marker::PhantomData; use borsh::{BorshDeserialize, BorshSerialize}; use serde::{Deserialize, Serialize}; @@ -327,22 +326,6 @@ pub fn sequencer_commitment_to_response( } } -/// The response to a JSON-RPC request for a particular transaction. -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct TxResponse { - /// The hex encoded transaction hash. - #[serde(with = "utils::rpc_hex")] - pub hash: [u8; 32], - /// The transaction body, if stored by the rollup. - #[serde(skip_serializing_if = "Option::is_none")] - pub body: Option, - /// The custom receipt specified by the rollup. This typically contains - /// information about the outcome of the transaction. - #[serde(skip_serializing)] - pub phantom_data: PhantomData, -} - /// An RPC response which might contain a full item or just its hash. #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] #[serde(untagged, rename_all = "camelCase")] diff --git a/crates/sovereign-sdk/rollup-interface/src/state_machine/stf.rs b/crates/sovereign-sdk/rollup-interface/src/state_machine/stf.rs index 8c8f69507..3c0806b0d 100644 --- a/crates/sovereign-sdk/rollup-interface/src/state_machine/stf.rs +++ b/crates/sovereign-sdk/rollup-interface/src/state_machine/stf.rs @@ -294,6 +294,8 @@ pub enum SoftConfirmationModuleCallError { EvmMisplacedSystemTx, /// Address does not have enough funds to pay for L1 fee EvmNotEnoughFundsForL1Fee, + /// An EVM transaction in the soft confirmation was not serializable + EvmTxNotSerializable, /// The sov-tx was not sent by the rule enforcer authority RuleEnforcerUnauthorized, /// The EVM transaction type is not supported @@ -397,6 +399,9 @@ impl std::fmt::Display for SoftConfirmationModuleCallError { SoftConfirmationModuleCallError::RuleEnforcerUnauthorized => { write!(f, "Rule enforcer unauthorized") } + SoftConfirmationModuleCallError::EvmTxNotSerializable => { + write!(f, "EVM tx not serializable") + } } } } diff --git a/guests/risc0/Cargo.toml b/guests/risc0/Cargo.toml index f8027b5b3..fbc6c312d 100644 --- a/guests/risc0/Cargo.toml +++ b/guests/risc0/Cargo.toml @@ -19,4 +19,4 @@ methods = [ [features] bench = [] -short-prefix = [] +testing = [] diff --git a/guests/risc0/batch-proof-bitcoin/Cargo.lock b/guests/risc0/batch-proof-bitcoin/Cargo.lock index ba1440059..8292dd597 100644 --- a/guests/risc0/batch-proof-bitcoin/Cargo.lock +++ b/guests/risc0/batch-proof-bitcoin/Cargo.lock @@ -251,7 +251,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa64d80ae58ffaafdff9d5d84f58d03775f66c84433916dc9a64ed16af5755da" dependencies = [ "serde", - "winnow 0.6.13", + "winnow 0.6.20", ] [[package]] @@ -3861,9 +3861,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.13" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" [[package]] name = "wyz" diff --git a/guests/risc0/batch-proof-bitcoin/Cargo.toml b/guests/risc0/batch-proof-bitcoin/Cargo.toml index cc2e3b910..b6a79db22 100644 --- a/guests/risc0/batch-proof-bitcoin/Cargo.toml +++ b/guests/risc0/batch-proof-bitcoin/Cargo.toml @@ -22,7 +22,7 @@ sov-rollup-interface = { path = "../../../crates/sovereign-sdk/rollup-interface" sov-state = { path = "../../../crates/sovereign-sdk/module-system/sov-state" } [features] -short-prefix = ["citrea-primitives/short-prefix"] +testing = ["citrea-primitives/testing"] [patch.crates-io] sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.8-risczero.0" } diff --git a/guests/risc0/batch-proof-mock/Cargo.toml b/guests/risc0/batch-proof-mock/Cargo.toml index 33f468ecb..08a412b50 100644 --- a/guests/risc0/batch-proof-mock/Cargo.toml +++ b/guests/risc0/batch-proof-mock/Cargo.toml @@ -22,7 +22,7 @@ sov-rollup-interface = { path = "../../../crates/sovereign-sdk/rollup-interface" sov-state = { path = "../../../crates/sovereign-sdk/module-system/sov-state" } [features] -short-prefix = ["citrea-primitives/short-prefix"] +testing = ["citrea-primitives/testing"] [patch.crates-io] sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.8-risczero.0" } diff --git a/guests/risc0/build.rs b/guests/risc0/build.rs index 9dea3a17d..163238bf0 100644 --- a/guests/risc0/build.rs +++ b/guests/risc0/build.rs @@ -53,8 +53,8 @@ fn get_guest_options() -> HashMap<&'static str, risc0_build::GuestOptions> { let mut features = Vec::new(); - if std::env::var("CARGO_FEATURE_SHORT_PREFIX").is_ok() { - features.push("short-prefix".to_string()); + if std::env::var("CARGO_FEATURE_TESTING").is_ok() { + features.push("testing".to_string()); } let use_docker = if std::env::var("REPR_GUEST_BUILD").is_ok() { diff --git a/guests/risc0/light-client-proof-bitcoin/Cargo.toml b/guests/risc0/light-client-proof-bitcoin/Cargo.toml index 035b16576..a603b6097 100644 --- a/guests/risc0/light-client-proof-bitcoin/Cargo.toml +++ b/guests/risc0/light-client-proof-bitcoin/Cargo.toml @@ -23,7 +23,7 @@ sov-rollup-interface = { path = "../../../crates/sovereign-sdk/rollup-interface" sov-state = { path = "../../../crates/sovereign-sdk/module-system/sov-state" } [features] -short-prefix = ["citrea-primitives/short-prefix"] +testing = ["citrea-primitives/testing"] [patch.crates-io] sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.8-risczero.0" } diff --git a/guests/risc0/light-client-proof-mock/Cargo.toml b/guests/risc0/light-client-proof-mock/Cargo.toml index 7e14d80b0..a67d8999c 100644 --- a/guests/risc0/light-client-proof-mock/Cargo.toml +++ b/guests/risc0/light-client-proof-mock/Cargo.toml @@ -24,7 +24,7 @@ sov-rollup-interface = { path = "../../../crates/sovereign-sdk/rollup-interface" sov-state = { path = "../../../crates/sovereign-sdk/module-system/sov-state" } [features] -short-prefix = ["citrea-primitives/short-prefix"] +testing = ["citrea-primitives/testing"] [patch.crates-io] sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.8-risczero.0" }