diff --git a/Cargo.lock b/Cargo.lock index d686c1f428..838de227b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1871,6 +1871,7 @@ dependencies = [ "serde_json", "sov-modules-api", "sov-prover-storage-manager", + "sov-rollup-interface", "sov-state", "tempfile", "thiserror", @@ -1919,9 +1920,10 @@ dependencies = [ "anyhow", "backoff", "lru", - "sov-db", + "serde", "sov-rollup-interface", "tokio", + "tracing", ] [[package]] @@ -2038,6 +2040,7 @@ dependencies = [ "anyhow", "borsh", "citrea-evm", + "citrea-primitives", "clap", "hex", "jsonrpsee", @@ -8556,6 +8559,7 @@ dependencies = [ "bincode", "borsh", "byteorder", + "citrea-primitives", "criterion", "hex", "jmt", @@ -8715,6 +8719,7 @@ dependencies = [ "serde_json", "sov-modules-api", "sov-modules-core", + "sov-rollup-interface", "sov-state", "syn 1.0.109", "trybuild", @@ -8749,6 +8754,7 @@ version = "0.4.0-rc.3" dependencies = [ "anyhow", "borsh", + "citrea-primitives", "hex", "itertools 0.13.0", "jmt", @@ -8960,6 +8966,7 @@ dependencies = [ "anyhow", "async-trait", "borsh", + "citrea-primitives", "futures", "hex", "hyper 0.14.29", diff --git a/Cargo.toml b/Cargo.toml index 5683b88903..ddd892f3fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,6 +93,7 @@ futures = "0.3" pin-project = { version = "1.1.3" } hashbrown = { version = "0.14", default-features = false, features = ["ahash"] } hex = { version = "0.4.3", default-features = false, features = ["alloc", "serde"] } +lazy_static = { version = "1.5.0" } log-panics = { version = "2", features = ["with-backtrace"] } once_cell = { version = "1.19.0", default-features = false, features = ["alloc"] } prometheus = { version = "0.13.3", default-features = false } diff --git a/bin/citrea/provers/risc0/guest-bitcoin/Cargo.lock b/bin/citrea/provers/risc0/guest-bitcoin/Cargo.lock index 82160a9311..a97330c846 100644 --- a/bin/citrea/provers/risc0/guest-bitcoin/Cargo.lock +++ b/bin/citrea/provers/risc0/guest-bitcoin/Cargo.lock @@ -904,6 +904,7 @@ dependencies = [ "anyhow", "borsh", "citrea-evm", + "citrea-primitives", "hex", "secp256k1", "serde", @@ -3101,6 +3102,7 @@ version = "0.4.0-rc.3" dependencies = [ "anyhow", "borsh", + "citrea-primitives", "hex", "itertools 0.13.0", "jmt", @@ -3171,6 +3173,7 @@ version = "0.4.0-rc.3" dependencies = [ "anyhow", "borsh", + "citrea-primitives", "hex", "num_cpus", "serde", diff --git a/bin/citrea/provers/risc0/guest-bitcoin/src/bin/bitcoin_da.rs b/bin/citrea/provers/risc0/guest-bitcoin/src/bin/bitcoin_da.rs index 637ef1636b..13634cae1d 100644 --- a/bin/citrea/provers/risc0/guest-bitcoin/src/bin/bitcoin_da.rs +++ b/bin/citrea/provers/risc0/guest-bitcoin/src/bin/bitcoin_da.rs @@ -1,7 +1,6 @@ #![no_main] use bitcoin_da::spec::RollupParams; use bitcoin_da::verifier::BitcoinVerifier; - use citrea_primitives::{DA_TX_ID_LEADING_ZEROS, ROLLUP_NAME}; use citrea_stf::runtime::Runtime; use citrea_stf::StfVerifier; diff --git a/bin/citrea/provers/risc0/guest-mock/Cargo.lock b/bin/citrea/provers/risc0/guest-mock/Cargo.lock index 42f4783ec7..8bfe5df055 100644 --- a/bin/citrea/provers/risc0/guest-mock/Cargo.lock +++ b/bin/citrea/provers/risc0/guest-mock/Cargo.lock @@ -777,6 +777,14 @@ dependencies = [ "thiserror", ] +[[package]] +name = "citrea-primitives" +version = "0.4.0-rc.3" +dependencies = [ + "anyhow", + "sov-rollup-interface", +] + [[package]] name = "citrea-stf" version = "0.4.0-rc.3" @@ -784,6 +792,7 @@ dependencies = [ "anyhow", "borsh", "citrea-evm", + "citrea-primitives", "hex", "secp256k1", "serde", @@ -2893,6 +2902,7 @@ version = "0.4.0-rc.3" dependencies = [ "anyhow", "borsh", + "citrea-primitives", "hex", "itertools 0.13.0", "jmt", @@ -2963,6 +2973,7 @@ version = "0.4.0-rc.3" dependencies = [ "anyhow", "borsh", + "citrea-primitives", "hex", "num_cpus", "serde", diff --git a/bin/citrea/src/rollup/mod.rs b/bin/citrea/src/rollup/mod.rs index d513ea3221..809dffa062 100644 --- a/bin/citrea/src/rollup/mod.rs +++ b/bin/citrea/src/rollup/mod.rs @@ -1,20 +1,26 @@ +use anyhow::anyhow; use async_trait::async_trait; -pub use bitcoin::*; use citrea_fullnode::{CitreaFullnode, FullNode}; +use citrea_primitives::fork::ForkManager; +use citrea_primitives::forks::FORKS; use citrea_prover::{CitreaProver, Prover}; use citrea_sequencer::{CitreaSequencer, Sequencer, SequencerConfig}; -pub use mock::*; use sov_db::ledger_db::SharedLedgerOps; +use sov_db::schema::types::BatchNumber; use sov_modules_api::storage::HierarchicalStorageManager; use sov_modules_api::Spec; use sov_modules_rollup_blueprint::RollupBlueprint; use sov_modules_stf_blueprint::{Runtime as RuntimeTrait, StfBlueprint}; +use sov_rollup_interface::spec::SpecId; use sov_state::storage::NativeStorage; use sov_stf_runner::{FullNodeConfig, InitVariant, ProverConfig}; use tokio::sync::broadcast; use tracing::instrument; + mod bitcoin; mod mock; +pub use bitcoin::*; +pub use mock::*; /// Overrides RollupBlueprint methods #[async_trait] @@ -79,6 +85,18 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { }, }; + let current_l2_height = ledger_db + .get_head_soft_batch() + .map_err(|e| anyhow!("Failed to get head soft batch: {}", e))? + .map(|(l2_height, _)| l2_height) + .unwrap_or(BatchNumber(0)); + + let active_spec: SpecId = ledger_db.get_active_fork()?; + + let mut fork_manager = + ForkManager::new(current_l2_height.into(), active_spec, FORKS.to_vec()); + fork_manager.register_handler(Box::new(ledger_db.clone())); + let seq = CitreaSequencer::new( da_service, prover_storage, @@ -89,6 +107,7 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { rollup_config.public_keys, ledger_db, rollup_config.rpc, + fork_manager, soft_confirmation_tx, ) .unwrap(); @@ -161,6 +180,17 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { let code_commitment = self.get_code_commitment(); + let current_l2_height = ledger_db + .get_head_soft_batch() + .map_err(|e| anyhow!("Failed to get head soft batch: {}", e))? + .map(|(l2_height, _)| l2_height) + .unwrap_or(BatchNumber(0)); + + let active_spec: SpecId = ledger_db.get_active_fork()?; + let mut fork_manager = + ForkManager::new(current_l2_height.into(), active_spec, FORKS.to_vec()); + fork_manager.register_handler(Box::new(ledger_db.clone())); + let runner = CitreaFullnode::new( runner_config, rollup_config.public_keys, @@ -172,6 +202,7 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { init_variant, code_commitment, rollup_config.sync_blocks_count, + fork_manager, soft_confirmation_tx, )?; @@ -248,6 +279,17 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { let code_commitment = self.get_code_commitment(); + let current_l2_height = ledger_db + .get_head_soft_batch() + .map_err(|e| anyhow!("Failed to get head soft batch: {}", e))? + .map(|(l2_height, _)| l2_height) + .unwrap_or(BatchNumber(0)); + + let active_spec: SpecId = ledger_db.get_active_fork()?; + let mut fork_manager = + ForkManager::new(current_l2_height.into(), active_spec, FORKS.to_vec()); + fork_manager.register_handler(Box::new(ledger_db.clone())); + let runner = CitreaProver::new( runner_config, rollup_config.public_keys, @@ -261,6 +303,7 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { Some(prover_config), code_commitment, rollup_config.sync_blocks_count, + fork_manager, soft_confirmation_tx, )?; diff --git a/crates/citrea-stf/Cargo.toml b/crates/citrea-stf/Cargo.toml index 352303df61..e7aab24947 100644 --- a/crates/citrea-stf/Cargo.toml +++ b/crates/citrea-stf/Cargo.toml @@ -31,6 +31,7 @@ sov-state = { path = "../sovereign-sdk/module-system/sov-state" } sov-stf-runner = { path = "../sovereign-sdk/full-node/sov-stf-runner" } citrea-evm = { path = "../evm" } +citrea-primitives = { path = "../primitives" } soft-confirmation-rule-enforcer = { path = "../soft-confirmation-rule-enforcer" } [dev-dependencies] diff --git a/crates/citrea-stf/src/hooks_impl.rs b/crates/citrea-stf/src/hooks_impl.rs index 0482b1b074..fd19a4e4fd 100644 --- a/crates/citrea-stf/src/hooks_impl.rs +++ b/crates/citrea-stf/src/hooks_impl.rs @@ -25,7 +25,11 @@ impl TxHooks for Runtime { working_set: &mut WorkingSet, arg: &RuntimeTxHook, ) -> anyhow::Result { - let RuntimeTxHook { height, sequencer } = arg; + let RuntimeTxHook { + height, + sequencer, + current_spec: _current_spec, + } = arg; let AccountsTxHook { sender, sequencer } = self.accounts .pre_dispatch_tx_hook(tx, working_set, sequencer)?; diff --git a/crates/citrea-stf/src/verifier.rs b/crates/citrea-stf/src/verifier.rs index ce1f004a66..20188bbf74 100644 --- a/crates/citrea-stf/src/verifier.rs +++ b/crates/citrea-stf/src/verifier.rs @@ -1,5 +1,6 @@ use std::marker::PhantomData; +use citrea_primitives::forks::FORKS; use sov_rollup_interface::da::{BlockHeaderTrait, DaVerifier}; use sov_rollup_interface::stf::StateTransitionFunction; use sov_rollup_interface::zk::{StateTransition, StateTransitionData, Zkvm, ZkvmGuest}; @@ -61,6 +62,7 @@ where data.da_block_headers_of_soft_confirmations, &validity_condition, data.soft_confirmations, + FORKS.to_vec(), ); println!("out of apply_soft_confirmations_from_sequencer_commitments"); diff --git a/crates/evm/Cargo.toml b/crates/evm/Cargo.toml index 7276708923..59024981eb 100644 --- a/crates/evm/Cargo.toml +++ b/crates/evm/Cargo.toml @@ -51,6 +51,7 @@ reth-provider = { workspace = true } revm = { workspace = true, features = ["optional_block_gas_limit", "optional_eip3607", "optional_no_base_fee"] } 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"] } tempfile = { workspace = true } tracing-subscriber = { workspace = true } walkdir = "2.3.3" diff --git a/crates/evm/src/tests/call_tests.rs b/crates/evm/src/tests/call_tests.rs index b1ba5140be..690b0dd2f7 100644 --- a/crates/evm/src/tests/call_tests.rs +++ b/crates/evm/src/tests/call_tests.rs @@ -8,6 +8,7 @@ use sov_modules_api::default_context::DefaultContext; use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::utils::generate_address; use sov_modules_api::{Context, Module, StateMapAccessor, StateVecAccessor}; +use sov_rollup_interface::spec::SpecId as SovSpecId; use crate::call::CallMessage; use crate::evm::primitive_types::Receipt; @@ -55,6 +56,7 @@ fn call_multiple_test() { 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, @@ -163,6 +165,7 @@ fn call_test() { 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, @@ -242,6 +245,7 @@ fn failed_transaction_test() { 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, @@ -299,6 +303,7 @@ fn self_destruct_test() { 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, @@ -359,6 +364,7 @@ fn self_destruct_test() { da_slot_height: 2, da_slot_txs_commitment: [42u8; 32], pre_state_root: [99u8; 32].to_vec(), + current_spec: SovSpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, @@ -440,6 +446,7 @@ fn test_block_hash_in_evm() { 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, @@ -475,6 +482,7 @@ fn test_block_hash_in_evm() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [99u8; 32].to_vec(), + current_spec: SovSpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, @@ -551,6 +559,7 @@ fn test_block_gas_limit() { 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, @@ -830,6 +839,7 @@ fn test_l1_fee_success() { 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, @@ -933,6 +943,7 @@ fn test_l1_fee_not_enough_funds() { 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, @@ -993,6 +1004,7 @@ fn test_l1_fee_halt() { 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, diff --git a/crates/evm/src/tests/ef_tests/cases/blockchain_test.rs b/crates/evm/src/tests/ef_tests/cases/blockchain_test.rs index 01887ea8fd..31241731b6 100644 --- a/crates/evm/src/tests/ef_tests/cases/blockchain_test.rs +++ b/crates/evm/src/tests/ef_tests/cases/blockchain_test.rs @@ -14,6 +14,7 @@ use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::utils::generate_address; use sov_modules_api::{Context, StateMapAccessor, StateValueAccessor, WorkingSet}; use sov_prover_storage_manager::SnapshotManager; +use sov_rollup_interface::spec::SpecId as SovSpecId; use sov_state::{DefaultStorageSpec, ProverStorage}; use crate::primitive_types::Block; @@ -69,6 +70,7 @@ impl BlockchainTestCase { da_slot_height: 0, da_slot_txs_commitment: [0u8; 32], pre_state_root: root.to_vec(), + current_spec: SovSpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 0, diff --git a/crates/evm/src/tests/hooks_tests.rs b/crates/evm/src/tests/hooks_tests.rs index 080f33daf4..e2cc808a03 100644 --- a/crates/evm/src/tests/hooks_tests.rs +++ b/crates/evm/src/tests/hooks_tests.rs @@ -7,6 +7,7 @@ use reth_primitives::{ }; use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::{StateMapAccessor, StateValueAccessor, StateVecAccessor}; +use sov_rollup_interface::spec::SpecId; use super::genesis_tests::{GENESIS_DA_TXS_COMMITMENT, TEST_CONFIG}; use crate::evm::primitive_types::{ @@ -31,6 +32,7 @@ fn begin_soft_confirmation_hook_creates_pending_block() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, @@ -66,6 +68,7 @@ fn end_soft_confirmation_hook_sets_head() { da_slot_height: 1, da_slot_txs_commitment: txs_commitment.into(), pre_state_root: pre_state_root.to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, @@ -141,6 +144,7 @@ fn end_soft_confirmation_hook_moves_transactions_and_receipts() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, @@ -246,6 +250,7 @@ fn finalize_hook_creates_final_block() { da_slot_height: 1, da_slot_txs_commitment: txs_commitment.into(), pre_state_root: root.to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, @@ -276,6 +281,7 @@ fn finalize_hook_creates_final_block() { da_slot_height: 1, da_slot_txs_commitment: txs_commitment.into(), pre_state_root: root_hash.to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, @@ -362,6 +368,7 @@ fn begin_soft_confirmation_hook_appends_last_block_hashes() { da_slot_height: 1, da_slot_txs_commitment: txs_commitment.into(), pre_state_root: root.to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, @@ -403,6 +410,7 @@ fn begin_soft_confirmation_hook_appends_last_block_hashes() { da_slot_height: 1, da_slot_txs_commitment: random_32_bytes, pre_state_root: random_32_bytes.to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, @@ -425,6 +433,7 @@ fn begin_soft_confirmation_hook_appends_last_block_hashes() { da_slot_height: 1, da_slot_txs_commitment: random_32_bytes, pre_state_root: random_32_bytes.to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, diff --git a/crates/evm/src/tests/queries/evm_call_tests.rs b/crates/evm/src/tests/queries/evm_call_tests.rs index f20deb8382..ce6a91e497 100644 --- a/crates/evm/src/tests/queries/evm_call_tests.rs +++ b/crates/evm/src/tests/queries/evm_call_tests.rs @@ -7,6 +7,7 @@ use reth_rpc_types::request::{TransactionInput, TransactionRequest}; use revm::primitives::U256; use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::WorkingSet; +use sov_rollup_interface::spec::SpecId; use super::C; use crate::smart_contracts::SimpleStorageContract; @@ -76,6 +77,7 @@ fn test_state_change() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, diff --git a/crates/evm/src/tests/queries/log_tests.rs b/crates/evm/src/tests/queries/log_tests.rs index 7edd3d2688..75d8da5b7f 100644 --- a/crates/evm/src/tests/queries/log_tests.rs +++ b/crates/evm/src/tests/queries/log_tests.rs @@ -8,6 +8,7 @@ use sov_modules_api::default_context::DefaultContext; use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::utils::generate_address; use sov_modules_api::{Context, Module, StateVecAccessor}; +use sov_rollup_interface::spec::SpecId; use crate::call::CallMessage; use crate::smart_contracts::LogsContract; @@ -71,6 +72,7 @@ fn log_filter_test_at_block_hash() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, @@ -277,6 +279,7 @@ fn log_filter_test_with_range() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, @@ -338,6 +341,7 @@ fn log_filter_test_with_range() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [99u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, @@ -399,6 +403,7 @@ fn test_log_limits() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, @@ -499,6 +504,7 @@ fn test_log_limits() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [99u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, diff --git a/crates/evm/src/tests/queries/mod.rs b/crates/evm/src/tests/queries/mod.rs index ebd0a7c332..e8b8e402d2 100644 --- a/crates/evm/src/tests/queries/mod.rs +++ b/crates/evm/src/tests/queries/mod.rs @@ -11,6 +11,7 @@ use sov_modules_api::default_context::DefaultContext; use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::utils::generate_address; use sov_modules_api::{Context, Module, WorkingSet}; +use sov_rollup_interface::spec::SpecId as SovSpecId; use crate::call::CallMessage; use crate::smart_contracts::{ @@ -67,6 +68,7 @@ fn init_evm() -> (Evm, WorkingSet, TestSigner) { 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: 1, @@ -107,6 +109,7 @@ fn init_evm() -> (Evm, WorkingSet, TestSigner) { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [99u8; 32].to_vec(), + current_spec: SovSpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, @@ -148,6 +151,7 @@ fn init_evm() -> (Evm, WorkingSet, TestSigner) { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [100u8; 32].to_vec(), + current_spec: SovSpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, @@ -224,6 +228,7 @@ pub fn init_evm_single_block() -> (Evm, WorkingSet, TestSigner) { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [0u8; 32].to_vec(), + current_spec: SovSpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, @@ -295,6 +300,7 @@ pub fn init_evm_with_caller_contract() -> (Evm, WorkingSet, TestSigner) { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [0u8; 32].to_vec(), + current_spec: SovSpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, @@ -334,6 +340,7 @@ pub fn init_evm_with_caller_contract() -> (Evm, WorkingSet, TestSigner) { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [2u8; 32].to_vec(), + current_spec: SovSpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, diff --git a/crates/evm/src/tests/sys_tx_tests.rs b/crates/evm/src/tests/sys_tx_tests.rs index 5ce4dffec6..a613fc5531 100644 --- a/crates/evm/src/tests/sys_tx_tests.rs +++ b/crates/evm/src/tests/sys_tx_tests.rs @@ -10,6 +10,7 @@ use sov_modules_api::default_context::DefaultContext; use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::utils::generate_address; use sov_modules_api::{Context, Module, StateMapAccessor, StateVecAccessor}; +use sov_rollup_interface::spec::SpecId; use crate::call::CallMessage; use crate::evm::primitive_types::Receipt; @@ -144,6 +145,7 @@ fn test_sys_bitcoin_light_client() { da_slot_height: 2, da_slot_txs_commitment: [3u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, @@ -280,6 +282,7 @@ fn test_sys_tx_gas_usage_effect_on_block_gas_limit() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, @@ -311,6 +314,7 @@ fn test_sys_tx_gas_usage_effect_on_block_gas_limit() { da_slot_height: 2, da_slot_txs_commitment: [43u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate, @@ -387,6 +391,7 @@ fn test_bridge() { 214, 251, 181, 122, 169, 246, 188, 29, 186, 32, 227, 33, 199, 38, ], pre_state_root: [1u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -521,6 +526,7 @@ fn test_upgrade_light_client() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, @@ -645,6 +651,7 @@ fn test_change_upgrade_owner() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, @@ -680,6 +687,7 @@ fn test_change_upgrade_owner() { da_slot_height: 1, da_slot_txs_commitment: [42u8; 32], pre_state_root: [10u8; 32].to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 1, diff --git a/crates/evm/src/tests/utils.rs b/crates/evm/src/tests/utils.rs index e6d79f724b..6bd9701245 100644 --- a/crates/evm/src/tests/utils.rs +++ b/crates/evm/src/tests/utils.rs @@ -5,6 +5,7 @@ use sov_modules_api::default_context::DefaultContext; use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::{Module, WorkingSet}; use sov_prover_storage_manager::{new_orphan_storage, SnapshotManager}; +use sov_rollup_interface::spec::SpecId; use sov_state::{DefaultStorageSpec, ProverStorage, Storage}; use crate::{Evm, EvmConfig}; @@ -61,6 +62,7 @@ pub(crate) fn get_evm(config: &EvmConfig) -> (Evm, WorkingSet) { da_slot_height: 1, da_slot_txs_commitment: [2u8; 32], pre_state_root: root.to_vec(), + current_spec: SpecId::Genesis, pub_key: vec![], deposit_data: vec![], l1_fee_rate: 0, diff --git a/crates/fullnode/src/runner.rs b/crates/fullnode/src/runner.rs index 2f645d8038..0f66eaba3a 100644 --- a/crates/fullnode/src/runner.rs +++ b/crates/fullnode/src/runner.rs @@ -7,6 +7,7 @@ use anyhow::{anyhow, bail}; use backoff::future::retry as retry_backoff; use backoff::ExponentialBackoffBuilder; use borsh::de::BorshDeserialize; +use citrea_primitives::fork::{Fork, ForkManager}; use citrea_primitives::types::SoftConfirmationHash; use citrea_primitives::{get_da_block_at_height, L1BlockCache, SyncError}; use jsonrpsee::core::client::Error as JsonrpseeError; @@ -66,6 +67,7 @@ where accept_public_input_as_proven: bool, l1_block_cache: Arc>>, sync_blocks_count: u64, + fork_manager: ForkManager, soft_confirmation_tx: broadcast::Sender, } @@ -101,6 +103,7 @@ where init_variant: InitVariant, code_commitment: Vm::CodeCommitment, sync_blocks_count: u64, + fork_manager: ForkManager, soft_confirmation_tx: broadcast::Sender, ) -> Result { let (prev_state_root, prev_batch_hash) = match init_variant { @@ -152,6 +155,7 @@ where .unwrap_or(false), sync_blocks_count, l1_block_cache: Arc::new(Mutex::new(L1BlockCache::new())), + fork_manager, soft_confirmation_tx, }) } @@ -364,8 +368,8 @@ where if stored_soft_batches.len() < ((end_l2_height - start_l2_height) as usize) { return Err(SyncError::MissingL2( "L2 range not synced yet", - BatchNumber(start_l2_height), - BatchNumber(end_l2_height), + start_l2_height, + end_l2_height, )); } @@ -428,6 +432,7 @@ where .create_storage_on_l2_height(l2_height)?; let slot_result = self.stf.apply_soft_batch( + self.fork_manager.active_fork(), self.sequencer_pub_key.as_slice(), // TODO(https://github.com/Sovereign-Labs/sovereign-sdk/issues/1247): incorrect pre-state root in case of re-org &self.state_root, @@ -479,6 +484,10 @@ where BatchNumber(l2_height), )?; + // Register this new block with the fork manager to active + // the new fork on the next block. + self.fork_manager.register_block(l2_height)?; + // Only errors when there are no receivers let _ = self.soft_confirmation_tx.send(l2_height); diff --git a/crates/fullnode/tests/hash_stf.rs b/crates/fullnode/tests/hash_stf.rs index 50db117290..c4c3d7f761 100644 --- a/crates/fullnode/tests/hash_stf.rs +++ b/crates/fullnode/tests/hash_stf.rs @@ -7,6 +7,7 @@ use sov_modules_api::Context; use sov_modules_stf_blueprint::StfBlueprintTrait; use sov_prover_storage_manager::{new_orphan_storage, SnapshotManager}; use sov_rollup_interface::da::{BlobReaderTrait, BlockHeaderTrait, DaSpec}; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::stf::{SlotResult, StateTransitionFunction}; use sov_rollup_interface::zk::{CumulativeStateDiff, ValidityCondition, Zkvm}; use sov_state::storage::{NativeStorage, StorageKey, StorageValue}; @@ -70,6 +71,7 @@ impl StfBlueprintTrai { fn begin_soft_batch( &self, + _current_spec: SpecId, _sequencer_public_key: &[u8], _pre_state_root: &Self::StateRoot, _pre_state: Self::PreState, @@ -85,6 +87,7 @@ impl StfBlueprintTrai fn apply_soft_batch_txs( &self, + _current_spec: SpecId, _txs: Vec>, _batch_workspace: sov_modules_api::WorkingSet, ) -> ( @@ -96,6 +99,7 @@ impl StfBlueprintTrai fn end_soft_batch( &self, + _current_spec: SpecId, _sequencer_public_key: &[u8], _soft_batch: &mut sov_modules_api::SignedSoftConfirmationBatch, _tx_receipts: Vec< @@ -111,6 +115,7 @@ impl StfBlueprintTrai fn finalize_soft_batch( &self, + _current_spec: SpecId, _batch_receipt: sov_modules_stf_blueprint::BatchReceipt< (), sov_modules_stf_blueprint::TxEffect, @@ -154,6 +159,7 @@ impl StateTransitionFunction( &self, + _current_spec: SpecId, pre_state_root: &Self::StateRoot, storage: Self::PreState, mut witness: Self::Witness, @@ -205,6 +211,7 @@ impl StateTransitionFunction StateTransitionFunction, >, + _forks: Vec<(SpecId, u64)>, ) -> (Self::StateRoot, CumulativeStateDiff) { todo!() } @@ -319,6 +327,7 @@ pub fn get_result_from_blocks( MockDaSpec, >>::apply_slot::<&mut Vec>( &stf, + SpecId::Genesis, &state_root, storage, ArrayWitness::default(), diff --git a/crates/fullnode/tests/runner_initialization_tests.rs b/crates/fullnode/tests/runner_initialization_tests.rs index 47d8145d3c..012bf699a6 100644 --- a/crates/fullnode/tests/runner_initialization_tests.rs +++ b/crates/fullnode/tests/runner_initialization_tests.rs @@ -1,10 +1,12 @@ use std::sync::Arc; use citrea_fullnode::CitreaFullnode; +use citrea_primitives::fork::ForkManager; use sov_db::ledger_db::LedgerDB; use sov_mock_da::{MockAddress, MockDaConfig, MockDaService, MockDaSpec, MockValidityCond}; use sov_mock_zkvm::{MockCodeCommitment, MockZkvm}; use sov_prover_storage_manager::ProverStorageManager; +use sov_rollup_interface::spec::SpecId; use sov_state::DefaultStorageSpec; use sov_stf_runner::{ FullNodeConfig, InitVariant, RollupPublicKeys, RpcConfig, RunnerConfig, StorageConfig, @@ -53,6 +55,7 @@ fn initialize_runner( sov_modules_api::default_context::DefaultContext, LedgerDB, > { + let specs = vec![(SpecId::Genesis, 0)]; let da_storage_path = storage_path.join("da").to_path_buf(); let rollup_storage_path = storage_path.join("rollup").to_path_buf(); @@ -109,6 +112,8 @@ fn initialize_runner( // let vm = MockZkvm::new(MockValidityCond::default()); // let verifier = MockDaVerifier::default(); + let fork_manager = ForkManager::new(0, SpecId::Genesis, specs); + CitreaFullnode::new( rollup_config.runner.unwrap(), rollup_config.public_keys, @@ -120,6 +125,7 @@ fn initialize_runner( init_variant, MockCodeCommitment([1u8; 32]), 10, + fork_manager, broadcast::channel(1).0, ) .unwrap() diff --git a/crates/fullnode/tests/runner_reorg_tests.rs b/crates/fullnode/tests/runner_reorg_tests.rs index f392bdb050..0eccada0d7 100644 --- a/crates/fullnode/tests/runner_reorg_tests.rs +++ b/crates/fullnode/tests/runner_reorg_tests.rs @@ -1,12 +1,14 @@ use std::sync::Arc; use citrea_fullnode::CitreaFullnode; +use citrea_primitives::fork::ForkManager; use sov_mock_da::{ MockAddress, MockBlob, MockBlock, MockBlockHeader, MockDaConfig, MockDaService, MockDaSpec, MockValidityCond, PlannedFork, }; use sov_mock_zkvm::MockZkvm; use sov_modules_api::default_context::DefaultContext; +use sov_rollup_interface::spec::SpecId; use sov_stf_runner::{ FullNodeConfig, InitVariant, RollupPublicKeys, RpcConfig, RunnerConfig, StorageConfig, }; @@ -120,6 +122,7 @@ async fn runner_execution( init_variant: MockInitVariant, da_service: Arc, ) -> ([u8; 32], [u8; 32]) { + let specs = vec![(SpecId::Genesis, 0)]; let rollup_storage_path = storage_path.join("rollup").to_path_buf(); let rollup_config = FullNodeConfig:: { storage: StorageConfig { @@ -161,6 +164,8 @@ async fn runner_execution( }; let storage_manager = ProverStorageManager::new(storage_config).unwrap(); + let fork_manager = ForkManager::new(0, SpecId::Genesis, specs); + let mut runner: CitreaFullnode<_, _, _, _, DefaultContext, _> = CitreaFullnode::new( rollup_config.runner.unwrap(), rollup_config.public_keys, @@ -172,6 +177,7 @@ async fn runner_execution( init_variant, MockCodeCommitment([1u8; 32]), 10, + fork_manager, broadcast::channel(1).0, ) .unwrap(); diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 10b31e0c11..64a436e03d 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -8,20 +8,26 @@ publish = false [dependencies] # Sov SDK deps -sov-db = { path = "../sovereign-sdk/full-node/db/sov-db", optional = true } sov-rollup-interface = { path = "../sovereign-sdk/rollup-interface" } # 3rd-party deps anyhow = { workspace = true } backoff = { workspace = true, optional = true } lru = { workspace = true, optional = true } +serde = { workspace = true, optional = true } tokio = { workspace = true, optional = true } +tracing = { workspace = true, optional = true } + +[dev-dependencies] +# Sov SDK deps +sov-rollup-interface = { path = "../sovereign-sdk/rollup-interface", features = ["testing"] } [features] native = [ + "dep:backoff", "dep:lru", - "sov-rollup-interface/native", - "sov-db", + "dep:serde", "dep:tokio", - "dep:backoff", + "dep:tracing", + "sov-rollup-interface/native", ] diff --git a/crates/primitives/src/error.rs b/crates/primitives/src/error.rs index 9b9635e839..da11e19c78 100644 --- a/crates/primitives/src/error.rs +++ b/crates/primitives/src/error.rs @@ -1,8 +1,8 @@ -use sov_db::schema::types::BatchNumber; +use crate::types::BlockNumber; #[derive(Debug)] pub enum SyncError { - MissingL2(&'static str, BatchNumber, BatchNumber), + MissingL2(&'static str, BlockNumber, BlockNumber), Error(anyhow::Error), } diff --git a/crates/primitives/src/fork/manager.rs b/crates/primitives/src/fork/manager.rs new file mode 100644 index 0000000000..c8a5ac2335 --- /dev/null +++ b/crates/primitives/src/fork/manager.rs @@ -0,0 +1,83 @@ +use std::collections::VecDeque; + +use sov_rollup_interface::spec::SpecId; +#[cfg(feature = "native")] +use tracing::info; + +use super::ForkMigration; + +/// Defines the interface which a fork manager needs to implement. +pub trait Fork { + /// Returns the currently active fork. + fn active_fork(&self) -> SpecId; + + /// Register a new L2 block with fork manager + fn register_block(&mut self, height: u64) -> anyhow::Result<()>; +} + +pub type SpecActivationBlockHeight = u64; + +pub struct ForkManager { + active_spec: SpecId, + specs: VecDeque<(SpecId, SpecActivationBlockHeight)>, + migration_handlers: Vec>, +} + +impl ForkManager { + pub fn new( + current_l2_height: u64, + active_spec: SpecId, + mut specs: Vec<(SpecId, SpecActivationBlockHeight)>, + ) -> Self { + // Filter out specs which have already been activated. + specs.retain(|(spec, block)| *spec != active_spec && *block > current_l2_height); + // Make sure the list of specs is sorted by the block number at which they activate. + specs.sort_by_key(|(_, block_number)| *block_number); + Self { + specs: specs.into(), + active_spec, + migration_handlers: vec![], + } + } + + pub fn register_handler(&mut self, handler: Box) { + self.migration_handlers.push(handler); + } +} + +impl Fork for ForkManager { + fn active_fork(&self) -> SpecId { + self.active_spec + } + + fn register_block(&mut self, height: u64) -> anyhow::Result<()> { + if let Some((new_spec, activation_block_height)) = self.specs.front() { + if height == *activation_block_height { + #[cfg(feature = "native")] + info!("Activating fork {:?} at height: {}", *new_spec, height); + + self.active_spec = *new_spec; + for handler in self.migration_handlers.iter() { + handler.spec_activated(self.active_spec)?; + } + self.specs.pop_front(); + } + } + Ok(()) + } +} + +/// Simple search for the fork to which a specific block number blongs. +/// This assumes that the list of forks is sorted by block number in ascending fashion. +pub fn fork_from_block_number(forks: &[(SpecId, u64)], block_number: u64) -> SpecId { + let mut fork = forks[0].0; + if forks.len() == 1 { + return fork; + } + for (spec_id, activation_block) in &forks[1..] { + if block_number >= *activation_block { + fork = *spec_id; + } + } + fork +} diff --git a/crates/primitives/src/fork/migration.rs b/crates/primitives/src/fork/migration.rs new file mode 100644 index 0000000000..f87783e15d --- /dev/null +++ b/crates/primitives/src/fork/migration.rs @@ -0,0 +1,16 @@ +use sov_rollup_interface::spec::SpecId; + +/// Defines the interface of a migration +pub trait ForkMigration { + /// Invoked when a spec is activated. + fn spec_activated(&self, spec_id: SpecId) -> anyhow::Result<()>; +} + +pub struct NoOpMigration {} + +impl ForkMigration for NoOpMigration { + fn spec_activated(&self, _spec_id: SpecId) -> anyhow::Result<()> { + // Do nothing + Ok(()) + } +} diff --git a/crates/primitives/src/fork/mod.rs b/crates/primitives/src/fork/mod.rs new file mode 100644 index 0000000000..b77cfcf7e9 --- /dev/null +++ b/crates/primitives/src/fork/mod.rs @@ -0,0 +1,7 @@ +mod manager; +mod migration; +#[cfg(test)] +mod tests; + +pub use manager::*; +pub use migration::*; diff --git a/crates/primitives/src/fork/tests.rs b/crates/primitives/src/fork/tests.rs new file mode 100644 index 0000000000..8026979631 --- /dev/null +++ b/crates/primitives/src/fork/tests.rs @@ -0,0 +1,64 @@ +use anyhow::anyhow; +use sov_rollup_interface::spec::SpecId; + +use super::{Fork, ForkManager}; +use crate::fork::{fork_from_block_number, ForkMigration}; + +#[test] +fn test_fork_from_block_number() { + let forks = vec![ + (SpecId::Genesis, 0), + (SpecId::Fork1, 100), + (SpecId::Fork2, 500), + ]; + + assert_eq!(fork_from_block_number(&forks, 5), SpecId::Genesis); + assert_eq!(fork_from_block_number(&forks, 105), SpecId::Fork1); + assert_eq!(fork_from_block_number(&forks, 350), SpecId::Fork1); + assert_eq!(fork_from_block_number(&forks, 505), SpecId::Fork2); +} + +#[test] +fn test_fork_manager() { + let forks = vec![ + (SpecId::Genesis, 0), + (SpecId::Fork1, 100), + (SpecId::Fork2, 500), + ]; + let mut fork_manager = ForkManager::new(0, SpecId::Genesis, forks); + fork_manager.register_block(5).unwrap(); + assert_eq!(fork_manager.active_fork(), SpecId::Genesis); + fork_manager.register_block(100).unwrap(); + assert_eq!(fork_manager.active_fork(), SpecId::Fork1); + fork_manager.register_block(350).unwrap(); + assert_eq!(fork_manager.active_fork(), SpecId::Fork1); + fork_manager.register_block(500).unwrap(); + assert_eq!(fork_manager.active_fork(), SpecId::Fork2); +} + +#[test] +fn test_fork_manager_callbacks() { + let forks = vec![ + (SpecId::Genesis, 0), + (SpecId::Fork1, 100), + (SpecId::Fork2, 500), + ]; + + struct Handler {} + impl ForkMigration for Handler { + fn spec_activated(&self, spec_id: SpecId) -> anyhow::Result<()> { + if spec_id == SpecId::Fork1 { + return Err(anyhow!("Called")); + } + Ok(()) + } + } + let handler = Box::new(Handler {}); + let mut fork_manager = ForkManager::new(0, SpecId::Genesis, forks); + fork_manager.register_handler(handler); + let result = fork_manager.register_block(100); + assert!(result.is_err()); + if let Err(msg) = result { + assert_eq!(msg.to_string(), "Called"); + } +} diff --git a/crates/primitives/src/forks.rs b/crates/primitives/src/forks.rs new file mode 100644 index 0000000000..b5cba58db1 --- /dev/null +++ b/crates/primitives/src/forks.rs @@ -0,0 +1,10 @@ +use sov_rollup_interface::spec::SpecId; + +/// This defines the list of forks which will be activated +/// at specific heights. +pub const FORKS: [(SpecId, u64); 1] = [ + (SpecId::Genesis, 0), + // Examples of how we can define further forks + // (SpecId::Fork1, 100), + // (SpecId::Fork2, 200) +]; diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index dc53eab267..b91c008e15 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -5,6 +5,8 @@ mod constants; mod da; #[cfg(feature = "native")] mod error; +pub mod fork; +pub mod forks; pub mod types; #[cfg(feature = "native")] diff --git a/crates/primitives/src/types.rs b/crates/primitives/src/types.rs index 61d8239df9..4158e59bab 100644 --- a/crates/primitives/src/types.rs +++ b/crates/primitives/src/types.rs @@ -1 +1,2 @@ pub type SoftConfirmationHash = [u8; 32]; +pub type BlockNumber = u64; diff --git a/crates/prover/src/runner.rs b/crates/prover/src/runner.rs index 16d16f42e6..669b5b493c 100644 --- a/crates/prover/src/runner.rs +++ b/crates/prover/src/runner.rs @@ -9,6 +9,7 @@ use anyhow::{anyhow, bail}; use backoff::exponential::ExponentialBackoffBuilder; use backoff::future::retry as retry_backoff; use borsh::de::BorshDeserialize; +use citrea_primitives::fork::{Fork, ForkManager}; use citrea_primitives::types::SoftConfirmationHash; use citrea_primitives::{get_da_block_at_height, L1BlockCache}; use jsonrpsee::core::client::Error as JsonrpseeError; @@ -73,6 +74,7 @@ where code_commitment: Vm::CodeCommitment, l1_block_cache: Arc>>, sync_blocks_count: u64, + fork_manager: ForkManager, soft_confirmation_tx: broadcast::Sender, } @@ -111,6 +113,7 @@ where prover_config: Option, code_commitment: Vm::CodeCommitment, sync_blocks_count: u64, + fork_manager: ForkManager, soft_confirmation_tx: broadcast::Sender, ) -> Result { let (prev_state_root, prev_batch_hash) = match init_variant { @@ -157,6 +160,7 @@ where code_commitment, l1_block_cache: Arc::new(Mutex::new(L1BlockCache::new())), sync_blocks_count, + fork_manager, soft_confirmation_tx, }) } @@ -332,6 +336,7 @@ where .create_storage_on_l2_height(l2_height)?; let slot_result = self.stf.apply_soft_batch( + self.fork_manager.active_fork(), self.sequencer_pub_key.as_slice(), // TODO(https://github.com/Sovereign-Labs/sovereign-sdk/issues/1247): incorrect pre-state root in case of re-org &self.state_root, @@ -386,6 +391,10 @@ where BatchNumber(l2_height), )?; + // Register this new block with the fork manager to active + // the new fork on the next block + self.fork_manager.register_block(l2_height)?; + // Only errors when there are no receivers let _ = self.soft_confirmation_tx.send(l2_height); diff --git a/crates/sequencer/src/sequencer.rs b/crates/sequencer/src/sequencer.rs index a40c62bb57..7e56adfb2d 100644 --- a/crates/sequencer/src/sequencer.rs +++ b/crates/sequencer/src/sequencer.rs @@ -9,6 +9,7 @@ use std::vec; use anyhow::anyhow; use borsh::BorshDeserialize; use citrea_evm::{CallMessage, Evm, RlpEvmTransaction, MIN_TRANSACTION_GAS}; +use citrea_primitives::fork::{Fork, ForkManager}; use citrea_primitives::types::SoftConfirmationHash; use citrea_stf::runtime::Runtime; use digest::Digest; @@ -92,6 +93,7 @@ where rpc_config: RpcConfig, soft_confirmation_rule_enforcer: SoftConfirmationRuleEnforcer, last_state_diff: StateDiff, + fork_manager: ForkManager, soft_confirmation_tx: broadcast::Sender, } @@ -126,6 +128,7 @@ where public_keys: RollupPublicKeys, ledger_db: DB, rpc_config: RpcConfig, + fork_manager: ForkManager, soft_confirmation_tx: broadcast::Sender, ) -> anyhow::Result { let (l2_force_block_tx, l2_force_block_rx) = unbounded(); @@ -184,6 +187,7 @@ where rpc_config, soft_confirmation_rule_enforcer, last_state_diff, + fork_manager, soft_confirmation_tx, }) } @@ -267,6 +271,7 @@ where l2_block_mode: L2BlockMode, ) -> anyhow::Result<(Vec, Vec)> { match self.stf.begin_soft_batch( + self.fork_manager.active_fork(), pub_key, &self.state_root, prestate.clone(), @@ -303,9 +308,11 @@ where let txs = vec![signed_blob.clone()]; - let (batch_workspace, _) = self - .stf - .apply_soft_batch_txs(txs.clone(), working_set_to_discard); + let (batch_workspace, _) = self.stf.apply_soft_batch_txs( + self.fork_manager.active_fork(), + txs.clone(), + working_set_to_discard, + ); working_set_to_discard = batch_workspace; @@ -387,6 +394,7 @@ where da_slot_txs_commitment: da_block.header().txs_commitment().into(), pre_state_root: self.state_root.clone().as_ref().to_vec(), deposit_data: deposit_data.clone(), + current_spec: self.fork_manager.active_fork(), pub_key, l1_fee_rate, timestamp, @@ -428,6 +436,7 @@ where // Execute the selected transactions match self.stf.begin_soft_batch( + self.fork_manager.active_fork(), &pub_key, &self.state_root, prestate.clone(), @@ -443,8 +452,11 @@ where let signed_blob = self.make_blob(raw_message, &mut batch_workspace)?; let txs = vec![signed_blob.clone()]; - let (batch_workspace, tx_receipts) = - self.stf.apply_soft_batch_txs(txs.clone(), batch_workspace); + let (batch_workspace, tx_receipts) = self.stf.apply_soft_batch_txs( + self.fork_manager.active_fork(), + txs.clone(), + batch_workspace, + ); // create the unsigned batch with the txs then sign th sc let unsigned_batch = UnsignedSoftConfirmationBatch::new( @@ -461,6 +473,7 @@ where self.sign_soft_confirmation_batch(unsigned_batch, self.batch_hash)?; let (batch_receipt, checkpoint) = self.stf.end_soft_batch( + self.fork_manager.active_fork(), self.sequencer_pub_key.as_ref(), &mut signed_soft_batch, tx_receipts, @@ -469,6 +482,7 @@ where // Finalize soft confirmation let slot_result = self.stf.finalize_soft_batch( + self.fork_manager.active_fork(), batch_receipt, checkpoint, prestate, @@ -534,6 +548,10 @@ where BatchNumber(l2_height), )?; + // Register this new block with the fork manager to active + // the new fork on the next block + self.fork_manager.register_block(l2_height)?; + // Only errors when there are no receivers let _ = self.soft_confirmation_tx.send(l2_height); diff --git a/crates/soft-confirmation-rule-enforcer/Cargo.toml b/crates/soft-confirmation-rule-enforcer/Cargo.toml index dda909a5e2..edac260367 100644 --- a/crates/soft-confirmation-rule-enforcer/Cargo.toml +++ b/crates/soft-confirmation-rule-enforcer/Cargo.toml @@ -28,6 +28,7 @@ lazy_static = "1.4.0" sov-mock-da = { path = "../sovereign-sdk/adapters/mock-da", features = ["native"] } sov-modules-api = { path = "../sovereign-sdk/module-system/sov-modules-api", features = ["native"] } 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"] } tempfile = { workspace = true } [features] diff --git a/crates/soft-confirmation-rule-enforcer/src/tests/hooks_tests.rs b/crates/soft-confirmation-rule-enforcer/src/tests/hooks_tests.rs index 01e862ce1f..8eb27a6a9c 100644 --- a/crates/soft-confirmation-rule-enforcer/src/tests/hooks_tests.rs +++ b/crates/soft-confirmation-rule-enforcer/src/tests/hooks_tests.rs @@ -7,6 +7,7 @@ use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::utils::generate_address; use sov_modules_api::{Context, Module, Spec, StateValueAccessor}; use sov_rollup_interface::soft_confirmation::SignedSoftConfirmationBatch; +use sov_rollup_interface::spec::SpecId; use crate::call::CallMessage; use crate::tests::genesis_tests::{get_soft_confirmation_rule_enforcer, TEST_CONFIG}; @@ -55,6 +56,7 @@ fn begin_soft_confirmation_hook_checks_max_l2_blocks_per_l1() { &mut HookSoftConfirmationInfo::new( signed_soft_confirmation_batch.clone(), vec![0; 32], + SpecId::Genesis, ), &mut working_set, ) @@ -87,7 +89,11 @@ fn begin_soft_confirmation_hook_checks_l1_fee_rate() { // call first with 100 fee rate to set last_l1_fee_rate let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); @@ -98,7 +104,11 @@ fn begin_soft_confirmation_hook_checks_l1_fee_rate() { signed_soft_confirmation_batch.set_l1_fee_rate(111); let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); @@ -123,7 +133,11 @@ fn begin_soft_confirmation_hook_checks_l1_fee_rate() { signed_soft_confirmation_batch.set_l1_fee_rate(110); let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); @@ -133,7 +147,11 @@ fn begin_soft_confirmation_hook_checks_l1_fee_rate() { signed_soft_confirmation_batch.set_l1_fee_rate(122); let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); @@ -142,7 +160,11 @@ fn begin_soft_confirmation_hook_checks_l1_fee_rate() { signed_soft_confirmation_batch.set_l1_fee_rate(121); let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); @@ -152,13 +174,21 @@ fn begin_soft_confirmation_hook_checks_l1_fee_rate() { signed_soft_confirmation_batch.set_l1_fee_rate(109); let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); assert!(res.is_ok()); signed_soft_confirmation_batch.set_l1_fee_rate(100); let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); assert!(res.is_ok()); @@ -170,7 +200,11 @@ fn begin_soft_confirmation_hook_checks_l1_fee_rate() { signed_soft_confirmation_batch.set_l1_fee_rate(89); let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); @@ -194,7 +228,11 @@ fn begin_soft_confirmation_hook_checks_l1_fee_rate() { signed_soft_confirmation_batch.set_l1_fee_rate(90); let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); @@ -205,7 +243,11 @@ fn begin_soft_confirmation_hook_checks_l1_fee_rate() { signed_soft_confirmation_batch.set_l1_fee_rate(89); let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); @@ -235,7 +277,11 @@ fn begin_soft_confirmation_hook_checks_timestamp() { // call first with `original_timestamp` let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); @@ -258,7 +304,11 @@ fn begin_soft_confirmation_hook_checks_timestamp() { ); let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); @@ -296,7 +346,11 @@ fn begin_soft_confirmation_hook_checks_timestamp() { ); let res = soft_confirmation_rule_enforcer.begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ); diff --git a/crates/soft-confirmation-rule-enforcer/src/tests/query_tests.rs b/crates/soft-confirmation-rule-enforcer/src/tests/query_tests.rs index a85cf86885..dabb8e64a2 100644 --- a/crates/soft-confirmation-rule-enforcer/src/tests/query_tests.rs +++ b/crates/soft-confirmation-rule-enforcer/src/tests/query_tests.rs @@ -2,6 +2,7 @@ use sov_mock_da::MockDaSpec; use sov_modules_api::hooks::HookSoftConfirmationInfo; use sov_modules_api::StateMapAccessor; use sov_rollup_interface::soft_confirmation::SignedSoftConfirmationBatch; +use sov_rollup_interface::spec::SpecId; use crate::tests::genesis_tests::{get_soft_confirmation_rule_enforcer, TEST_CONFIG}; @@ -30,6 +31,7 @@ fn block_count_per_da_hash_must_be_correct() { &mut HookSoftConfirmationInfo::new( signed_soft_confirmation_batch.clone(), vec![0; 32], + SpecId::Genesis, ), &mut working_set, ) @@ -49,7 +51,11 @@ fn block_count_per_da_hash_must_be_correct() { // call with a different da hash soft_confirmation_rule_enforcer .begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ) .unwrap(); @@ -91,7 +97,11 @@ fn get_max_l1_fee_rate_change_percentage_must_be_correct() { soft_confirmation_rule_enforcer .begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ) .unwrap(); @@ -132,7 +142,11 @@ fn get_last_l1_fee_rate_must_be_correct() { ); soft_confirmation_rule_enforcer .begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ) .unwrap(); @@ -174,7 +188,11 @@ fn get_last_timestamp_must_be_correct() { ); soft_confirmation_rule_enforcer .begin_soft_confirmation_hook( - &mut HookSoftConfirmationInfo::new(signed_soft_confirmation_batch.clone(), vec![0; 32]), + &mut HookSoftConfirmationInfo::new( + signed_soft_confirmation_batch.clone(), + vec![0; 32], + SpecId::Genesis, + ), &mut working_set, ) .unwrap(); diff --git a/crates/sovereign-sdk/examples/demo-simple-stf/src/lib.rs b/crates/sovereign-sdk/examples/demo-simple-stf/src/lib.rs index 7e5c4f478c..0bbc45bd3a 100644 --- a/crates/sovereign-sdk/examples/demo-simple-stf/src/lib.rs +++ b/crates/sovereign-sdk/examples/demo-simple-stf/src/lib.rs @@ -5,6 +5,7 @@ use std::marker::PhantomData; use sha2::Digest; use sov_rollup_interface::da::{BlobReaderTrait, DaSpec}; use sov_rollup_interface::soft_confirmation::SignedSoftConfirmationBatch; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::stf::{BatchReceipt, SlotResult, StateTransitionFunction}; use sov_rollup_interface::zk::{CumulativeStateDiff, ValidityCondition, Zkvm}; @@ -58,6 +59,7 @@ impl StateTransitionFunction( &self, + _current_spec: SpecId, _pre_state_root: &[u8; 0], _base_state: Self::PreState, _witness: Self::Witness, @@ -112,6 +114,7 @@ impl StateTransitionFunction StateTransitionFunction::BlockHeader>>, _validity_condition: &::ValidityCondition, _soft_batch: std::collections::VecDeque>, + _forks: Vec<(SpecId, u64)>, ) -> (Self::StateRoot, CumulativeStateDiff) { todo!() } diff --git a/crates/sovereign-sdk/examples/demo-simple-stf/tests/stf_test.rs b/crates/sovereign-sdk/examples/demo-simple-stf/tests/stf_test.rs index 73ca15d372..2930a42a36 100644 --- a/crates/sovereign-sdk/examples/demo-simple-stf/tests/stf_test.rs +++ b/crates/sovereign-sdk/examples/demo-simple-stf/tests/stf_test.rs @@ -2,6 +2,7 @@ use demo_simple_stf::CheckHashPreimageStf; use sov_mock_da::verifier::MockDaSpec; use sov_mock_da::{MockAddress, MockBlob, MockBlockHeader, MockValidityCond}; use sov_mock_zkvm::MockZkvm; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::stf::StateTransitionFunction; #[test] @@ -28,6 +29,7 @@ fn test_stf_success() { let result = StateTransitionFunction::, MockDaSpec>::apply_slot( stf, + SpecId::Genesis, &[], (), (), diff --git a/crates/sovereign-sdk/examples/demo-stf/src/hooks_impl.rs b/crates/sovereign-sdk/examples/demo-stf/src/hooks_impl.rs index e9afc5f592..6ab15c7320 100644 --- a/crates/sovereign-sdk/examples/demo-stf/src/hooks_impl.rs +++ b/crates/sovereign-sdk/examples/demo-stf/src/hooks_impl.rs @@ -23,7 +23,11 @@ impl TxHooks for Runtime { working_set: &mut WorkingSet, arg: &RuntimeTxHook, ) -> anyhow::Result { - let RuntimeTxHook { height, sequencer } = arg; + let RuntimeTxHook { + height, + sequencer, + current_spec: _current_spec, + } = arg; let AccountsTxHook { sender, sequencer } = self.accounts .pre_dispatch_tx_hook(tx, working_set, sequencer)?; diff --git a/crates/sovereign-sdk/full-node/db/sov-db/Cargo.toml b/crates/sovereign-sdk/full-node/db/sov-db/Cargo.toml index 17cd71c1dd..e6c4f82630 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/Cargo.toml +++ b/crates/sovereign-sdk/full-node/db/sov-db/Cargo.toml @@ -16,44 +16,39 @@ resolver = "2" [dependencies] # Maintained by sovereign labs jmt = { workspace = true } +sov-rollup-interface = { path = "../../../rollup-interface", features = ["native"] } sov-schema-db = { path = "../sov-schema-db" } -sov-rollup-interface = { path = "../../../rollup-interface", features = [ - "native", -] } + +citrea-primitives = { path = "../../../../primitives" } # External anyhow = { workspace = true, default-features = true } arbitrary = { workspace = true, optional = true } +bincode = { workspace = true } +borsh = { workspace = true, default-features = true, features = ["bytes", "rc"] } byteorder = { workspace = true, default-features = true } -borsh = { workspace = true, default-features = true, features = [ - "bytes", - "rc", -] } +hex = { workspace = true } proptest = { workspace = true, optional = true, default-features = true } proptest-derive = { workspace = true, optional = true } +rocksdb = { workspace = true } serde = { workspace = true, default-features = true, features = ["rc"] } tempfile = { workspace = true, optional = true } -rocksdb = { workspace = true } -bincode = { workspace = true } tokio = { workspace = true } tracing = { workspace = true } -hex = { workspace = true } - [dev-dependencies] -sov-mock-da = { path = "../../../adapters/mock-da", features = ["native"] } -tempfile = { workspace = true } criterion = "0.5.1" rand = { workspace = true } sha2 = { workspace = true } - +sov-mock-da = { path = "../../../adapters/mock-da", features = ["native"] } +tempfile = { workspace = true } [features] arbitrary = [ - "dep:arbitrary", - "dep:proptest", - "dep:proptest-derive", - "dep:tempfile", + "dep:arbitrary", + "dep:proptest", + "dep:proptest-derive", + "dep:tempfile", ] [[bench]] 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 46cf52bf52..f585499ad5 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,10 +1,12 @@ use std::path::Path; use std::sync::{Arc, Mutex}; +use citrea_primitives::fork::ForkMigration; use serde::de::DeserializeOwned; use serde::Serialize; use sov_rollup_interface::da::{DaSpec, SequencerCommitment}; use sov_rollup_interface::services::da::SlotData; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::stf::{BatchReceipt, Event, SoftBatchReceipt, StateDiff}; use sov_rollup_interface::zk::Proof; use sov_schema_db::{Schema, SchemaBatch, SeekKeyEncoder, DB}; @@ -13,8 +15,8 @@ use tracing::instrument; use crate::rocks_db_config::gen_rocksdb_options; use crate::schema::tables::{ - BatchByHash, BatchByNumber, CommitmentsByNumber, EventByKey, EventByNumber, L2GenesisStateRoot, - L2RangeByL1Height, L2Witness, LastSequencerCommitmentSent, LastStateDiff, + ActiveFork, BatchByHash, BatchByNumber, CommitmentsByNumber, EventByKey, EventByNumber, + L2GenesisStateRoot, L2RangeByL1Height, L2Witness, LastSequencerCommitmentSent, LastStateDiff, PendingSequencerCommitmentL2Range, ProofBySlotNumber, ProverLastScannedSlot, SlotByHash, SlotByNumber, SoftBatchByHash, SoftBatchByNumber, SoftConfirmationStatus, TxByHash, TxByNumber, VerifiedProofsBySlotNumber, LEDGER_TABLES, @@ -456,6 +458,14 @@ impl SharedLedgerOps for LedgerDB { ) -> Result, anyhow::Error> { self.db.get::(number) } + + /// Gets the currently active fork + #[instrument(level = "trace", skip(self), err, ret)] + fn get_active_fork(&self) -> Result { + self.db + .get::(&()) + .map(|fork| fork.unwrap_or_default()) + } } impl ProverLedgerOps for LedgerDB { @@ -794,3 +804,10 @@ impl NodeLedgerOps for LedgerDB { self.db.get::(&hash).map(|v| v.map(|a| a.0)) } } + +impl ForkMigration for LedgerDB { + fn spec_activated(&self, _spec_id: SpecId) -> anyhow::Result<()> { + // TODO: Implement later + Ok(()) + } +} 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 db35a137fa..cb69385d0f 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 @@ -3,6 +3,7 @@ use serde::de::DeserializeOwned; use serde::Serialize; use sov_rollup_interface::da::{DaSpec, SequencerCommitment}; use sov_rollup_interface::services::da::SlotData; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::stf::{Event, SoftBatchReceipt, StateDiff}; use sov_rollup_interface::zk::Proof; use sov_schema_db::SchemaBatch; @@ -118,6 +119,9 @@ pub trait SharedLedgerOps { /// Gets all soft confirmations by numbers fn get_soft_batch_by_number(&self, number: &BatchNumber) -> Result>; + + /// Gets the currently active fork + fn get_active_fork(&self) -> Result; } /// Node ledger operations 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 c37c20fac9..02f05fe1b8 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 @@ -30,6 +30,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use jmt::storage::{NibblePath, Node, NodeKey}; use jmt::Version; use sov_rollup_interface::da::SequencerCommitment; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::stf::{Event, EventKey, StateDiff}; use sov_schema_db::schema::{KeyDecoder, KeyEncoder, ValueCodec}; use sov_schema_db::{CodecError, SeekKeyEncoder}; @@ -51,6 +52,7 @@ pub const STATE_TABLES: &[&str] = &[ /// A list of all tables used by the LedgerDB. These tables store rollup "history" - meaning /// transaction, events, receipts, etc. pub const LEDGER_TABLES: &[&str] = &[ + ActiveFork::table_name(), SlotByNumber::table_name(), SlotByHash::table_name(), SoftBatchByNumber::table_name(), @@ -220,6 +222,11 @@ macro_rules! define_table_with_seek_key_codec { }; } +define_table_with_seek_key_codec!( + /// The currently active fork + (ActiveFork) () => SpecId +); + define_table_with_seek_key_codec!( /// The State diff storage (LastStateDiff) () => StateDiff diff --git a/crates/sovereign-sdk/full-node/sov-sequencer/src/batch_builder.rs b/crates/sovereign-sdk/full-node/sov-sequencer/src/batch_builder.rs index 2150c037b9..0908f10961 100644 --- a/crates/sovereign-sdk/full-node/sov-sequencer/src/batch_builder.rs +++ b/crates/sovereign-sdk/full-node/sov-sequencer/src/batch_builder.rs @@ -7,6 +7,7 @@ use sov_modules_api::digest::Digest; use sov_modules_api::transaction::Transaction; use sov_modules_api::{Context, DispatchCall, PublicKey, Spec, WorkingSet}; use sov_rollup_interface::services::batch_builder::BatchBuilder; +use sov_rollup_interface::spec::SpecId; use tracing::{info, warn}; /// Transaction stored in the mempool. @@ -122,7 +123,7 @@ where /// Builds a new batch of valid transactions in order they were added to mempool /// Only transactions, which are dispatched successfully are included in the batch - fn get_next_blob(&mut self) -> anyhow::Result>> { + fn get_next_blob(&mut self, current_spec: SpecId) -> anyhow::Result>> { let mut working_set = WorkingSet::new(self.current_storage.clone()); let mut txs = Vec::new(); let mut current_batch_size = 0; @@ -144,7 +145,10 @@ where // FIXME! This should use the correct height let ctx = C::new(sender_address, self.sequencer.clone(), 0); - if let Err(error) = self.runtime.dispatch_call(msg, &mut working_set, &ctx) { + if let Err(error) = + self.runtime + .dispatch_call(msg, &mut working_set, current_spec, &ctx) + { warn!(%error, tx = hex::encode(&pooled.raw), "Error during transaction dispatch"); continue; } @@ -381,7 +385,7 @@ mod tests { let (mut batch_builder, storage) = create_batch_builder(10, &tmpdir); setup_runtime(storage, None); - let build_result = batch_builder.get_next_blob(); + let build_result = batch_builder.get_next_blob(SpecId::Genesis); assert!(build_result.is_err()); assert_eq!( "No valid transactions are available", @@ -409,7 +413,7 @@ mod tests { assert_eq!(txs.len(), batch_builder.mempool.len()); - let build_result = batch_builder.get_next_blob(); + let build_result = batch_builder.get_next_blob(SpecId::Genesis); assert!(build_result.is_err()); assert_eq!( "No valid transactions are available", @@ -442,7 +446,7 @@ mod tests { assert_eq!(txs.len(), batch_builder.mempool.len()); - let build_result = batch_builder.get_next_blob(); + let build_result = batch_builder.get_next_blob(SpecId::Genesis); assert!(build_result.is_ok()); let blob = build_result.unwrap(); assert_eq!(2, blob.len()); diff --git a/crates/sovereign-sdk/full-node/sov-sequencer/src/lib.rs b/crates/sovereign-sdk/full-node/sov-sequencer/src/lib.rs index 5b48233d98..b111d1acae 100644 --- a/crates/sovereign-sdk/full-node/sov-sequencer/src/lib.rs +++ b/crates/sovereign-sdk/full-node/sov-sequencer/src/lib.rs @@ -14,6 +14,7 @@ use jsonrpsee::RpcModule; use sov_modules_api::utils::to_jsonrpsee_error_object; use sov_rollup_interface::services::batch_builder::BatchBuilder; use sov_rollup_interface::services::da::DaService; +use sov_rollup_interface::spec::SpecId; const SEQUENCER_RPC_ERROR: &str = "SEQUENCER_RPC_ERROR"; @@ -43,7 +44,7 @@ impl Sequencer .batch_builder .lock() .map_err(|e| anyhow!("failed to lock mempool: {}", e.to_string()))?; - batch_builder.get_next_blob()? + batch_builder.get_next_blob(SpecId::Genesis)? }; let num_txs = blob.len(); let blob: Vec = borsh::to_vec(&blob)?; @@ -154,7 +155,7 @@ mod tests { Ok(()) } - fn get_next_blob(&mut self) -> anyhow::Result>> { + fn get_next_blob(&mut self, _current_spec: SpecId) -> anyhow::Result>> { if self.mempool.is_empty() { anyhow::bail!("Mock mempool is empty"); } diff --git a/crates/sovereign-sdk/full-node/sov-stf-runner/Cargo.toml b/crates/sovereign-sdk/full-node/sov-stf-runner/Cargo.toml index 894d05be8d..88e31eab50 100644 --- a/crates/sovereign-sdk/full-node/sov-stf-runner/Cargo.toml +++ b/crates/sovereign-sdk/full-node/sov-stf-runner/Cargo.toml @@ -35,6 +35,7 @@ sov-modules-api = { path = "../../module-system/sov-modules-api", default-featur sov-rollup-interface = { path = "../../rollup-interface" } # Citrea-Deps +citrea-primitives = { path = "../../../primitives" } shared-backup-db = { path = "../../../shared-backup-db", optional = true } [dev-dependencies] diff --git a/crates/sovereign-sdk/full-node/sov-stf-runner/src/mock/mod.rs b/crates/sovereign-sdk/full-node/sov-stf-runner/src/mock/mod.rs index 5b2410af65..b9ec1bf86e 100644 --- a/crates/sovereign-sdk/full-node/sov-stf-runner/src/mock/mod.rs +++ b/crates/sovereign-sdk/full-node/sov-stf-runner/src/mock/mod.rs @@ -1,6 +1,7 @@ use std::marker::PhantomData; use sov_rollup_interface::da::DaSpec; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::stf::{BatchReceipt, SlotResult, StateTransitionFunction}; use sov_rollup_interface::zk::{CumulativeStateDiff, ValidityCondition, Zkvm}; @@ -33,6 +34,7 @@ impl StateTransitionFunction( &self, + _current_spec: SpecId, _pre_state_root: &[u8; 0], _base_state: Self::PreState, _witness: Self::Witness, @@ -65,6 +67,7 @@ impl StateTransitionFunction StateTransitionFunction, >, + _forks: Vec<(SpecId, u64)>, ) -> (Self::StateRoot, CumulativeStateDiff) { todo!() } diff --git a/crates/sovereign-sdk/module-system/sov-modules-api/src/hooks.rs b/crates/sovereign-sdk/module-system/sov-modules-api/src/hooks.rs index aa872ab312..40397ee2a1 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-api/src/hooks.rs +++ b/crates/sovereign-sdk/module-system/sov-modules-api/src/hooks.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use sov_modules_core::{AccessoryWorkingSet, Context, Spec, Storage, WorkingSet}; use sov_rollup_interface::da::{BlobReaderTrait, DaSpec}; use sov_rollup_interface::soft_confirmation::SignedSoftConfirmationBatch; +use sov_rollup_interface::spec::SpecId; use thiserror::Error; use crate::transaction::Transaction; @@ -123,6 +124,8 @@ pub struct HookSoftConfirmationInfo { pub da_slot_txs_commitment: [u8; 32], /// Previous batch's pre state root pub pre_state_root: Vec, + /// The current spec + pub current_spec: SpecId, /// Public key of signer pub pub_key: Vec, /// Deposit data from the L1 chain @@ -137,12 +140,14 @@ impl HookSoftConfirmationInfo { pub fn new( signed_soft_confirmation: SignedSoftConfirmationBatch, pre_state_root: Vec, + current_spec: SpecId, ) -> Self { HookSoftConfirmationInfo { da_slot_height: signed_soft_confirmation.da_slot_height(), da_slot_hash: signed_soft_confirmation.da_slot_hash(), da_slot_txs_commitment: signed_soft_confirmation.da_slot_txs_commitment(), pre_state_root: pre_state_root.to_vec(), + current_spec, pub_key: signed_soft_confirmation.sequencer_pub_key().to_vec(), deposit_data: signed_soft_confirmation.deposit_data(), l1_fee_rate: signed_soft_confirmation.l1_fee_rate(), diff --git a/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs b/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs index 6abfd8834a..d0bb4b1153 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs +++ b/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs @@ -1,6 +1,7 @@ //! Runtime call message definitions. use borsh::io; +use sov_rollup_interface::spec::SpecId; use crate::common::ModuleError; use crate::module::{CallResponse, Context, Spec}; @@ -22,6 +23,7 @@ pub trait DispatchCall: Send + Sync { &self, message: Self::Decodable, working_set: &mut WorkingSet, + current_spec: SpecId, context: &Self::Context, ) -> Result; diff --git a/crates/sovereign-sdk/module-system/sov-modules-macros/Cargo.toml b/crates/sovereign-sdk/module-system/sov-modules-macros/Cargo.toml index 4f20e4ce02..13c556b3cd 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-macros/Cargo.toml +++ b/crates/sovereign-sdk/module-system/sov-modules-macros/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "sov-modules-macros" -description = "Macros for use with the Sovereign SDK module system" authors = { workspace = true } edition = { workspace = true } homepage = { workspace = true } license = { workspace = true } repository = { workspace = true } +description = "Macros for use with the Sovereign SDK module system" version = { workspace = true } +autotests = false readme = "README.md" resolver = "2" -autotests = false [lib] proc-macro = true @@ -25,8 +25,9 @@ jsonrpsee = { workspace = true, features = ["macros", "http-client", "server"] } serde = { workspace = true } trybuild = "1.0" -sov-modules-api = { path = "../sov-modules-api", features = [ "native" ] } +sov-modules-api = { path = "../sov-modules-api", features = ["native"] } sov-modules-core = { path = "../sov-modules-core" } +sov-rollup-interface = { path = "../../rollup-interface" } sov-state = { path = "../sov-state" } [dependencies] @@ -38,7 +39,6 @@ quote = "1.0" serde_json = { workspace = true } syn = { version = "1.0", features = ["full"] } - [build-dependencies] anyhow = { workspace = true } @@ -48,4 +48,4 @@ native = ["jsonrpsee"] [package.metadata.cargo-udeps.ignore] normal = ["borsh"] -development = ["clap", "sov-modules-core", "sov-modules-api", "sov-state"] +development = ["clap", "sov-modules-core", "sov-modules-api", "sov-state", "sov-rollup-interface"] diff --git a/crates/sovereign-sdk/module-system/sov-modules-macros/src/dispatch/dispatch_call.rs b/crates/sovereign-sdk/module-system/sov-modules-macros/src/dispatch/dispatch_call.rs index 3dc8ac75df..35c8a8042d 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-macros/src/dispatch/dispatch_call.rs +++ b/crates/sovereign-sdk/module-system/sov-modules-macros/src/dispatch/dispatch_call.rs @@ -67,6 +67,7 @@ impl<'a> StructDef<'a> { &self, decodable: Self::Decodable, working_set: &mut ::sov_modules_api::WorkingSet, + current_spec: ::sov_rollup_interface::spec::SpecId, context: &Self::Context, ) -> ::core::result::Result<::sov_modules_api::CallResponse, ::sov_modules_api::Error> { diff --git a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/dispatch/derive_dispatch.rs b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/dispatch/derive_dispatch.rs index 9d6107774c..7a942bbfba 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/dispatch/derive_dispatch.rs +++ b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/dispatch/derive_dispatch.rs @@ -6,6 +6,7 @@ use sov_modules_api::macros::DefaultRuntime; use sov_modules_api::{ Address, Context, DispatchCall, EncodeCall, Genesis, MessageCodec, ModuleInfo, }; +use sov_rollup_interface::spec::SpecId; use sov_state::ZkStorage; #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] @@ -42,7 +43,7 @@ fn main() { assert_eq!(runtime.module_address(&module), runtime.first.address()); let _ = runtime - .dispatch_call(module, working_set, &context) + .dispatch_call(module, working_set, SpecId::Genesis, &context) .unwrap(); } @@ -62,7 +63,7 @@ fn main() { assert_eq!(runtime.module_address(&module), runtime.second.address()); let _ = runtime - .dispatch_call(module, working_set, &context) + .dispatch_call(module, working_set, SpecId::Genesis, &context) .unwrap(); } diff --git a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_type_not_static.rs b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_type_not_static.rs index a9a6adfee1..811c20a9d6 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_type_not_static.rs +++ b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_type_not_static.rs @@ -94,6 +94,7 @@ pub mod my_module { } use my_module::query::{QueryModuleRpcImpl, QueryModuleRpcServer}; +use sov_rollup_interface::spec::SpecId; #[expose_rpc] #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] @@ -126,6 +127,6 @@ fn main() { let context = C::new(sender, sequencer, 1); let _ = runtime - .dispatch_call(module, working_set, &context) + .dispatch_call(module, working_set, SpecId::Genesis, &context) .unwrap(); } diff --git a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_type_not_static.stderr b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_type_not_static.stderr index d19127ac9c..afdea88140 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_type_not_static.stderr +++ b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_type_not_static.stderr @@ -1,7 +1,7 @@ error[E0310]: the parameter type `S` may not live long enough - --> tests/rpc/expose_rpc_associated_type_not_static.rs:98:1 + --> tests/rpc/expose_rpc_associated_type_not_static.rs:99:1 | -98 | #[expose_rpc] +99 | #[expose_rpc] | ^^^^^^^^^^^^^ | | | the parameter type `S` must be valid for the static lifetime... @@ -10,5 +10,5 @@ error[E0310]: the parameter type `S` may not live long enough = note: this error originates in the attribute macro `expose_rpc` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding an explicit lifetime bound | -101| struct Runtime { +102| struct Runtime { | +++++++++ diff --git a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_types.rs b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_types.rs index 67b089c3a3..72242687f4 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_types.rs +++ b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_types.rs @@ -94,6 +94,7 @@ pub mod my_module { } use my_module::query::{QueryModuleRpcImpl, QueryModuleRpcServer}; +use sov_rollup_interface::spec::SpecId; #[expose_rpc] #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] @@ -126,6 +127,6 @@ fn main() { let context = C::new(sender, sequencer, 1); let _ = runtime - .dispatch_call(module, working_set, &context) + .dispatch_call(module, working_set, SpecId::Genesis, &context) .unwrap(); } diff --git a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_types_nested.rs b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_types_nested.rs index cf44a4a251..a07f773386 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_types_nested.rs +++ b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_associated_types_nested.rs @@ -99,6 +99,7 @@ pub mod my_module { } use my_module::query::{QueryModuleRpcImpl, QueryModuleRpcServer}; +use sov_rollup_interface::spec::SpecId; #[expose_rpc] #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] @@ -139,6 +140,6 @@ fn main() { let context = C::new(sender, sequencer, 1); let _ = runtime - .dispatch_call(module, working_set, &context) + .dispatch_call(module, working_set, SpecId::Genesis, &context) .unwrap(); } diff --git a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_first_generic_not_context.rs b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_first_generic_not_context.rs index 93d9b615e9..4cacc47b7e 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_first_generic_not_context.rs +++ b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_first_generic_not_context.rs @@ -92,6 +92,7 @@ pub mod my_module { } use my_module::query::{QueryModuleRpcImpl, QueryModuleRpcServer}; +use sov_rollup_interface::spec::SpecId; #[expose_rpc] #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] @@ -124,6 +125,6 @@ fn main() { let context = C::new(sender, sequencer, 1); let _ = runtime - .dispatch_call(module, working_set, &context) + .dispatch_call(module, working_set, SpecId::Genesis, &context) .unwrap(); } diff --git a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_first_generic_not_context.stderr b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_first_generic_not_context.stderr index cb99bf2ba7..790a9dead9 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_first_generic_not_context.stderr +++ b/crates/sovereign-sdk/module-system/sov-modules-macros/tests/rpc/expose_rpc_first_generic_not_context.stderr @@ -1,128 +1,128 @@ error[E0220]: associated type `Storage` not found for `S` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:96:1 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:1 | -96 | #[expose_rpc] +97 | #[expose_rpc] | ^^^^^^^^^^^^^ associated type `Storage` not found | = note: this error originates in the attribute macro `expose_rpc` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `S: sov_modules_api::Context` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:16 - | -99 | struct Runtime { - | ^ the trait `sov_modules_api::Context` is not implemented for `S` - | + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:16 + | +100 | struct Runtime { + | ^ the trait `sov_modules_api::Context` is not implemented for `S` + | note: required by a bound in `sov_modules_api::Genesis::Context` - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/mod.rs - | - | type Context: Context; - | ^^^^^^^ required by this bound in `Genesis::Context` + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/mod.rs + | + | type Context: Context; + | ^^^^^^^ required by this bound in `Genesis::Context` help: consider further restricting this bound - | -99 | struct Runtime { - | ++++++++++++++++++++++++++ + | +100 | struct Runtime { + | ++++++++++++++++++++++++++ error[E0277]: `::Data` cannot be shared between threads safely - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:8 - | -99 | struct Runtime { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `::Data` cannot be shared between threads safely - | - = help: within `Runtime`, the trait `std::marker::Sync` is not implemented for `::Data`, which is required by `Runtime: std::marker::Sync` + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:8 + | +100 | struct Runtime { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `::Data` cannot be shared between threads safely + | + = help: within `Runtime`, the trait `std::marker::Sync` is not implemented for `::Data`, which is required by `Runtime: std::marker::Sync` note: required because it appears within the type `PhantomData<::Data>` - --> $RUST/core/src/marker.rs - | - | pub struct PhantomData; - | ^^^^^^^^^^^ + --> $RUST/core/src/marker.rs + | + | pub struct PhantomData; + | ^^^^^^^^^^^ note: required because it appears within the type `sov_modules_api::StateValue<::Data>` - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-api/src/containers/value.rs - | - | pub struct StateValue { - | ^^^^^^^^^^ + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-api/src/containers/value.rs + | + | pub struct StateValue { + | ^^^^^^^^^^ note: required because it appears within the type `QueryModule::Data>` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:33:16 - | -33 | pub struct QueryModule { - | ^^^^^^^^^^^ + --> tests/rpc/expose_rpc_first_generic_not_context.rs:33:16 + | +33 | pub struct QueryModule { + | ^^^^^^^^^^^ note: required because it appears within the type `Runtime` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:8 - | -99 | struct Runtime { - | ^^^^^^^ + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:8 + | +100 | struct Runtime { + | ^^^^^^^ note: required by a bound in `sov_modules_api::DispatchCall` - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs - | - | pub trait DispatchCall: Send + Sync { - | ^^^^ required by this bound in `DispatchCall` + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs + | + | pub trait DispatchCall: Send + Sync { + | ^^^^ required by this bound in `DispatchCall` help: consider further restricting the associated type - | -99 | struct Runtime where ::Data: std::marker::Sync { - | ++++++++++++++++++++++++++++++++++++++++++++++ + | +100 | struct Runtime where ::Data: std::marker::Sync { + | ++++++++++++++++++++++++++++++++++++++++++++++ error[E0277]: `::Data` cannot be sent between threads safely - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:8 - | -99 | struct Runtime { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `::Data` cannot be sent between threads safely - | - = help: within `Runtime`, the trait `Send` is not implemented for `::Data`, which is required by `Runtime: Send` + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:8 + | +100 | struct Runtime { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `::Data` cannot be sent between threads safely + | + = help: within `Runtime`, the trait `Send` is not implemented for `::Data`, which is required by `Runtime: Send` note: required because it appears within the type `PhantomData<::Data>` - --> $RUST/core/src/marker.rs - | - | pub struct PhantomData; - | ^^^^^^^^^^^ + --> $RUST/core/src/marker.rs + | + | pub struct PhantomData; + | ^^^^^^^^^^^ note: required because it appears within the type `sov_modules_api::StateValue<::Data>` - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-api/src/containers/value.rs - | - | pub struct StateValue { - | ^^^^^^^^^^ + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-api/src/containers/value.rs + | + | pub struct StateValue { + | ^^^^^^^^^^ note: required because it appears within the type `QueryModule::Data>` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:33:16 - | -33 | pub struct QueryModule { - | ^^^^^^^^^^^ + --> tests/rpc/expose_rpc_first_generic_not_context.rs:33:16 + | +33 | pub struct QueryModule { + | ^^^^^^^^^^^ note: required because it appears within the type `Runtime` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:8 - | -99 | struct Runtime { - | ^^^^^^^ + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:8 + | +100 | struct Runtime { + | ^^^^^^^ note: required by a bound in `sov_modules_api::DispatchCall` - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs - | - | pub trait DispatchCall: Send + Sync { - | ^^^^ required by this bound in `DispatchCall` + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs + | + | pub trait DispatchCall: Send + Sync { + | ^^^^ required by this bound in `DispatchCall` help: consider further restricting the associated type - | -99 | struct Runtime where ::Data: Send { - | +++++++++++++++++++++++++++++++++ + | +100 | struct Runtime where ::Data: Send { + | +++++++++++++++++++++++++++++++++ error[E0277]: the trait bound `S: sov_modules_api::Context` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:16 - | -99 | struct Runtime { - | ^ the trait `sov_modules_api::Context` is not implemented for `S` - | + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:16 + | +100 | struct Runtime { + | ^ the trait `sov_modules_api::Context` is not implemented for `S` + | note: required by a bound in `sov_modules_api::DispatchCall::Context` - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs - | - | type Context: Context; - | ^^^^^^^ required by this bound in `DispatchCall::Context` + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs + | + | type Context: Context; + | ^^^^^^^ required by this bound in `DispatchCall::Context` help: consider further restricting this bound - | -99 | struct Runtime { - | ++++++++++++++++++++++++++ + | +100 | struct Runtime { + | ++++++++++++++++++++++++++ error[E0277]: `::Data` cannot be shared between threads safely - --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:19 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:98:19 | -97 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] +98 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] | ^^^^^^^^^^^^ `::Data` cannot be shared between threads safely | = help: within `RuntimeCall`, the trait `std::marker::Sync` is not implemented for `::Data`, which is required by `RuntimeCall: std::marker::Sync` note: required because it appears within the type `RuntimeCall` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:19 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:98:19 | -97 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] +98 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] | ^^^^^^^^^^^^ note: required by a bound in `sov_modules_api::DispatchCall::Decodable` --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs @@ -132,20 +132,20 @@ note: required by a bound in `sov_modules_api::DispatchCall::Decodable` = note: this error originates in the derive macro `DispatchCall` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting the associated type | -99 | struct Runtime where ::Data: std::marker::Sync { +100| struct Runtime where ::Data: std::marker::Sync { | ++++++++++++++++++++++++++++++++++++++++++++++ error[E0277]: `::Data` cannot be sent between threads safely - --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:19 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:98:19 | -97 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] +98 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] | ^^^^^^^^^^^^ `::Data` cannot be sent between threads safely | = help: within `RuntimeCall`, the trait `Send` is not implemented for `::Data`, which is required by `RuntimeCall: Send` note: required because it appears within the type `RuntimeCall` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:19 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:98:19 | -97 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] +98 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] | ^^^^^^^^^^^^ note: required by a bound in `sov_modules_api::DispatchCall::Decodable` --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/dispatch.rs @@ -155,108 +155,108 @@ note: required by a bound in `sov_modules_api::DispatchCall::Decodable` = note: this error originates in the derive macro `DispatchCall` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting the associated type | -99 | struct Runtime where ::Data: Send { +100| struct Runtime where ::Data: Send { | +++++++++++++++++++++++++++++++++ error[E0277]: the trait bound `S: Spec` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:19 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:98:19 | -97 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] +98 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] | ^^^^^^^^^^^^ the trait `Spec` is not implemented for `S` | = note: this error originates in the derive macro `DispatchCall` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound | -99 | struct Runtime { +100| struct Runtime { | +++++++++++++++++++++++ error[E0277]: the trait bound `S: Spec` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:96:1 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:1 | -96 | #[expose_rpc] +97 | #[expose_rpc] | ^^^^^^^^^^^^^ the trait `Spec` is not implemented for `S` | = note: this error originates in the attribute macro `expose_rpc` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound | -99 | struct Runtime { +100| struct Runtime { | +++++++++++++++++++++++ error[E0053]: method `get_working_set` has an incompatible type for trait - --> tests/rpc/expose_rpc_first_generic_not_context.rs:96:1 - | -96 | #[expose_rpc] - | ^^^^^^^^^^^^^ - | | - | expected type parameter `C`, found type parameter `S` - | help: change the output type to match the trait: `sov_modules_api::WorkingSet` + --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:1 + | +97 | #[expose_rpc] + | ^^^^^^^^^^^^^ + | | + | expected type parameter `C`, found type parameter `S` + | help: change the output type to match the trait: `sov_modules_api::WorkingSet` ... -99 | struct Runtime { - | - - expected type parameter - | | - | found type parameter - | +100 | struct Runtime { + | - - expected type parameter + | | + | found type parameter + | note: type in trait - --> tests/rpc/expose_rpc_first_generic_not_context.rs:86:57 - | -86 | pub fn query_value(&self, working_set: &mut WorkingSet) -> RpcResult { - | ^^^^^^^^^^^^^ - = note: expected signature `fn(&RpcStorage<_, _>) -> sov_modules_api::WorkingSet` - found signature `fn(&RpcStorage<_, _>) -> sov_modules_api::WorkingSet` - = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters - = note: this error originates in the attribute macro `expose_rpc` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/rpc/expose_rpc_first_generic_not_context.rs:86:57 + | +86 | pub fn query_value(&self, working_set: &mut WorkingSet) -> RpcResult { + | ^^^^^^^^^^^^^ + = note: expected signature `fn(&RpcStorage<_, _>) -> sov_modules_api::WorkingSet` + found signature `fn(&RpcStorage<_, _>) -> sov_modules_api::WorkingSet` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + = note: this error originates in the attribute macro `expose_rpc` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `S: sov_modules_api::Context` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:10 - | -97 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] - | ^^^^^^^ the trait `sov_modules_api::Context` is not implemented for `S` - | + --> tests/rpc/expose_rpc_first_generic_not_context.rs:98:10 + | +98 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] + | ^^^^^^^ the trait `sov_modules_api::Context` is not implemented for `S` + | note: required by a bound in `sov_modules_api::WorkingSet` - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/storage/scratchpad.rs - | - | pub struct WorkingSet { - | ^^^^^^^ required by this bound in `WorkingSet` - = note: this error originates in the derive macro `Genesis` (in Nightly builds, run with -Z macro-backtrace for more info) + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/storage/scratchpad.rs + | + | pub struct WorkingSet { + | ^^^^^^^ required by this bound in `WorkingSet` + = note: this error originates in the derive macro `Genesis` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound - | -99 | struct Runtime { - | ++++++++++++++++++++++++++ + | +100 | struct Runtime { + | ++++++++++++++++++++++++++ error[E0277]: the trait bound `S: sov_modules_api::Context` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:19 - | -97 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] - | ^^^^^^^^^^^^ the trait `sov_modules_api::Context` is not implemented for `S` - | + --> tests/rpc/expose_rpc_first_generic_not_context.rs:98:19 + | +98 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] + | ^^^^^^^^^^^^ the trait `sov_modules_api::Context` is not implemented for `S` + | note: required by a bound in `sov_modules_api::WorkingSet` - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/storage/scratchpad.rs - | - | pub struct WorkingSet { - | ^^^^^^^ required by this bound in `WorkingSet` - = note: this error originates in the derive macro `DispatchCall` (in Nightly builds, run with -Z macro-backtrace for more info) + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/storage/scratchpad.rs + | + | pub struct WorkingSet { + | ^^^^^^^ required by this bound in `WorkingSet` + = note: this error originates in the derive macro `DispatchCall` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound - | -99 | struct Runtime { - | ++++++++++++++++++++++++++ + | +100 | struct Runtime { + | ++++++++++++++++++++++++++ error[E0277]: the trait bound `S: sov_modules_api::Context` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:96:1 - | -96 | #[expose_rpc] - | ^^^^^^^^^^^^^ the trait `sov_modules_api::Context` is not implemented for `S` - | + --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:1 + | +97 | #[expose_rpc] + | ^^^^^^^^^^^^^ the trait `sov_modules_api::Context` is not implemented for `S` + | note: required by a bound in `sov_modules_api::WorkingSet` - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/storage/scratchpad.rs - | - | pub struct WorkingSet { - | ^^^^^^^ required by this bound in `WorkingSet` - = note: this error originates in the attribute macro `expose_rpc` (in Nightly builds, run with -Z macro-backtrace for more info) + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/storage/scratchpad.rs + | + | pub struct WorkingSet { + | ^^^^^^^ required by this bound in `WorkingSet` + = note: this error originates in the attribute macro `expose_rpc` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound - | -99 | struct Runtime { - | ++++++++++++++++++++++++++ + | +100 | struct Runtime { + | ++++++++++++++++++++++++++ error[E0599]: no method named `set` found for struct `sov_modules_api::StateValue` in the current scope --> tests/rpc/expose_rpc_first_generic_not_context.rs:55:23 @@ -325,127 +325,127 @@ help: trait `StateValueAccessor` which provides `get` is implemented but not in | error[E0271]: type mismatch resolving `::Data> as ModuleInfo>::Context == S` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:10 - | -97 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] - | ^^^^^^^ expected type parameter `S`, found type parameter `C` -98 | #[serialization(borsh::BorshDeserialize, borsh::BorshSerialize)] -99 | struct Runtime { - | - - found type parameter - | | - | expected type parameter - | - = note: expected type parameter `S` - found type parameter `C` - = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters - = note: required for the cast from `&QueryModule::Data>` to `&dyn sov_modules_api::ModuleInfo` - = note: this error originates in the derive macro `Genesis` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/rpc/expose_rpc_first_generic_not_context.rs:98:10 + | +98 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] + | ^^^^^^^ expected type parameter `S`, found type parameter `C` +99 | #[serialization(borsh::BorshDeserialize, borsh::BorshSerialize)] +100 | struct Runtime { + | - - found type parameter + | | + | expected type parameter + | + = note: expected type parameter `S` + found type parameter `C` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + = note: required for the cast from `&QueryModule::Data>` to `&dyn sov_modules_api::ModuleInfo` + = note: this error originates in the derive macro `Genesis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `S: sov_modules_api::Context` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:10 - | -97 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] - | ^^^^^^^ the trait `sov_modules_api::Context` is not implemented for `S` - | + --> tests/rpc/expose_rpc_first_generic_not_context.rs:98:10 + | +98 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] + | ^^^^^^^ the trait `sov_modules_api::Context` is not implemented for `S` + | note: required by a bound in `sort_values_by_modules_dependencies` - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-api/src/lib.rs - | - | pub fn sort_values_by_modules_dependencies( - | ^^^^^^^ required by this bound in `sort_values_by_modules_dependencies` - = note: this error originates in the derive macro `Genesis` (in Nightly builds, run with -Z macro-backtrace for more info) + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-api/src/lib.rs + | + | pub fn sort_values_by_modules_dependencies( + | ^^^^^^^ required by this bound in `sort_values_by_modules_dependencies` + = note: this error originates in the derive macro `Genesis` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound - | -99 | struct Runtime { - | ++++++++++++++++++++++++++ + | +100 | struct Runtime { + | ++++++++++++++++++++++++++ error[E0308]: mismatched types - --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:10 - | -97 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] - | ^^^^^^^ - | | - | expected `&mut WorkingSet`, found `&mut WorkingSet` - | arguments to this function are incorrect -98 | #[serialization(borsh::BorshDeserialize, borsh::BorshSerialize)] -99 | struct Runtime { - | - - expected type parameter - | | - | found type parameter - | - = note: expected mutable reference `&mut sov_modules_api::WorkingSet` - found mutable reference `&mut sov_modules_api::WorkingSet` - = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + --> tests/rpc/expose_rpc_first_generic_not_context.rs:98:10 + | +98 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] + | ^^^^^^^ + | | + | expected `&mut WorkingSet`, found `&mut WorkingSet` + | arguments to this function are incorrect +99 | #[serialization(borsh::BorshDeserialize, borsh::BorshSerialize)] +100 | struct Runtime { + | - - expected type parameter + | | + | found type parameter + | + = note: expected mutable reference `&mut sov_modules_api::WorkingSet` + found mutable reference `&mut sov_modules_api::WorkingSet` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters note: method defined here - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/mod.rs - | - | fn genesis( - | ^^^^^^^ - = note: this error originates in the derive macro `Genesis` (in Nightly builds, run with -Z macro-backtrace for more info) + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/mod.rs + | + | fn genesis( + | ^^^^^^^ + = note: this error originates in the derive macro `Genesis` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: arguments to this function are incorrect - --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:19 - | -97 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] - | ^^^^^^^^^^^^ - | | - | expected `&C`, found `&S` - | expected `&mut WorkingSet`, found `&mut WorkingSet` -98 | #[serialization(borsh::BorshDeserialize, borsh::BorshSerialize)] -99 | struct Runtime { - | - - - | | | - | | expected type parameter - | | expected type parameter - | found type parameter - | found type parameter - | - = note: expected reference `&C` - found reference `&S` - = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters - = note: expected mutable reference `&mut sov_modules_api::WorkingSet` - found mutable reference `&mut sov_modules_api::WorkingSet` - = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + --> tests/rpc/expose_rpc_first_generic_not_context.rs:98:19 + | +98 | #[derive(Genesis, DispatchCall, MessageCodec, DefaultRuntime)] + | ^^^^^^^^^^^^ + | | + | expected `&C`, found `&S` + | expected `&mut WorkingSet`, found `&mut WorkingSet` +99 | #[serialization(borsh::BorshDeserialize, borsh::BorshSerialize)] +100 | struct Runtime { + | - - + | | | + | | expected type parameter + | | expected type parameter + | found type parameter + | found type parameter + | + = note: expected reference `&C` + found reference `&S` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + = note: expected mutable reference `&mut sov_modules_api::WorkingSet` + found mutable reference `&mut sov_modules_api::WorkingSet` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters note: method defined here - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/mod.rs - | - | fn call( - | ^^^^ - = note: this error originates in the derive macro `DispatchCall` (in Nightly builds, run with -Z macro-backtrace for more info) + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/module/mod.rs + | + | fn call( + | ^^^^ + = note: this error originates in the derive macro `DispatchCall` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `S: sov_modules_api::Context` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:96:1 - | -96 | #[expose_rpc] - | ^^^^^^^^^^^^^ the trait `sov_modules_api::Context` is not implemented for `S` - | + --> tests/rpc/expose_rpc_first_generic_not_context.rs:97:1 + | +97 | #[expose_rpc] + | ^^^^^^^^^^^^^ the trait `sov_modules_api::Context` is not implemented for `S` + | note: required by a bound in `sov_modules_api::WorkingSet::::new` - --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/storage/scratchpad.rs - | - | impl WorkingSet { - | ^^^^^^^ required by this bound in `WorkingSet::::new` + --> $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-core/src/storage/scratchpad.rs + | + | impl WorkingSet { + | ^^^^^^^ required by this bound in `WorkingSet::::new` ... - | pub fn new(inner: ::Storage) -> Self { - | --- required by a bound in this associated function - = note: this error originates in the attribute macro `expose_rpc` (in Nightly builds, run with -Z macro-backtrace for more info) + | pub fn new(inner: ::Storage) -> Self { + | --- required by a bound in this associated function + = note: this error originates in the attribute macro `expose_rpc` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound - | -99 | struct Runtime { - | ++++++++++++++++++++++++++ + | +100 | struct Runtime { + | ++++++++++++++++++++++++++ error[E0599]: the function or associated item `default` exists for struct `Runtime`, but its trait bounds were not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:114:50 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:115:50 | -99 | struct Runtime { +100 | struct Runtime { | --------------------------------------- function or associated item `default` not found for this struct because it doesn't satisfy `_: Default` ... -103 | struct ActualSpec; +104 | struct ActualSpec; | ----------------- doesn't satisfy `ActualSpec: sov_modules_api::Context` ... -114 | let runtime = &mut Runtime::::default(); +115 | let runtime = &mut Runtime::::default(); | ^^^^^^^ function or associated item cannot be called on `Runtime` due to unsatisfied trait bounds | ::: $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-api/src/default_context.rs @@ -466,79 +466,79 @@ note: the trait `sov_modules_api::Context` must be implemented candidate #1: `std::default::Default` error[E0277]: the trait bound `ZkDefaultContext: TestSpec` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:114:24 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:115:24 | -114 | let runtime = &mut Runtime::::default(); +115 | let runtime = &mut Runtime::::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TestSpec` is not implemented for `ZkDefaultContext` | = help: the trait `TestSpec` is implemented for `ActualSpec` note: required by a bound in `Runtime` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:19 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:19 | -99 | struct Runtime { +100 | struct Runtime { | ^^^^^^^^ required by this bound in `Runtime` error[E0277]: the trait bound `ActualSpec: sov_modules_api::Context` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:114:24 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:115:24 | -114 | let runtime = &mut Runtime::::default(); +115 | let runtime = &mut Runtime::::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `sov_modules_api::Context` is not implemented for `ActualSpec` | = help: the following other types implement trait `sov_modules_api::Context`: DefaultContext ZkDefaultContext note: required by a bound in `Runtime` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:32 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:32 | -99 | struct Runtime { +100 | struct Runtime { | ^^^^^^^ required by this bound in `Runtime` error[E0277]: the trait bound `Runtime: EncodeCall>` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:120:10 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:121:10 | -120 | >>::encode_call(message); +121 | >>::encode_call(message); | ^^ the trait `EncodeCall>` is not implemented for `Runtime` | = help: the trait `EncodeCall::Data>>` is implemented for `Runtime` error[E0277]: the trait bound `ZkDefaultContext: TestSpec` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:120:10 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:121:10 | -120 | >>::encode_call(message); +121 | >>::encode_call(message); | ^^ the trait `TestSpec` is not implemented for `ZkDefaultContext` | = help: the trait `TestSpec` is implemented for `ActualSpec` note: required by a bound in `Runtime` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:19 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:19 | -99 | struct Runtime { +100 | struct Runtime { | ^^^^^^^^ required by this bound in `Runtime` error[E0277]: the trait bound `ActualSpec: sov_modules_api::Context` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:120:10 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:121:10 | -120 | >>::encode_call(message); +121 | >>::encode_call(message); | ^^ the trait `sov_modules_api::Context` is not implemented for `ActualSpec` | = help: the following other types implement trait `sov_modules_api::Context`: DefaultContext ZkDefaultContext note: required by a bound in `Runtime` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:32 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:32 | -99 | struct Runtime { +100 | struct Runtime { | ^^^^^^^ required by this bound in `Runtime` error[E0599]: the function or associated item `decode_call` exists for struct `Runtime`, but its trait bounds were not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:121:22 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:122:22 | -99 | struct Runtime { +100 | struct Runtime { | --------------------------------------- function or associated item `decode_call` not found for this struct because it doesn't satisfy `_: DispatchCall` ... -103 | struct ActualSpec; +104 | struct ActualSpec; | ----------------- doesn't satisfy `ActualSpec: sov_modules_api::Context` ... -121 | let module = RT::decode_call(&serialized_message).unwrap(); +122 | let module = RT::decode_call(&serialized_message).unwrap(); | ^^^^^^^^^^^ function or associated item cannot be called on `Runtime` due to unsatisfied trait bounds | ::: $WORKSPACE/crates/sovereign-sdk/module-system/sov-modules-api/src/default_context.rs @@ -559,29 +559,29 @@ note: the trait `sov_modules_api::Context` must be implemented candidate #1: `sov_modules_api::DispatchCall` error[E0277]: the trait bound `ZkDefaultContext: TestSpec` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:121:18 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:122:18 | -121 | let module = RT::decode_call(&serialized_message).unwrap(); +122 | let module = RT::decode_call(&serialized_message).unwrap(); | ^^ the trait `TestSpec` is not implemented for `ZkDefaultContext` | = help: the trait `TestSpec` is implemented for `ActualSpec` note: required by a bound in `Runtime` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:19 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:19 | -99 | struct Runtime { +100 | struct Runtime { | ^^^^^^^^ required by this bound in `Runtime` error[E0277]: the trait bound `ActualSpec: sov_modules_api::Context` is not satisfied - --> tests/rpc/expose_rpc_first_generic_not_context.rs:121:18 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:122:18 | -121 | let module = RT::decode_call(&serialized_message).unwrap(); +122 | let module = RT::decode_call(&serialized_message).unwrap(); | ^^ the trait `sov_modules_api::Context` is not implemented for `ActualSpec` | = help: the following other types implement trait `sov_modules_api::Context`: DefaultContext ZkDefaultContext note: required by a bound in `Runtime` - --> tests/rpc/expose_rpc_first_generic_not_context.rs:99:32 + --> tests/rpc/expose_rpc_first_generic_not_context.rs:100:32 | -99 | struct Runtime { +100 | struct Runtime { | ^^^^^^^ required by this bound in `Runtime` diff --git a/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/Cargo.toml b/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/Cargo.toml index 731a6c2909..8f5be70af2 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/Cargo.toml +++ b/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "sov-modules-stf-blueprint" -description = "Defines a generic state transition function for use with the Sovereign SDK module system" authors = { workspace = true } edition = { workspace = true } homepage = { workspace = true } license = { workspace = true } repository = { workspace = true } +description = "Defines a generic state transition function for use with the Sovereign SDK module system" version = { workspace = true } readme = "README.md" @@ -13,39 +13,44 @@ resolver = "2" [dependencies] anyhow = { workspace = true } -thiserror = { workspace = true } borsh = { workspace = true } -serde = { workspace = true, features = ["derive"] } -tracing = { workspace = true, optional = true } -jmt = { workspace = true } hex = { workspace = true } itertools = { workspace = true } +jmt = { workspace = true } +jsonrpsee = { workspace = true, features = ["server"], optional = true } +rs_merkle = { workspace = true } +serde = { workspace = true, features = ["derive"] } +thiserror = { workspace = true } +tracing = { workspace = true, optional = true } + +# Risc0 deps +risc0-zkvm = { workspace = true, default-features = false, features = ["std"], optional = true } +risc0-zkvm-platform = { workspace = true, optional = true } + +# Sovereign-SDK deps +sov-modules-api = { path = "../sov-modules-api", default-features = false } sov-rollup-interface = { path = "../../rollup-interface" } sov-state = { path = "../sov-state" } -sov-modules-api = { path = "../sov-modules-api", default-features = false } sov-zk-cycle-macros = { path = "../../utils/zk-cycle-macros", optional = true } sov-zk-cycle-utils = { path = "../../utils/zk-cycle-utils", optional = true } -risc0-zkvm = { workspace = true, default-features = false, features = [ - "std", -], optional = true } -risc0-zkvm-platform = { workspace = true, optional = true } -rs_merkle = { workspace = true } -jsonrpsee = { workspace = true, features = ["server"], optional = true } + +# Citrea Deps +citrea-primitives = { path = "../../../primitives" } [features] bench = ["sov-zk-cycle-macros", "risc0-zkvm", "risc0-zkvm-platform"] default = [] native = [ - "sov-state/native", - "sov-modules-api/native", - "dep:tracing", - "jsonrpsee", + "sov-state/native", + "sov-modules-api/native", + "dep:tracing", + "jsonrpsee", ] [package.metadata.cargo-udeps.ignore] normal = [ - "risc0-zkvm", - "risc0-zkvm-platform", - "sov-zk-cycle-macros", - "sov-zk-cycle-utils", + "risc0-zkvm", + "risc0-zkvm-platform", + "sov-zk-cycle-macros", + "sov-zk-cycle-utils", ] diff --git a/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/src/lib.rs b/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/src/lib.rs index a4044990ab..3e16633b71 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/src/lib.rs +++ b/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/src/lib.rs @@ -1,12 +1,8 @@ #![deny(missing_docs)] #![doc = include_str!("../README.md")] -mod batch; -mod stf_blueprint; -mod tx_verifier; - -pub use batch::Batch; use borsh::BorshDeserialize; +use citrea_primitives::fork::{fork_from_block_number, Fork, ForkManager}; use itertools::Itertools; use rs_merkle::algorithms::Sha256; use rs_merkle::MerkleTree; @@ -22,10 +18,17 @@ use sov_modules_api::{ use sov_rollup_interface::da::{DaData, SequencerCommitment}; use sov_rollup_interface::digest::Digest; use sov_rollup_interface::soft_confirmation::SignedSoftConfirmationBatch; +use sov_rollup_interface::spec::SpecId; pub use sov_rollup_interface::stf::{BatchReceipt, TransactionReceipt}; use sov_rollup_interface::stf::{SlotResult, StateTransitionFunction}; use sov_rollup_interface::zk::CumulativeStateDiff; use sov_state::Storage; + +mod batch; +mod stf_blueprint; +mod tx_verifier; + +pub use batch::Batch; pub use stf_blueprint::StfBlueprint; pub use tx_verifier::RawTx; @@ -35,6 +38,8 @@ pub struct RuntimeTxHook { pub height: u64, /// Sequencer public key pub sequencer: C::PublicKey, + /// Current spec + pub current_spec: SpecId, } /// This trait has to be implemented by a runtime in order to be used in `StfBlueprint`. @@ -127,8 +132,10 @@ pub trait StfBlueprintTrait: StateTransitionFunction { /// Begin a soft batch + #[allow(clippy::too_many_arguments)] fn begin_soft_batch( &self, + current_spec: SpecId, sequencer_public_key: &[u8], pre_state_root: &Self::StateRoot, pre_state: Self::PreState, @@ -140,6 +147,7 @@ pub trait StfBlueprintTrait: /// Apply soft batch transactions fn apply_soft_batch_txs( &self, + current_spec: SpecId, txs: Vec>, batch_workspace: WorkingSet, ) -> (WorkingSet, Vec>); @@ -147,6 +155,7 @@ pub trait StfBlueprintTrait: /// End a soft batch fn end_soft_batch( &self, + current_spec: SpecId, sequencer_public_key: &[u8], soft_batch: &mut SignedSoftConfirmationBatch, tx_receipts: Vec>, @@ -156,6 +165,7 @@ pub trait StfBlueprintTrait: /// Finalizes a soft batch fn finalize_soft_batch( &self, + current_spec: SpecId, batch_receipt: BatchReceipt<(), TxEffect>, checkpoint: StateCheckpoint, pre_state: Self::PreState, @@ -178,6 +188,7 @@ where { fn begin_soft_batch( &self, + current_spec: SpecId, sequencer_public_key: &[u8], pre_state_root: &Self::StateRoot, pre_state: ::Storage, @@ -210,19 +221,21 @@ where let checkpoint = StateCheckpoint::with_witness(pre_state, witness); - self.begin_soft_confirmation_inner(checkpoint, soft_batch, pre_state_root) + self.begin_soft_confirmation_inner(checkpoint, soft_batch, pre_state_root, current_spec) } fn apply_soft_batch_txs( &self, + current_spec: SpecId, txs: Vec>, batch_workspace: WorkingSet, ) -> (WorkingSet, Vec>) { - self.apply_sov_txs_inner(txs, batch_workspace) + self.apply_sov_txs_inner(txs, current_spec, batch_workspace) } fn end_soft_batch( &self, + _current_spec: SpecId, sequencer_public_key: &[u8], soft_batch: &mut SignedSoftConfirmationBatch, tx_receipts: Vec>, @@ -266,6 +279,7 @@ where fn finalize_soft_batch( &self, + _current_spec: SpecId, batch_receipt: BatchReceipt<(), TxEffect>, checkpoint: StateCheckpoint, pre_state: Self::PreState, @@ -386,6 +400,7 @@ where fn apply_slot<'a, I>( &self, + _current_spec: SpecId, _pre_state_root: &Self::StateRoot, _pre_state: Self::PreState, _witness: Self::Witness, @@ -407,6 +422,7 @@ where fn apply_soft_batch( &self, + current_spec: SpecId, sequencer_public_key: &[u8], pre_state_root: &Self::StateRoot, pre_state: Self::PreState, @@ -422,6 +438,7 @@ where Self::Witness, > { match self.begin_soft_batch( + current_spec, sequencer_public_key, pre_state_root, pre_state.clone(), @@ -431,16 +448,23 @@ where ) { (Ok(()), batch_workspace) => { let (batch_workspace, tx_receipts) = - self.apply_soft_batch_txs(soft_batch.txs(), batch_workspace); + self.apply_soft_batch_txs(current_spec, soft_batch.txs(), batch_workspace); let (batch_receipt, checkpoint) = self.end_soft_batch( + current_spec, sequencer_public_key, soft_batch, tx_receipts, batch_workspace, ); - self.finalize_soft_batch(batch_receipt, checkpoint, pre_state, soft_batch) + self.finalize_soft_batch( + current_spec, + batch_receipt, + checkpoint, + pre_state, + soft_batch, + ) } (Err(err), batch_workspace) => { native_warn!( @@ -472,6 +496,7 @@ where slot_headers: std::collections::VecDeque::BlockHeader>>, validity_condition: &::ValidityCondition, soft_confirmations: std::collections::VecDeque>, + forks: Vec<(SpecId, u64)>, ) -> (Self::StateRoot, CumulativeStateDiff) { let mut state_diff = CumulativeStateDiff::default(); @@ -638,6 +663,10 @@ where let mut da_block_headers_iter = da_block_headers.into_iter().peekable(); let mut da_block_header = da_block_headers_iter.next().unwrap(); + let mut l2_height = sequencer_commitment.l2_start_block_number; + let mut current_spec = fork_from_block_number(&forks, l2_height); + let mut fork_manager = ForkManager::new(l2_height, current_spec, forks.clone()); + // now that we verified the claimed root, we can apply the soft confirmations // should panic if the number of witnesses and soft confirmations don't match for (mut soft_confirmation, witness) in soft_confirmations.into_iter().zip_eq(witnesses) @@ -647,6 +676,7 @@ where } let result = self.apply_soft_batch( + current_spec, sequencer_public_key, ¤t_state_root, pre_state.clone(), @@ -658,7 +688,18 @@ where current_state_root = result.state_root; state_diff.extend(result.state_diff); + + // Notify fork manager about the block so that the next spec / fork + // is transitioned into if criteria is met. + if let Err(e) = fork_manager.register_block(l2_height) { + panic!("Fork transition failed {}", e); + } + l2_height += 1; + + // Update current spec for the next iteration + current_spec = fork_manager.active_fork(); } + assert_eq!(sequencer_commitment.l2_end_block_number, l2_height - 1); } (current_state_root, state_diff) diff --git a/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/src/stf_blueprint.rs b/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/src/stf_blueprint.rs index 0246ec2d74..7dd1199cd1 100644 --- a/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/src/stf_blueprint.rs +++ b/crates/sovereign-sdk/module-system/sov-modules-stf-blueprint/src/stf_blueprint.rs @@ -5,6 +5,7 @@ use sov_modules_api::{ native_debug, native_error, Context, DaSpec, DispatchCall, StateCheckpoint, WorkingSet, }; use sov_rollup_interface::soft_confirmation::SignedSoftConfirmationBatch; +use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::stf::{BatchReceipt, TransactionReceipt}; use sov_state::Storage; #[cfg(all(target_os = "zkvm", feature = "bench"))] @@ -61,6 +62,7 @@ where pub fn apply_sov_txs_inner( &self, txs: Vec>, + current_spec: SpecId, mut batch_workspace: WorkingSet, ) -> (WorkingSet, Vec>) { let txs = self.verify_txs_stateless_soft(&txs); @@ -85,6 +87,7 @@ where let hook = RuntimeTxHook { height: 1, sequencer: tx.pub_key().clone(), + current_spec, }; let ctx = match self .runtime @@ -109,7 +112,9 @@ where // Commit changes after pre_dispatch_tx_hook batch_workspace = batch_workspace.checkpoint().to_revertable(); - let tx_result = self.runtime.dispatch_call(msg, &mut batch_workspace, &ctx); + let tx_result = + self.runtime + .dispatch_call(msg, &mut batch_workspace, current_spec, &ctx); let events = batch_workspace.take_events(); let tx_effect = match tx_result { @@ -156,6 +161,7 @@ where checkpoint: StateCheckpoint, soft_batch: &mut SignedSoftConfirmationBatch, pre_state_root: &::Root, + current_spec: SpecId, ) -> (Result<(), ApplySoftConfirmationError>, WorkingSet) { native_debug!( "Beginning soft batch 0x{} from sequencer: 0x{}", @@ -170,6 +176,7 @@ where &mut HookSoftConfirmationInfo::new( soft_batch.clone(), pre_state_root.as_ref().to_vec(), + current_spec, ), &mut batch_workspace, ) { @@ -230,12 +237,18 @@ where checkpoint: StateCheckpoint, soft_batch: &mut SignedSoftConfirmationBatch, pre_state_root: &::Root, + current_spec: SpecId, ) -> (ApplySoftConfirmationResult, StateCheckpoint) { - match self.begin_soft_confirmation_inner(checkpoint, soft_batch, pre_state_root) { + match self.begin_soft_confirmation_inner( + checkpoint, + soft_batch, + pre_state_root, + current_spec, + ) { (Ok(()), batch_workspace) => { // TODO: wait for txs here, apply_sov_txs can be called multiple times let (batch_workspace, tx_receipts) = - self.apply_sov_txs_inner(soft_batch.txs(), batch_workspace); + self.apply_sov_txs_inner(soft_batch.txs(), current_spec, batch_workspace); self.end_soft_confirmation_inner(soft_batch, tx_receipts, batch_workspace) } diff --git a/crates/sovereign-sdk/rollup-interface/Cargo.toml b/crates/sovereign-sdk/rollup-interface/Cargo.toml index da5d0963a8..476070f8e1 100644 --- a/crates/sovereign-sdk/rollup-interface/Cargo.toml +++ b/crates/sovereign-sdk/rollup-interface/Cargo.toml @@ -43,6 +43,7 @@ proptest-derive = { workspace = true } default = ["std"] native = ["std", "tokio", "futures"] fuzzing = ["proptest", "proptest-derive", "sha2", "std"] +testing = ["native"] std = [ "anyhow/default", "borsh/default", diff --git a/crates/sovereign-sdk/rollup-interface/Makefile b/crates/sovereign-sdk/rollup-interface/Makefile index bc3018f1aa..cce3522d52 100644 --- a/crates/sovereign-sdk/rollup-interface/Makefile +++ b/crates/sovereign-sdk/rollup-interface/Makefile @@ -6,5 +6,5 @@ help: ## Display this help message check-no-std: ## Checks that project compiles without std # check bare metal cargo hack check --feature-powerset \ - --exclude-features default,fuzzing,std,native \ + --exclude-features default,fuzzing,std,native,testing \ --target thumbv6m-none-eabi diff --git a/crates/sovereign-sdk/rollup-interface/src/lib.rs b/crates/sovereign-sdk/rollup-interface/src/lib.rs index f36ba6bc1e..40c02a474d 100644 --- a/crates/sovereign-sdk/rollup-interface/src/lib.rs +++ b/crates/sovereign-sdk/rollup-interface/src/lib.rs @@ -26,3 +26,6 @@ pub use alloc::sync::Arc as RefCount; pub use node::*; pub use {anyhow, digest}; + +/// Specs module +pub mod spec; diff --git a/crates/sovereign-sdk/rollup-interface/src/node/services/batch_builder.rs b/crates/sovereign-sdk/rollup-interface/src/node/services/batch_builder.rs index 3524dc2077..ead46e34ed 100644 --- a/crates/sovereign-sdk/rollup-interface/src/node/services/batch_builder.rs +++ b/crates/sovereign-sdk/rollup-interface/src/node/services/batch_builder.rs @@ -4,6 +4,8 @@ extern crate alloc; use alloc::vec::Vec; +use crate::spec::SpecId; + /// BlockBuilder trait is responsible for managing mempool and building batches. pub trait BatchBuilder { /// Accept a new transaction. @@ -12,5 +14,5 @@ pub trait BatchBuilder { /// Builds a new batch out of transactions in mempool. /// Logic of which transactions and how many of them is included in batch is up to implementation. - fn get_next_blob(&mut self) -> anyhow::Result>>; + fn get_next_blob(&mut self, current_spec: SpecId) -> anyhow::Result>>; } diff --git a/crates/sovereign-sdk/rollup-interface/src/spec.rs b/crates/sovereign-sdk/rollup-interface/src/spec.rs new file mode 100644 index 0000000000..d48c63ed0a --- /dev/null +++ b/crates/sovereign-sdk/rollup-interface/src/spec.rs @@ -0,0 +1,56 @@ +#![allow(clippy::module_inception)] +use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; +pub use spec::*; + +#[cfg(not(feature = "testing"))] +mod spec { + use super::*; + /// Fork specification + #[derive( + Debug, + Clone, + Copy, + Eq, + PartialEq, + Default, + BorshDeserialize, + BorshSerialize, + Serialize, + Deserialize, + )] + #[borsh(use_discriminant = true)] + pub enum SpecId { + /// Genesis spec + #[default] + Genesis = 0, + } +} + +#[cfg(feature = "testing")] +mod spec { + use super::*; + /// Fork specification + #[derive( + Debug, + Clone, + Copy, + Eq, + PartialEq, + Default, + BorshDeserialize, + BorshSerialize, + Serialize, + Deserialize, + )] + #[borsh(use_discriminant = true)] + pub enum SpecId { + /// Genesis spec + #[default] + Genesis = 0, + /// First fork + Fork1 = 1, + /// Second fork + Fork2 = 2, + } +} 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 8d46784fd2..e468c0d679 100644 --- a/crates/sovereign-sdk/rollup-interface/src/state_machine/stf.rs +++ b/crates/sovereign-sdk/rollup-interface/src/state_machine/stf.rs @@ -17,6 +17,7 @@ use serde::{Deserialize, Serialize}; use crate::da::DaSpec; use crate::soft_confirmation::SignedSoftConfirmationBatch; +use crate::spec::SpecId; use crate::zk::{CumulativeStateDiff, ValidityCondition, Zkvm}; #[cfg(any(all(test, feature = "sha2"), feature = "fuzzing"))] @@ -197,8 +198,10 @@ pub trait StateTransitionFunction { /// /// Commits state changes to the database #[allow(clippy::type_complexity)] + #[allow(clippy::too_many_arguments)] fn apply_slot<'a, I>( &self, + current_spec: SpecId, pre_state_root: &Self::StateRoot, pre_state: Self::PreState, witness: Self::Witness, @@ -230,6 +233,7 @@ pub trait StateTransitionFunction { #[allow(clippy::too_many_arguments)] fn apply_soft_batch( &self, + current_spec: SpecId, sequencer_public_key: &[u8], pre_state_root: &Self::StateRoot, pre_state: Self::PreState, @@ -263,6 +267,7 @@ pub trait StateTransitionFunction { slot_headers: VecDeque>, validity_condition: &Da::ValidityCondition, soft_confirmations: VecDeque>, + forks: Vec<(SpecId, u64)>, ) -> (Self::StateRoot, CumulativeStateDiff); }