diff --git a/Cargo.lock b/Cargo.lock
index aaba2eec5fe3..b351a18ece36 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1255,6 +1255,39 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "antelope-client"
+version = "0.3.0"
+source = "git+https://github.com/telosnetwork/antelope-rs?branch=master#fea2203b2edb5cfcedd5365031e5286b47dc5c66"
+dependencies = [
+ "antelope-client-macros",
+ "async-trait",
+ "base64 0.21.7",
+ "bs58",
+ "chrono",
+ "digest 0.10.7",
+ "ecdsa",
+ "flate2",
+ "hex",
+ "hmac 0.12.1",
+ "k256",
+ "log",
+ "once_cell",
+ "p256",
+ "rand 0.8.5",
+ "rand_core 0.6.4",
+ "reqwest 0.11.27",
+ "ripemd",
+ "serde",
+ "serde-big-array",
+ "serde_json",
+ "sha2 0.10.8",
+ "signature",
+ "thiserror",
+ "tokio",
+ "tracing",
+]
+
[[package]]
name = "antelope-client-macros"
version = "0.2.0"
@@ -5539,7 +5572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
dependencies = [
"cfg-if",
- "windows-targets 0.52.6",
+ "windows-targets 0.48.5",
]
[[package]]
@@ -8755,6 +8788,7 @@ dependencies = [
"revm-primitives",
"secp256k1",
"serde_json",
+ "sha2 0.10.8",
]
[[package]]
@@ -9391,7 +9425,7 @@ dependencies = [
"alloy-signer-local",
"alloy-sol-types",
"alloy-transport-http 0.4.2",
- "antelope-client",
+ "antelope-client 0.3.0",
"clap",
"derive_more 1.0.0",
"env_logger 0.11.5",
@@ -9402,6 +9436,7 @@ dependencies = [
"reth-basic-payload-builder",
"reth-beacon-consensus",
"reth-chainspec",
+ "reth-db",
"reth-e2e-test-utils",
"reth-ethereum-engine-primitives",
"reth-ethereum-payload-builder",
@@ -9417,6 +9452,7 @@ dependencies = [
"reth-rpc",
"reth-stages",
"reth-telos-rpc",
+ "reth-telos-rpc-engine-api 1.0.8",
"reth-tracing",
"reth-transaction-pool",
"serde",
@@ -10556,6 +10592,7 @@ dependencies = [
"alloy-eips 0.4.2",
"alloy-primitives",
"alloy-rlp",
+ "alloy-rpc-types 0.4.2",
"alloy-serde 0.4.2",
"arbitrary",
"bytes",
@@ -10573,7 +10610,7 @@ dependencies = [
"alloy-network 0.4.2",
"alloy-primitives",
"alloy-rpc-types 0.4.2",
- "antelope-client",
+ "antelope-client 0.3.0",
"async-trait",
"derive_more 1.0.0",
"jsonrpsee-types",
@@ -10619,6 +10656,7 @@ dependencies = [
"revm",
"revm-primitives",
"serde",
+ "sha2 0.10.8",
"tracing",
]
@@ -10843,7 +10881,7 @@ dependencies = [
[[package]]
name = "revm"
version = "14.0.3"
-source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#af62c2673affaa39636744b2383c9e980aed754c"
+source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#1706d6bea3f2771e4603e827994038a8786d1256"
dependencies = [
"auto_impl",
"cfg-if",
@@ -10875,7 +10913,7 @@ dependencies = [
[[package]]
name = "revm-interpreter"
version = "10.0.3"
-source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#af62c2673affaa39636744b2383c9e980aed754c"
+source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#1706d6bea3f2771e4603e827994038a8786d1256"
dependencies = [
"revm-primitives",
"serde",
@@ -10884,7 +10922,7 @@ dependencies = [
[[package]]
name = "revm-precompile"
version = "11.0.3"
-source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#af62c2673affaa39636744b2383c9e980aed754c"
+source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#1706d6bea3f2771e4603e827994038a8786d1256"
dependencies = [
"aurora-engine-modexp",
"blst",
@@ -10903,7 +10941,7 @@ dependencies = [
[[package]]
name = "revm-primitives"
version = "10.0.0"
-source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#af62c2673affaa39636744b2383c9e980aed754c"
+source = "git+https://github.com/telosnetwork/telos-revm?branch=telos-main#1706d6bea3f2771e4603e827994038a8786d1256"
dependencies = [
"alloy-eip2930",
"alloy-eip7702",
@@ -12045,7 +12083,7 @@ dependencies = [
"alloy",
"alloy-consensus 0.3.6",
"alloy-rlp",
- "antelope-client",
+ "antelope-client 0.2.1",
"arrowbatch",
"base64 0.22.1",
"bytes",
@@ -12077,10 +12115,12 @@ dependencies = [
name = "telos-reth"
version = "1.0.8"
dependencies = [
+ "alloy-primitives",
"clap",
"reth",
"reth-chainspec",
"reth-cli-util",
+ "reth-db",
"reth-node-builder",
"reth-node-telos",
"reth-provider",
@@ -12097,7 +12137,7 @@ dependencies = [
"alloy-consensus 0.3.6",
"alloy-eips 0.3.6",
"alloy-rlp",
- "antelope-client",
+ "antelope-client 0.2.1",
"bytes",
"clap",
"dashmap 5.5.3",
@@ -13278,7 +13318,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys 0.48.0",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 710e36b25017..62025e2ea230 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -601,7 +601,7 @@ reth-node-telos = { path = "crates/telos/node" }
reth-telos-rpc = { path = "crates/telos/rpc" }
reth-telos-primitives-traits = { path = "crates/telos/primitives-traits" }
reth-telos-rpc-engine-api = { path = "crates/telos/rpc-engine-api" }
-antelope-client = { git = "https://github.com/telosnetwork/antelope-rs", branch = "development" }
+antelope-client = { git = "https://github.com/telosnetwork/antelope-rs", branch = "master" }
[patch.crates-io]
#alloy-consensus = { git = "https://github.com/alloy-rs/alloy", rev = "8c499409"}
diff --git a/crates/ethereum/evm/Cargo.toml b/crates/ethereum/evm/Cargo.toml
index 413a3e75411c..7a7989f8e05d 100644
--- a/crates/ethereum/evm/Cargo.toml
+++ b/crates/ethereum/evm/Cargo.toml
@@ -20,6 +20,7 @@ reth-revm.workspace = true
reth-ethereum-consensus.workspace = true
reth-prune-types.workspace = true
reth-execution-types.workspace = true
+sha2.workspace = true
# Ethereum
revm-primitives.workspace = true
diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs
index 188ca0e21f25..b14a93fc572f 100644
--- a/crates/ethereum/evm/src/execute.rs
+++ b/crates/ethereum/evm/src/execute.rs
@@ -38,6 +38,8 @@ use reth_telos_rpc_engine_api::compare::compare_state_diffs;
use revm_primitives::{Address, Account, AccountInfo, AccountStatus, Bytecode, HashMap, KECCAK_EMPTY};
#[cfg(feature = "telos")]
use alloy_primitives::B256;
+#[cfg(feature = "telos")]
+use sha2::{Sha256, Digest};
/// Provides executors to execute regular ethereum blocks
#[derive(Debug, Clone)]
@@ -192,6 +194,7 @@ where
// execute transactions
let mut cumulative_gas_used = 0;
+ #[cfg(not(feature = "telos"))]
let mut receipts = Vec::with_capacity(block.body.transactions.len());
for (sender, transaction) in block.transactions_with_sender() {
#[cfg(feature = "telos")]
@@ -233,6 +236,7 @@ where
// append gas used
cumulative_gas_used += result.gas_used();
+ #[cfg(not(feature = "telos"))]
// Push transaction changeset and calculate header bloom filter for receipt.
receipts.push(
#[allow(clippy::needless_update)] // side-effect of optimism fields
@@ -259,23 +263,32 @@ where
new_addresses_using_create_iter.next();
}
- #[cfg(feature = "telos")] {
- // Perform state diff comparision
- let revm_state_diffs = evm.db_mut().transition_state.clone().unwrap_or_default().transitions;
- let block_num = block.block.header.number;
- println!(
- "Compare: block {block_num} {}",
- compare_state_diffs(
- &mut evm,
- revm_state_diffs,
- unwrapped_telos_extra_fields.statediffs_account.unwrap_or_default(),
- unwrapped_telos_extra_fields.statediffs_accountstate.unwrap_or_default(),
- unwrapped_telos_extra_fields.new_addresses_using_create.unwrap_or_default(),
- unwrapped_telos_extra_fields.new_addresses_using_openwallet.unwrap_or_default()
- )
- );
+ // #[cfg(feature = "telos")]
+ {
+ // Perform state diff comparision
+ let revm_state_diffs = evm.db_mut().transition_state.clone().unwrap_or_default().transitions;
+ let block_num = block.block.header.number;
+ println!(
+ "Compare: block {block_num} {}",
+ compare_state_diffs(
+ &mut evm,
+ revm_state_diffs,
+ unwrapped_telos_extra_fields.statediffs_account.clone().unwrap_or_default(),
+ unwrapped_telos_extra_fields.statediffs_accountstate.clone().unwrap_or_default(),
+ unwrapped_telos_extra_fields.new_addresses_using_create.clone().unwrap_or_default(),
+ unwrapped_telos_extra_fields.new_addresses_using_openwallet.clone().unwrap_or_default(),
+ false
+ )
+ );
}
+ #[cfg(feature = "telos")]
+ let receipts = if unwrapped_telos_extra_fields.receipts.is_some() {
+ unwrapped_telos_extra_fields.receipts.clone().unwrap()
+ } else {
+ vec![]
+ };
+
let requests = if self.chain_spec.is_prague_active_at_timestamp(block.timestamp) {
// Collect all EIP-6110 deposits
let deposit_requests =
@@ -288,7 +301,44 @@ where
vec![]
};
- Ok(EthExecuteOutput { receipts, requests, gas_used: cumulative_gas_used })
+ // #[cfg(feature = "telos")]
+ // {
+ // let mut addr_to_accstate: HashMap
> = HashMap::new();
+
+ // for sdiff_accstate in unwrapped_telos_extra_fields.clone().statediffs_accountstate.unwrap_or(vec![]) {
+ // if !addr_to_accstate.contains_key(&sdiff_accstate.address) {
+ // addr_to_accstate.insert(sdiff_accstate.address, HashMap::new());
+ // }
+ // let mut acc_storage = addr_to_accstate.get_mut(&sdiff_accstate.address).unwrap();
+ // acc_storage.insert(sdiff_accstate.key, EvmStorageSlot { original_value: Default::default(), present_value: sdiff_accstate.value, is_cold: false });
+ // }
+
+ // let mut state: HashMap = HashMap::new();
+
+ // for sdiff_acc in unwrapped_telos_extra_fields.clone().statediffs_account.unwrap_or(vec![]) {
+ // state.insert(
+ // sdiff_acc.address,
+ // Account {
+ // info: AccountInfo {
+ // balance: sdiff_acc.balance,
+ // nonce: sdiff_acc.nonce,
+ // code_hash: B256::from(Sha256::digest(sdiff_acc.code.as_ref()).as_ref()),
+ // code: Some(Bytecode::LegacyRaw(sdiff_acc.code)),
+ // },
+ // storage: addr_to_accstate.get(&sdiff_acc.address).unwrap_or(&HashMap::new()).clone(),
+ // status: AccountStatus::Touched | AccountStatus::LoadedAsNotExisting,
+ // }
+ // );
+ // }
+
+ // evm.db_mut().commit(state);
+ // }
+
+ Ok(EthExecuteOutput {
+ receipts,
+ requests,
+ gas_used: cumulative_gas_used
+ })
}
}
@@ -366,7 +416,12 @@ where
let env = self.evm_env_for_block(&block.header, total_difficulty);
let output = {
let evm = self.executor.evm_config.evm_with_env(&mut self.state, env);
- self.executor.execute_state_transitions(block, evm, #[cfg(feature = "telos")] telos_extra_fields)
+ self.executor.execute_state_transitions(
+ block,
+ evm,
+ #[cfg(feature = "telos")]
+ telos_extra_fields
+ )
}?;
// 3. apply post execution changes
diff --git a/crates/telos/bin/Cargo.toml b/crates/telos/bin/Cargo.toml
index 462451dfb839..1669f380b311 100644
--- a/crates/telos/bin/Cargo.toml
+++ b/crates/telos/bin/Cargo.toml
@@ -16,6 +16,8 @@ reth-chainspec.workspace = true
reth-provider.workspace = true
reth-node-telos.workspace = true
reth-telos-rpc.workspace = true
+reth-db.workspace = true
+alloy-primitives.workspace = true
clap = { workspace = true, features = ["derive", "env"] }
diff --git a/crates/telos/bin/src/main.rs b/crates/telos/bin/src/main.rs
index 6e73d37e15bb..7f660ee0ee31 100644
--- a/crates/telos/bin/src/main.rs
+++ b/crates/telos/bin/src/main.rs
@@ -4,6 +4,7 @@
static ALLOC: reth_cli_util::allocator::Allocator = reth_cli_util::allocator::new_allocator();
use clap::Parser;
+use tracing::{error, info, warn};
use reth::args::utils::EthereumChainSpecParser;
use reth_node_builder::{engine_tree_config::TreeConfig, EngineNodeLauncher};
use reth::cli::Cli;
@@ -11,10 +12,16 @@ use reth_node_telos::{TelosArgs, TelosNode};
use reth_node_telos::node::TelosAddOns;
use reth_provider::providers::BlockchainProvider2;
use reth_telos_rpc::TelosClient;
+use reth::primitives::BlockId;
+use reth::rpc::types::BlockNumberOrTag;
+use reth_provider::{DatabaseProviderFactory, StateProviderFactory};
+use reth_db::{PlainAccountState, PlainStorageState};
#[cfg(feature = "telos")]
fn main() {
+ use reth_provider::BlockNumReader;
+
reth_cli_util::sigsegv_handler::install();
// Enable backtraces unless a RUST_BACKTRACE value has already been explicitly provided.
@@ -45,6 +52,10 @@ fn main() {
handle.node_exit_future.await
},
false => {
+ let two_way_storage_compare = telos_args.two_way_storage_compare.clone();
+ let telos_rpc = telos_args.telos_endpoint.clone();
+ let block_delta = telos_args.block_delta.clone();
+
let handle = builder
.node(TelosNode::new(telos_args.clone()))
.extend_rpc_modules(move |ctx| {
@@ -59,6 +70,36 @@ fn main() {
.launch()
.await?;
+ match two_way_storage_compare {
+ true => {
+ if telos_rpc.is_none() {
+ warn!("Telos RPC Endpoint is not specified, skipping two-way storage compare");
+ } else if block_delta.is_none() {
+ warn!("Block delta is not specified, skipping two-way storage compare");
+ } else {
+ info!("Fetching account and accountstate from Telos native RPC (Can take a long time)...");
+
+ let (account_table, accountstate_table, block_number) = reth_node_telos::two_way_storage_compare::get_telos_tables(telos_rpc.unwrap().as_str(), block_delta.unwrap()).await;
+
+ if block_number.as_u64().unwrap() <= handle.node.provider.best_block_number().unwrap() {
+ info!("Two-way comparing state (Reth vs. Telos) at height: {:?}", block_number);
+
+ let state_at_specific_height = handle.node.provider.state_by_block_id(BlockId::Number(BlockNumberOrTag::Number(block_number.as_u64().unwrap()))).unwrap();
+ let plain_account_state = handle.node.provider.database_provider_ro().unwrap().table::().unwrap();
+ let plain_storage_state = handle.node.provider.database_provider_ro().unwrap().table::().unwrap();
+
+ let match_counter = reth_node_telos::two_way_storage_compare::two_side_state_compare(account_table, accountstate_table, state_at_specific_height, plain_account_state, plain_storage_state).await;
+ match_counter.print();
+
+ info!("Comparing done");
+ } else {
+ error!("Nodeos is ahead of reth, failed to compare state");
+ }
+ }
+ }
+ _ => {}
+ }
+
handle.node_exit_future.await
}
}
diff --git a/crates/telos/node/Cargo.toml b/crates/telos/node/Cargo.toml
index 3d7b8e01117d..a530dd01d848 100644
--- a/crates/telos/node/Cargo.toml
+++ b/crates/telos/node/Cargo.toml
@@ -34,6 +34,9 @@ reth-stages.workspace = true
reth-telos-rpc.workspace = true
reth-tracing.workspace = true
reth-transaction-pool.workspace = true
+reth-telos-rpc-engine-api.workspace = true
+alloy-primitives.workspace = true
+reth-db.workspace = true
clap.workspace = true
serde = { workspace = true, features = ["derive"] }
diff --git a/crates/telos/node/src/args.rs b/crates/telos/node/src/args.rs
index f65912512ca2..8c66a55b837d 100644
--- a/crates/telos/node/src/args.rs
+++ b/crates/telos/node/src/args.rs
@@ -45,6 +45,14 @@ pub struct TelosArgs {
/// a batch of downloaded blocks.
#[arg(long = "engine.max-execute-block-batch-size", requires = "experimental", default_value_t = DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE)]
pub max_execute_block_batch_size: usize,
+
+ /// Enable Two-way storage compare between reth and telos
+ #[arg(long = "telos.two_way_storage_compare", default_value = "false")]
+ pub two_way_storage_compare: bool,
+
+ /// Block delta between native and EVM
+ #[arg(long = "telos.block_delta")]
+ pub block_delta: Option,
}
impl From for TelosClientArgs {
diff --git a/crates/telos/node/src/lib.rs b/crates/telos/node/src/lib.rs
index 962a444aa9c1..3f432da1b519 100644
--- a/crates/telos/node/src/lib.rs
+++ b/crates/telos/node/src/lib.rs
@@ -11,6 +11,7 @@
pub mod args;
pub mod node;
+pub mod two_way_storage_compare;
pub use crate::args::TelosArgs;
pub use crate::node::TelosNode;
diff --git a/crates/telos/node/src/two_way_storage_compare.rs b/crates/telos/node/src/two_way_storage_compare.rs
new file mode 100644
index 000000000000..e39c03d63f6d
--- /dev/null
+++ b/crates/telos/node/src/two_way_storage_compare.rs
@@ -0,0 +1,367 @@
+//! Two-way storage compare between Reth and Telos
+
+use antelope::serializer::{Decoder, Encoder, Packer};
+use antelope::chain::name::Name;
+use std::collections::HashMap;
+use alloy_primitives::{Address, B256, U256};
+use antelope::api::client::{APIClient, DefaultProvider};
+use antelope::api::v1::structs::{GetTableRowsParams, TableIndexType};
+use antelope::{name, StructPacker};
+use antelope::chain::checksum::{Checksum160, Checksum256};
+use serde::{Deserialize, Serialize};
+use tracing::{error, info};
+use reth::primitives::{Account, BlockId};
+use reth_db::common::KeyValue;
+use reth::providers::StateProviderBox;
+use reth_db::{PlainAccountState, PlainStorageState};
+
+#[derive(Debug, Clone, Default, Serialize, Deserialize, StructPacker)]
+struct AccountRow {
+ index: u64,
+ address: Checksum160,
+ account: Name,
+ nonce: u64,
+ code: Vec,
+ balance: Checksum256,
+}
+
+#[derive(Debug, Clone, Default, Serialize, Deserialize, StructPacker)]
+struct AccountStateRow {
+ index: u64,
+ key: Checksum256,
+ value: Checksum256,
+}
+
+/// This struct holds matching statistics
+#[derive(Debug, Clone, Default)]
+pub struct MatchCounter {
+ total_telos_accounts: u64,
+ total_telos_storages: u64,
+ mismatched_telos_accounts: u64,
+ mismatched_telos_storages: u64,
+ total_reth_accounts: u64,
+ total_reth_storages: u64,
+ mismatched_reth_accounts: u64,
+ mismatched_reth_storages: u64,
+}
+impl MatchCounter {
+ /// Creates a new match counter for two-way storage compare
+ pub fn new() -> Self {
+ Self {
+ total_telos_accounts: 0,
+ total_telos_storages: 0,
+ mismatched_telos_accounts: 0,
+ mismatched_telos_storages: 0,
+ total_reth_accounts: 0,
+ total_reth_storages: 0,
+ mismatched_reth_accounts: 0,
+ mismatched_reth_storages: 0,
+ }
+ }
+
+ /// Prints the match counter
+ pub fn print(&self) {
+ info!("Comparing results:");
+ info!("Total telos accounts: {}", self.total_telos_accounts);
+ info!("Total telos storages: {}", self.total_telos_storages);
+ info!("Mismatched telos accounts: {}", self.mismatched_telos_accounts);
+ info!("Mismatched telos storages: {}", self.mismatched_telos_storages);
+ info!("Total reth accounts: {}", self.total_reth_accounts);
+ info!("Total reth storages: {}", self.total_reth_storages);
+ info!("Mismatched reth accounts: {}", self.mismatched_reth_accounts);
+ info!("Mismatched reth storages: {}", self.mismatched_reth_storages);
+ info!("Matching result: {}",self.matches());
+ }
+
+ fn add_telos_total_account(&mut self) {
+ self.total_telos_accounts += 1;
+ }
+
+ fn add_telos_total_storage(&mut self) {
+ self.total_telos_storages += 1;
+ }
+
+ fn add_telos_mismatched_account(&mut self) {
+ self.mismatched_telos_accounts += 1;
+ }
+
+ fn add_telos_mismatched_storage(&mut self) {
+ self.mismatched_telos_storages += 1;
+ }
+
+ fn add_reth_total_account(&mut self) {
+ self.total_reth_accounts += 1;
+ }
+
+ fn add_reth_total_storage(&mut self) {
+ self.total_reth_storages += 1;
+ }
+
+ fn add_reth_mismatched_account(&mut self) {
+ self.mismatched_reth_accounts += 1;
+ }
+
+ fn add_reth_mismatched_storage(&mut self) {
+ self.mismatched_reth_storages += 1;
+ }
+
+ /// Check whether both sides matches
+ pub fn matches(&self) -> bool {
+ self.mismatched_telos_accounts == 0
+ && self.mismatched_telos_storages == 0
+ && self.mismatched_reth_accounts == 0
+ && self.mismatched_reth_storages == 0
+ }
+}
+
+/// This function compares reth and telos state against each other at specific height
+pub async fn two_side_state_compare(
+ account_table: HashMap,
+ accountstate_table: HashMap<(Address, B256), U256>,
+ state_at_specific_height: StateProviderBox,
+ plain_account_state: Vec>,
+ plain_storage_state: Vec>,
+) -> MatchCounter {
+
+ let mut match_counter = MatchCounter::new();
+
+ for (address, telos_account) in &account_table {
+ let account_at_specific_height = state_at_specific_height.basic_account(*address);
+ match account_at_specific_height {
+ Ok(reth_account) => {
+ match reth_account {
+ Some(reth_account) => {
+ if reth_account.balance != telos_account.balance || reth_account.nonce != telos_account.nonce {
+ match_counter.add_telos_mismatched_account();
+ error!("Difference in account: {:?}", address);
+ error!("Telos side: {:?}", telos_account);
+ error!("Reth side: {:?}", reth_account);
+ }
+ },
+ None => {
+ if telos_account.balance != U256::ZERO || telos_account.nonce != 0 {
+ match_counter.add_telos_mismatched_account();
+ error!("Difference in account: {:?}", address);
+ error!("Telos side: {:?}", telos_account);
+ error!("Reth side: None");
+ }
+ },
+ }
+ },
+ Err(_) => {
+ match_counter.add_telos_mismatched_account();
+ error!("Difference in account: {:?}", address);
+ error!("Telos side: {:?}", telos_account);
+ error!("Reth side: None");
+ },
+ }
+ match_counter.add_telos_total_account();
+ }
+
+ for ((address, key), telos_value) in &accountstate_table {
+ let storage_at_specific_height = state_at_specific_height.storage(*address, *key);
+ match storage_at_specific_height {
+ Ok(storage) => {
+ match storage {
+ Some(reth_value) => {
+ if reth_value != *telos_value {
+ match_counter.add_telos_mismatched_storage();
+ error!("Difference in accountstate: {:?}, key: {:?}", address, key);
+ error!("Telos side: {:?}", telos_value);
+ error!("Reth side: {:?}", reth_value);
+ }
+ },
+ None => {
+ match_counter.add_telos_mismatched_storage();
+ error!("Difference in accountstate: {:?}, key: {:?}", address, key);
+ error!("Telos side: {:?}", telos_value);
+ error!("Reth side: None");
+ },
+ }
+ },
+ Err(_) => {
+ match_counter.add_telos_mismatched_storage();
+ error!("Difference in accountstate: {:?}, key: {:?}", address, key);
+ error!("Telos side: {:?}", telos_value);
+ error!("Reth side: None");
+ },
+ }
+ match_counter.add_telos_total_storage();
+ }
+
+
+ for (address, _) in plain_account_state.iter() {
+ let account_at_specific_height = state_at_specific_height.basic_account(*address);
+ let telos_account = account_table.get(address);
+ match account_at_specific_height {
+ Ok(account) => {
+ match account {
+ Some(reth_account) => {
+ if telos_account.is_none() {
+ match_counter.add_reth_mismatched_account();
+ error!("Difference in account: {:?}", address);
+ error!("Telos side: None");
+ error!("Reth side: {:?}", reth_account);
+ } else {
+ let telos_account_unwrapped = telos_account.unwrap();
+ if reth_account.balance != telos_account_unwrapped.balance || reth_account.nonce != telos_account_unwrapped.nonce {
+ match_counter.add_reth_mismatched_account();
+ error!("Difference in account: {:?}", address);
+ error!("Telos side: {:?}", telos_account);
+ error!("Reth side: {:?}", reth_account);
+ }
+ }
+
+ },
+ None => {
+ if telos_account.is_some() {
+ match_counter.add_reth_mismatched_account();
+ error!("Difference in account: {:?}", address);
+ error!("Telos side: {:?}", telos_account.unwrap());
+ error!("Reth side: None");
+ }
+ },
+ }
+ },
+ Err(_) => {
+ if telos_account.is_some() {
+ match_counter.add_reth_mismatched_account();
+ error!("Difference in account: {:?}", address);
+ error!("Telos side: {:?}", telos_account.unwrap());
+ error!("Reth side: None");
+ }
+ },
+ }
+ match_counter.add_reth_total_account();
+ }
+
+ for (address,storage_entry) in plain_storage_state.iter() {
+ let storage_at_specific_height = state_at_specific_height.storage(*address, storage_entry.key);
+ let telos_accountstate = accountstate_table.get(&(*address, storage_entry.key));
+ match storage_at_specific_height {
+ Ok(storage) => {
+ match storage {
+ Some(reth_value) => {
+ if telos_accountstate.is_none() {
+ if reth_value != U256::ZERO {
+ match_counter.add_reth_mismatched_storage();
+ error!("Difference in accountstate: {:?}", address);
+ error!("Telos side: None");
+ error!("Reth side: {:?}", reth_value);
+ }
+ } else {
+ let telos_value = *telos_accountstate.unwrap();
+ if reth_value != telos_value {
+ match_counter.add_reth_mismatched_storage();
+ error!("Difference in accountstate: {:?}", address);
+ error!("Telos side: {:?}", telos_value);
+ error!("Reth side: {:?}", reth_value);
+ }
+ }
+ },
+ None => {
+ if telos_accountstate.is_some() {
+ match_counter.add_reth_mismatched_storage();
+ error!("Difference in accountstate: {:?}", address);
+ error!("Telos side: {:?}", telos_accountstate.unwrap());
+ error!("Reth side: None");
+ }
+ },
+ }
+ },
+ Err(_) => {
+ if telos_accountstate.is_some() {
+ match_counter.add_reth_mismatched_storage();
+ error!("Difference in accountstate: {:?}", address);
+ error!("Telos side: {:?}", telos_accountstate.unwrap());
+ error!("Reth side: None");
+ }
+ },
+ }
+ match_counter.add_reth_total_storage();
+ }
+
+ match_counter
+}
+
+/// This function retrieves account and accountstate tables from native RPC
+pub async fn get_telos_tables(telos_rpc: &str, block_delta: u32) -> (HashMap, HashMap<(Address, B256), U256>, BlockId) {
+
+ let api_client = APIClient::::default_provider(telos_rpc.into(), Some(5)).unwrap();
+ let info_start = api_client.v1_chain.get_info().await.unwrap();
+
+ let evm_block_num_start = info_start.head_block_num - block_delta;
+
+ let mut has_more_account = true;
+ let mut lower_bound_account = Some(TableIndexType::UINT64(0));
+
+ let evm_block_id = BlockId::from(evm_block_num_start as u64);
+
+ let mut account_table = HashMap::default();
+ let mut accountstate_table = HashMap::default();
+
+ while has_more_account {
+ let query_params_account = GetTableRowsParams {
+ code: name!("eosio.evm"),
+ table: name!("account"),
+ scope: None,
+ lower_bound: lower_bound_account,
+ upper_bound: None,
+ limit: Some(5000),
+ reverse: None,
+ index_position: None,
+ show_payer: None,
+ };
+ let account_rows = api_client.v1_chain.get_table_rows::(query_params_account).await;
+ if let Ok(account_rows) = account_rows {
+ lower_bound_account = account_rows.next_key;
+ has_more_account = lower_bound_account.is_some();
+ for account_row in account_rows.rows {
+ let address = Address::from_slice(account_row.address.data.as_slice());
+ lower_bound_account = Some(TableIndexType::UINT64(account_row.index + 1));
+ account_table.insert(address,Account {
+ nonce: account_row.nonce,
+ balance: U256::from_be_bytes(account_row.balance.data),
+ bytecode_hash: None,
+ });
+ let mut has_more_accountstate = true;
+ let mut lower_bound_accountstate = Some(TableIndexType::UINT64(0));
+ while has_more_accountstate {
+ let query_params_accountstate = GetTableRowsParams {
+ code: name!("eosio.evm"),
+ table: name!("accountstate"),
+ scope: Some(Name::from_u64(account_row.index)),
+ lower_bound: lower_bound_accountstate,
+ upper_bound: None,
+ limit: Some(5000),
+ reverse: None,
+ index_position: None,
+ show_payer: None,
+ };
+ let accountstate_rows = api_client.v1_chain.get_table_rows::(query_params_accountstate).await;
+ if let Ok(accountstate_rows) = accountstate_rows {
+ lower_bound_accountstate = accountstate_rows.next_key;
+ has_more_accountstate = lower_bound_accountstate.is_some();
+ for accountstate_row in accountstate_rows.rows {
+ lower_bound_accountstate = Some(TableIndexType::UINT64(accountstate_row.index + 1));
+ accountstate_table.insert((address,B256::from(accountstate_row.key.data)),U256::from_be_bytes(accountstate_row.value.data));
+ }
+ } else {
+ panic!("Failed to fetch accountstate row");
+ }
+ }
+ }
+ } else {
+ panic!("Failed to fetch account row");
+ }
+ }
+
+ let info_end = api_client.v1_chain.get_info().await.unwrap();
+ let evm_block_num_end = info_end.head_block_num - block_delta;
+
+ if evm_block_num_start != evm_block_num_end {
+ panic!("Nodeos is syncing, it is impossible to get an accurate state from a syncing native RPC");
+ }
+
+ (account_table, accountstate_table, evm_block_id)
+}
\ No newline at end of file
diff --git a/crates/telos/node/tests/integration.rs b/crates/telos/node/tests/integration.rs
index 268fde39928c..e6f09a9d715d 100644
--- a/crates/telos/node/tests/integration.rs
+++ b/crates/telos/node/tests/integration.rs
@@ -160,6 +160,8 @@ async fn testing_chain_sync() {
persistence_threshold: 0,
memory_block_buffer_target: 1,
max_execute_block_batch_size: 100,
+ two_way_storage_compare: false,
+ block_delta: None,
};
let node_handle = NodeBuilder::new(node_config.clone())
diff --git a/crates/telos/node/tests/main.rs b/crates/telos/node/tests/main.rs
index 43614c668a2c..a23cd12d3808 100644
--- a/crates/telos/node/tests/main.rs
+++ b/crates/telos/node/tests/main.rs
@@ -1,4 +1,5 @@
-mod integration;
-pub mod live_test_runner;
+// mod integration;
+// pub mod live_test_runner;
+pub mod storage_compare;
const fn main() {}
\ No newline at end of file
diff --git a/crates/telos/node/tests/state_bypass.rs b/crates/telos/node/tests/state_bypass.rs
new file mode 100644
index 000000000000..88bfc9fd0d03
--- /dev/null
+++ b/crates/telos/node/tests/state_bypass.rs
@@ -0,0 +1,456 @@
+use std::{fmt, fs};
+use std::fmt::{Display, Formatter};
+use std::path::PathBuf;
+use std::str::FromStr;
+use std::sync::Arc;
+use alloy_provider::{Provider, ProviderBuilder};
+use reqwest::Url;
+use serde_json::json;
+use telos_consensus_client::execution_api_client::{ExecutionApiClient, RpcRequest};
+use telos_consensus_client::execution_api_client::ExecutionApiMethod::{ForkChoiceUpdatedV1, NewPayloadV1};
+use tracing::info;
+use reth::args::RpcServerArgs;
+use reth::builder::NodeConfig;
+use alloy_primitives::{Address, B256, hex, U256, Bytes, map::HashMap};
+use alloy_primitives::hex::FromHex;
+use alloy_rpc_types::engine::ExecutionPayloadV1;
+use reth::primitives::revm_primitives::{Bytecode as RevmBytecode, LegacyAnalyzedBytecode};
+use reth::providers::ProviderError;
+use reth::revm;
+use reth::revm::db::{CacheDB, EmptyDBTyped, StorageWithOriginalValues, states::StorageSlot};
+use reth::revm::{Database, DatabaseCommit, DatabaseRef, Evm, State, TransitionAccount};
+use reth::revm::primitives::{AccountInfo, EvmStorageSlot};
+use reth::rpc::types::engine::ForkchoiceState;
+use reth::tasks::TaskManager;
+use reth_chainspec::{ChainSpec, ChainSpecBuilder, TEVMTESTNET};
+use reth_e2e_test_utils::node::NodeTestContext;
+use reth_node_builder::NodeBuilder;
+use reth_node_telos::{TelosArgs, TelosNode};
+use reth_primitives::constants::{EMPTY_ROOT_HASH, MIN_PROTOCOL_BASE_FEE};
+use reth_primitives::revm_primitives::AccountStatus;
+use reth_telos_rpc::TelosClient;
+use reth_telos_rpc_engine_api::compare::compare_state_diffs;
+use reth_telos_rpc_engine_api::structs::{TelosAccountTableRow, TelosAccountStateTableRow, TelosEngineAPIExtraFields};
+use revm::primitives::Account;
+
+#[derive(Debug)]
+enum MockDBError {
+ GenericError(String)
+}
+
+impl Into for MockDBError {
+ fn into(self) -> ProviderError {
+ match self {
+ MockDBError::GenericError(msg) => {
+ ProviderError::NippyJar(msg)
+ }
+ }
+ }
+}
+
+impl Display for MockDBError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ match self {
+ MockDBError::GenericError(msg) => {
+ f.write_str(&msg)
+ }
+ }
+ }
+}
+
+fn init_reth() -> eyre::Result<(NodeConfig, String)> {
+ let chain_spec = Arc::new(
+ ChainSpecBuilder::default()
+ .chain(TEVMTESTNET.chain)
+ .genesis(TEVMTESTNET.genesis.clone())
+ .frontier_activated()
+ .homestead_activated()
+ .tangerine_whistle_activated()
+ .spurious_dragon_activated()
+ .byzantium_activated()
+ .constantinople_activated()
+ .petersburg_activated()
+ .istanbul_activated()
+ .berlin_activated()
+ .build(),
+ );
+
+ let mut rpc_config = RpcServerArgs::default().with_unused_ports().with_http();
+ rpc_config.auth_jwtsecret = Some(PathBuf::from("tests/assets/jwt.hex"));
+
+ // Node setup
+ let node_config = NodeConfig::test().with_chain(chain_spec).with_rpc(rpc_config.clone());
+
+ let jwt = fs::read_to_string(node_config.rpc.auth_jwtsecret.clone().unwrap())?;
+ Ok((node_config, jwt))
+}
+
+#[tokio::test]
+async fn test_integration_tevm_only() {
+ tracing_subscriber::fmt::init();
+
+ let (node_config, jwt_secret) = init_reth().unwrap();
+
+ let exec = TaskManager::current();
+ let exec = exec.executor();
+
+ reth_tracing::init_test_tracing();
+
+ let telos_args = TelosArgs {
+ telos_endpoint: None,
+ signer_account: Some("rpc.evm".to_string()),
+ signer_permission: Some("active".to_string()),
+ signer_key: Some("5Jr65kdYmn33C3UabzhmWDm2PuqbRfPuDStts3ZFNSBLM7TqaiL".to_string()),
+ gas_cache_seconds: None,
+ experimental: false,
+ persistence_threshold: 0,
+ memory_block_buffer_target: 0,
+ max_execute_block_batch_size: 0,
+ };
+
+ let node_handle = NodeBuilder::new(node_config.clone())
+ .testing_node(exec)
+ .node(TelosNode::new(telos_args.clone()))
+ .extend_rpc_modules(move |ctx| {
+ if telos_args.telos_endpoint.is_some() {
+ ctx.registry.eth_api().set_telos_client(TelosClient::new(telos_args.into()));
+ }
+
+ Ok(())
+ })
+ .launch()
+ .await
+ .unwrap();
+
+ let execution_port = node_handle.node.auth_server_handle().local_addr().port();
+ let rpc_port = node_handle.node.rpc_server_handles.rpc.http_local_addr().unwrap().port();
+ println!("Starting Reth on RPC port {}!", rpc_port);
+ let _ = NodeTestContext::new(node_handle.node.clone()).await.unwrap();
+
+ let custom_balance = U256::from(80085);
+
+ let exec_client = ExecutionApiClient::new(&format!("http://127.0.0.1:{}", execution_port), &jwt_secret).unwrap();
+
+ let execution_payload = ExecutionPayloadV1 {
+ parent_hash: B256::from_hex("b25034033c9ca7a40e879ddcc29cf69071a22df06688b5fe8cc2d68b4e0528f9").unwrap(),
+ fee_recipient: Default::default(),
+ state_root: EMPTY_ROOT_HASH,
+ receipts_root: EMPTY_ROOT_HASH,
+ logs_bloom: Default::default(),
+ prev_randao: Default::default(),
+ block_number: 1,
+ gas_limit: 0x7fffffff,
+ gas_used: 0,
+ timestamp: 1728067687,
+ extra_data: Default::default(),
+ base_fee_per_gas: U256::try_from(MIN_PROTOCOL_BASE_FEE).unwrap(),
+ block_hash: B256::from_hex("0a1d73423169c8b4124121d40c0e13eb078621e73effd2d183f9a1d8017537dd").unwrap(),
+ transactions: vec![],
+ };
+
+ let test_addr = Address::from_hex("00000000000000000000000000000000deadbeef").unwrap();
+
+ let extra_fields = TelosEngineAPIExtraFields {
+ statediffs_account: Some(vec![TelosAccountTableRow {
+ removed: false,
+ address: test_addr,
+ account: "eosio".to_string(),
+ nonce: 0,
+ code: Default::default(),
+ balance: custom_balance,
+ }]),
+ statediffs_accountstate: Some(vec![]),
+ revision_changes: None,
+ gasprice_changes: None,
+ new_addresses_using_create: Some(vec![]),
+ new_addresses_using_openwallet: Some(vec![]),
+ receipts: Some(vec![]),
+ };
+
+ let block_req = RpcRequest {
+ method: NewPayloadV1,
+ params: vec![
+ json![execution_payload],
+ json![extra_fields]
+ ].into()
+ };
+
+ let new_block_result = exec_client.rpc(block_req).await.unwrap();
+
+ info!("new_block: {:#?}", new_block_result);
+
+ let fork_choice_result = exec_client.rpc(RpcRequest {
+ method: ForkChoiceUpdatedV1,
+ params: json![vec![ForkchoiceState {
+ head_block_hash: execution_payload.block_hash,
+ safe_block_hash: execution_payload.block_hash,
+ finalized_block_hash: execution_payload.block_hash
+ }]]
+ }).await.unwrap();
+
+ info!("fork_choice: {:#?}", fork_choice_result);
+
+
+ let provider = ProviderBuilder::new()
+ //.network::()
+ .on_http(Url::from_str(format!("http://localhost:{}", rpc_port).as_str()).unwrap());
+
+ let balance = provider.get_balance(test_addr).await.unwrap();
+ info!("balance: {:#?}", balance);
+
+ assert_eq!(balance, custom_balance);
+}
+
+#[test]
+fn test_db_both_sides_present_but_dif() {
+ let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap();
+
+ let init_balance = U256::from(0);
+ let custom_balance = U256::from(80085);
+
+ let init_nonce = 0;
+ let custom_nonce = 69;
+
+ let revm_acc_info = AccountInfo {
+ balance: init_balance,
+ nonce: init_nonce,
+ code_hash: Default::default(),
+ code: None,
+ };
+
+ let mut db = CacheDB::new(EmptyDBTyped::::new());
+ db.insert_account_info(test_addr, revm_acc_info);
+
+ let mut state = State::builder().with_database(db).build();
+
+ let mut evm = Evm::builder().with_db(&mut state).build();
+
+ let statediffs_account = vec![TelosAccountTableRow {
+ removed: false,
+ address: test_addr,
+ account: "eosio".to_string(),
+ nonce: custom_nonce,
+ code: Default::default(),
+ balance: custom_balance,
+ }];
+
+ compare_state_diffs(
+ &mut evm,
+ HashMap::default(),
+ statediffs_account.clone(),
+ vec![],
+ vec![],
+ vec![],
+ false
+ );
+
+ let db_acc = evm.db_mut().basic(test_addr).unwrap().unwrap();
+ assert_eq!(db_acc.nonce, statediffs_account[0].nonce);
+ assert_eq!(db_acc.balance, statediffs_account[0].balance);
+}
+
+#[test]
+fn test_db_both_sides_only_code() {
+ let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap();
+
+ let custom_code = Bytes::from(&hex!("ffff"));
+ let custom_bytecode = RevmBytecode::LegacyRaw(custom_code.clone());
+
+ let revm_acc_info = AccountInfo {
+ balance: U256::from(0),
+ nonce: 0,
+ code_hash: Default::default(),
+ code: None,
+ };
+
+ let mut db = CacheDB::new(EmptyDBTyped::::new());
+ db.insert_account_info(test_addr, revm_acc_info);
+
+ let mut state = State::builder().with_database(db).build();
+
+ let mut evm = Evm::builder().with_db(&mut state).build();
+
+ let statediffs_account = vec![TelosAccountTableRow {
+ removed: false,
+ address: test_addr,
+ account: "eosio".to_string(),
+ nonce: 0,
+ code: custom_code.clone(),
+ balance: U256::from(0),
+ }];
+
+ compare_state_diffs(
+ &mut evm,
+ HashMap::default(),
+ statediffs_account.clone(),
+ vec![],
+ vec![],
+ vec![],
+ false
+ );
+
+ let db_acc = evm.db_mut().basic(test_addr).unwrap().unwrap();
+ assert_eq!(db_acc.code, Some(custom_bytecode));
+}
+
+#[test]
+fn test_revm_state_both_sides_present_but_dif() {
+ let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap();
+
+ let revm_acc_info = AccountInfo {
+ balance: U256::from(1),
+ nonce: 0,
+ code_hash: Default::default(),
+ code: None,
+ };
+
+ let mut revm_state_diffs = HashMap::default();
+
+ let mut transition_account = TransitionAccount::new_empty_eip161(HashMap::default());
+
+ transition_account.info = Some(revm_acc_info);
+
+ revm_state_diffs.insert(test_addr, transition_account);
+
+ let mut db = CacheDB::new(EmptyDBTyped::::new());
+
+ let mut state = State::builder().with_database(db).build();
+
+ let mut evm = Evm::builder().with_db(&mut state).build();
+
+ let statediffs_account = vec![TelosAccountTableRow {
+ removed: false,
+ address: test_addr,
+ account: "eosio".to_string(),
+ nonce: 1,
+ code: Default::default(),
+ balance: U256::from(80085),
+ }];
+
+ compare_state_diffs(
+ &mut evm,
+ revm_state_diffs,
+ statediffs_account.clone(),
+ vec![],
+ vec![],
+ vec![],
+ false
+ );
+
+ let db_acc = evm.db_mut().basic(test_addr).unwrap().unwrap();
+ assert_eq!(db_acc.nonce, statediffs_account[0].nonce);
+ assert_eq!(db_acc.balance, statediffs_account[0].balance);
+}
+
+#[test]
+fn test_tevm_only() {
+ let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap();
+
+ let mut db = CacheDB::new(EmptyDBTyped::::new());
+
+ let mut state = State::builder().with_database(db).build();
+
+ let mut evm = Evm::builder().with_db(&mut state).build();
+
+ let statediffs_account = vec![TelosAccountTableRow {
+ removed: false,
+ address: test_addr,
+ account: "eosio".to_string(),
+ nonce: 1,
+ code: Default::default(),
+ balance: U256::from(80085),
+ }];
+
+ compare_state_diffs(
+ &mut evm,
+ HashMap::default(),
+ statediffs_account.clone(),
+ vec![],
+ vec![],
+ vec![],
+ false
+ );
+
+ let db_acc = evm.db_mut().basic(test_addr).unwrap().unwrap();
+ assert_eq!(db_acc.nonce, statediffs_account[0].nonce);
+ assert_eq!(db_acc.balance, statediffs_account[0].balance);
+}
+
+#[test]
+fn test_accstate_diff_from_storage() {
+ let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap();
+
+ let revm_acc_info = AccountInfo {
+ balance: U256::from(1),
+ nonce: 0,
+ code_hash: Default::default(),
+ code: None,
+ };
+
+ let key = U256::from(420);
+ let value = U256::from(0);
+ let custom_value = U256::from(80085);
+
+ let mut db = CacheDB::new(EmptyDBTyped::::new());
+
+ let mut storage = HashMap::default();
+ storage.insert(key, value);
+
+ let mut state = State::builder().with_database(db).build();
+
+ state.insert_account_with_storage(test_addr, revm_acc_info, storage);
+
+ let mut evm = Evm::builder().with_db(&mut state).build();
+
+ let statediffs_accountstate = vec![TelosAccountStateTableRow {
+ removed: false,
+ address: test_addr,
+ key,
+ value: custom_value
+ }];
+
+ compare_state_diffs(
+ &mut evm,
+ HashMap::default(),
+ vec![],
+ statediffs_accountstate.clone(),
+ vec![],
+ vec![],
+ false
+ );
+
+ let db_value = evm.db_mut().storage(test_addr, key).unwrap();
+ assert_eq!(db_value, custom_value);
+}
+// #[test]
+// fn test_accstate_telos_only() {
+// let test_addr = Address::from_str("00000000000000000000000000000000deadbeef").unwrap();
+//
+// let key = U256::from(420);
+// let custom_value = U256::from(80085);
+//
+// let mut db = CacheDB::new(EmptyDBTyped::::new());
+//
+// let mut state = State::builder().with_database(db).build();
+//
+// // state.insert_not_existing(test_addr);
+//
+// let mut evm = Evm::builder().with_db(&mut state).build();
+//
+// let statediffs_accountstate = vec![TelosAccountStateTableRow {
+// removed: false,
+// address: test_addr,
+// key,
+// value: custom_value
+// }];
+//
+// compare_state_diffs(
+// &mut evm,
+// HashMap::default(),
+// vec![],
+// statediffs_accountstate.clone(),
+// vec![],
+// vec![],
+// true
+// );
+// }
diff --git a/crates/telos/node/tests/storage_compare.rs b/crates/telos/node/tests/storage_compare.rs
new file mode 100644
index 000000000000..2fc40cf1cd7b
--- /dev/null
+++ b/crates/telos/node/tests/storage_compare.rs
@@ -0,0 +1,224 @@
+use std::str::FromStr;
+use alloy_primitives::{Address, StorageValue, U256};
+use alloy_provider::{Provider, ProviderBuilder, ReqwestProvider};
+use alloy_rpc_types::BlockId;
+use antelope::api::client::{APIClient, DefaultProvider};
+use antelope::api::v1::structs::{GetTableRowsParams, TableIndexType};
+use antelope::chain::name::Name;
+use antelope::{name, StructPacker};
+use antelope::chain::{Encoder, Decoder, Packer};
+use antelope::chain::checksum::{Checksum160, Checksum256};
+use reqwest::Url;
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, Default, Serialize, Deserialize, StructPacker)]
+pub struct AccountRow {
+ pub index: u64,
+ pub address: Checksum160,
+ pub account: Name,
+ pub nonce: u64,
+ pub code: Vec,
+ pub balance: Checksum256,
+}
+
+#[derive(Debug, Clone, Default, Serialize, Deserialize, StructPacker)]
+pub struct AccountStateRow {
+ pub index: u64,
+ pub key: Checksum256,
+ pub value: Checksum256,
+}
+
+#[derive(Debug)]
+struct MatchCounter {
+ evm_block_number: BlockId,
+ total_accounts: u64,
+ total_storage_rows: u64,
+ mismatched_accounts: u64,
+ mismatched_storage_rows: u64,
+}
+
+impl MatchCounter {
+ pub fn new(evm_block_number: BlockId) -> Self {
+ Self {
+ evm_block_number,
+ total_accounts: 0,
+ total_storage_rows: 0,
+ mismatched_accounts: 0,
+ mismatched_storage_rows: 0,
+ }
+ }
+
+ pub fn print(&self) {
+ println!("Compared at block: {:?}", self.evm_block_number);
+ println!("Mismatched accounts: {}", self.mismatched_accounts);
+ println!("Mismatched storage rows: {}", self.mismatched_storage_rows);
+ println!("Matching accounts: {}", self.total_accounts - self.mismatched_accounts);
+ println!("Matching storage rows: {}", self.total_storage_rows - self.mismatched_storage_rows);
+ println!("Total accounts: {}", self.total_accounts);
+ println!("Total storage rows: {}", self.total_storage_rows);
+ }
+
+ pub fn add_matching_account(&mut self) {
+ self.total_accounts += 1;
+ }
+
+ pub fn add_matching_account_storage(&mut self) {
+ self.total_storage_rows += 1;
+ }
+
+ pub fn add_mismatched_account(&mut self) {
+ self.total_accounts += 1;
+ self.mismatched_accounts += 1;
+ }
+
+ pub fn add_mismatched_account_storage(&mut self) {
+ self.total_storage_rows += 1;
+ self.mismatched_storage_rows += 1;
+ }
+
+ pub fn matches(&self) -> bool {
+ self.mismatched_accounts == 0 && self.mismatched_storage_rows == 0
+ }
+
+}
+
+#[tokio::test]
+pub async fn compare() {
+ // let evm_rpc = "http://38.91.106.49:9545";
+ let evm_rpc = "http://localhost:8545";
+ // let telos_rpc = "http://192.168.0.20:8884";
+ let telos_rpc = "http://38.91.106.49:8899";
+ let block_delta = 57;
+
+ assert!(storage_matches(evm_rpc, telos_rpc, block_delta).await);
+}
+
+pub async fn storage_matches(evm_rpc: &str, telos_rpc: &str, block_delta: u32) -> bool {
+ let api_client = APIClient::::default_provider(telos_rpc.into(), Some(5)).unwrap();
+ let info = api_client.v1_chain.get_info().await.unwrap();
+
+ let provider = ProviderBuilder::new()
+ .on_http(Url::from_str(evm_rpc).unwrap());
+
+ let evm_block_num = info.head_block_num - block_delta;
+ println!("Telos EVM Block Number: {:?}", evm_block_num);
+
+ let mut has_more = true;
+ let mut lower_bound = Some(TableIndexType::UINT64(0));
+
+ let mut count = 0;
+
+ let evm_block_id = BlockId::from(evm_block_num as u64);
+ let mut match_counter = MatchCounter::new(evm_block_id);
+
+ while has_more {
+ let query_params = GetTableRowsParams {
+ code: name!("eosio.evm"),
+ table: name!("account"),
+ scope: None,
+ lower_bound,
+ upper_bound: None,
+ limit: Some(5000),
+ reverse: None,
+ index_position: None,
+ show_payer: None,
+ };
+ let account_rows = api_client.v1_chain.get_table_rows::(query_params).await;
+ if let Ok(account_rows) = account_rows {
+ lower_bound = account_rows.next_key;
+ has_more = lower_bound.is_some();
+ for account_row in account_rows.rows {
+ let address = Address::from_slice(account_row.address.data.as_slice());
+ lower_bound = Some(TableIndexType::UINT64(account_row.index + 1));
+ compare_account(&mut match_counter, &account_row, &api_client, &provider).await;
+ count += 1;
+ }
+ } else {
+ panic!("Failed to fetch account row");
+ }
+ }
+
+ match_counter.print();
+ match_counter.matches()
+}
+
+async fn compare_account(match_counter: &mut MatchCounter, account_row: &AccountRow, api_client: &APIClient, provider: &ReqwestProvider) {
+ let at_block = match_counter.evm_block_number;
+ let address = Address::from_slice(account_row.address.data.as_slice());
+ let telos_balance = U256::from_be_slice(account_row.balance.data.as_slice());
+
+ let reth_balance = provider.get_balance(address).block_id(at_block).await.unwrap();
+ let reth_nonce = provider.get_transaction_count(address).block_id(at_block).await.unwrap();
+ let reth_code = provider.get_code_at(address).block_id(at_block).await.unwrap().to_vec();
+
+ let balance_missmatch = telos_balance != reth_balance;
+ let nonce_missmatch = account_row.nonce != reth_nonce;
+ let code_missmatch = account_row.code != reth_code;
+
+ if balance_missmatch || nonce_missmatch || code_missmatch {
+ println!("ACCOUNT MISMATCH!!!");
+ println!("Account: {:?}", address);
+ println!("Telos balance: {:?}", telos_balance);
+ println!("Telos nonce: {:?}", account_row.nonce);
+ println!("Telos code: {:?}", account_row.code);
+ println!("Reth balance: {:?}", reth_balance);
+ println!("Reth nonce: {:?}", reth_nonce);
+ println!("Reth code: {:?}", reth_code);
+ match_counter.add_mismatched_account();
+ } else {
+ match_counter.add_matching_account();
+ }
+
+ compare_account_storage(match_counter, account_row, api_client, provider).await;
+}
+
+async fn compare_account_storage(match_counter: &mut MatchCounter, account_row: &AccountRow, api_client: &APIClient, provider: &ReqwestProvider) {
+ let address = Address::from_slice(account_row.address.data.as_slice());
+
+ let mut has_more = true;
+ let mut lower_bound = Some(TableIndexType::UINT64(0));
+
+ let mut count = 0;
+
+ while has_more {
+ let scope = if account_row.index == 0 {
+ Some(name!(""))
+ } else {
+ Some(Name::from_u64(account_row.index))
+ };
+ let query_params = GetTableRowsParams {
+ code: name!("eosio.evm"),
+ table: name!("accountstate"),
+ scope: Some(scope.unwrap()),
+ lower_bound,
+ upper_bound: None,
+ limit: Some(5000),
+ reverse: None,
+ index_position: None,
+ show_payer: None,
+ };
+ let account_state_rows = api_client.v1_chain.get_table_rows::(query_params).await;
+ if let Ok(account_state_rows) = account_state_rows {
+ lower_bound = account_state_rows.next_key;
+ has_more = lower_bound.is_some();
+ for account_state_row in account_state_rows.rows {
+ let key = U256::from_be_slice(account_state_row.key.data.as_slice());
+ let telos_value: U256 = U256::from_be_slice(account_state_row.value.data.as_slice());
+ let reth_value: U256 = provider.get_storage_at(address, key).block_id(match_counter.evm_block_number).await.unwrap();
+ if telos_value != reth_value {
+ match_counter.add_mismatched_account_storage();
+ println!("STORAGE MISMATCH!!!");
+ println!("Storage account: {:?} with scope: {:?} and key: {:?}", address, scope.unwrap(), key);
+ println!("Telos Storage value: {:?}", telos_value);
+ println!("Reth storage value: {:?}", reth_value);
+ } else {
+ match_counter.add_matching_account_storage();
+ }
+ lower_bound = Some(TableIndexType::UINT64(account_state_row.index + 1));
+ count += 1;
+ }
+ } else {
+ panic!("Failed to fetch account state row");
+ }
+ }
+}
\ No newline at end of file
diff --git a/crates/telos/primitives-traits/Cargo.toml b/crates/telos/primitives-traits/Cargo.toml
index 08755271599d..d728cd7a679a 100644
--- a/crates/telos/primitives-traits/Cargo.toml
+++ b/crates/telos/primitives-traits/Cargo.toml
@@ -14,6 +14,7 @@ alloy-consensus = { workspace = true }
alloy-primitives = { version = "0.8.5", features = ["rlp"], default-features = false }
alloy-eips = { version = "0.4", features = ["kzg-sidecar"], default-features = false }
alloy-rlp = { version = "0.3", default-features = false }
+alloy-rpc-types = { version = "0.4", default-features = false }
alloy-serde = { version = "0.4", optional = true, default-features = false }
serde = { version = "1.0", features = ["derive", "alloc"], default-features = false }
serde_with = { version = "3.3.0", optional = true }
diff --git a/crates/telos/primitives-traits/src/header.rs b/crates/telos/primitives-traits/src/header.rs
index a16e63e25e6c..41777da226b1 100644
--- a/crates/telos/primitives-traits/src/header.rs
+++ b/crates/telos/primitives-traits/src/header.rs
@@ -15,6 +15,7 @@ use alloy_rlp::{
length_of_length, Buf, BufMut, Decodable, Encodable, EMPTY_LIST_CODE, EMPTY_STRING_CODE,
};
use core::mem;
+use alloy_rpc_types::ConversionError;
use reth_codecs::Compact;
use crate::TelosBlockExtension;
@@ -946,3 +947,35 @@ impl Compact for TelosHeader {
(alloy_header, buf)
}
}
+
+#[cfg(feature = "serde")]
+impl TryFrom for TelosHeader {
+ type Error = ConversionError;
+
+ fn try_from(header: alloy_rpc_types::Header) -> Result {
+ Ok(Self {
+ parent_hash: header.parent_hash,
+ ommers_hash: header.uncles_hash,
+ beneficiary: header.miner,
+ state_root: header.state_root,
+ transactions_root: header.transactions_root,
+ receipts_root: header.receipts_root,
+ logs_bloom: header.logs_bloom,
+ difficulty: header.difficulty,
+ number: header.number,
+ gas_limit: header.gas_limit,
+ gas_used: header.gas_used,
+ timestamp: header.timestamp,
+ extra_data: header.extra_data,
+ mix_hash: header.mix_hash.unwrap_or_default(),
+ nonce: header.nonce.unwrap_or_default(),
+ base_fee_per_gas: header.base_fee_per_gas,
+ withdrawals_root: header.withdrawals_root,
+ blob_gas_used: header.blob_gas_used,
+ excess_blob_gas: header.excess_blob_gas,
+ parent_beacon_block_root: header.parent_beacon_block_root,
+ requests_root: header.requests_root,
+ telos_block_extension: TelosBlockExtension::default(),
+ })
+ }
+}
\ No newline at end of file
diff --git a/crates/telos/rpc-engine-api/Cargo.toml b/crates/telos/rpc-engine-api/Cargo.toml
index 30e0d56832e9..417f4537c268 100644
--- a/crates/telos/rpc-engine-api/Cargo.toml
+++ b/crates/telos/rpc-engine-api/Cargo.toml
@@ -16,6 +16,7 @@ reth-storage-errors.workspace = true
revm.workspace = true
revm-primitives.workspace = true
tracing.workspace = true
+sha2.workspace = true
[lints]
workspace = true
diff --git a/crates/telos/rpc-engine-api/src/compare.rs b/crates/telos/rpc-engine-api/src/compare.rs
index 5c0367763ed0..b11bed53ce1b 100644
--- a/crates/telos/rpc-engine-api/src/compare.rs
+++ b/crates/telos/rpc-engine-api/src/compare.rs
@@ -1,13 +1,112 @@
use std::collections::HashSet;
use std::fmt::Display;
-use alloy_primitives::{Address, B256, U256};
-use revm_primitives::HashMap;
-use revm::db::AccountStatus;
-use revm::{Database, Evm, State, TransitionAccount};
-use tracing::debug;
+use alloy_primitives::{Address, B256, Bytes, U256};
+use revm_primitives::{Account, AccountInfo, Bytecode, EvmStorageSlot, HashMap};
+use revm::{Database, Evm, State, TransitionAccount, db::AccountStatus as DBAccountStatus};
+use revm_primitives::db::DatabaseCommit;
+use revm_primitives::state::AccountStatus;
+use sha2::{Digest, Sha256};
+use tracing::{debug, warn, info};
+use reth_primitives::KECCAK_EMPTY;
use reth_storage_errors::provider::ProviderError;
use crate::structs::{TelosAccountStateTableRow, TelosAccountTableRow};
+struct StateOverride {
+ accounts: HashMap
+}
+
+impl StateOverride {
+ pub fn new() -> Self {
+ StateOverride {
+ accounts: HashMap::default()
+ }
+ }
+
+ fn maybe_init_account (&mut self, revm_db: &mut &mut State, address: Address) {
+ let maybe_acc = self.accounts.get_mut(&address);
+ if maybe_acc.is_none() {
+ let mut status = AccountStatus::LoadedAsNotExisting | AccountStatus::Touched;
+ let info = match revm_db.basic(address) {
+ Ok(maybe_info) => {
+ maybe_info.unwrap_or_else(|| AccountInfo::default())
+ },
+ Err(_) => {
+ status = AccountStatus::Created | AccountStatus::Touched;
+ AccountInfo::default()
+ }
+ };
+
+ self.accounts.insert(address, Account {
+ info,
+ storage: Default::default(),
+ status,
+ });
+ }
+ }
+
+ pub fn override_account (&mut self, revm_db: &mut &mut State, telos_row: &TelosAccountTableRow) {
+ self.maybe_init_account(revm_db, telos_row.address);
+ let mut acc = self.accounts.get_mut(&telos_row.address).unwrap();
+ acc.info.balance = telos_row.balance;
+ acc.info.nonce = telos_row.nonce;
+ if telos_row.code.len() > 0 {
+ acc.info.code_hash = B256::from_slice(Sha256::digest(telos_row.code.as_ref()).as_slice());
+ acc.info.code = Some(Bytecode::LegacyRaw(telos_row.code.clone()));
+ } else {
+ acc.info.code_hash = KECCAK_EMPTY;
+ acc.info.code = None;
+ }
+ }
+
+ pub fn override_balance (&mut self, revm_db: &mut &mut State, address: Address, balance: U256) {
+ self.maybe_init_account(revm_db, address);
+ let mut acc = self.accounts.get_mut(&address).unwrap();
+ acc.info.balance = balance;
+ }
+
+ pub fn override_nonce (&mut self, revm_db: &mut &mut State, address: Address, nonce: u64) {
+ self.maybe_init_account(revm_db, address);
+ let mut acc = self.accounts.get_mut(&address).unwrap();
+ acc.info.nonce = nonce;
+ }
+
+ pub fn override_code (&mut self, revm_db: &mut &mut State, address: Address, maybe_code: &Bytes) {
+ self.maybe_init_account(revm_db, address);
+ let mut acc = self.accounts.get_mut(&address).unwrap();
+ if maybe_code.len() > 0 {
+ acc.info.code_hash = B256::from_slice(Sha256::digest(maybe_code.as_ref()).as_slice());
+ acc.info.code = Some(Bytecode::LegacyRaw(maybe_code.clone()));
+ } else {
+ acc.info.code_hash = KECCAK_EMPTY;
+ acc.info.code = None;
+ }
+ }
+
+ pub fn override_storage (&mut self, revm_db: &mut &mut State, address: Address, key: U256, new_val: U256, old_val: U256) {
+ self.maybe_init_account(revm_db, address);
+ let mut acc = self.accounts.get_mut(&address).unwrap();
+ acc.storage.insert(key, EvmStorageSlot {
+ original_value: old_val,
+ present_value: new_val,
+ is_cold: false
+ });
+ }
+
+ pub fn apply (&self, revm_db: &mut &mut State) {
+ revm_db.commit(self.accounts.clone());
+ }
+}
+
+macro_rules! maybe_panic {
+ ($panic_mode:expr, $($arg:tt)*) => {
+ if $panic_mode {
+ panic!($($arg)*);
+ } else {
+ warn!($($arg)*);
+ }
+ };
+}
+
/// This function compares the state diffs between revm and Telos EVM contract
pub fn compare_state_diffs(
evm: &mut Evm<'_, Ext, &mut State>,
@@ -16,6 +115,7 @@ pub fn compare_state_diffs(
statediffs_accountstate: Vec,
_new_addresses_using_create: Vec<(u64, U256)>,
new_addresses_using_openwallet: Vec<(u64, U256)>,
+ panic_mode: bool
) -> bool
where
DB: Database,
@@ -34,6 +134,8 @@ where
let revm_db: &mut &mut State = evm.db_mut();
+ let mut state_override = StateOverride::new();
+
let mut new_addresses_using_openwallet_hashset = HashSet::new();
for row in &new_addresses_using_openwallet {
new_addresses_using_openwallet_hashset.insert(Address::from_word(B256::from(row.1)));
@@ -43,10 +145,10 @@ where
for row in &statediffs_account {
statediffs_account_hashmap.insert(row.address);
}
- let mut statediffs_accountstate_hashmap = HashSet::new();
- for row in &statediffs_accountstate {
- statediffs_accountstate_hashmap.insert((row.address,row.key));
- }
+ // let mut statediffs_accountstate_hashmap = HashSet::new();
+ // for row in &statediffs_accountstate {
+ // statediffs_accountstate_hashmap.insert((row.address,row.key));
+ // }
for row in &statediffs_account {
// Skip if address is created using openwallet and is empty
@@ -55,80 +157,138 @@ where
}
// Skip if row is removed
if row.removed {
+ // TODO: Does the Telos EVM contract ever remove account rows, or should this be a panic??
continue
}
if let Ok(revm_row) = revm_db.basic(row.address) {
if let Some(unwrapped_revm_row) = revm_row {
// Check balance inequality
if unwrapped_revm_row.balance != row.balance {
- panic!("Difference in balance, address: {:?} - revm: {:?} - tevm: {:?}",row.address,unwrapped_revm_row.balance,row.balance);
+ maybe_panic!(panic_mode, "Difference in balance, address: {:?} - revm: {:?} - tevm: {:?}",row.address,unwrapped_revm_row.balance,row.balance);
+ state_override.override_balance(revm_db, row.address, row.balance);
}
// Check nonce inequality
if unwrapped_revm_row.nonce != row.nonce {
- panic!("Difference in nonce, address: {:?} - revm: {:?} - tevm: {:?}",row.address,unwrapped_revm_row.nonce,row.nonce);
+ maybe_panic!(panic_mode, "Difference in nonce, address: {:?} - revm: {:?} - tevm: {:?}",row.address,unwrapped_revm_row.nonce,row.nonce);
+ state_override.override_nonce(revm_db, row.address, row.nonce);
}
// Check code size inequality
- if unwrapped_revm_row.clone().code.is_none() && row.code.len() != 0 || unwrapped_revm_row.clone().code.is_some() && !unwrapped_revm_row.clone().code.unwrap().is_empty() && row.code.len() == 0 {
- match revm_db.code_by_hash(unwrapped_revm_row.code_hash) {
- Ok(code_by_hash) =>
- if (code_by_hash.is_empty() && row.code.len() != 0) || (!code_by_hash.is_empty() && row.code.len() == 0) {
- panic!("Difference in code existence, address: {:?} - revm: {:?} - tevm: {:?}",row.address,code_by_hash,row.code)
- },
- Err(_) => panic!("Difference in code existence, address: {:?} - revm: {:?} - tevm: {:?}",row.address,unwrapped_revm_row.code,row.code),
+ let maybe_revm_code = unwrapped_revm_row.clone().code;
+
+ match maybe_revm_code {
+ None => {
+ if row.code.len() != 0 {
+ match revm_db.code_by_hash(unwrapped_revm_row.code_hash()) {
+ Ok(bytecode) => {
+ if bytecode.len() != row.code.len() {
+ maybe_panic!(panic_mode, "Difference in code size, address: {:?} - revm: {} - tevm: {}",row.address,bytecode.len(),row.code.len());
+ state_override.override_code(revm_db, row.address, &row.code);
+ }
+ }
+ Err(_) => {
+ maybe_panic!(panic_mode, "Difference in code existence, error while fetching db, address: {:?} - revm: Err - tevm: {}",row.address,row.code.len());
+ state_override.override_code(revm_db, row.address, &row.code);
+ }
+ }
+ }
+ }
+ Some(revm_bytecode) => {
+ match revm_bytecode {
+ Bytecode::LegacyRaw(code) => {
+ if code.len() != row.code.len() {
+ maybe_panic!(panic_mode, "Difference in legacy code size, address: {:?} - revm: {:?} - tevm: {:?}",row.address,code.len(),row.code.len());
+ state_override.override_code(revm_db, row.address, &row.code);
+ }
+ }
+ Bytecode::LegacyAnalyzed(code) => {
+ if code.original_len() != row.code.len() {
+ maybe_panic!(panic_mode, "Difference in legacy (analyzed) code size, address: {:?} - revm: {:?} - tevm: {:?}",row.address,code.original_len(),row.code.len());
+ state_override.override_code(revm_db, row.address, &row.code);
+ }
+ }
+ Bytecode::Eof(_) => panic!("Eof not implemented!"),
+ Bytecode::Eip7702(_) => panic!("EIP7702 not implemented!")
+ }
}
}
// // Check code content inequality
// if unwrapped_revm_row.clone().unwrap().code.is_some() && !unwrapped_revm_row.clone().unwrap().code.unwrap().is_empty() && unwrapped_revm_row.clone().unwrap().code.unwrap().bytes() != row.code {
- // panic!("Difference in code content, revm: {:?}, tevm: {:?}",unwrapped_revm_row.clone().unwrap().code.unwrap().bytes(),row.code);
+ // panic!(panic_mode, "Difference in code content, revm: {:?}, tevm: {:?}",unwrapped_revm_row.clone().unwrap().code.unwrap().bytes(),row.code);
// }
} else {
// Skip if address is empty on both sides
if !(row.balance == U256::ZERO && row.nonce == 0 && row.code.len() == 0) {
if let Some(unwrapped_revm_state_diff) = revm_state_diffs.get(&row.address) {
- if !(unwrapped_revm_state_diff.status == AccountStatus::Destroyed && row.nonce == 0 && row.balance == U256::ZERO && row.code.len() == 0) {
- panic!("A modified `account` table row was found on both revm state and revm state diffs, but seems to be destroyed on just one side, address: {:?}",row.address);
+ if !(unwrapped_revm_state_diff.status == DBAccountStatus::Destroyed && row.nonce == 0 && row.balance == U256::ZERO && row.code.len() == 0) {
+ maybe_panic!(panic_mode, "A modified `account` table row was found on both revm state and revm state diffs, but seems to be destroyed on just one side, address: {:?}",row.address);
+ state_override.override_account(revm_db, &row);
}
} else {
- panic!("A modified `account` table row was found on revm state, but contains no information, address: {:?}",row.address);
+ maybe_panic!(panic_mode, "A modified `account` table row was found on revm state, but contains no information, address: {:?}",row.address);
+ state_override.override_account(revm_db, &row);
}
}
}
} else {
// Skip if address is empty on both sides
if !(row.balance == U256::ZERO && row.nonce == 0 && row.code.len() == 0) {
- panic!("A modified `account` table row was not found on revm state, address: {:?}",row.address);
+ maybe_panic!(panic_mode, "A modified `account` table row was not found on revm state, address: {:?}",row.address);
+ state_override.override_account(revm_db, &row);
}
}
}
- for row in &statediffs_accountstate {
- if let Ok(revm_row) = revm_db.storage(row.address, row.key) {
- // The values should match, but if it is removed, then the revm value should be zero
- if !(revm_row == row.value) && !(revm_row != U256::ZERO || row.removed == true) {
- panic!("Difference in value on revm storage, address: {:?}, key: {:?}, revm-value: {:?}, tevm-row: {:?}",row.address,row.key,revm_row,row);
- }
- } else {
- panic!("Key was not found on revm storage, address: {:?}, key: {:?}",row.address,row.key);
- }
- }
+ // for row in &statediffs_accountstate {
+ // if let None = revm_db.cache.accounts.get_mut(&row.address) {
+ // let cached_account = revm_db.load_cache_account(row.address);
+ // match cached_account {
+ // Ok(cached_account) => {
+ // if cached_account.account.is_none() {
+ // panic!("An account state modification was made for an account that is not in revm storage, address: {:?}", row.address);
+ // }
+ // },
+ // Err(_) => {
+ // panic!("An account state modification was made for an account that returned Err from load_cache_account, address: {:?}", row.address);
+ // }
+ // }
+ // }
+ // if let Ok(revm_row) = revm_db.storage(row.address, row.key) {
+ // // The values should match, but if it is removed, then the revm value should be zero
+ // if revm_row != row.value {
+ // if revm_row != U256::ZERO && row.removed == true {
+ // maybe_panic!(panic_mode, "Difference in value on revm storage, removed on Telos, non-ZERO on revm, address: {:?}, key: {:?}, revm-value: {:?}, tevm-row: {:?}", row.address, row.key, revm_row, row);
+ // state_override.override_storage(revm_db, row.address, row.key, U256::ZERO, revm_row);
+ // }
+ // if row.removed == false {
+ // maybe_panic!(panic_mode, "Difference in value on revm storage, address: {:?}, key: {:?}, revm-value: {:?}, tevm-row: {:?}", row.address, row.key, revm_row, row);
+ // state_override.override_storage(revm_db, row.address, row.key, row.value, revm_row);
+ // }
+ // }
+ // } else {
+ // maybe_panic!(panic_mode, "Key was not found on revm storage, address: {:?}, key: {:?}",row.address,row.key);
+ // state_override.override_storage(revm_db, row.address, row.key, row.value, U256::ZERO);
+ // }
+ // }
for (address, account) in &revm_state_diffs {
if let (Some(info),Some(previous_info)) = (account.info.clone(),account.previous_info.clone()) {
if !(info.balance == previous_info.balance && info.nonce == previous_info.nonce && info.code_hash == previous_info.code_hash) {
if statediffs_account_hashmap.get(address).is_none() {
- panic!("A modified address was not found on tevm state diffs, address: {:?}",address);
+ panic!("A modified address was not found on tevm state diffs, address: {:?}",address);
}
}
} else {
if statediffs_account_hashmap.get(address).is_none() {
- panic!("A modified address was not found on tevm state diffs, address: {:?}",address);
- }
- }
- for (key,_) in account.storage.clone() {
- if statediffs_accountstate_hashmap.get(&(*address,key)).is_none() {
- panic!("A modified storage slot was not found on tevm state diffs, address: {:?}",address);
+ panic!("A modified address was not found on tevm state diffs, info/previous_info were not Some, address: {:?}",address);
}
}
+ // for (key,_) in account.storage.clone() {
+ // if statediffs_accountstate_hashmap.get(&(*address,key)).is_none() {
+ // panic!("A modified storage slot was not found on tevm state diffs, address: {:?}, key: {:?}", address, key);
+ // }
+ // }
}
-
- return true
+
+ state_override.apply(revm_db);
+
+ true
}
diff --git a/crates/telos/rpc/src/eth/mod.rs b/crates/telos/rpc/src/eth/mod.rs
index fd3227b6a0fa..42e4c8f06aeb 100644
--- a/crates/telos/rpc/src/eth/mod.rs
+++ b/crates/telos/rpc/src/eth/mod.rs
@@ -26,7 +26,7 @@ use reth_provider::{
BlockIdReader, BlockNumReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider,
StageCheckpointReader, StateProviderFactory,
};
-use reth_rpc::eth::{core::EthApiInner, DevSigner};
+use reth_rpc::eth::{core::EthApiInner, DevSigner, EthTxBuilder};
use reth_rpc_eth_api::{
helpers::{
AddDevSigners, EthApiSpec, EthFees, EthSigner, EthState, LoadBlock, LoadFee, LoadState,
@@ -104,7 +104,7 @@ where
{
type Error = TelosEthApiError;
type NetworkTypes = AnyNetwork;
- type TransactionCompat = ();
+ type TransactionCompat = EthTxBuilder;
}
impl EthApiSpec for TelosEthApi