diff --git a/Cargo.lock b/Cargo.lock index 6c3c2e93dc..7433e279f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -463,6 +463,16 @@ dependencies = [ "serde", ] +[[package]] +name = "bcs" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd3ffe8b19a604421a5d461d4a70346223e535903fbc3067138bddbebddcf77" +dependencies = [ + "serde", + "thiserror", +] + [[package]] name = "bech32" version = "0.7.3" @@ -7019,6 +7029,7 @@ name = "sov-state" version = "0.1.0" dependencies = [ "anyhow", + "bcs", "borsh", "hex", "jmt", diff --git a/Cargo.toml b/Cargo.toml index 0285772e35..0b443de753 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ borsh = { version = "0.10.3", features = ["rc", "bytes"] } # TODO: Consider replacing this serialization format # https://github.com/Sovereign-Labs/sovereign-sdk/issues/283 bincode = "1.3.3" +bcs = "0.1.5" byteorder = "1.4.3" bytes = "1.2.1" hex = "0.4.3" @@ -75,7 +76,7 @@ proptest-derive = "0.3.0" rand = "0.8" rayon = "1.5.2" rocksdb = { version = "0.21.0", features = ["lz4"] } -serde = { version = "1.0.185", features = ["derive", "rc"] } +serde = { version = "1.0.185", features = ["derive", "rc"]} serde_json = { version = "1.0" } sha2 = "0.10.6" digest = "0.10.6" diff --git a/module-system/module-implementations/sov-evm/src/call.rs b/module-system/module-implementations/sov-evm/src/call.rs index 3917115e19..06729fab85 100644 --- a/module-system/module-implementations/sov-evm/src/call.rs +++ b/module-system/module-implementations/sov-evm/src/call.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use ethers_core::types::{OtherFields, TransactionReceipt}; use revm::primitives::{CfgEnv, U256}; use sov_modules_api::CallResponse; use sov_state::WorkingSet; @@ -8,7 +9,7 @@ use crate::evm::executor::{self}; use crate::evm::transaction::{BlockEnv, EvmTransactionSignedEcRecovered}; use crate::evm::{contract_address, EvmChainCfg, RawEvmTransaction}; use crate::experimental::SpecIdWrapper; -use crate::{Evm, TransactionReceipt}; +use crate::Evm; #[cfg_attr( feature = "native", @@ -46,24 +47,30 @@ impl Evm { let receipt = TransactionReceipt { transaction_hash: hash.into(), // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 - transaction_index: 0, + transaction_index: 0u64.into(), // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 block_hash: Default::default(), // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 - block_number: Some(0), + block_number: Some(0u64.into()), from: evm_tx_recovered.signer().into(), - to: evm_tx_recovered.to(), + to: evm_tx_recovered.to().map(|to| to.into()), // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 cumulative_gas_used: Default::default(), // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 gas_used: Default::default(), contract_address: contract_address(result).map(|addr| addr.into()), // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 - status: Some(1), + status: Some(1u64.into()), root: Default::default(), // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 - transaction_type: Some(1), + transaction_type: Some(1u64.into()), effective_gas_price: Default::default(), + // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 + logs_bloom: Default::default(), + // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 + other: OtherFields::default(), + // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 + logs: Default::default(), }; self.receipts diff --git a/module-system/module-implementations/sov-evm/src/lib.rs b/module-system/module-implementations/sov-evm/src/lib.rs index 1968bab7fd..ef1f0c3b60 100644 --- a/module-system/module-implementations/sov-evm/src/lib.rs +++ b/module-system/module-implementations/sov-evm/src/lib.rs @@ -8,15 +8,11 @@ pub mod genesis; #[cfg(feature = "experimental")] pub mod query; #[cfg(feature = "experimental")] -mod receipt; -#[cfg(feature = "experimental")] #[cfg(test)] mod tests; #[cfg(feature = "experimental")] pub use experimental::{AccountData, Evm, EvmConfig, SpecIdWrapper}; #[cfg(feature = "experimental")] -pub use receipt::TransactionReceipt; -#[cfg(feature = "experimental")] pub use revm::primitives::SpecId; #[cfg(feature = "experimental")] @@ -24,6 +20,7 @@ mod experimental { use std::collections::HashMap; use derive_more::{From, Into}; + use ethers::types::TransactionReceipt; use revm::primitives::{SpecId, KECCAK_EMPTY, U256}; use sov_modules_api::{Error, ModuleInfo}; use sov_state::WorkingSet; @@ -32,8 +29,6 @@ mod experimental { use super::evm::transaction::BlockEnv; use super::evm::{DbAccount, EthAddress}; use crate::evm::{Bytes32, EvmChainCfg, RawEvmTransaction}; - use crate::TransactionReceipt; - #[derive(Clone, Debug)] pub struct AccountData { pub address: EthAddress, @@ -92,7 +87,11 @@ mod experimental { pub(crate) transactions: sov_state::StateMap, #[state] - pub(crate) receipts: sov_state::StateMap, + pub(crate) receipts: sov_state::StateMap< + ethereum_types::H256, + TransactionReceipt, + sov_state::codec::BcsCodec, + >, } impl sov_modules_api::Module for Evm { diff --git a/module-system/module-implementations/sov-evm/src/query.rs b/module-system/module-implementations/sov-evm/src/query.rs index d4b51ca001..cc0112d111 100644 --- a/module-system/module-implementations/sov-evm/src/query.rs +++ b/module-system/module-implementations/sov-evm/src/query.rs @@ -75,8 +75,9 @@ impl Evm { working_set: &mut WorkingSet, ) -> RpcResult> { info!("evm module: eth_getTransactionReceipt"); - let receipt = self.receipts.get(hash.as_fixed_bytes(), working_set); - Ok(receipt.map(|r| r.into())) + + let receipt = self.receipts.get(&hash, working_set); + Ok(receipt) } //https://github.com/paradigmxyz/reth/blob/f577e147807a783438a3f16aad968b4396274483/crates/rpc/rpc/src/eth/api/transactions.rs#L502 diff --git a/module-system/module-implementations/sov-evm/src/receipt.rs b/module-system/module-implementations/sov-evm/src/receipt.rs deleted file mode 100644 index 67d1a48e53..0000000000 --- a/module-system/module-implementations/sov-evm/src/receipt.rs +++ /dev/null @@ -1,64 +0,0 @@ -use ethers_core::types::transaction::response; -use ethers_core::types::OtherFields; - -use crate::evm::{Bytes32, EthAddress}; - -#[derive(borsh::BorshDeserialize, borsh::BorshSerialize, Debug, PartialEq, Clone)] -pub struct TransactionReceipt { - /// Transaction hash. - pub transaction_hash: Bytes32, - /// Index within the block. - pub transaction_index: u64, - /// Hash of the block this transaction was included within. - pub block_hash: Option, - /// Number of the block this transaction was included within. - pub block_number: Option, - /// address of the sender. - pub from: EthAddress, - // address of the receiver. null when its a contract creation transaction. - pub to: Option, - /// Cumulative gas used within the block after this was executed. - pub cumulative_gas_used: Bytes32, - pub gas_used: Bytes32, - pub contract_address: Option, - // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 - // pub logs: Vec, - // Status: either 1 (success) or 0 (failure). Only present after activation of [EIP-658](https://eips.ethereum.org/EIPS/eip-658) - pub status: Option, - /// State root. Only present before activation of [EIP-658](https://eips.ethereum.org/EIPS/eip-658) - pub root: Option, - // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 - // Logs bloom - // pub logs_bloom: Bloom, - /// Transaction type, Some(1) for AccessList transaction, None for Legacy - pub transaction_type: Option, - /// The price paid post-execution by the transaction (i.e. base fee + priority fee). - /// Both fields in 1559-style transactions are *maximums* (max fee + max priority fee), the - /// amount that's actually paid by users can only be determined post-execution - pub effective_gas_price: Option, -} - -impl From for response::TransactionReceipt { - fn from(receipt: TransactionReceipt) -> Self { - Self { - transaction_hash: receipt.transaction_hash.into(), - transaction_index: receipt.transaction_index.into(), - block_hash: receipt.block_hash.map(|hash| hash.into()), - block_number: receipt.block_number.map(|bn| bn.into()), - from: receipt.from.into(), - to: receipt.to.map(|to| to.into()), - cumulative_gas_used: receipt.cumulative_gas_used.into(), - gas_used: Some(receipt.gas_used.into()), - contract_address: receipt.contract_address.map(|addr| addr.into()), - // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 - logs: Default::default(), - status: receipt.status.map(|s| s.into()), - root: receipt.root.map(|r| r.into()), - // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/504 - logs_bloom: Default::default(), - transaction_type: receipt.transaction_type.map(|t| t.into()), - effective_gas_price: receipt.effective_gas_price.map(|p| p.into()), - other: OtherFields::default(), - } - } -} diff --git a/module-system/sov-state/Cargo.toml b/module-system/sov-state/Cargo.toml index b1b5e800b1..65575f77f0 100644 --- a/module-system/sov-state/Cargo.toml +++ b/module-system/sov-state/Cargo.toml @@ -14,6 +14,7 @@ resolver = "2" [dependencies] anyhow = { workspace = true } borsh = { workspace = true } +bcs = { workspace = true } serde = { workspace = true } thiserror = { workspace = true } sov-rollup-interface = { path = "../../rollup-interface", version = "0.1" } diff --git a/module-system/sov-state/src/borsh_codec.rs b/module-system/sov-state/src/borsh_codec.rs new file mode 100644 index 0000000000..20e139d35e --- /dev/null +++ b/module-system/sov-state/src/borsh_codec.rs @@ -0,0 +1,35 @@ +use crate::codec::{StateKeyCodec, StateValueCodec}; + +/// A [`StateCodec`] that uses [`borsh`] for all keys and values. +#[derive(Debug, Default, PartialEq, Eq, Clone, borsh::BorshDeserialize, borsh::BorshSerialize)] +pub struct BorshCodec; + +impl StateKeyCodec for BorshCodec +where + K: borsh::BorshSerialize + borsh::BorshDeserialize, +{ + type KeyError = std::io::Error; + + fn encode_key(&self, key: &K) -> Vec { + key.try_to_vec().expect("Failed to serialize key") + } + + fn try_decode_key(&self, bytes: &[u8]) -> Result { + K::try_from_slice(bytes) + } +} + +impl StateValueCodec for BorshCodec +where + V: borsh::BorshSerialize + borsh::BorshDeserialize, +{ + type ValueError = std::io::Error; + + fn encode_value(&self, value: &V) -> Vec { + value.try_to_vec().expect("Failed to serialize value") + } + + fn try_decode_value(&self, bytes: &[u8]) -> Result { + V::try_from_slice(bytes) + } +} diff --git a/module-system/sov-state/src/codec/bcs_codec.rs b/module-system/sov-state/src/codec/bcs_codec.rs new file mode 100644 index 0000000000..2a8fc467f8 --- /dev/null +++ b/module-system/sov-state/src/codec/bcs_codec.rs @@ -0,0 +1,20 @@ +use crate::codec::StateValueCodec; + +/// A [`StateCodec`] that uses [`bcs`] for all keys and values. +#[derive(Debug, Default, PartialEq, Eq, Clone)] +pub struct BcsCodec; + +impl StateValueCodec for BcsCodec +where + V: serde::Serialize + for<'a> serde::Deserialize<'a>, +{ + type Error = bcs::Error; + + fn encode_value(&self, value: &V) -> Vec { + bcs::to_bytes(value).expect("Failed to serialize key") + } + + fn try_decode_value(&self, bytes: &[u8]) -> Result { + bcs::from_bytes(bytes) + } +} diff --git a/module-system/sov-state/src/codec/borsh_codec.rs b/module-system/sov-state/src/codec/borsh_codec.rs new file mode 100644 index 0000000000..4647755dea --- /dev/null +++ b/module-system/sov-state/src/codec/borsh_codec.rs @@ -0,0 +1,20 @@ +use crate::codec::StateValueCodec; + +/// A [`StateValueCodec`] that uses [`borsh`] for all values. +#[derive(Debug, Default, PartialEq, Eq, Clone, borsh::BorshDeserialize, borsh::BorshSerialize)] +pub struct BorshCodec; + +impl StateValueCodec for BorshCodec +where + V: borsh::BorshSerialize + borsh::BorshDeserialize, +{ + type Error = std::io::Error; + + fn encode_value(&self, value: &V) -> Vec { + value.try_to_vec().expect("Failed to serialize value") + } + + fn try_decode_value(&self, bytes: &[u8]) -> Result { + V::try_from_slice(bytes) + } +} diff --git a/module-system/sov-state/src/codec.rs b/module-system/sov-state/src/codec/mod.rs similarity index 69% rename from module-system/sov-state/src/codec.rs rename to module-system/sov-state/src/codec/mod.rs index 755a238e38..cf3cfe91d4 100644 --- a/module-system/sov-state/src/codec.rs +++ b/module-system/sov-state/src/codec/mod.rs @@ -1,5 +1,11 @@ //! Serialization and deserialization -related logic. +mod bcs_codec; +mod borsh_codec; + +pub use bcs_codec::BcsCodec; +pub use borsh_codec::BorshCodec; + /// A trait for types that can serialize and deserialize values for storage /// access. pub trait StateValueCodec { @@ -34,22 +40,3 @@ pub trait StateValueCodec { .unwrap() } } - -/// A [`StateValueCodec`] that uses [`borsh`] for all values. -#[derive(Debug, Default, PartialEq, Eq, Clone, borsh::BorshDeserialize, borsh::BorshSerialize)] -pub struct BorshCodec; - -impl StateValueCodec for BorshCodec -where - V: borsh::BorshSerialize + borsh::BorshDeserialize, -{ - type Error = std::io::Error; - - fn encode_value(&self, value: &V) -> Vec { - value.try_to_vec().expect("Failed to serialize value") - } - - fn try_decode_value(&self, bytes: &[u8]) -> Result { - V::try_from_slice(bytes) - } -}