From 2ce5a7e75a037a63c7a7d2d0c106f80470f6efbc Mon Sep 17 00:00:00 2001 From: bkolad Date: Wed, 2 Aug 2023 12:07:37 +0200 Subject: [PATCH 1/9] add RollupRunner --- examples/demo-rollup/rollup_config.toml | 2 +- examples/demo-rollup/src/main.rs | 239 ++++++++++++------------ 2 files changed, 124 insertions(+), 117 deletions(-) diff --git a/examples/demo-rollup/rollup_config.toml b/examples/demo-rollup/rollup_config.toml index 64c9df193..5cbf9f649 100644 --- a/examples/demo-rollup/rollup_config.toml +++ b/examples/demo-rollup/rollup_config.toml @@ -4,7 +4,7 @@ start_height = 1 [da] # The JWT used to authenticate with the celestia light client. Instructions for generating this token can be found in the README -celestia_rpc_auth_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJwdWJsaWMiLCJyZWFkIiwid3JpdGUiLCJhZG1pbiJdfQ.YO1sa3cHeTsZx-NR06sIXSRNrLAJvr4oKuvFq3MvaJo" +celestia_rpc_auth_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJwdWJsaWMiLCJyZWFkIiwid3JpdGUiLCJhZG1pbiJdfQ.ZZ2hijMw1uHUcrgtuRhm1WcOPqxMFfu3K8pkC4Qpydc" # The address of the *trusted* Celestia light client to interact with celestia_rpc_address = "http://127.0.0.1:26658" # The largest response the rollup will accept from the Celestia node. Defaults to 100 MB diff --git a/examples/demo-rollup/src/main.rs b/examples/demo-rollup/src/main.rs index 59ce6b77b..b4837d017 100644 --- a/examples/demo-rollup/src/main.rs +++ b/examples/demo-rollup/src/main.rs @@ -23,7 +23,7 @@ use sov_db::ledger_db::{LedgerDB, SlotCommit}; use sov_ethereum::get_ethereum_rpc; use sov_modules_api::RpcRunner; use sov_rollup_interface::crypto::NoOpHasher; -use sov_rollup_interface::da::{BlockHeaderTrait, DaVerifier}; +use sov_rollup_interface::da::{BlockHeaderTrait, DaSpec, DaVerifier}; use sov_rollup_interface::services::da::{DaService, SlotData}; use sov_rollup_interface::services::stf_runner::StateTransitionRunner; use sov_rollup_interface::stf::StateTransitionFunction; @@ -126,9 +126,6 @@ async fn main() -> Result<(), anyhow::Error> { let rollup_config: RollupConfig = from_toml_path(&rollup_config_path).context("Failed to read rollup configuration")?; - let rpc_config = rollup_config.rpc_config; - let address = SocketAddr::new(rpc_config.bind_host.parse()?, rpc_config.bind_port); - // Initializing logging let subscriber = tracing_subscriber::fmt() .with_max_level(Level::INFO) @@ -137,136 +134,146 @@ async fn main() -> Result<(), anyhow::Error> { .map_err(|_err| eprintln!("Unable to set global default subscriber")) .expect("Cannot fail to set subscriber"); - // Initialize the ledger database, which stores blocks, transactions, events, etc. let ledger_db = initialize_ledger(&rollup_config.runner.storage.path); - // Initialize the Celestia service using the DaService interface - let da_service = Arc::new( - CelestiaService::new( - rollup_config.da.clone(), - RollupParams { - namespace: ROLLUP_NAMESPACE, - }, - ) - .await, - ); + let da_service = CelestiaService::new( + rollup_config.da.clone(), + RollupParams { + namespace: ROLLUP_NAMESPACE, + }, + ) + .await; - // Our state transition function implements the StateTransitionRunner interface, - // so we use that to initialize the STF - let mut demo_runner = - NativeAppRunner::::new(rollup_config.runner.clone()); - - // Our state transition also implements the RpcRunner interface, - // so we use that to initialize the RPC server. - let storage = demo_runner.get_storage(); - let is_storage_empty = storage.is_empty(); - let mut methods = get_rpc_methods::(storage); - // register rpc methods - { - register_ledger(ledger_db.clone(), &mut methods)?; - register_sequencer(da_service.clone(), &mut demo_runner, &mut methods)?; - #[cfg(feature = "experimental")] - register_ethereum(rollup_config.da.clone(), &mut methods)?; - } + let mut runner = RollupRunner::::new(rollup_config, da_service, ledger_db)?; + runner.run().await?; - let _handle = tokio::spawn(async move { - start_rpc_server(methods, address).await; - }); - - // For demonstration, we also initialize the DaVerifier interface. - // Running the verifier is only *necessary* during proof generation not normal execution - let da_verifier = Arc::new(CelestiaVerifier::new(RollupParams { - namespace: ROLLUP_NAMESPACE, - })); - - let demo = demo_runner.inner_mut(); - let mut prev_state_root = { - // Check if the rollup has previously been initialized - if is_storage_empty { - info!("No history detected. Initializing chain..."); - demo.init_chain(get_genesis_config()); - info!("Chain initialization is done."); - } else { - debug!("Chain is already initialized. Skipping initialization."); + Ok(()) +} + +struct RollupRunner +where + DA: DaService, +{ + start_height: u64, + da_service: DA, + app: NativeAppRunner::Spec as DaSpec>::BlobTransaction>, + ledger_db: LedgerDB, + state_root: [u8; 32], +} + +impl RollupRunner +where + DA: DaService + Clone + Send + Sync + 'static, +{ + fn new( + rollup_config: RollupConfig, + da_service: DA, + ledger_db: LedgerDB, + ) -> Result { + let mut app = NativeAppRunner::< + Risc0Verifier, + <::Spec as DaSpec>::BlobTransaction, + >::new(rollup_config.runner.clone()); + + let storage = app.get_storage(); + let is_storage_empty = storage.is_empty(); + let mut methods = get_rpc_methods::(storage); + + // register rpc methods + { + register_ledger(ledger_db.clone(), &mut methods)?; + register_sequencer(da_service.clone(), &mut app, &mut methods)?; + #[cfg(feature = "experimental")] + register_ethereum(rollup_config.da.clone(), &mut methods)?; } - let res = demo.apply_slot(Default::default(), []); - // HACK: Tell the rollup that you're running an empty DA layer block so that it will return the latest state root. - // This will be removed shortly. - res.state_root.0 - }; - - // Start the main rollup loop - let item_numbers = ledger_db.get_next_items_numbers(); - let last_slot_processed_before_shutdown = item_numbers.slot_number - 1; - let start_height = rollup_config.start_height + last_slot_processed_before_shutdown; - - for height in start_height.. { - info!( - "Requesting data for height {} and prev_state_root 0x{}", - height, - hex::encode(prev_state_root) - ); + let rpc_config = rollup_config.rpc_config; + let address = SocketAddr::new(rpc_config.bind_host.parse()?, rpc_config.bind_port); + let _handle = tokio::spawn(async move { + start_rpc_server(methods, address).await; + }); + + let app_runner = app.inner_mut(); + let prev_state_root = { + // Check if the rollup has previously been initialized + if is_storage_empty { + info!("No history detected. Initializing chain..."); + app_runner.init_chain(get_genesis_config()); + info!("Chain initialization is done."); + } else { + debug!("Chain is already initialized. Skipping initialization."); + } + + let res = app_runner.apply_slot(Default::default(), []); + // HACK: Tell the rollup that you're running an empty DA layer block so that it will return the latest state root. + // This will be removed shortly. + res.state_root.0 + }; - // Fetch the relevant subset of the next Celestia block - let filtered_block = da_service.get_finalized_at(height).await?; - let header = filtered_block.header(); + // Start the main rollup loop + let item_numbers = ledger_db.get_next_items_numbers(); + let last_slot_processed_before_shutdown = item_numbers.slot_number - 1; + let start_height = rollup_config.start_height + last_slot_processed_before_shutdown; + + Ok(Self { + start_height, + da_service, + app, + ledger_db, + state_root: prev_state_root, + }) + } - // For the demo, we create and verify a proof that the data has been extracted from Celestia correctly. - // In a production implementation, this logic would only run on the prover node - regular full nodes could - // simply download the data from Celestia without extracting and checking a merkle proof here, - let mut blobs = da_service.extract_relevant_txs(&filtered_block); + async fn run(&mut self) -> Result<[u8; 32], anyhow::Error> { + let app_runner = self.app.inner_mut(); - info!( - "Extracted {} relevant blobs at height {}", - blobs.len(), - height - ); + for height in self.start_height.. { + info!( + "Requesting data for height {} and prev_state_root 0x{}", + height, + hex::encode(self.state_root) + ); + + // Fetch the relevant subset of the next Celestia block + let filtered_block = self.da_service.get_finalized_at(height).await?; + + let mut blobs = self.da_service.extract_relevant_txs(&filtered_block); + + info!( + "Extracted {} relevant blobs at height {}", + blobs.len(), + height + ); - let mut data_to_commit = SlotCommit::new(filtered_block.clone()); + let mut data_to_commit = SlotCommit::new(filtered_block.clone()); - let slot_result = demo.apply_slot(Default::default(), &mut blobs); - for receipt in slot_result.batch_receipts { - data_to_commit.add_batch(receipt); + let slot_result = app_runner.apply_slot(Default::default(), &mut blobs); + for receipt in slot_result.batch_receipts { + data_to_commit.add_batch(receipt); + } + let next_state_root = slot_result.state_root; + + self.ledger_db.commit_slot(data_to_commit)?; + self.state_root = next_state_root.0; } - let next_state_root = slot_result.state_root; - - let (inclusion_proof, completeness_proof) = da_service - .get_extraction_proof(&filtered_block, &blobs) - .await; - - let validity_condition = da_verifier - .verify_relevant_tx_list::( - header, - &blobs, - inclusion_proof, - completeness_proof, - ) - .expect("Failed to verify relevant tx list but prover is honest"); - - // For demonstration purposes, we also show how you would check the extra validity condition - // imposed by celestia (that the Celestia block processed be the next one from the canonical chain). - // In a real rollup, this check would only be made by light clients. - let mut checker = CelestiaChainChecker { - current_block_hash: *header.hash().inner(), - }; - checker.check(&validity_condition)?; - // Store the resulting receipts in the ledger database - ledger_db.commit_slot(data_to_commit)?; - prev_state_root = next_state_root.0; + Ok(self.state_root) } - - Ok(()) } -fn register_sequencer( - da_service: Arc, - demo_runner: &mut NativeAppRunner, +fn register_sequencer( + da_service: DA, + demo_runner: &mut NativeAppRunner< + Risc0Verifier, + <::Spec as DaSpec>::BlobTransaction, + >, methods: &mut jsonrpsee::RpcModule<()>, -) -> Result<(), anyhow::Error> { +) -> Result<(), anyhow::Error> +where + DA: DaService + Send + Sync + 'static, +{ let batch_builder = demo_runner.take_batch_builder().unwrap(); - let sequencer_rpc = get_sequencer_rpc(batch_builder, da_service); + let sequencer_rpc = get_sequencer_rpc(batch_builder, Arc::new(da_service)); methods .merge(sequencer_rpc) .context("Failed to merge Txs RPC modules") From 9f3aaf6a1ba89ec3cfc0e57132ebaaadd3d8eda6 Mon Sep 17 00:00:00 2001 From: bkolad Date: Fri, 4 Aug 2023 10:06:10 +0200 Subject: [PATCH 2/9] Add sov-stf-runner crate --- Cargo.lock | 35 ++- Cargo.toml | 1 + examples/demo-prover/Cargo.lock | 239 ++++++++++++++++-- examples/demo-prover/host/Cargo.toml | 1 + examples/demo-prover/host/src/main.rs | 19 +- examples/demo-prover/methods/guest/Cargo.lock | 107 ++++---- .../methods/guest/src/bin/rollup.rs | 12 +- examples/demo-rollup/Cargo.toml | 2 + examples/demo-rollup/README.md | 7 +- examples/demo-rollup/benches/rollup_bench.rs | 12 +- .../benches/rollup_coarse_measure.rs | 12 +- examples/demo-rollup/rollup_config.toml | 2 +- examples/demo-rollup/src/lib.rs | 1 - examples/demo-rollup/src/main.rs | 199 +++------------ examples/demo-rollup/src/test_rpc.rs | 8 +- examples/demo-stf/Cargo.toml | 2 + examples/demo-stf/README.md | 6 +- examples/demo-stf/src/app.rs | 110 ++------ examples/demo-stf/src/lib.rs | 4 +- examples/demo-stf/src/runtime.rs | 2 + examples/demo-stf/src/sov-cli/native.rs | 19 +- examples/demo-stf/src/tests/mod.rs | 8 +- full-node/sov-stf-runner/Cargo.toml | 41 +++ full-node/sov-stf-runner/README.md | 7 + .../sov-stf-runner}/src/batch_builder.rs | 1 + .../sov-stf-runner}/src/config.rs | 13 +- full-node/sov-stf-runner/src/ledger_rpc.rs | 94 +++++++ full-node/sov-stf-runner/src/lib.rs | 141 +++++++++++ .../sov-stf-runner}/src/runner_config.rs | 4 +- module-system/RPC_WALKTHROUGH.md | 36 +-- .../sov-evm/src/tests/tx_tests.rs | 2 +- module-system/sov-modules-api/src/lib.rs | 7 - .../src/app_template.rs | 10 +- .../sov-modules-stf-template/src/lib.rs | 14 +- rollup-interface/src/node/services/mod.rs | 1 - .../src/node/services/stf_runner.rs | 56 ---- 36 files changed, 730 insertions(+), 505 deletions(-) create mode 100644 full-node/sov-stf-runner/Cargo.toml create mode 100644 full-node/sov-stf-runner/README.md rename {examples/demo-stf => full-node/sov-stf-runner}/src/batch_builder.rs (99%) rename {examples/demo-rollup => full-node/sov-stf-runner}/src/config.rs (86%) create mode 100644 full-node/sov-stf-runner/src/ledger_rpc.rs create mode 100644 full-node/sov-stf-runner/src/lib.rs rename {examples/demo-stf => full-node/sov-stf-runner}/src/runner_config.rs (95%) delete mode 100644 rollup-interface/src/node/services/stf_runner.rs diff --git a/Cargo.lock b/Cargo.lock index 8c4d51b2c..366cdf460 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1342,6 +1342,7 @@ dependencies = [ "sov-sequencer", "sov-sequencer-registry", "sov-state", + "sov-stf-runner", "sov-value-setter", "tempfile", "tokio", @@ -6273,6 +6274,7 @@ dependencies = [ "demo-stf", "futures", "hex", + "jmt", "jsonrpsee 0.18.2", "jupiter", "prettytable-rs", @@ -6292,6 +6294,7 @@ dependencies = [ "sov-rollup-interface", "sov-sequencer", "sov-state", + "sov-stf-runner", "sov-value-setter", "tempfile", "tendermint", @@ -6477,8 +6480,8 @@ dependencies = [ "async-trait", "borsh", "bytes", + "digest 0.10.7", "hex", - "jmt", "proptest", "proptest-derive", "serde", @@ -6551,6 +6554,36 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sov-stf-runner" +version = "0.1.0" +dependencies = [ + "anyhow", + "borsh", + "futures", + "hex", + "jsonrpsee 0.18.2", + "jupiter", + "rand 0.8.5", + "serde", + "serde_json", + "sov-accounts", + "sov-bank", + "sov-db", + "sov-election", + "sov-modules-api", + "sov-modules-stf-template", + "sov-rollup-interface", + "sov-sequencer-registry", + "sov-state", + "sov-value-setter", + "tempfile", + "tokio", + "toml 0.7.6", + "tracing", + "tracing-subscriber", +] + [[package]] name = "sov-value-setter" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 31f2ce9a4..4a1942f0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "full-node/db/sov-db", "full-node/sov-sequencer", "full-node/sov-ethereum", + "full-node/sov-stf-runner", "module-system/sov-modules-stf-template", "module-system/sov-modules-macros", diff --git a/examples/demo-prover/Cargo.lock b/examples/demo-prover/Cargo.lock index 78bd76205..1e3db0d2d 100644 --- a/examples/demo-prover/Cargo.lock +++ b/examples/demo-prover/Cargo.lock @@ -673,7 +673,7 @@ dependencies = [ "clap", "const-rollup-config", "hex", - "jsonrpsee", + "jsonrpsee 0.18.2", "serde", "serde_json", "sov-accounts", @@ -685,6 +685,7 @@ dependencies = [ "sov-sequencer", "sov-sequencer-registry", "sov-state", + "sov-stf-runner", "sov-value-setter", "tokio", "toml 0.7.6", @@ -1301,13 +1302,29 @@ dependencies = [ "http", "hyper", "log", - "rustls", + "rustls 0.20.8", "rustls-native-certs", "tokio", - "tokio-rustls", + "tokio-rustls 0.23.4", "webpki-roots", ] +[[package]] +name = "hyper-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +dependencies = [ + "futures-util", + "http", + "hyper", + "log", + "rustls 0.21.5", + "rustls-native-certs", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -1486,11 +1503,23 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" dependencies = [ - "jsonrpsee-core", - "jsonrpsee-http-client", + "jsonrpsee-core 0.16.2", + "jsonrpsee-http-client 0.16.2", + "jsonrpsee-server 0.16.2", + "jsonrpsee-types 0.16.2", +] + +[[package]] +name = "jsonrpsee" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1822d18e4384a5e79d94dc9e4d1239cfa9fad24e55b44d2efeff5b394c9fece4" +dependencies = [ + "jsonrpsee-core 0.18.2", + "jsonrpsee-http-client 0.18.2", "jsonrpsee-proc-macros", - "jsonrpsee-server", - "jsonrpsee-types", + "jsonrpsee-server 0.18.2", + "jsonrpsee-types 0.18.2", "tracing", ] @@ -1508,7 +1537,31 @@ dependencies = [ "futures-util", "globset", "hyper", - "jsonrpsee-types", + "jsonrpsee-types 0.16.2", + "parking_lot", + "rand 0.8.5", + "rustc-hash", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c6832a55f662b5a6ecc844db24b8b9c387453f923de863062c60ce33d62b81" +dependencies = [ + "anyhow", + "async-trait", + "beef", + "futures-util", + "globset", + "hyper", + "jsonrpsee-types 0.18.2", "parking_lot", "rand 0.8.5", "rustc-hash", @@ -1528,9 +1581,9 @@ checksum = "cc345b0a43c6bc49b947ebeb936e886a419ee3d894421790c969cc56040542ad" dependencies = [ "async-trait", "hyper", - "hyper-rustls", - "jsonrpsee-core", - "jsonrpsee-types", + "hyper-rustls 0.23.2", + "jsonrpsee-core 0.16.2", + "jsonrpsee-types 0.16.2", "rustc-hash", "serde", "serde_json", @@ -1539,11 +1592,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-http-client" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1705c65069729e3dccff6fd91ee431d5d31cabcf00ce68a62a2c6435ac713af9" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls 0.24.1", + "jsonrpsee-core 0.18.2", + "jsonrpsee-types 0.18.2", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", +] + [[package]] name = "jsonrpsee-proc-macros" -version = "0.16.2" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baa6da1e4199c10d7b1d0a6e5e8bd8e55f351163b6f4b3cbb044672a69bd4c1c" +checksum = "c6027ac0b197ce9543097d02a290f550ce1d9432bf301524b013053c0b75cc94" dependencies = [ "heck", "proc-macro-crate 1.3.1", @@ -1562,8 +1634,28 @@ dependencies = [ "futures-util", "http", "hyper", - "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-core 0.16.2", + "jsonrpsee-types 0.16.2", + "serde", + "serde_json", + "soketto", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tracing", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f06661d1a6b6e5b85469dc9c29acfbb9b3bb613797a6fd10a3ebb8a70754057" +dependencies = [ + "futures-util", + "hyper", + "jsonrpsee-core 0.18.2", + "jsonrpsee-types 0.18.2", "serde", "serde_json", "soketto", @@ -1588,6 +1680,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-types" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5bf6c75ce2a4217421154adfc65a24d2b46e77286e59bba5d9fa6544ccc8f4" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + [[package]] name = "jupiter" version = "0.1.0" @@ -1599,7 +1705,7 @@ dependencies = [ "borsh", "hex", "hex-literal", - "jsonrpsee", + "jsonrpsee 0.16.2", "nmt-rs", "prost", "prost-build", @@ -2117,6 +2223,26 @@ dependencies = [ "indexmap 1.9.3", ] +[[package]] +name = "pin-project" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.26", +] + [[package]] name = "pin-project-lite" version = "0.2.10" @@ -2747,6 +2873,18 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustls" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -2768,6 +2906,16 @@ dependencies = [ "base64 0.21.2", ] +[[package]] +name = "rustls-webpki" +version = "0.101.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.15" @@ -3080,7 +3228,7 @@ dependencies = [ "anyhow", "borsh", "clap", - "jsonrpsee", + "jsonrpsee 0.18.2", "schemars", "serde", "serde_json", @@ -3097,7 +3245,7 @@ dependencies = [ "borsh", "clap", "hex", - "jsonrpsee", + "jsonrpsee 0.18.2", "schemars", "serde", "serde_json", @@ -3131,7 +3279,7 @@ dependencies = [ "const-rollup-config", "demo-stf", "hex", - "jsonrpsee", + "jsonrpsee 0.16.2", "jupiter", "methods", "risc0-adapter", @@ -3142,6 +3290,7 @@ dependencies = [ "sov-modules-api", "sov-rollup-interface", "sov-state", + "sov-stf-runner", "tokio", "tracing", "tracing-subscriber", @@ -3155,7 +3304,7 @@ dependencies = [ "borsh", "clap", "hex", - "jsonrpsee", + "jsonrpsee 0.18.2", "schemars", "serde", "serde_json", @@ -3182,6 +3331,7 @@ dependencies = [ "derive_more", "ed25519-dalek", "hex", + "jsonrpsee 0.18.2", "rand 0.7.3", "schemars", "serde", @@ -3199,7 +3349,7 @@ version = "0.1.0" dependencies = [ "anyhow", "borsh", - "jsonrpsee", + "jsonrpsee 0.18.2", "proc-macro2", "quote", "schemars", @@ -3229,8 +3379,8 @@ dependencies = [ "async-trait", "borsh", "bytes", + "digest 0.10.7", "hex", - "jmt", "serde", "sha2 0.10.7", ] @@ -3254,8 +3404,9 @@ dependencies = [ "anyhow", "borsh", "hex", - "jsonrpsee", + "jsonrpsee 0.18.2", "serde", + "sov-modules-api", "sov-rollup-interface", "tracing", ] @@ -3267,7 +3418,7 @@ dependencies = [ "anyhow", "borsh", "clap", - "jsonrpsee", + "jsonrpsee 0.18.2", "schemars", "serde", "serde_json", @@ -3293,6 +3444,28 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sov-stf-runner" +version = "0.1.0" +dependencies = [ + "anyhow", + "borsh", + "futures", + "hex", + "jsonrpsee 0.18.2", + "jupiter", + "serde", + "serde_json", + "sov-db", + "sov-modules-api", + "sov-rollup-interface", + "sov-state", + "tokio", + "toml 0.7.6", + "tracing", + "tracing-subscriber", +] + [[package]] name = "sov-value-setter" version = "0.1.0" @@ -3300,7 +3473,7 @@ dependencies = [ "anyhow", "borsh", "clap", - "jsonrpsee", + "jsonrpsee 0.18.2", "schemars", "serde", "serde_json", @@ -3560,11 +3733,21 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls", + "rustls 0.20.8", "tokio", "webpki", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.5", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -3640,6 +3823,10 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", "tower-layer", "tower-service", "tracing", diff --git a/examples/demo-prover/host/Cargo.toml b/examples/demo-prover/host/Cargo.toml index 07ac196f7..756610af4 100644 --- a/examples/demo-prover/host/Cargo.toml +++ b/examples/demo-prover/host/Cargo.toml @@ -25,5 +25,6 @@ risc0-adapter = { path = "../../../adapters/risc0" } const-rollup-config = { path = "../../const-rollup-config" } sov-modules-api = { path = "../../../module-system/sov-modules-api", features = ["native"] } sov-state = { path = "../../../module-system/sov-state", features = ["native"] } +sov-stf-runner = { path = "../../../full-node/sov-stf-runner" } methods = { path = "../methods" } diff --git a/examples/demo-prover/host/src/main.rs b/examples/demo-prover/host/src/main.rs index 670b2e7e1..6840bc4d6 100644 --- a/examples/demo-prover/host/src/main.rs +++ b/examples/demo-prover/host/src/main.rs @@ -2,22 +2,20 @@ use std::env; use anyhow::Context; use const_rollup_config::{ROLLUP_NAMESPACE_RAW, SEQUENCER_DA_ADDRESS}; -use demo_stf::app::{DefaultPrivateKey, NativeAppRunner}; +use demo_stf::app::{App, DefaultPrivateKey}; use demo_stf::genesis_config::create_demo_genesis_config; -use demo_stf::runner_config::{from_toml_path, Config as RunnerConfig}; use jupiter::da_service::{CelestiaService, DaServiceConfig}; use jupiter::types::NamespaceId; use jupiter::verifier::RollupParams; -use jupiter::BlobWithSender; use methods::{ROLLUP_ELF, ROLLUP_ID}; -use risc0_adapter::host::Risc0Host; +use risc0_adapter::host::{Risc0Host, Risc0Verifier}; use serde::Deserialize; -use sov_modules_api::{PrivateKey, RpcRunner}; +use sov_modules_api::PrivateKey; use sov_rollup_interface::services::da::DaService; -use sov_rollup_interface::services::stf_runner::StateTransitionRunner; use sov_rollup_interface::stf::StateTransitionFunction; use sov_rollup_interface::zk::ZkvmHost; use sov_state::Storage; +use sov_stf_runner::{from_toml_path, Config as RunnerConfig}; use tracing::{info, Level}; #[derive(Debug, Clone, PartialEq, Deserialize)] @@ -56,10 +54,11 @@ async fn main() -> Result<(), anyhow::Error> { let sequencer_private_key = DefaultPrivateKey::generate(); - let mut demo_runner = - NativeAppRunner::::new(rollup_config.runner.clone()); - let is_storage_empty = demo_runner.get_storage().is_empty(); - let demo = demo_runner.inner_mut(); + let app: App = + App::new(rollup_config.runner.storage.clone()); + + let is_storage_empty = app.get_storage().is_empty(); + let mut demo = app.stf; if is_storage_empty { let genesis_config = create_demo_genesis_config( diff --git a/examples/demo-prover/methods/guest/Cargo.lock b/examples/demo-prover/methods/guest/Cargo.lock index 740870b96..bba15d2f1 100644 --- a/examples/demo-prover/methods/guest/Cargo.lock +++ b/examples/demo-prover/methods/guest/Cargo.lock @@ -54,12 +54,6 @@ version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - [[package]] name = "async-trait" version = "0.1.71" @@ -288,8 +282,7 @@ dependencies = [ [[package]] name = "cc" version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +source = "git+https://github.com/rust-lang/cc-rs?rev=e5bbdfa#e5bbdfa1fa468c028cb38fee6c35a3cf2e5a2736" dependencies = [ "jobserver", ] @@ -958,10 +951,11 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.2" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ + "futures-util", "http", "hyper", "log", @@ -969,7 +963,6 @@ dependencies = [ "rustls-native-certs", "tokio", "tokio-rustls", - "webpki-roots", ] [[package]] @@ -1125,9 +1118,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.16.2" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" +checksum = "1822d18e4384a5e79d94dc9e4d1239cfa9fad24e55b44d2efeff5b394c9fece4" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -1137,15 +1130,13 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.16.2" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e70b4439a751a5de7dd5ed55eacff78ebf4ffe0fc009cb1ebb11417f5b536b" +checksum = "64c6832a55f662b5a6ecc844db24b8b9c387453f923de863062c60ce33d62b81" dependencies = [ "anyhow", - "arrayvec", "async-trait", "beef", - "futures-channel", "futures-util", "globset", "hyper", @@ -1163,32 +1154,30 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.16.2" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc345b0a43c6bc49b947ebeb936e886a419ee3d894421790c969cc56040542ad" +checksum = "1705c65069729e3dccff6fd91ee431d5d31cabcf00ce68a62a2c6435ac713af9" dependencies = [ "async-trait", "hyper", "hyper-rustls", "jsonrpsee-core", "jsonrpsee-types", - "rustc-hash", "serde", "serde_json", "thiserror", "tokio", + "tower", "tracing", ] [[package]] name = "jsonrpsee-server" -version = "0.16.2" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb69dad85df79527c019659a992498d03f8495390496da2f07e6c24c2b356fc" +checksum = "4f06661d1a6b6e5b85469dc9c29acfbb9b3bb613797a6fd10a3ebb8a70754057" dependencies = [ - "futures-channel", "futures-util", - "http", "hyper", "jsonrpsee-core", "jsonrpsee-types", @@ -1204,9 +1193,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.16.2" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd522fe1ce3702fd94812965d7bb7a3364b1c9aba743944c5a00529aae80f8c" +checksum = "6e5bf6c75ce2a4217421154adfc65a24d2b46e77286e59bba5d9fa6544ccc8f4" dependencies = [ "anyhow", "beef", @@ -1553,6 +1542,26 @@ dependencies = [ "indexmap", ] +[[package]] +name = "pin-project" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.26", +] + [[package]] name = "pin-project-lite" version = "0.2.10" @@ -1989,14 +1998,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" dependencies = [ "log", "ring", + "rustls-webpki", "sct", - "webpki", ] [[package]] @@ -2020,6 +2029,16 @@ dependencies = [ "base64 0.21.2", ] +[[package]] +name = "rustls-webpki" +version = "0.101.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.15" @@ -2409,8 +2428,8 @@ dependencies = [ "async-trait", "borsh", "bytes", + "digest 0.10.7", "hex", - "jmt", "serde", ] @@ -2675,13 +2694,12 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.23.4" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", - "webpki", ] [[package]] @@ -2725,6 +2743,10 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", "tower-layer", "tower-service", "tracing", @@ -2952,25 +2974,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.22.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] - [[package]] name = "which" version = "4.4.0" diff --git a/examples/demo-prover/methods/guest/src/bin/rollup.rs b/examples/demo-prover/methods/guest/src/bin/rollup.rs index 0a6ed67b8..491c43e68 100644 --- a/examples/demo-prover/methods/guest/src/bin/rollup.rs +++ b/examples/demo-prover/methods/guest/src/bin/rollup.rs @@ -3,7 +3,7 @@ #![no_main] use const_rollup_config::ROLLUP_NAMESPACE_RAW; -use demo_stf::app::ZkAppRunner; +use demo_stf::app::create_zk_app_template; use demo_stf::ArrayWitness; use jupiter::types::NamespaceId; use jupiter::verifier::{CelestiaSpec, CelestiaVerifier}; @@ -12,7 +12,6 @@ use risc0_adapter::guest::Risc0Guest; use risc0_zkvm::guest::env; use sov_rollup_interface::crypto::NoOpHasher; use sov_rollup_interface::da::{DaSpec, DaVerifier}; -use sov_rollup_interface::services::stf_runner::StateTransitionRunner; use sov_rollup_interface::stf::{StateTransitionFunction, ZkConfig}; use sov_rollup_interface::zk::{StateTransition, ZkvmGuest}; @@ -45,18 +44,13 @@ pub fn main() { env::write(&"blobs have been read\n"); // Step 2: Apply blobs - let mut demo_runner = as StateTransitionRunner< - ZkConfig, - Risc0Guest, - BlobWithSender, - >>::new(prev_state_root_hash); - let demo = demo_runner.inner_mut(); + let mut app = create_zk_app_template::(prev_state_root_hash); let witness: ArrayWitness = guest.read_from_host(); env::write(&"Witness have been read\n"); env::write(&"Applying slot...\n"); - let result = demo.apply_slot(witness, &mut blobs); + let result = app.apply_slot(witness, &mut blobs); env::write(&"Slot has been applied\n"); diff --git a/examples/demo-rollup/Cargo.toml b/examples/demo-rollup/Cargo.toml index 53688968d..bc6b7211b 100644 --- a/examples/demo-rollup/Cargo.toml +++ b/examples/demo-rollup/Cargo.toml @@ -20,6 +20,7 @@ serde_json = { workspace = true } tracing = { workspace = true } hex = { workspace = true } bytes = { workspace = true } +jmt = { workspace = true } futures = "0.3" # Crates which only this package depends on @@ -32,6 +33,7 @@ sov-rollup-interface = { path = "../../rollup-interface" } sov-db = { path = "../../full-node/db/sov-db" } sov-ethereum = { path = "../../full-node/sov-ethereum", optional = true } sov-sequencer = { path = "../../full-node/sov-sequencer" } +sov-stf-runner = { path = "../../full-node/sov-stf-runner" } risc0-adapter = { path = "../../adapters/risc0" } sov-modules-stf-template = { path = "../../module-system/sov-modules-stf-template" } diff --git a/examples/demo-rollup/README.md b/examples/demo-rollup/README.md index db0b8fcb3..71f7f219a 100644 --- a/examples/demo-rollup/README.md +++ b/examples/demo-rollup/README.md @@ -376,12 +376,11 @@ automatically picked up by the node implementation. For this tutorial, the Makef ### 2. Initialize the State Transition Function -The next step is to initialize your state transition function. If it implements the [StateTransitionRunner](../../rollup-interface/src/state_machine/stf.rs) -interface, you can use that for easy initialization. +The next step is to initialize your state transition function. ```rust -let mut stf_runner = NativeAppRunner::::new(rollup_config); -let mut stf = stf_runner.inner_mut(); + let mut app: App = + App::new(config); ``` If your StateTransitionRunner provides an RPC interface, you should initialize that too. If it implements RpcRunner, you diff --git a/examples/demo-rollup/benches/rollup_bench.rs b/examples/demo-rollup/benches/rollup_bench.rs index 7f59c3b0d..ab54b659f 100644 --- a/examples/demo-rollup/benches/rollup_bench.rs +++ b/examples/demo-rollup/benches/rollup_bench.rs @@ -6,20 +6,18 @@ use std::time::Duration; use anyhow::Context; use const_rollup_config::SEQUENCER_DA_ADDRESS; use criterion::{criterion_group, criterion_main, Criterion}; -use demo_stf::app::NativeAppRunner; +use demo_stf::app::App; use demo_stf::genesis_config::create_demo_genesis_config; -use demo_stf::runner_config::from_toml_path; use jupiter::verifier::address::CelestiaAddress; use risc0_adapter::host::Risc0Verifier; use sov_db::ledger_db::{LedgerDB, SlotCommit}; -use sov_demo_rollup::config::RollupConfig; use sov_demo_rollup::rng_xfers::RngDaService; use sov_modules_api::default_signature::private_key::DefaultPrivateKey; use sov_modules_api::PrivateKey; use sov_rollup_interface::mocks::{TestBlob, TestBlock, TestBlockHeader, TestHash}; use sov_rollup_interface::services::da::DaService; -use sov_rollup_interface::services::stf_runner::StateTransitionRunner; use sov_rollup_interface::stf::StateTransitionFunction; +use sov_stf_runner::{from_toml_path, RollupConfig}; use tempfile::TempDir; fn rollup_bench(_bench: &mut Criterion) { @@ -44,10 +42,10 @@ fn rollup_bench(_bench: &mut Criterion) { let da_service = Arc::new(RngDaService::new()); - let mut demo_runner = - NativeAppRunner::>::new(rollup_config.runner); + let demo_runner = + App::>::new(rollup_config.runner.storage); - let demo = demo_runner.inner_mut(); + let mut demo = demo_runner.stf; let sequencer_private_key = DefaultPrivateKey::generate(); let demo_genesis_config = create_demo_genesis_config( 100000000, diff --git a/examples/demo-rollup/benches/rollup_coarse_measure.rs b/examples/demo-rollup/benches/rollup_coarse_measure.rs index ff67299de..63a79c618 100644 --- a/examples/demo-rollup/benches/rollup_coarse_measure.rs +++ b/examples/demo-rollup/benches/rollup_coarse_measure.rs @@ -5,21 +5,19 @@ use std::time::{Duration, Instant}; use anyhow::Context; use const_rollup_config::SEQUENCER_DA_ADDRESS; -use demo_stf::app::NativeAppRunner; +use demo_stf::app::App; use demo_stf::genesis_config::create_demo_genesis_config; -use demo_stf::runner_config::from_toml_path; use jupiter::verifier::address::CelestiaAddress; use prometheus::{Histogram, HistogramOpts, Registry}; use risc0_adapter::host::Risc0Verifier; use sov_db::ledger_db::{LedgerDB, SlotCommit}; -use sov_demo_rollup::config::RollupConfig; use sov_demo_rollup::rng_xfers::RngDaService; use sov_modules_api::default_signature::private_key::DefaultPrivateKey; use sov_modules_api::PrivateKey; use sov_rollup_interface::mocks::{TestBlob, TestBlock, TestBlockHeader, TestHash}; use sov_rollup_interface::services::da::DaService; -use sov_rollup_interface::services::stf_runner::StateTransitionRunner; use sov_rollup_interface::stf::StateTransitionFunction; +use sov_stf_runner::{from_toml_path, RollupConfig}; use tempfile::TempDir; #[macro_use] @@ -92,10 +90,10 @@ async fn main() -> Result<(), anyhow::Error> { let da_service = Arc::new(RngDaService::new()); - let mut demo_runner = - NativeAppRunner::>::new(rollup_config.runner); + let demo_runner = + App::>::new(rollup_config.runner.storage); - let demo = demo_runner.inner_mut(); + let mut demo = demo_runner.stf; let sequencer_private_key = DefaultPrivateKey::generate(); let demo_genesis_config = create_demo_genesis_config( 100000000, diff --git a/examples/demo-rollup/rollup_config.toml b/examples/demo-rollup/rollup_config.toml index 5cbf9f649..aa75b9539 100644 --- a/examples/demo-rollup/rollup_config.toml +++ b/examples/demo-rollup/rollup_config.toml @@ -4,7 +4,7 @@ start_height = 1 [da] # The JWT used to authenticate with the celestia light client. Instructions for generating this token can be found in the README -celestia_rpc_auth_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJwdWJsaWMiLCJyZWFkIiwid3JpdGUiLCJhZG1pbiJdfQ.ZZ2hijMw1uHUcrgtuRhm1WcOPqxMFfu3K8pkC4Qpydc" +celestia_rpc_auth_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJwdWJsaWMiLCJyZWFkIiwid3JpdGUiLCJhZG1pbiJdfQ.joa9EBtLIr9FNdl62jDZmEDmXIxsPtw1zkuenL784uE" # The address of the *trusted* Celestia light client to interact with celestia_rpc_address = "http://127.0.0.1:26658" # The largest response the rollup will accept from the Celestia node. Defaults to 100 MB diff --git a/examples/demo-rollup/src/lib.rs b/examples/demo-rollup/src/lib.rs index e6b0ea52b..12bcceea9 100644 --- a/examples/demo-rollup/src/lib.rs +++ b/examples/demo-rollup/src/lib.rs @@ -1,2 +1 @@ -pub mod config; pub mod rng_xfers; diff --git a/examples/demo-rollup/src/main.rs b/examples/demo-rollup/src/main.rs index b4837d017..6ff4ea635 100644 --- a/examples/demo-rollup/src/main.rs +++ b/examples/demo-rollup/src/main.rs @@ -1,42 +1,26 @@ use std::env; -use std::net::SocketAddr; use std::sync::Arc; use anyhow::Context; use const_rollup_config::{ROLLUP_NAMESPACE_RAW, SEQUENCER_DA_ADDRESS}; -use demo_stf::app::{ - DefaultContext, DefaultPrivateKey, DemoBatchReceipt, DemoTxReceipt, NativeAppRunner, -}; +use demo_stf::app::{App, DefaultContext, DefaultPrivateKey}; use demo_stf::genesis_config::create_demo_genesis_config; -use demo_stf::runner_config::from_toml_path; use demo_stf::runtime::{get_rpc_methods, GenesisConfig}; -use jsonrpsee::core::server::Methods; use jupiter::da_service::CelestiaService; #[cfg(feature = "experimental")] use jupiter::da_service::DaServiceConfig; use jupiter::types::NamespaceId; -use jupiter::verifier::{CelestiaVerifier, ChainValidityCondition, RollupParams}; -use jupiter::BlobWithSender; +use jupiter::verifier::RollupParams; use risc0_adapter::host::Risc0Verifier; -use sov_db::ledger_db::{LedgerDB, SlotCommit}; +use sov_db::ledger_db::LedgerDB; #[cfg(feature = "experimental")] use sov_ethereum::get_ethereum_rpc; -use sov_modules_api::RpcRunner; -use sov_rollup_interface::crypto::NoOpHasher; -use sov_rollup_interface::da::{BlockHeaderTrait, DaSpec, DaVerifier}; -use sov_rollup_interface::services::da::{DaService, SlotData}; -use sov_rollup_interface::services::stf_runner::StateTransitionRunner; -use sov_rollup_interface::stf::StateTransitionFunction; -use sov_rollup_interface::zk::ValidityConditionChecker; -// RPC related imports +use sov_modules_stf_template::{SequencerOutcome, TxEffect}; +use sov_rollup_interface::services::da::DaService; use sov_sequencer::get_sequencer_rpc; -use sov_state::Storage; -use tracing::{debug, info, Level}; - -use crate::config::RollupConfig; - -mod config; -mod ledger_rpc; +use sov_state::storage::Storage; +use sov_stf_runner::{from_toml_path, get_ledger_rpc, RollupConfig, StateTransitionRunner}; +use tracing::{debug, Level}; #[cfg(test)] mod test_rpc; @@ -52,17 +36,6 @@ pub fn initialize_ledger(path: impl AsRef) -> LedgerDB { LedgerDB::with_path(path).expect("Ledger DB failed to open") } -async fn start_rpc_server(methods: impl Into, address: SocketAddr) { - let server = jsonrpsee::server::ServerBuilder::default() - .build([address].as_ref()) - .await - .unwrap(); - - info!("Starting RPC server at {} ", server.local_addr().unwrap()); - let _server_handle = server.start(methods).unwrap(); - futures::future::pending::<()>().await; -} - // TODO: Remove this when sov-cli is in its own crate. #[derive(Debug, serde::Serialize, serde::Deserialize)] struct HexKey { @@ -100,22 +73,6 @@ pub fn get_genesis_config() -> GenesisConfig { ) } -pub struct CelestiaChainChecker { - current_block_hash: [u8; 32], -} - -impl ValidityConditionChecker for CelestiaChainChecker { - type Error = anyhow::Error; - - fn check(&mut self, condition: &ChainValidityCondition) -> Result<(), anyhow::Error> { - anyhow::ensure!( - condition.block_hash == self.current_block_hash, - "Invalid block hash" - ); - Ok(()) - } -} - #[tokio::main] async fn main() -> Result<(), anyhow::Error> { let rollup_config_path = env::args() @@ -144,135 +101,47 @@ async fn main() -> Result<(), anyhow::Error> { ) .await; - let mut runner = RollupRunner::::new(rollup_config, da_service, ledger_db)?; - runner.run().await?; + let mut app: App = + App::new(rollup_config.runner.storage.clone()); - Ok(()) -} + let storage = app.get_storage(); + let mut methods = get_rpc_methods::(storage); -struct RollupRunner -where - DA: DaService, -{ - start_height: u64, - da_service: DA, - app: NativeAppRunner::Spec as DaSpec>::BlobTransaction>, - ledger_db: LedgerDB, - state_root: [u8; 32], -} - -impl RollupRunner -where - DA: DaService + Clone + Send + Sync + 'static, -{ - fn new( - rollup_config: RollupConfig, - da_service: DA, - ledger_db: LedgerDB, - ) -> Result { - let mut app = NativeAppRunner::< - Risc0Verifier, - <::Spec as DaSpec>::BlobTransaction, - >::new(rollup_config.runner.clone()); - - let storage = app.get_storage(); - let is_storage_empty = storage.is_empty(); - let mut methods = get_rpc_methods::(storage); - - // register rpc methods - { - register_ledger(ledger_db.clone(), &mut methods)?; - register_sequencer(da_service.clone(), &mut app, &mut methods)?; - #[cfg(feature = "experimental")] - register_ethereum(rollup_config.da.clone(), &mut methods)?; - } - - let rpc_config = rollup_config.rpc_config; - let address = SocketAddr::new(rpc_config.bind_host.parse()?, rpc_config.bind_port); - let _handle = tokio::spawn(async move { - start_rpc_server(methods, address).await; - }); - - let app_runner = app.inner_mut(); - let prev_state_root = { - // Check if the rollup has previously been initialized - if is_storage_empty { - info!("No history detected. Initializing chain..."); - app_runner.init_chain(get_genesis_config()); - info!("Chain initialization is done."); - } else { - debug!("Chain is already initialized. Skipping initialization."); - } - - let res = app_runner.apply_slot(Default::default(), []); - // HACK: Tell the rollup that you're running an empty DA layer block so that it will return the latest state root. - // This will be removed shortly. - res.state_root.0 - }; - - // Start the main rollup loop - let item_numbers = ledger_db.get_next_items_numbers(); - let last_slot_processed_before_shutdown = item_numbers.slot_number - 1; - let start_height = rollup_config.start_height + last_slot_processed_before_shutdown; - - Ok(Self { - start_height, - da_service, - app, - ledger_db, - state_root: prev_state_root, - }) + // register rpc methods + { + register_ledger(ledger_db.clone(), &mut methods)?; + register_sequencer(da_service.clone(), &mut app, &mut methods)?; + #[cfg(feature = "experimental")] + register_ethereum(rollup_config.da.clone(), &mut methods)?; } - async fn run(&mut self) -> Result<[u8; 32], anyhow::Error> { - let app_runner = self.app.inner_mut(); - - for height in self.start_height.. { - info!( - "Requesting data for height {} and prev_state_root 0x{}", - height, - hex::encode(self.state_root) - ); - - // Fetch the relevant subset of the next Celestia block - let filtered_block = self.da_service.get_finalized_at(height).await?; - - let mut blobs = self.da_service.extract_relevant_txs(&filtered_block); - - info!( - "Extracted {} relevant blobs at height {}", - blobs.len(), - height - ); + let storage = app.get_storage(); + let genesis_config = get_genesis_config(); - let mut data_to_commit = SlotCommit::new(filtered_block.clone()); + let mut runner = StateTransitionRunner::new( + rollup_config, + da_service, + ledger_db, + app.stf, + storage.is_empty(), + genesis_config, + )?; - let slot_result = app_runner.apply_slot(Default::default(), &mut blobs); - for receipt in slot_result.batch_receipts { - data_to_commit.add_batch(receipt); - } - let next_state_root = slot_result.state_root; - - self.ledger_db.commit_slot(data_to_commit)?; - self.state_root = next_state_root.0; - } + runner.start_rpc_server(methods).await; + runner.run().await?; - Ok(self.state_root) - } + Ok(()) } fn register_sequencer( da_service: DA, - demo_runner: &mut NativeAppRunner< - Risc0Verifier, - <::Spec as DaSpec>::BlobTransaction, - >, + demo_runner: &mut App, methods: &mut jsonrpsee::RpcModule<()>, ) -> Result<(), anyhow::Error> where DA: DaService + Send + Sync + 'static, { - let batch_builder = demo_runner.take_batch_builder().unwrap(); + let batch_builder = demo_runner.batch_builder.take().unwrap(); let sequencer_rpc = get_sequencer_rpc(batch_builder, Arc::new(da_service)); methods .merge(sequencer_rpc) @@ -283,7 +152,7 @@ fn register_ledger( ledger_db: LedgerDB, methods: &mut jsonrpsee::RpcModule<()>, ) -> Result<(), anyhow::Error> { - let ledger_rpc = ledger_rpc::get_ledger_rpc::(ledger_db); + let ledger_rpc = get_ledger_rpc::(ledger_db); methods .merge(ledger_rpc) .context("Failed to merge ledger RPC modules") diff --git a/examples/demo-rollup/src/test_rpc.rs b/examples/demo-rollup/src/test_rpc.rs index 6372d64de..4180d6fab 100644 --- a/examples/demo-rollup/src/test_rpc.rs +++ b/examples/demo-rollup/src/test_rpc.rs @@ -12,12 +12,12 @@ use sov_rollup_interface::mocks::{TestBlock, TestBlockHeader, TestHash}; use sov_rollup_interface::services::da::SlotData; use sov_rollup_interface::stf::fuzzing::BatchReceiptStrategyArgs; use sov_rollup_interface::stf::{BatchReceipt, Event, TransactionReceipt}; +#[cfg(test)] +use sov_stf_runner::get_ledger_rpc; +use sov_stf_runner::RpcConfig; use tendermint::crypto::Sha256; use tokio::sync::oneshot; -use crate::config::RpcConfig; -use crate::ledger_rpc; - struct TestExpect { payload: serde_json::Value, expected: serde_json::Value, @@ -72,7 +72,7 @@ fn test_helper(test_queries: Vec, slots: Vec(ledger_db.clone()); + let ledger_rpc_module = get_ledger_rpc::(ledger_db.clone()); rt.spawn(async move { let server = jsonrpsee::server::ServerBuilder::default() diff --git a/examples/demo-stf/Cargo.toml b/examples/demo-stf/Cargo.toml index 950ba0835..a98699989 100644 --- a/examples/demo-stf/Cargo.toml +++ b/examples/demo-stf/Cargo.toml @@ -37,6 +37,7 @@ sov-accounts = { path = "../../module-system/module-implementations/sov-accounts sov-state = { path = "../../module-system/sov-state", default-features = false } sov-modules-api = { path = "../../module-system/sov-modules-api", default-features = false, features = ["macros"] } sov-sequencer = { path = "../../full-node/sov-sequencer", optional = true } +sov-stf-runner = { path = "../../full-node/sov-stf-runner", optional = true } # Only enable the evm on "experimental" feature sov-evm = { path = "../../module-system/module-implementations/sov-evm", default-features = false, optional = true } @@ -59,6 +60,7 @@ native = [ "sov-modules-api/native", "sov-rollup-interface/mocks", "sov-sequencer", + "sov-stf-runner", "clap", "serde_json", "jsonrpsee", diff --git a/examples/demo-stf/README.md b/examples/demo-stf/README.md index 7e333f6f2..14d41e68e 100644 --- a/examples/demo-stf/README.md +++ b/examples/demo-stf/README.md @@ -218,8 +218,4 @@ impl StateTransitionRunner for DemoAppRunner { - pub stf: DemoApp, - pub batch_builder: Option, C>>, -} - -pub type ZkAppRunner = DemoAppRunner; - +use sov_stf_runner::FiFoStrictBatchBuilder; #[cfg(feature = "native")] -pub type NativeAppRunner = DemoAppRunner; +use sov_stf_runner::StorageConfig; -pub type DemoApp = AppTemplate, Vm, B>; - -/// Batch receipt type used by the demo app. We export this type so that it's easily accessible to the full node. -pub type DemoBatchReceipt = SequencerOutcome; -/// Tx receipt type used by the demo app. We export this type so that it's easily accessible to the full node. -pub type DemoTxReceipt = TxEffect; +use crate::runtime::Runtime; #[cfg(feature = "native")] -impl StateTransitionRunner - for DemoAppRunner -{ - type RuntimeConfig = Config; - type Inner = DemoApp; - type BatchBuilder = FiFoStrictBatchBuilder, DefaultContext>; - - fn new(runtime_config: Self::RuntimeConfig) -> Self { - let storage = ProverStorage::with_config(runtime_config.storage) - .expect("Failed to open prover storage"); - let app = AppTemplate::new(storage.clone(), Runtime::default()); - let batch_size_bytes = 1024 * 100; // 100 KB - let batch_builder = FiFoStrictBatchBuilder::new( - batch_size_bytes, - u32::MAX as usize, - Runtime::default(), - storage, - ); - Self { - stf: app, - batch_builder: Some(batch_builder), - } - } - - fn inner(&self) -> &Self::Inner { - &self.stf - } - - fn inner_mut(&mut self) -> &mut Self::Inner { - &mut self.stf - } - - fn take_batch_builder(&mut self) -> Option { - self.batch_builder.take() - } +pub struct App { + pub stf: AppTemplate, Vm, B>, + pub batch_builder: Option, DefaultContext>>, } -impl StateTransitionRunner - for DemoAppRunner -{ - type RuntimeConfig = [u8; 32]; - type Inner = DemoApp; - type BatchBuilder = FiFoStrictBatchBuilder, ZkDefaultContext>; - - fn new(runtime_config: Self::RuntimeConfig) -> Self { - let storage = ZkStorage::with_config(runtime_config).expect("Failed to open zk storage"); - let app: AppTemplate, Vm, B> = - AppTemplate::new(storage.clone(), Runtime::default()); - +#[cfg(feature = "native")] +impl App { + pub fn new(storage_config: StorageConfig) -> Self { + let storage = + ProverStorage::with_config(storage_config).expect("Failed to open prover storage"); + let app = AppTemplate::new(storage.clone(), Runtime::default()); let batch_size_bytes = 1024 * 100; // 100 KB let batch_builder = FiFoStrictBatchBuilder::new( batch_size_bytes, @@ -105,23 +44,14 @@ impl StateTransitionRunner } } - fn inner(&self) -> &Self::Inner { - &self.stf - } - - fn inner_mut(&mut self) -> &mut Self::Inner { - &mut self.stf - } - - fn take_batch_builder(&mut self) -> Option { - self.batch_builder.take() + pub fn get_storage(&self) -> ::Storage { + self.stf.current_storage.clone() } } -#[cfg(feature = "native")] -impl RpcRunner for DemoAppRunner { - type Context = DefaultContext; - fn get_storage(&self) -> ::Storage { - self.inner().current_storage.clone() - } +pub fn create_zk_app_template( + runtime_config: [u8; 32], +) -> AppTemplate, Vm, B> { + let storage = ZkStorage::with_config(runtime_config).expect("Failed to open zk storage"); + AppTemplate::new(storage, Runtime::default()) } diff --git a/examples/demo-stf/src/lib.rs b/examples/demo-stf/src/lib.rs index bdd858f82..24b2cf573 100644 --- a/examples/demo-stf/src/lib.rs +++ b/examples/demo-stf/src/lib.rs @@ -1,10 +1,8 @@ pub mod app; -pub mod batch_builder; + #[cfg(feature = "native")] pub mod genesis_config; pub mod hooks_impl; -#[cfg(feature = "native")] -pub mod runner_config; pub mod runtime; #[cfg(test)] pub mod tests; diff --git a/examples/demo-stf/src/runtime.rs b/examples/demo-stf/src/runtime.rs index 9b73db8d8..6ab3c131e 100644 --- a/examples/demo-stf/src/runtime.rs +++ b/examples/demo-stf/src/runtime.rs @@ -78,3 +78,5 @@ pub struct Runtime { #[cfg_attr(feature = "native", cli_skip)] pub evm: sov_evm::Evm, } + +impl sov_modules_stf_template::Runtime for Runtime {} diff --git a/examples/demo-stf/src/sov-cli/native.rs b/examples/demo-stf/src/sov-cli/native.rs index 9044ab66f..5f27c459e 100644 --- a/examples/demo-stf/src/sov-cli/native.rs +++ b/examples/demo-stf/src/sov-cli/native.rs @@ -344,16 +344,15 @@ pub async fn main() -> Result<(), anyhow::Error> { #[cfg(test)] mod test { use borsh::BorshDeserialize; - use demo_stf::app::{DemoApp, DemoAppRunner}; + use demo_stf::app::App; use demo_stf::genesis_config::{create_demo_config, DEMO_SEQUENCER_DA_ADDRESS, LOCKED_AMOUNT}; - use demo_stf::runner_config::Config; - use demo_stf::runtime::GenesisConfig; - use sov_modules_api::{Address, PrivateKey}; - use sov_modules_stf_template::{Batch, RawTx, SequencerOutcome}; + use demo_stf::runtime::{GenesisConfig, Runtime}; + use sov_modules_api::Address; + use sov_modules_stf_template::{AppTemplate, Batch, RawTx, SequencerOutcome}; use sov_rollup_interface::mocks::MockZkvm; - use sov_rollup_interface::services::stf_runner::StateTransitionRunner; use sov_rollup_interface::stf::StateTransitionFunction; use sov_state::WorkingSet; + use sov_stf_runner::Config; use super::*; @@ -425,7 +424,7 @@ mod test { // Test helpers struct TestDemo { config: GenesisConfig, - demo: DemoApp, + demo: AppTemplate, MockZkvm, TestBlob>, } impl TestDemo { @@ -445,7 +444,7 @@ mod test { Self { config: genesis_config, - demo: DemoAppRunner::::new(runner_config).stf, + demo: App::::new(runner_config.storage).stf, } } } @@ -501,7 +500,7 @@ mod test { } fn execute_txs( - demo: &mut DemoApp, + demo: &mut AppTemplate, MockZkvm, TestBlob>, config: GenesisConfig, txs: Vec, ) { @@ -527,7 +526,7 @@ mod test { } fn get_balance( - demo: &mut DemoApp, + demo: &mut AppTemplate, MockZkvm, TestBlob>, token_deployer_address: &Address, user_address: Address, ) -> Option { diff --git a/examples/demo-stf/src/tests/mod.rs b/examples/demo-stf/src/tests/mod.rs index c77577995..b100992bf 100644 --- a/examples/demo-stf/src/tests/mod.rs +++ b/examples/demo-stf/src/tests/mod.rs @@ -7,7 +7,6 @@ use sov_modules_stf_template::{AppTemplate, Batch, SequencerOutcome, TxEffect}; use sov_rollup_interface::stf::BatchReceipt; use sov_state::ProverStorage; -use crate::app::DemoApp; use crate::runtime::Runtime; mod data_generation; @@ -19,7 +18,12 @@ pub type TestBlob = sov_rollup_interface::mocks::TestBlob
; pub fn create_new_demo( path: impl AsRef, -) -> DemoApp { +) -> AppTemplate< + DefaultContext, + Runtime, + sov_rollup_interface::mocks::MockZkvm, + TestBlob, +> { let runtime = Runtime::default(); let storage = ProverStorage::with_path(path).unwrap(); AppTemplate::new(storage, runtime) diff --git a/full-node/sov-stf-runner/Cargo.toml b/full-node/sov-stf-runner/Cargo.toml new file mode 100644 index 000000000..9eb1a8d8e --- /dev/null +++ b/full-node/sov-stf-runner/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "sov-stf-runner" +authors = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +rust-version = { workspace = true } +version = { workspace = true } +readme = "README.md" +resolver = "2" + +[dependencies] +anyhow = { workspace = true } +borsh = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +toml = { workspace = true } +jsonrpsee = { workspace = true, features = ["http-client", "server"] } +tokio = { workspace = true } +hex = { workspace = true } +tracing = { workspace = true } +futures = "0.3" +tracing-subscriber = "0.3.17" + +sov-db = { path = "../db/sov-db" } +sov-rollup-interface = { path = "../../rollup-interface", version = "0.1" } +sov-state = { path = "../../module-system/sov-state", version = "0.1"} +sov-modules-api = { path = "../../module-system/sov-modules-api", version = "0.1" } +jupiter = { path = "../../adapters/celestia" } + +[dev-dependencies] +tempfile = { workspace = true } +rand = { workspace = true } + +sov-election = { path = "../../module-system/module-implementations/examples/sov-election", default-features = false } +sov-sequencer-registry = { path = "../../module-system/module-implementations/sov-sequencer-registry", default-features = false } +sov-bank = { path = "../../module-system/module-implementations/sov-bank", default-features = false } +sov-modules-stf-template = { path = "../../module-system/sov-modules-stf-template" } +sov-value-setter = { path = "../../module-system/module-implementations/examples/sov-value-setter", default-features = false } +sov-accounts = { path = "../../module-system/module-implementations/sov-accounts", default-features = false } diff --git a/full-node/sov-stf-runner/README.md b/full-node/sov-stf-runner/README.md new file mode 100644 index 000000000..2332ab2c6 --- /dev/null +++ b/full-node/sov-stf-runner/README.md @@ -0,0 +1,7 @@ +# Sov-Stf-Runner + +Generic logic for running the rollup. + +### StateTransitionRunner + +The `StateTransitionRunner` combines the `StateTransitionFunction` with `DaService` and runs the rollup by invoking the blob processing logic on blocks obtained from `DaService`. Additionally, it allows the initiation of an RPC server with externally defined RPC methods diff --git a/examples/demo-stf/src/batch_builder.rs b/full-node/sov-stf-runner/src/batch_builder.rs similarity index 99% rename from examples/demo-stf/src/batch_builder.rs rename to full-node/sov-stf-runner/src/batch_builder.rs index 8f79e4461..0af49152e 100644 --- a/examples/demo-stf/src/batch_builder.rs +++ b/full-node/sov-stf-runner/src/batch_builder.rs @@ -20,6 +20,7 @@ pub struct FiFoStrictBatchBuilder { } impl FiFoStrictBatchBuilder { + /// BatchBuilder constructor. pub fn new( max_batch_size_bytes: usize, mempool_max_txs_count: usize, diff --git a/examples/demo-rollup/src/config.rs b/full-node/sov-stf-runner/src/config.rs similarity index 86% rename from examples/demo-rollup/src/config.rs rename to full-node/sov-stf-runner/src/config.rs index f0c0f83ce..55e72d505 100644 --- a/examples/demo-rollup/src/config.rs +++ b/full-node/sov-stf-runner/src/config.rs @@ -1,18 +1,27 @@ -use demo_stf::runner_config::Config as RunnerConfig; use jupiter::da_service::DaServiceConfig; use serde::Deserialize; +use crate::runner_config::Config as RunnerConfig; + +/// RPC configuration. #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct RpcConfig { + /// RPC host. pub bind_host: String, + /// RPC port. pub bind_port: u16, } +/// Rollup Configuration #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct RollupConfig { + /// DA start height. pub start_height: u64, + /// DA configuration. pub da: DaServiceConfig, + /// Runner configuration. pub runner: RunnerConfig, + /// RPC configuration. pub rpc_config: RpcConfig, } @@ -21,10 +30,10 @@ mod tests { use std::io::Write; use std::path::PathBuf; - use demo_stf::runner_config::{from_toml_path, StorageConfig}; use tempfile::NamedTempFile; use super::*; + use crate::runner_config::{from_toml_path, StorageConfig}; fn create_config_from(content: &str) -> NamedTempFile { let mut config_file = NamedTempFile::new().unwrap(); diff --git a/full-node/sov-stf-runner/src/ledger_rpc.rs b/full-node/sov-stf-runner/src/ledger_rpc.rs new file mode 100644 index 000000000..18fb52111 --- /dev/null +++ b/full-node/sov-stf-runner/src/ledger_rpc.rs @@ -0,0 +1,94 @@ +use jsonrpsee::RpcModule; +use serde::de::DeserializeOwned; +use serde::Serialize; +use sov_db::ledger_db::LedgerDB; +use sov_modules_api::utils::to_jsonrpsee_error_object; +use sov_rollup_interface::rpc::{ + BatchIdentifier, EventIdentifier, LedgerRpcProvider, SlotIdentifier, TxIdentifier, +}; + +const LEDGER_RPC_ERROR: &str = "LEDGER_RPC_ERROR"; + +use self::query_args::{extract_query_args, QueryArgs}; + +/// Registers the following RPC methods +/// - `ledger_head` +/// Example Query: `curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"ledger_head","params":[],"id":1}' http://127.0.0.1:12345` +/// - ledger_getSlots +/// Example Query: `curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"ledger_getSlots","params":[[1, 2], "Compact"],"id":1}' http://127.0.0.1:12345` +/// - ledger_getBatches +/// Example Query: `curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"ledger_getBatches","params":[[1, 2], "Standard"],"id":1}' http://127.0.0.1:12345` +/// - ledger_getTransactions +/// Example Query: `curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"ledger_getBatches","params":[[1, 2], "Full"],"id":1}' http://127.0.0.1:12345` +/// - ledger_getEvents +/// Example Query: `curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"ledger_getBatches","params":[1, 2],"id":1}' http://127.0.0.1:12345` +fn register_ledger_rpc_methods< + B: Serialize + DeserializeOwned + Clone + 'static, + T: Serialize + DeserializeOwned + Clone + 'static, +>( + rpc: &mut RpcModule, +) -> Result<(), jsonrpsee::core::Error> { + rpc.register_method("ledger_getHead", move |_, db| { + db.get_head::() + .map_err(|e| to_jsonrpsee_error_object(e, LEDGER_RPC_ERROR)) + })?; + + rpc.register_method("ledger_getSlots", move |params, db| { + let args: QueryArgs = extract_query_args(params)?; + db.get_slots::(&args.0, args.1) + .map_err(|e| to_jsonrpsee_error_object(e, LEDGER_RPC_ERROR)) + })?; + + rpc.register_method("ledger_getBatches", move |params, db| { + let args: QueryArgs = extract_query_args(params)?; + db.get_batches::(&args.0, args.1) + .map_err(|e| to_jsonrpsee_error_object(e, LEDGER_RPC_ERROR)) + })?; + + rpc.register_method("ledger_getTransactions", move |params, db| { + let args: QueryArgs = extract_query_args(params)?; + db.get_transactions::(&args.0, args.1) + .map_err(|e| to_jsonrpsee_error_object(e, LEDGER_RPC_ERROR)) + })?; + + rpc.register_method("ledger_getEvents", move |params, db| { + let ids: Vec = params.parse()?; + db.get_events(&ids) + .map_err(|e| to_jsonrpsee_error_object(e, LEDGER_RPC_ERROR)) + })?; + + Ok(()) +} + +/// Get standard RPC method for the rollup. +pub fn get_ledger_rpc< + B: Serialize + DeserializeOwned + Clone + 'static, + T: Serialize + DeserializeOwned + Clone + 'static, +>( + ledger_db: LedgerDB, +) -> RpcModule { + let mut rpc = RpcModule::new(ledger_db); + register_ledger_rpc_methods::(&mut rpc).expect("Failed to register ledger RPC methods"); + rpc +} + +mod query_args { + use jsonrpsee::types::ErrorObjectOwned; + use serde::de::DeserializeOwned; + use sov_rollup_interface::rpc::QueryMode; + + #[derive(serde::Deserialize)] + pub struct QueryArgs(pub Vec, #[serde(default)] pub QueryMode); + + /// Extract the args from an RPC query, being liberal in what is accepted. + /// To query for a list of items, users can either pass a list of ids, or tuple containing a list of ids and a query mode + pub fn extract_query_args( + params: jsonrpsee::types::Params, + ) -> Result, ErrorObjectOwned> { + if let Ok(args) = params.parse() { + return Ok(args); + } + let ids: Vec = params.parse()?; + Ok(QueryArgs(ids, Default::default())) + } +} diff --git a/full-node/sov-stf-runner/src/lib.rs b/full-node/sov-stf-runner/src/lib.rs new file mode 100644 index 000000000..03fd45515 --- /dev/null +++ b/full-node/sov-stf-runner/src/lib.rs @@ -0,0 +1,141 @@ +#![deny(missing_docs)] +#![doc = include_str!("../README.md")] + +mod batch_builder; +mod config; +pub use config::RpcConfig; +mod runner_config; +use std::net::SocketAddr; +mod ledger_rpc; +pub use batch_builder::FiFoStrictBatchBuilder; +pub use config::RollupConfig; +use jsonrpsee::RpcModule; +pub use ledger_rpc::get_ledger_rpc; +pub use runner_config::{from_toml_path, Config, StorageConfig}; +use sov_db::ledger_db::{LedgerDB, SlotCommit}; +use sov_rollup_interface::da::DaSpec; +use sov_rollup_interface::services::da::DaService; +use sov_rollup_interface::stf::StateTransitionFunction; +use sov_rollup_interface::zk::Zkvm; +use tracing::{debug, info}; + +type StateRoot = ::Spec as DaSpec>::BlobTransaction, +>>::StateRoot; + +type InitialState = ::Spec as DaSpec>::BlobTransaction, +>>::InitialState; + +/// Combines `DaService` with `StateTransitionFunction` and "runs" the rollup. +pub struct StateTransitionRunner +where + DA: DaService, + Vm: Zkvm, + ST: StateTransitionFunction::Spec as DaSpec>::BlobTransaction>, +{ + start_height: u64, + da_service: DA, + app: ST, + ledger_db: LedgerDB, + state_root: StateRoot, + socket_address: SocketAddr, +} + +impl StateTransitionRunner +where + DA: DaService + Clone + Send + Sync + 'static, + Vm: Zkvm, + ST: StateTransitionFunction::Spec as DaSpec>::BlobTransaction>, +{ + /// Creates a new `StateTransitionRunner` runner. + pub fn new( + rollup_config: RollupConfig, + da_service: DA, + ledger_db: LedgerDB, + mut app: ST, + is_storage_empty: bool, + genesis_config: InitialState, + ) -> Result { + let rpc_config = rollup_config.rpc_config; + + let prev_state_root = { + // Check if the rollup has previously been initialized + if is_storage_empty { + info!("No history detected. Initializing chain..."); + app.init_chain(genesis_config); + info!("Chain initialization is done."); + } else { + debug!("Chain is already initialized. Skipping initialization."); + } + + let res = app.apply_slot(Default::default(), []); + // HACK: Tell the rollup that you're running an empty DA layer block so that it will return the latest state root. + // This will be removed shortly. + res.state_root + }; + + let socket_address = SocketAddr::new(rpc_config.bind_host.parse()?, rpc_config.bind_port); + + // Start the main rollup loop + let item_numbers = ledger_db.get_next_items_numbers(); + let last_slot_processed_before_shutdown = item_numbers.slot_number - 1; + let start_height = rollup_config.start_height + last_slot_processed_before_shutdown; + + Ok(Self { + start_height, + da_service, + app, + ledger_db, + state_root: prev_state_root, + socket_address, + }) + } + + /// Starts an rpc server with provided rpc methods. + pub async fn start_rpc_server(&self, methods: RpcModule<()>) { + let socket_address = self.socket_address; + let _handle = tokio::spawn(async move { + let server = jsonrpsee::server::ServerBuilder::default() + .build([socket_address].as_ref()) + .await + .unwrap(); + + info!("Starting RPC server at {} ", server.local_addr().unwrap()); + let _server_handle = server.start(methods).unwrap(); + futures::future::pending::<()>().await; + }); + } + + /// Runs the rollup. + pub async fn run(&mut self) -> Result<(), anyhow::Error> { + for height in self.start_height.. { + info!("Requesting data for height {}", height,); + + let filtered_block = self.da_service.get_finalized_at(height).await?; + + let mut blobs = self.da_service.extract_relevant_txs(&filtered_block); + + info!( + "Extracted {} relevant blobs at height {}", + blobs.len(), + height + ); + + let mut data_to_commit = SlotCommit::new(filtered_block.clone()); + + let slot_result = self.app.apply_slot(Default::default(), &mut blobs); + for receipt in slot_result.batch_receipts { + data_to_commit.add_batch(receipt); + } + let next_state_root = slot_result.state_root; + + self.ledger_db.commit_slot(data_to_commit)?; + self.state_root = next_state_root; + } + + Ok(()) + } +} diff --git a/examples/demo-stf/src/runner_config.rs b/full-node/sov-stf-runner/src/runner_config.rs similarity index 95% rename from examples/demo-stf/src/runner_config.rs rename to full-node/sov-stf-runner/src/runner_config.rs index 5916e2d65..fb7d4ebdc 100644 --- a/examples/demo-stf/src/runner_config.rs +++ b/full-node/sov-stf-runner/src/runner_config.rs @@ -3,9 +3,9 @@ use std::io::Read; use std::path::Path; use serde::de::DeserializeOwned; -pub use sov_modules_api::default_context::DefaultContext; pub use sov_state::config::Config as StorageConfig; +/// Reads toml file as a specific type. pub fn from_toml_path, R: DeserializeOwned>(path: P) -> anyhow::Result { let mut contents = String::new(); { @@ -18,8 +18,10 @@ pub fn from_toml_path, R: DeserializeOwned>(path: P) -> anyhow::R Ok(result) } +/// StateTransitionRunner configuration #[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)] pub struct Config { + /// Storage config pub storage: StorageConfig, } diff --git a/module-system/RPC_WALKTHROUGH.md b/module-system/RPC_WALKTHROUGH.md index c53e5b907..b7bea1617 100644 --- a/module-system/RPC_WALKTHROUGH.md +++ b/module-system/RPC_WALKTHROUGH.md @@ -8,9 +8,8 @@ There are 5 steps that need to be completed to enable RPC on the full node: 1. Annotate you modules with `rpc_gen` and `rpc_method`. 2. Annotate your `native` `Runtime` with the `expose_rpc` macro. -3. Implement the `RpcRunner` trait on your `StateTransitionRunner`. -4. Import and call `get_rpc_methods` in your full node implementation. -5. Configure and start your RPC server in your full node implementation. +3. Import and call `get_rpc_methods` in your full node implementation. +4. Configure and start your RPC server in your full node implementation. ### Step 1: Generate an RPC Server for your Module @@ -77,44 +76,23 @@ pub struct Runtime { Note that`expose_rpc` takes a tuple as argument, each element of the tuple is a concrete Context. -### Step 3: Implement RpcRunner - -Next, we implement the `RpcRunner` trait on our `StateTransitionRunner`. If `expose_rpc` dictates which module RPCs we want to -enable, `RpcRunner` dictates what kind of state they have access to. In this example, we'll expose the current state of our -rollup by giving the `RpcRunner` a handle to our working database. However, we could just as easily use a different storage instance. -For example, we might want to use a read-only database snapshot, which would prevent contention between transaction execution -and RPC queries. - -```rust -// This code goes in your state transition function crate. For example demo-stf/app.rs -use sov_modules_api::RpcRunner; -impl RpcRunner for DemoAppRunner { - type Context = DefaultContext; - fn get_storage(&self) -> ::Storage { - self.inner().current_storage.clone() - } -} -``` - -### Step 4: Instantiate RPC Methods +### Step 3: Instantiate RPC Methods Now that we've implemented all of the necessary traits, a `get_rpc_methods` function will be auto-generated. To use it, simply import it from your state transition function. Given access to `Storage`, this function instantiates [`jsonrpsee::Methods`](https://docs.rs/jsonrpsee/latest/jsonrpsee/struct.Methods.html) which your full node can -execute. Thanks to the `RpcRunner` trait we just implemented, our full node now has easy access to an appropriate -storage instance. +execute. ```rust // This code goes in your full node implementation. For example demo-rollup/main.rs use demo_stf::runtime::get_rpc_methods; -use sov_modules_api::RpcRunner; #[tokio::main] fn main() { // ... - let mut demo_runner = NativeAppRunner...; + let mut app = App...; - let storage = demo_runner.get_storage(); + let storage = app.get_storage(); let methods = get_rpc_methods(storage); // ... } @@ -137,7 +115,7 @@ async fn start_rpc_server(methods: RpcModule<()>, address: SocketAddr) { #[tokio::main] fn main() { // ... - let mut demo_runner = NativeAppRunner...; + let mut demo_runner = App...; let storage = demo_runner.get_storage(); let methods = get_rpc_methods(storage); diff --git a/module-system/module-implementations/sov-evm/src/tests/tx_tests.rs b/module-system/module-implementations/sov-evm/src/tests/tx_tests.rs index e8221dc5b..dab82e3f9 100644 --- a/module-system/module-implementations/sov-evm/src/tests/tx_tests.rs +++ b/module-system/module-implementations/sov-evm/src/tests/tx_tests.rs @@ -151,7 +151,7 @@ impl TestClient { } // TODO enable in CI -#[ignore] +//#[ignore] #[tokio::test] async fn send_tx_test_to_eth() -> Result<(), Box> { let chain_id: u64 = 1; diff --git a/module-system/sov-modules-api/src/lib.rs b/module-system/sov-modules-api/src/lib.rs index 16b4b6124..b5395f529 100644 --- a/module-system/sov-modules-api/src/lib.rs +++ b/module-system/sov-modules-api/src/lib.rs @@ -333,13 +333,6 @@ pub trait ModuleInfo { fn dependencies(&self) -> Vec<&::Address>; } -/// A StateTransitionRunner needs to implement this if -/// the RPC service is needed -pub trait RpcRunner { - type Context: Context; - fn get_storage(&self) -> ::Storage; -} - struct ModuleVisitor<'a, C: Context> { visited: HashSet<&'a ::Address>, visited_on_this_path: Vec<&'a ::Address>, diff --git a/module-system/sov-modules-stf-template/src/app_template.rs b/module-system/sov-modules-stf-template/src/app_template.rs index 80653c053..8f2d828e5 100644 --- a/module-system/sov-modules-stf-template/src/app_template.rs +++ b/module-system/sov-modules-stf-template/src/app_template.rs @@ -1,8 +1,7 @@ use std::marker::PhantomData; use borsh::BorshDeserialize; -use sov_modules_api::hooks::{ApplyBlobHooks, TxHooks}; -use sov_modules_api::{Context, DispatchCall, Genesis}; +use sov_modules_api::{Context, DispatchCall}; use sov_rollup_interface::da::{BlobReaderTrait, CountedBufReader}; use sov_rollup_interface::stf::{BatchReceipt, TransactionReceipt}; use sov_rollup_interface::Buf; @@ -10,7 +9,7 @@ use sov_state::StateCheckpoint; use tracing::{debug, error}; use crate::tx_verifier::{verify_txs_stateless, TransactionAndRawHash}; -use crate::{Batch, SequencerOutcome, SlashingReason, TxEffect}; +use crate::{Batch, Runtime, SequencerOutcome, SlashingReason, TxEffect}; type ApplyBatchResult = Result; @@ -64,10 +63,7 @@ impl From for BatchReceipt { impl AppTemplate where - RT: DispatchCall - + Genesis - + TxHooks - + ApplyBlobHooks, + RT: Runtime, { /// [`AppTemplate`] constructor. pub fn new(storage: C::Storage, runtime: RT) -> Self { diff --git a/module-system/sov-modules-stf-template/src/lib.rs b/module-system/sov-modules-stf-template/src/lib.rs index 5a8eb70f5..e620d57d3 100644 --- a/module-system/sov-modules-stf-template/src/lib.rs +++ b/module-system/sov-modules-stf-template/src/lib.rs @@ -15,6 +15,15 @@ use sov_state::{StateCheckpoint, Storage}; use tracing::info; pub use tx_verifier::RawTx; +///TODO +pub trait Runtime: + DispatchCall + + Genesis + + TxHooks + + ApplyBlobHooks +{ +} + /// The receipts of all the transactions in a batch. #[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum TxEffect { @@ -76,10 +85,7 @@ impl AppTemplate { impl StateTransitionFunction for AppTemplate where - RT: DispatchCall - + Genesis - + TxHooks - + ApplyBlobHooks, + RT: Runtime, { type StateRoot = jmt::RootHash; diff --git a/rollup-interface/src/node/services/mod.rs b/rollup-interface/src/node/services/mod.rs index 1432e1b84..aa3b60fd6 100644 --- a/rollup-interface/src/node/services/mod.rs +++ b/rollup-interface/src/node/services/mod.rs @@ -4,4 +4,3 @@ pub mod batch_builder; pub mod da; -pub mod stf_runner; diff --git a/rollup-interface/src/node/services/stf_runner.rs b/rollup-interface/src/node/services/stf_runner.rs deleted file mode 100644 index 2d840a3fa..000000000 --- a/rollup-interface/src/node/services/stf_runner.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! This module defines the traits that are used by the full node to -//! instantiate and run the state transition function. -use crate::da::BlobReaderTrait; -use crate::services::batch_builder::BatchBuilder; -use crate::stf::{StateTransitionConfig, StateTransitionFunction}; -use crate::zk::Zkvm; - -/// A StateTransitionRunner (STR) is responsible for running the state transition function. For any particular function, -/// you might have a few different STRs, each with different runtime configs. For example, you might have a STR which takes -/// a path to a data directory as a runtime config, and another which takes a pre-built in-memory database. -/// -/// Using a separate trait for initialization makes it easy to store extra data in the STR, which -/// would not fit neatly in the state transition logic itself (such as a handle to the database). -/// This way, you can easily support ancillary functions like RPC, p2p networking etc in your full node implementation -/// -/// -/// The StateTransitionRunner is generic over a StateTransitionConfig, and a Zkvm. The ZKvm is simply forwarded to the inner STF. -/// StateTransitionConfig is a special marker trait which has only 3 possible instantiations: ProverConfig, NativeConfig, and ZkConfig. -/// This Config makes it easy to implement different instantiations of STR on the same struct, which are appropriate for different -/// modes of execution. -/// -/// For example: might have `impl StateTransitionRunner for MyRunner` which takes a path to a data directory as a runtime config, -/// -/// and a `impl StateTransitionRunner for MyRunner` which instead uses a state root as its runtime config. -/// -/// TODO: Why is it called runner? It only creates. Creator, Factory: -pub trait StateTransitionRunner { - /// The parameters of the state transition function which are set at runtime. For example, - /// the runtime config might contain path to a data directory. - type RuntimeConfig; - - /// The inner [`StateTransitionFunction`] which is being run. - type Inner: StateTransitionFunction; - - /// The [`BatchBuilder`] accepts transactions from the mempool and returns bundles of transactions - /// on request from the full node. - type BatchBuilder: BatchBuilder; - - // TODO: decide if `new` also requires ::ChainParams as an argument - /// Creates a [`StateTransitionRunner`] from the given runtime config. - fn new(runtime_config: Self::RuntimeConfig) -> Self; - - /// Return a reference to the inner STF implementation - fn inner(&self) -> &Self::Inner; - - /// Return a mutable reference to the inner STF implementation - fn inner_mut(&mut self) -> &mut Self::Inner; - - /// Gives batch builder, after it has been initialized and configured - /// Can be only called once. - fn take_batch_builder(&mut self) -> Option; - - // /// Report if the state transition function has been initialized. - // /// If not, node implementations should respond by running `init_chain` - // fn has_been_initialized(&self) -> bool; -} From adb9df514b618f55858a078dc64aa391eaab0cb9 Mon Sep 17 00:00:00 2001 From: bkolad Date: Mon, 7 Aug 2023 14:38:51 +0200 Subject: [PATCH 3/9] Update docs --- examples/demo-rollup/README.md | 11 ++------ examples/demo-stf/README.md | 49 ++++------------------------------ 2 files changed, 7 insertions(+), 53 deletions(-) diff --git a/examples/demo-rollup/README.md b/examples/demo-rollup/README.md index 71f7f219a..f87fee8bf 100644 --- a/examples/demo-rollup/README.md +++ b/examples/demo-rollup/README.md @@ -381,18 +381,11 @@ The next step is to initialize your state transition function. ```rust let mut app: App = App::new(config); -``` - -If your StateTransitionRunner provides an RPC interface, you should initialize that too. If it implements RpcRunner, you -can use that for easy access to RPC: -```rust -let rpc_module = get_rpc_module(stf_runner.get_storage()); -let _handle = tokio::spawn(async move { - start_rpc_server(module, address).await; -}); + app.start_rpc_server(..) ``` + ### 3. Run the Main Loop The full node implements a simple loop for processing blocks. The workflow is: diff --git a/examples/demo-stf/README.md b/examples/demo-stf/README.md index 14d41e68e..a815e2a51 100644 --- a/examples/demo-stf/README.md +++ b/examples/demo-stf/README.md @@ -160,59 +160,20 @@ customization. At the very least, you'll have to modify our `demo-rollup` exampl to import your custom STF! But, when you're building an STF it's useful to stick as closely as possible to some standard interfaces. That way, you can minimize the changeset for your custom node implementation, which reduces the risk of bugs. -To help you integrate with full node implementations, we provide standard traits for intitializing an app (`StateTransitionRunner`) and -starting an RPC server (`RpcRunner`). In this section, we'll briefly show how to implement both traits. Again, neither trait is strictly -required - just by implementing STF, you get the capability to integrate with DA layers and ZKVMs. But, implementing these traits +To help you integrate with full node implementations, we provide standard tools for intitializing an app (`StateTransitionRunner`). In this section, we'll briefly show how to use them. Again it is not strictly +required - just by implementing STF, you get the capability to integrate with DA layers and ZKVMs. But, using these structures makes you more compatible with full node implementations out of the box. ### Implementing State Transition Runner -The State Transition Runner trait contains logic related to initialization. It has just three methods: +The State Transition Runner struct contains logic related to initialization and running the rollup. It has just three methods: 1. `new` - which allows us to instantiate a state transition function using a `RuntimeConfig` specific to the particular execution mode. For example, when you're running a prover you likely want to configure a standard RocksDB instance - but in ZK mode, you have to set up your STF to read from a Merkle tree instead. Using STR, we can easily swap out this configuration. -2. `inner` - which returns an immutable reference to the inner state transition function -3. `inner mut` - which returns a mutable reference to the inner STF +2. `run` - which runs the rollup. +3. `start_rpc_server` - which exposes an RPC server. -As you can see in the demo codebase, we implement `StateTransitionRunner` two different times for the `DemoAppRunner` struct - once for `Prover` mode -and once for `Zk` mode. - -The `Prover` implementation is gated behind the `native` feature flag. This flag is what we use in the SDK to mark code which can only be run -outside of the zk-circuit. Since this implementation will always run on a physical machine, we can annotate it with the -` -c` macro telling it to enable RPC queries against the Bank, Election, and ValueSetter modules. -We'll cover this macro in more detail in the next section. - -```rust -pub struct DemoAppRunner(pub DemoApp); - -#[cfg(feature = "native")] -impl StateTransitionRunner for DemoAppRunner { - type RuntimeConfig = Config; - type Inner = DemoApp; - - fn new(runtime_config: Self::RuntimeConfig) -> Self { - let storage = ProverStorage::with_config(runtime_config.storage) - .expect("Failed to open prover storage"); - let app = AppTemplate::new(storage, Runtime::new()); - Self(app) - } - // ... -} - -impl StateTransitionRunner for DemoAppRunner { - type RuntimeConfig = [u8; 32]; - type Inner = DemoApp; - - fn new(runtime_config: Self::RuntimeConfig) -> Self { - let storage = ZkStorage::with_config(runtime_config).expect("Failed to open zk storage"); - let app = AppTemplate::new(storage, Runtime::new()); - Self(app) - } - // ... -} -``` ## Wrapping Up From 460d82a533c7082e8efb42b7c9e8752a8ef248c6 Mon Sep 17 00:00:00 2001 From: bkolad Date: Mon, 7 Aug 2023 14:46:59 +0200 Subject: [PATCH 4/9] Better docs --- examples/demo-stf/README.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/examples/demo-stf/README.md b/examples/demo-stf/README.md index a815e2a51..457244701 100644 --- a/examples/demo-stf/README.md +++ b/examples/demo-stf/README.md @@ -153,7 +153,7 @@ Your modules implement rpc methods via the `rpc_gen` macro, in order to enable t In the example above, you can see how to use the `expose_rpc` macro on the `native` `Runtime`. -## Make Full Node Itegrations Simpler with the State Transition Runner trait: +## Make Full Node Itegrations Simpler with the State Transition Runner: Now that we have an app, we want to be able to run it. For any custom state transition, your full node implementation is going to need a little customization. At the very least, you'll have to modify our `demo-rollup` example code @@ -164,17 +164,33 @@ To help you integrate with full node implementations, we provide standard tools required - just by implementing STF, you get the capability to integrate with DA layers and ZKVMs. But, using these structures makes you more compatible with full node implementations out of the box. -### Implementing State Transition Runner +### Using State Transition Runner The State Transition Runner struct contains logic related to initialization and running the rollup. It has just three methods: -1. `new` - which allows us to instantiate a state transition function using a `RuntimeConfig` specific to the particular execution mode. - For example, when you're running a prover you likely want to configure a standard RocksDB instance - but in ZK mode, you have to - set up your STF to read from a Merkle tree instead. Using STR, we can easily swap out this configuration. +1. `new` - which consumes all the dependencies need for running the rollup. 2. `run` - which runs the rollup. 3. `start_rpc_server` - which exposes an RPC server. +```rust +let mut app: App = + App::new(rollup_config.runner.storage.clone()); +... +let mut runner = StateTransitionRunner::new( + rollup_config, + da_service, + ledger_db, + app.stf, + storage.is_empty(), + genesis_config, +)?; + +runner.start_rpc_server(methods).await; +runner.run().await?; + +``` + ## Wrapping Up Whew, that was a lot of information. To recap, implementing your own state transition function is as simple as plugging From 0a0794e72374d8f66bf4aeea2d740d0b383b7dae Mon Sep 17 00:00:00 2001 From: bkolad Date: Mon, 7 Aug 2023 14:48:20 +0200 Subject: [PATCH 5/9] Ignore send_tx_test_to_eth test --- .../module-implementations/sov-evm/src/tests/tx_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-system/module-implementations/sov-evm/src/tests/tx_tests.rs b/module-system/module-implementations/sov-evm/src/tests/tx_tests.rs index dab82e3f9..e8221dc5b 100644 --- a/module-system/module-implementations/sov-evm/src/tests/tx_tests.rs +++ b/module-system/module-implementations/sov-evm/src/tests/tx_tests.rs @@ -151,7 +151,7 @@ impl TestClient { } // TODO enable in CI -//#[ignore] +#[ignore] #[tokio::test] async fn send_tx_test_to_eth() -> Result<(), Box> { let chain_id: u64 = 1; From c9671077ecc0f4710b9332b123c62a1cf6146616 Mon Sep 17 00:00:00 2001 From: bkolad Date: Mon, 7 Aug 2023 14:53:31 +0200 Subject: [PATCH 6/9] Update docs --- examples/demo-rollup/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/demo-rollup/README.md b/examples/demo-rollup/README.md index f87fee8bf..539f3edf0 100644 --- a/examples/demo-rollup/README.md +++ b/examples/demo-rollup/README.md @@ -381,8 +381,6 @@ The next step is to initialize your state transition function. ```rust let mut app: App = App::new(config); - - app.start_rpc_server(..) ``` From 25f7657ed87cdb85e83e4319f9276726aaf3ac91 Mon Sep 17 00:00:00 2001 From: bkolad Date: Mon, 7 Aug 2023 15:21:03 +0200 Subject: [PATCH 7/9] change socket_address to listen_address --- full-node/sov-stf-runner/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/full-node/sov-stf-runner/src/lib.rs b/full-node/sov-stf-runner/src/lib.rs index 03fd45515..5f4b64143 100644 --- a/full-node/sov-stf-runner/src/lib.rs +++ b/full-node/sov-stf-runner/src/lib.rs @@ -41,7 +41,7 @@ where app: ST, ledger_db: LedgerDB, state_root: StateRoot, - socket_address: SocketAddr, + listen_address: SocketAddr, } impl StateTransitionRunner @@ -77,7 +77,7 @@ where res.state_root }; - let socket_address = SocketAddr::new(rpc_config.bind_host.parse()?, rpc_config.bind_port); + let listen_address = SocketAddr::new(rpc_config.bind_host.parse()?, rpc_config.bind_port); // Start the main rollup loop let item_numbers = ledger_db.get_next_items_numbers(); @@ -90,16 +90,16 @@ where app, ledger_db, state_root: prev_state_root, - socket_address, + listen_address, }) } /// Starts an rpc server with provided rpc methods. pub async fn start_rpc_server(&self, methods: RpcModule<()>) { - let socket_address = self.socket_address; + let listen_address = self.listen_address; let _handle = tokio::spawn(async move { let server = jsonrpsee::server::ServerBuilder::default() - .build([socket_address].as_ref()) + .build([listen_address].as_ref()) .await .unwrap(); From 65d0fc2555b9e2d53fcf75ee7261a360dffeda32 Mon Sep 17 00:00:00 2001 From: bkolad Date: Mon, 7 Aug 2023 17:36:50 +0200 Subject: [PATCH 8/9] addressing code review comments --- examples/demo-rollup/rollup_config.toml | 2 +- module-system/sov-modules-stf-template/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/demo-rollup/rollup_config.toml b/examples/demo-rollup/rollup_config.toml index aa75b9539..73fd49c4d 100644 --- a/examples/demo-rollup/rollup_config.toml +++ b/examples/demo-rollup/rollup_config.toml @@ -4,7 +4,7 @@ start_height = 1 [da] # The JWT used to authenticate with the celestia light client. Instructions for generating this token can be found in the README -celestia_rpc_auth_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJwdWJsaWMiLCJyZWFkIiwid3JpdGUiLCJhZG1pbiJdfQ.joa9EBtLIr9FNdl62jDZmEDmXIxsPtw1zkuenL784uE" +celestia_rpc_auth_token = "MY.SECRET.TOKEN" # The address of the *trusted* Celestia light client to interact with celestia_rpc_address = "http://127.0.0.1:26658" # The largest response the rollup will accept from the Celestia node. Defaults to 100 MB diff --git a/module-system/sov-modules-stf-template/src/lib.rs b/module-system/sov-modules-stf-template/src/lib.rs index e620d57d3..cf5c1f3cd 100644 --- a/module-system/sov-modules-stf-template/src/lib.rs +++ b/module-system/sov-modules-stf-template/src/lib.rs @@ -15,7 +15,7 @@ use sov_state::{StateCheckpoint, Storage}; use tracing::info; pub use tx_verifier::RawTx; -///TODO +/// This trait has to be implemented by a runtime in order to be used in `AppTemplate`. pub trait Runtime: DispatchCall + Genesis From 8896c433499d3cab34eb2492ab5cd981201e2926 Mon Sep 17 00:00:00 2001 From: bkolad Date: Mon, 7 Aug 2023 17:53:05 +0200 Subject: [PATCH 9/9] rename is_storage_empty to should_init_chain --- full-node/sov-stf-runner/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/full-node/sov-stf-runner/src/lib.rs b/full-node/sov-stf-runner/src/lib.rs index 5f4b64143..173e2cccf 100644 --- a/full-node/sov-stf-runner/src/lib.rs +++ b/full-node/sov-stf-runner/src/lib.rs @@ -56,14 +56,14 @@ where da_service: DA, ledger_db: LedgerDB, mut app: ST, - is_storage_empty: bool, + should_init_chain: bool, genesis_config: InitialState, ) -> Result { let rpc_config = rollup_config.rpc_config; let prev_state_root = { // Check if the rollup has previously been initialized - if is_storage_empty { + if should_init_chain { info!("No history detected. Initializing chain..."); app.init_chain(genesis_config); info!("Chain initialization is done.");