From 05f5c71bc87351878d2835fce5e782f2f6df9479 Mon Sep 17 00:00:00 2001 From: Blazej Kolad Date: Sat, 1 Apr 2023 18:16:36 +0200 Subject: [PATCH] Remove `stf.rs` and use `sov-app-template` instead. (#5) --- Cargo.lock | 51 +++++---- Cargo.toml | 17 +-- src/batch.rs | 41 ------- src/context.rs | 59 ---------- src/helpers.rs | 9 +- src/main.rs | 25 +++-- src/stf.rs | 152 -------------------------- src/{tx_hooks.rs => tx_hooks_impl.rs} | 41 +++---- src/tx_verifier.rs | 80 -------------- src/tx_verifier_impl.rs | 56 ++++++++++ 10 files changed, 133 insertions(+), 398 deletions(-) delete mode 100644 src/batch.rs delete mode 100644 src/context.rs delete mode 100644 src/stf.rs rename src/{tx_hooks.rs => tx_hooks_impl.rs} (67%) delete mode 100644 src/tx_verifier.rs create mode 100644 src/tx_verifier_impl.rs diff --git a/Cargo.lock b/Cargo.lock index a531306..c32c1fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 3 [[package]] name = "accounts" version = "0.1.0" -source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=3f21032e7414400587f734abdefa3fd9c6081b25#3f21032e7414400587f734abdefa3fd9c6081b25" +source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=bfdb58159ff9215a84aa60b9a4d3ce1f32136597#bfdb58159ff9215a84aa60b9a4d3ce1f32136597" dependencies = [ "anyhow", "borsh", @@ -21,11 +21,11 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.3" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "cfg-if", + "getrandom", "once_cell", "version_check", ] @@ -150,7 +150,7 @@ source = "git+https://github.com/preston-evans98/borsh-rs.git?branch=release-2#e dependencies = [ "borsh-derive", "bytes", - "hashbrown 0.13.2", + "hashbrown", ] [[package]] @@ -349,7 +349,7 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "election" version = "0.1.0" -source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=3f21032e7414400587f734abdefa3fd9c6081b25#3f21032e7414400587f734abdefa3fd9c6081b25" +source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=bfdb58159ff9215a84aa60b9a4d3ce1f32136597#bfdb58159ff9215a84aa60b9a4d3ce1f32136597" dependencies = [ "anyhow", "borsh", @@ -415,7 +415,7 @@ dependencies = [ [[package]] name = "first-read-last-write-cache" version = "0.1.0" -source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=3f21032e7414400587f734abdefa3fd9c6081b25#3f21032e7414400587f734abdefa3fd9c6081b25" +source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=bfdb58159ff9215a84aa60b9a4d3ce1f32136597#bfdb58159ff9215a84aa60b9a4d3ce1f32136597" dependencies = [ "thiserror", ] @@ -587,12 +587,6 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ "ahash", ] @@ -723,7 +717,7 @@ dependencies = [ [[package]] name = "ics23" version = "0.9.0" -source = "git+https://github.com/penumbra-zone/ics23?branch=compare-prehashed-keys#603f973b37c557d2bb843ad96b37823a71672cd6" +source = "git+https://github.com/penumbra-zone/ics23?branch=compare-prehashed-keys#cc3a76dbe6e56340d3e10c63d1c32ce5afa2db48" dependencies = [ "anyhow", "bytes", @@ -757,7 +751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown 0.12.3", + "hashbrown", ] [[package]] @@ -910,7 +904,6 @@ dependencies = [ [[package]] name = "jupiter" version = "0.1.0" -source = "git+https://github.com/Sovereign-Labs/Jupiter.git?rev=43b3b4ce86ad0fa2a925e590275c68f7e4483438#43b3b4ce86ad0fa2a925e590275c68f7e4483438" dependencies = [ "anyhow", "base64 0.13.1", @@ -1684,7 +1677,7 @@ dependencies = [ [[package]] name = "schemadb" version = "0.1.0" -source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=3f21032e7414400587f734abdefa3fd9c6081b25#3f21032e7414400587f734abdefa3fd9c6081b25" +source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=bfdb58159ff9215a84aa60b9a4d3ce1f32136597#bfdb58159ff9215a84aa60b9a4d3ce1f32136597" dependencies = [ "anyhow", "byteorder", @@ -1898,6 +1891,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "sov-app-template" +version = "0.1.0" +source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=bfdb58159ff9215a84aa60b9a4d3ce1f32136597#bfdb58159ff9215a84aa60b9a4d3ce1f32136597" +dependencies = [ + "anyhow", + "borsh", + "sov-modules-api", + "sov-state", + "sovereign-db", + "sovereign-sdk", +] + [[package]] name = "sov-demo" version = "0.1.0" @@ -1911,6 +1917,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.6", + "sov-app-template", "sov-modules-api", "sov-modules-macros", "sov-state", @@ -1924,7 +1931,7 @@ dependencies = [ [[package]] name = "sov-modules-api" version = "0.1.0" -source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=3f21032e7414400587f734abdefa3fd9c6081b25#3f21032e7414400587f734abdefa3fd9c6081b25" +source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=bfdb58159ff9215a84aa60b9a4d3ce1f32136597#bfdb58159ff9215a84aa60b9a4d3ce1f32136597" dependencies = [ "anyhow", "borsh", @@ -1938,7 +1945,7 @@ dependencies = [ [[package]] name = "sov-modules-macros" version = "0.1.0" -source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=3f21032e7414400587f734abdefa3fd9c6081b25#3f21032e7414400587f734abdefa3fd9c6081b25" +source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=bfdb58159ff9215a84aa60b9a4d3ce1f32136597#bfdb58159ff9215a84aa60b9a4d3ce1f32136597" dependencies = [ "anyhow", "borsh", @@ -1952,7 +1959,7 @@ dependencies = [ [[package]] name = "sov-state" version = "0.1.0" -source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=3f21032e7414400587f734abdefa3fd9c6081b25#3f21032e7414400587f734abdefa3fd9c6081b25" +source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=bfdb58159ff9215a84aa60b9a4d3ce1f32136597#bfdb58159ff9215a84aa60b9a4d3ce1f32136597" dependencies = [ "anyhow", "borsh", @@ -1968,7 +1975,7 @@ dependencies = [ [[package]] name = "sovereign-db" version = "0.1.0" -source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=3f21032e7414400587f734abdefa3fd9c6081b25#3f21032e7414400587f734abdefa3fd9c6081b25" +source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=bfdb58159ff9215a84aa60b9a4d3ce1f32136597#bfdb58159ff9215a84aa60b9a4d3ce1f32136597" dependencies = [ "anyhow", "borsh", @@ -1982,7 +1989,7 @@ dependencies = [ [[package]] name = "sovereign-sdk" version = "0.1.0" -source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=3f21032e7414400587f734abdefa3fd9c6081b25#3f21032e7414400587f734abdefa3fd9c6081b25" +source = "git+https://github.com/Sovereign-Labs/sovereign.git?rev=bfdb58159ff9215a84aa60b9a4d3ce1f32136597#bfdb58159ff9215a84aa60b9a4d3ce1f32136597" dependencies = [ "anyhow", "borsh", diff --git a/Cargo.toml b/Cargo.toml index 9ee70ec..aa18d2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,14 +12,15 @@ tokio = { version = "1", features = ["full"] } serde = { version = "1", features = ["derive"] } serde_json = "1" sha2 = "0.10.6" -jupiter = { git = "https://github.com/Sovereign-Labs/Jupiter.git", rev = "43b3b4ce86ad0fa2a925e590275c68f7e4483438" } -accounts = { git = "https://github.com/Sovereign-Labs/sovereign.git", rev = "3f21032e7414400587f734abdefa3fd9c6081b25" } -election = { git = "https://github.com/Sovereign-Labs/sovereign.git", rev = "3f21032e7414400587f734abdefa3fd9c6081b25" } -sovereign-sdk = { git = "https://github.com/Sovereign-Labs/sovereign.git", rev = "3f21032e7414400587f734abdefa3fd9c6081b25" } -sov-state = { git = "https://github.com/Sovereign-Labs/sovereign.git", features = ["temp"], rev = "3f21032e7414400587f734abdefa3fd9c6081b25" } -sov-modules-api = { git = "https://github.com/Sovereign-Labs/sovereign.git", features = ["mocks"], rev = "3f21032e7414400587f734abdefa3fd9c6081b25" } -sov-modules-macros = { git = "https://github.com/Sovereign-Labs/sovereign.git", rev = "3f21032e7414400587f734abdefa3fd9c6081b25" } -sovereign-db = { git = "https://github.com/Sovereign-Labs/sovereign.git", features = ["temp"], rev = "3f21032e7414400587f734abdefa3fd9c6081b25" } +jupiter = { path ="../Jupiter"} +sov-app-template = { git = "https://github.com/Sovereign-Labs/sovereign.git", rev = "bfdb58159ff9215a84aa60b9a4d3ce1f32136597" } +accounts = { git = "https://github.com/Sovereign-Labs/sovereign.git", rev = "bfdb58159ff9215a84aa60b9a4d3ce1f32136597" } +election = { git = "https://github.com/Sovereign-Labs/sovereign.git", rev = "bfdb58159ff9215a84aa60b9a4d3ce1f32136597" } +sovereign-sdk = { git = "https://github.com/Sovereign-Labs/sovereign.git", rev = "bfdb58159ff9215a84aa60b9a4d3ce1f32136597" } +sov-state = { git = "https://github.com/Sovereign-Labs/sovereign.git", features = ["temp"], rev = "bfdb58159ff9215a84aa60b9a4d3ce1f32136597" } +sov-modules-api = { git = "https://github.com/Sovereign-Labs/sovereign.git", features = ["mocks"], rev = "bfdb58159ff9215a84aa60b9a4d3ce1f32136597" } +sov-modules-macros = { git = "https://github.com/Sovereign-Labs/sovereign.git", rev = "bfdb58159ff9215a84aa60b9a4d3ce1f32136597" } +sovereign-db = { git = "https://github.com/Sovereign-Labs/sovereign.git", features = ["temp"], rev = "bfdb58159ff9215a84aa60b9a4d3ce1f32136597" } tracing = "0.1.37" tracing-subscriber = "0.3.16" diff --git a/src/batch.rs b/src/batch.rs deleted file mode 100644 index 412c69e..0000000 --- a/src/batch.rs +++ /dev/null @@ -1,41 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; - -// Items that should go in prelude -use jmt::SimpleHasher; -use sov_modules_api::{mocks::MockContext, Spec}; - -use sovereign_sdk::{ - core::traits::{BatchTrait, CanonicalHash, TransactionTrait}, - jmt, -}; - -use crate::tx_verifier::RawTx; - -#[derive(Debug, PartialEq, BorshDeserialize, BorshSerialize, Clone)] -pub struct Batch { - pub txs: Vec, -} - -impl BatchTrait for Batch { - type Transaction = RawTx; - - fn transactions(&self) -> &[Self::Transaction] { - &self.txs - } - - fn take_transactions(self) -> Vec { - self.txs - } -} - -impl TransactionTrait for RawTx { - type Hash = [u8; 32]; -} - -impl CanonicalHash for RawTx { - type Output = [u8; 32]; - - fn hash(&self) -> Self::Output { - ::Hasher::hash(&self.data) - } -} diff --git a/src/context.rs b/src/context.rs deleted file mode 100644 index 9ce8b10..0000000 --- a/src/context.rs +++ /dev/null @@ -1,59 +0,0 @@ -use anyhow::bail; -use sov_modules_api::{ - mocks::{MockPublicKey, MockSignature}, - AddressTrait, Context, Spec, -}; -use sov_state::{mocks::MockStorageSpec, ProverStorage}; -use sovereign_sdk::core::types::ArrayWitness; - -/// Context for the demo rollup. -#[derive(Clone, Debug, PartialEq)] -pub struct DemoContext { - pub sender: Address, -} - -impl Spec for DemoContext { - type Address = Address; - type Storage = ProverStorage; - type Hasher = sha2::Sha256; - type PublicKey = MockPublicKey; - type Signature = MockSignature; - type Witness = ArrayWitness; -} - -impl Context for DemoContext { - fn sender(&self) -> &Self::Address { - &self.sender - } - - fn new(sender: Self::Address) -> Self { - Self { sender } - } -} - -impl AddressTrait for Address {} - -/// Default implementation of AddressTrait for the module system -#[derive(borsh::BorshDeserialize, borsh::BorshSerialize, Debug, PartialEq, Clone, Eq)] -pub struct Address { - addr: [u8; 32], -} - -impl<'a> TryFrom<&'a [u8]> for Address { - type Error = anyhow::Error; - - fn try_from(addr: &'a [u8]) -> Result { - if addr.len() != 32 { - bail!("Address must be 32 bytes long"); - } - let mut addr_bytes = [0u8; 32]; - addr_bytes.copy_from_slice(&addr); - Ok(Self { addr: addr_bytes }) - } -} - -impl AsRef<[u8]> for Address { - fn as_ref(&self) -> &[u8] { - self.addr.as_ref() - } -} diff --git a/src/helpers.rs b/src/helpers.rs index a56c3df..10b9015 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,14 +1,13 @@ -use sov_modules_api::DispatchQuery; +use sov_modules_api::{mocks::MockContext, DispatchQuery}; use sov_state::{mocks::MockStorageSpec, ProverStorage, WorkingSet}; -use crate::{context::DemoContext, runtime::Runtime}; - +use crate::runtime::Runtime; pub(crate) fn run_query( - runtime: &mut Runtime, + runtime: &mut Runtime, query: Vec, storage: ProverStorage, ) -> String { - let module = Runtime::::decode_query(&query).unwrap(); + let module = Runtime::::decode_query(&query).unwrap(); let query_response = runtime.dispatch_query(module, &mut WorkingSet::new(storage)); String::from_utf8(query_response.response).unwrap() diff --git a/src/main.rs b/src/main.rs index c427133..11922cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ -use batch::Batch; -use context::DemoContext; use jsonrpsee::http_client::HeaderMap; use jupiter::{ da_app::{CelestiaApp, TmHash}, da_service::{CelestiaService, FilteredCelestiaBlock}, }; use sha2::{Digest, Sha256}; +use sov_app_template::{AppTemplate, Batch}; +use sov_modules_api::mocks::MockContext; use sov_state::ProverStorage; use sovereign_db::{ ledger_db::{LedgerDB, SlotCommitBuilder}, @@ -21,24 +21,23 @@ use sovereign_sdk::{ }; use sovereign_sdk::{da::DaLayerTrait, stf::StateTransitionFunction}; use sovereign_sdk::{db::SlotStore, serial::Decode}; -use stf::Demo; + use tracing::Level; -use tx_verifier::DemoAppTxVerifier; +use tx_verifier_impl::DemoAppTxVerifier; use crate::{ - data_generation::QueryGenerator, helpers::run_query, runtime::Runtime, tx_hooks::DemoAppTxHooks, + data_generation::QueryGenerator, helpers::run_query, runtime::Runtime, + tx_hooks_impl::DemoAppTxHooks, }; -mod batch; -mod context; + mod data_generation; mod helpers; mod runtime; -mod stf; -mod tx_hooks; -mod tx_verifier; +mod tx_hooks_impl; +mod tx_verifier_impl; -type C = DemoContext; -type DemoApp = Demo, Runtime, DemoAppTxHooks>; +type C = MockContext; +type DemoApp = AppTemplate, Runtime, DemoAppTxHooks>; const CELESTIA_NODE_AUTH_TOKEN: &'static str = ""; const START_HEIGHT: u64 = HEIGHT_OF_FIRST_TXS - 5; @@ -168,6 +167,7 @@ async fn main() -> Result<(), anyhow::Error> { } } } + demo.end_slot(); data_to_persist.slot_data = Some(StoredSlot { hash: DbHash::new(slot_hash.to_vec()), @@ -177,6 +177,7 @@ async fn main() -> Result<(), anyhow::Error> { }); item_numbers.batch_number += num_batches as u64; ledger_db.commit_slot(data_to_persist.finalize()?)?; + println!( "Current state: {}", run_query( diff --git a/src/stf.rs b/src/stf.rs deleted file mode 100644 index 95e1e5e..0000000 --- a/src/stf.rs +++ /dev/null @@ -1,152 +0,0 @@ -use crate::batch::Batch; - -use crate::tx_verifier::{RawTx, TxVerifier}; - -use sov_modules_api::{Context, DispatchCall, Genesis}; -use tracing::info; - -use crate::tx_hooks::TxHooks; -use sov_state::{Storage, WorkingSet}; -use sovereign_sdk::{ - core::{mocks::MockProof, traits::BatchTrait}, - jmt, - stf::{ConsensusSetUpdate, OpaqueAddress, StateTransitionFunction}, -}; - -pub(crate) struct Demo { - pub(crate) current_storage: C::Storage, - pub(crate) runtime: RT, - tx_verifier: V, - tx_hooks: H, - working_set: Option>, -} - -impl Demo { - pub(crate) fn new(storage: C::Storage, runtime: RT, tx_verifier: V, tx_hooks: H) -> Self { - Self { - runtime, - current_storage: storage, - tx_verifier, - tx_hooks, - working_set: None, - } - } -} - -impl StateTransitionFunction for Demo -where - V: TxVerifier, - RT: DispatchCall + Genesis, - H: TxHooks, -{ - type StateRoot = jmt::RootHash; - - type ChainParams = (); - - type Transaction = RawTx; - - type Batch = Batch; - - type Proof = MockProof; - - type MisbehaviorProof = (); - - fn init_chain(&mut self, _params: Self::ChainParams) { - let working_set = &mut WorkingSet::new(self.current_storage.clone()); - self.runtime - .genesis(working_set) - .expect("module initialization must succeed"); - let (log, witness) = working_set.freeze(); - self.current_storage - .validate_and_commit(log, &witness) - .expect("Storage update must succeed"); - } - - fn begin_slot(&mut self) { - self.working_set = Some(WorkingSet::new(self.current_storage.clone())); - } - - fn apply_batch( - &mut self, - batch: Self::Batch, - sequencer: &[u8], - _misbehavior_hint: Option, - ) -> Result< - Vec>, - sovereign_sdk::stf::ConsensusSetUpdate, - > { - let mut events = Vec::new(); - - // Run the stateless verification. - info!("Running stateless verification"); - let txs = self - .tx_verifier - .verify_txs_stateless(batch.take_transactions()) - .or(Err(ConsensusSetUpdate::slashing(sequencer)))?; - let mut batch_workspace = WorkingSet::new(self.current_storage.clone()); - - for tx in txs { - batch_workspace = batch_workspace.to_revertable(); - info!("Running pre-dispatch hook"); - // Run the stateful verification, possibly modifies the state. - let verified_tx = self - .tx_hooks - .pre_dispatch_tx_hook(tx, &mut batch_workspace) - .or(Err(ConsensusSetUpdate::slashing(sequencer)))?; - - info!("Dispatching call"); - if let Ok(msg) = RT::decode_call(&verified_tx.runtime_msg) { - info!("Decoded call"); - let ctx = C::new(verified_tx.sender.clone()); - info!("executing runtime call"); - let tx_result = self.runtime.dispatch_call(msg, &mut batch_workspace, &ctx); - - info!("executing post hook"); - self.tx_hooks - .post_dispatch_tx_hook(verified_tx, &mut batch_workspace); - - match tx_result { - Ok(resp) => { - events.push(resp.events); - batch_workspace = batch_workspace.commit(); - } - Err(e) => { - // Don't merge the tx workspace. TODO add tests for this scenario - batch_workspace.revert(); - panic!("Demo app txs must succeed but failed with err: {}", e) - } - } - } else { - info!("failed to decode call"); - // If the serialization is invalid, the sequencer is malicious. Slash them. - batch_workspace.revert(); - return Err(ConsensusSetUpdate::slashing(sequencer)); - } - } - self.working_set = Some(batch_workspace); - - Ok(events) - } - - fn apply_proof( - &self, - _proof: Self::Proof, - _prover: &[u8], - ) -> Result<(), sovereign_sdk::stf::ConsensusSetUpdate> { - todo!() - } - - fn end_slot( - &mut self, - ) -> ( - Self::StateRoot, - Vec>, - ) { - let (cache_log, witness) = self.working_set.take().unwrap().freeze(); - let root_hash = self - .current_storage - .validate_and_commit(cache_log, &witness) - .expect("tree update must succeed"); - (jmt::RootHash(root_hash), vec![]) - } -} diff --git a/src/tx_hooks.rs b/src/tx_hooks_impl.rs similarity index 67% rename from src/tx_hooks.rs rename to src/tx_hooks_impl.rs index 4ae5313..7839081 100644 --- a/src/tx_hooks.rs +++ b/src/tx_hooks_impl.rs @@ -1,24 +1,25 @@ -use crate::tx_verifier::{Transaction, VerifiedTx}; +use sov_app_template::{TxHooks, VerifiedTx}; use sov_modules_api::{Context, Spec}; use sov_state::WorkingSet; -/// TxHooks allows injecting custom logic into a transaction processing pipeline. -pub(crate) trait TxHooks { - type Context: Context; +use crate::tx_verifier_impl::Transaction; - /// pre_dispatch_tx_hook runs just before a transaction is dispatched to an appropriate module. - fn pre_dispatch_tx_hook( - &mut self, - tx: Transaction, - working_set: &mut WorkingSet<::Storage>, - ) -> anyhow::Result>; +pub(crate) struct AppVerifiedTx { + pub(crate) pub_key: C::PublicKey, + pub(crate) sender: C::Address, + pub(crate) runtime_msg: Vec, +} - /// post_dispatch_tx_hook runs after the tx is dispatched to an appropriate module. - fn post_dispatch_tx_hook( - &mut self, - tx: VerifiedTx, - working_set: &mut WorkingSet<::Storage>, - ); +impl VerifiedTx for AppVerifiedTx { + type Address = C::Address; + + fn sender(&self) -> &Self::Address { + &self.sender + } + + fn runtime_message(&self) -> &[u8] { + &self.runtime_msg + } } pub(crate) struct DemoAppTxHooks { @@ -35,15 +36,17 @@ impl DemoAppTxHooks { impl TxHooks for DemoAppTxHooks { type Context = C; + type Transaction = Transaction; + type VerifiedTx = AppVerifiedTx; fn pre_dispatch_tx_hook( &mut self, tx: Transaction, working_set: &mut WorkingSet<::Storage>, - ) -> anyhow::Result> { + ) -> anyhow::Result { let addr = self.check_nonce_for_address(tx.nonce, tx.pub_key.clone(), working_set)?; - Ok(VerifiedTx { + Ok(AppVerifiedTx { pub_key: tx.pub_key, sender: addr, runtime_msg: tx.runtime_msg, @@ -52,7 +55,7 @@ impl TxHooks for DemoAppTxHooks { fn post_dispatch_tx_hook( &mut self, - tx: VerifiedTx, + tx: Self::VerifiedTx, working_set: &mut WorkingSet<::Storage>, ) { self.accounts_hooks diff --git a/src/tx_verifier.rs b/src/tx_verifier.rs deleted file mode 100644 index 588fc89..0000000 --- a/src/tx_verifier.rs +++ /dev/null @@ -1,80 +0,0 @@ -use borsh::{BorshDeserialize, BorshSerialize}; -use sov_modules_api::{Context, Signature}; -use sovereign_sdk::jmt::SimpleHasher; -use sovereign_sdk::serial::Decode; -use std::{io::Cursor, marker::PhantomData}; - -/// RawTx represents a serialized rollup transaction received from the DA. -#[derive(Debug, PartialEq, BorshDeserialize, BorshSerialize, Clone)] -pub struct RawTx { - pub(crate) data: Vec, -} - -/// Transaction represents a deserialized RawTx. -#[derive(Debug, PartialEq, Eq, Clone, BorshDeserialize, BorshSerialize)] -pub struct Transaction { - pub signature: C::Signature, - pub pub_key: C::PublicKey, - pub runtime_msg: Vec, - pub nonce: u64, -} - -/// VerifiedTx is a Transaction after verification. -pub(crate) struct VerifiedTx { - pub(crate) pub_key: C::PublicKey, - pub(crate) sender: C::Address, - pub(crate) runtime_msg: Vec, -} - -/// TxVerifier encapsulates Transaction verification. -pub trait TxVerifier { - type Context: Context; - - /// Runs stateless checks against a single RawTx. - fn verify_tx_stateless(&self, raw_tx: RawTx) -> anyhow::Result>; - - /// Runs stateless checks against RawTxs. - fn verify_txs_stateless( - &self, - raw_txs: Vec, - ) -> anyhow::Result>> { - let mut txs = Vec::with_capacity(raw_txs.len()); - for raw_tx in raw_txs { - let tx = self.verify_tx_stateless(raw_tx)?; - txs.push(tx); - } - - Ok(txs) - } -} - -pub(crate) struct DemoAppTxVerifier { - // TODO add Accounts module for stateful checks. - _phantom: PhantomData, -} - -impl DemoAppTxVerifier { - pub fn new() -> Self { - Self { - _phantom: PhantomData, - } - } -} - -impl TxVerifier for DemoAppTxVerifier { - type Context = C; - fn verify_tx_stateless(&self, raw_tx: RawTx) -> anyhow::Result> { - let mut data = Cursor::new(&raw_tx.data); - let tx = Transaction::::decode(&mut data)?; - - // We check signature against runtime_msg and nonce. - let mut hasher = C::Hasher::new(); - hasher.update(&tx.runtime_msg); - hasher.update(&tx.nonce.to_le_bytes()); - let msg_hash = hasher.finalize(); - - tx.signature.verify(&tx.pub_key, msg_hash)?; - - Ok(tx) - } -} diff --git a/src/tx_verifier_impl.rs b/src/tx_verifier_impl.rs new file mode 100644 index 0000000..4434df7 --- /dev/null +++ b/src/tx_verifier_impl.rs @@ -0,0 +1,56 @@ +use sov_app_template::{RawTx, TxVerifier}; +use sov_modules_api::{Context, Signature}; +use sovereign_sdk::jmt::SimpleHasher; +use sovereign_sdk::serial::Decode; +use std::{io::Cursor, marker::PhantomData}; + +/// Transaction represents a deserialized RawTx. +#[derive(Debug, PartialEq, Eq, Clone, borsh::BorshDeserialize, borsh::BorshSerialize)] +pub(crate) struct Transaction { + pub(crate) signature: C::Signature, + pub(crate) pub_key: C::PublicKey, + pub(crate) runtime_msg: Vec, + pub(crate) nonce: u64, +} + +impl Transaction { + pub fn new(msg: Vec, pub_key: C::PublicKey, signature: C::Signature, nonce: u64) -> Self { + Self { + signature, + runtime_msg: msg, + pub_key, + nonce, + } + } +} + +pub(crate) struct DemoAppTxVerifier { + _phantom: PhantomData, +} + +impl DemoAppTxVerifier { + pub fn new() -> Self { + Self { + _phantom: PhantomData, + } + } +} + +impl TxVerifier for DemoAppTxVerifier { + type Transaction = Transaction; + + fn verify_tx_stateless(&self, raw_tx: RawTx) -> anyhow::Result { + let mut data = Cursor::new(&raw_tx.data); + let tx = Transaction::::decode(&mut data)?; + + // We check signature against runtime_msg and nonce. + let mut hasher = C::Hasher::new(); + hasher.update(&tx.runtime_msg); + hasher.update(&tx.nonce.to_le_bytes()); + let msg_hash = hasher.finalize(); + + tx.signature.verify(&tx.pub_key, msg_hash)?; + + Ok(tx) + } +}