diff --git a/Cargo.lock b/Cargo.lock index ff5652518..34b9005a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,12 +157,6 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" -[[package]] -name = "arc-swap" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" - [[package]] name = "ark-ff" version = "0.3.0" @@ -465,27 +459,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "binary_macros" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97f04c0f684dc99a60afdd43630fba712e2511dc514dd0a10fb1a6674771be6e" -dependencies = [ - "binary_macros_impl", - "proc-macro-hack", -] - -[[package]] -name = "binary_macros_impl" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e118b97bd238be7b22b50bb5d9380686603ccb6307daf134d02eea75754d63f" -dependencies = [ - "data-encoding", - "dotenv", - "proc-macro-hack", -] - [[package]] name = "bincode" version = "1.3.3" @@ -1045,12 +1018,6 @@ dependencies = [ "syn 2.0.76", ] -[[package]] -name = "data-encoding" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" - [[package]] name = "debugid" version = "0.8.0" @@ -1157,12 +1124,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - [[package]] name = "dotenvy" version = "0.15.7" @@ -1392,17 +1353,6 @@ dependencies = [ "rand", ] -[[package]] -name = "fancy-duration" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3ae60718ae501dca9d27fd0e322683c86a95a1a01fac1807aa2f9b035cc0882" -dependencies = [ - "anyhow", - "lazy_static", - "regex", -] - [[package]] name = "fastrand" version = "2.0.1" @@ -2998,15 +2948,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "openssl-src" -version = "300.2.2+3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bbfad0063610ac26ee79f7484739e2b07555a75c42453b89263830b5c8103bc" -dependencies = [ - "cc", -] - [[package]] name = "openssl-sys" version = "0.9.104" @@ -3015,7 +2956,6 @@ checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", - "openssl-src", "pkg-config", "vcpkg", ] @@ -3404,12 +3344,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.86" @@ -3619,23 +3553,6 @@ dependencies = [ "sasl2-sys", ] -[[package]] -name = "redis" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc5b667390cb038bc65fc4b18c06e2550469f7e06a02d886f1a018a11f63563" -dependencies = [ - "arc-swap", - "combine", - "itoa", - "num-bigint", - "percent-encoding", - "ryu", - "sha1_smol", - "socket2", - "url", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -4595,12 +4512,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha1_smol" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" - [[package]] name = "sha2" version = "0.10.8" @@ -4988,7 +4899,6 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "binary_macros", "bincode", "cfg-if", "chrono", @@ -5005,7 +4915,6 @@ dependencies = [ "ethereum-types", "ethers-core", "fake", - "fancy-duration", "futures", "futures-channel", "futures-timer", @@ -5030,7 +4939,6 @@ dependencies = [ "nonempty", "once_cell", "oneshot", - "openssl", "opentelemetry", "opentelemetry-otlp", "opentelemetry_sdk", @@ -5043,7 +4951,6 @@ dependencies = [ "quick_cache", "rand", "rdkafka", - "redis", "reqwest 0.12.4", "revm", "rlp", @@ -5061,7 +4968,6 @@ dependencies = [ "smallvec", "sqlx", "static_assertions", - "stringreader", "strum", "sugars", "tempfile", @@ -5092,12 +4998,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "stringreader" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "913e7b03d63752f6cdd2df77da36749d82669904798fe8944b9ec3d23f159905" - [[package]] name = "strsim" version = "0.11.1" diff --git a/Cargo.toml b/Cargo.toml index 6db3cb008..efb72fa0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -111,7 +111,6 @@ tracing-subscriber = { version = "=0.3.18", features = ["env-filter", "json"] } tracing-serde = "=0.1.3" # storage -redis = "=0.26.0" rocksdb = { version = "=0.22.0", features = ["multi-threaded-cf"] } sqlx = { version = "=0.8.2", features = [ "runtime-tokio", @@ -123,7 +122,6 @@ sqlx = { version = "=0.8.2", features = [ # test fake = { version = "=2.9.2", features = ["chrono", "derive"] } rdkafka = {version = "=0.36.2", features = ["ssl", "sasl"] } -openssl = { version = "=0.10.68", features = ["vendored"] } sasl2-sys = { version = "=0.1.22", features = ["vendored"] } # Historic events processor @@ -153,10 +151,7 @@ console-subscriber = { git = "https://github.com/tokio-rs/console.git", rev = "8 # ------------------------------------------------------------------------------ [dev-dependencies] -binary_macros = "=1.0.0" -fancy-duration = "=0.9.2" serde_plain = "=1.0.2" -stringreader = "=0.1.1" tempfile = "=3.10.1" glob = "=0.3.1" diff --git a/README.md b/README.md index 77ef35624..3760bb5aa 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ Welcome to Stratus, the cutting-edge EVM executor and JSON-RPC server with custo ## Current storage implementations - In Memory -- Redis - RocksDB (default) ## Performance Landscape diff --git a/docker-compose.yaml b/docker-compose.yaml index c549984fe..6b87ba146 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -24,22 +24,7 @@ services: - manual # ---------------------------------------------------------------------------- - # Redis - # ---------------------------------------------------------------------------- - redis: - image: redis:7.2.5 - ports: - - "6379:6379" - - redis-commander: - image: rediscommander/redis-commander:latest - ports: - - "8081:8081" - environment: - - REDIS_HOSTS=local:redis:6379 - - # ---------------------------------------------------------------------------- - # PromethMeus + # Prometheus # ---------------------------------------------------------------------------- prometheus: image: prom/prometheus diff --git a/e2e/cloudwalk-contracts/integration/package-lock.json b/e2e/cloudwalk-contracts/integration/package-lock.json index 48a848ee3..f2051e77e 100644 --- a/e2e/cloudwalk-contracts/integration/package-lock.json +++ b/e2e/cloudwalk-contracts/integration/package-lock.json @@ -12,7 +12,7 @@ }, "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^4.0.0", - "@openzeppelin/hardhat-upgrades": "^3.0.1", + "@openzeppelin/hardhat-upgrades": "3.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "axios": "^1.6.7", "ethers": "^6.9.0", @@ -1909,15 +1909,15 @@ } }, "node_modules/@openzeppelin/hardhat-upgrades": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-3.5.0.tgz", - "integrity": "sha512-Ju/JnT7NRiOMi5m5Y0dGiz37d8wnjVBep1v5Vr7+6+MFNuQa1yddUEVWhWhoEw4udI3/mYwyw4Sfz3sq7vhicQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-3.3.0.tgz", + "integrity": "sha512-0RwCpkBKWViG0nIERk8tV5E71DCtZ6PXgsjoCYg+Bi2IWYgD8Skt4Q8b6QqE7tuWsFCK5yVQIVfCFL99JKMK5A==", "dev": true, "dependencies": { "@openzeppelin/defender-sdk-base-client": "^1.14.4", "@openzeppelin/defender-sdk-deploy-client": "^1.14.4", "@openzeppelin/defender-sdk-network-client": "^1.14.4", - "@openzeppelin/upgrades-core": "^1.40.0", + "@openzeppelin/upgrades-core": "^1.35.0", "chalk": "^4.1.0", "debug": "^4.1.1", "ethereumjs-util": "^7.1.5", diff --git a/e2e/cloudwalk-contracts/integration/package.json b/e2e/cloudwalk-contracts/integration/package.json index 9d921e2a3..2c9e5b96e 100644 --- a/e2e/cloudwalk-contracts/integration/package.json +++ b/e2e/cloudwalk-contracts/integration/package.json @@ -2,7 +2,7 @@ "name": "hardhat-project", "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^4.0.0", - "@openzeppelin/hardhat-upgrades": "^3.0.1", + "@openzeppelin/hardhat-upgrades": "3.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "axios": "^1.6.7", "ethers": "^6.9.0", diff --git a/justfile b/justfile index 08559f5df..6e67a4ec6 100644 --- a/justfile +++ b/justfile @@ -364,8 +364,6 @@ e2e-leader-follower-up test="brlc" release_flag="--release": fi ) fi - killport 3000 -s sigterm - killport 3001 -s sigterm # E2E: Leader & Follower Down e2e-leader-follower-down: @@ -543,6 +541,8 @@ stratus-test-coverage output="": -rm -r temp_3001-rocksdb -docker compose down -v just e2e-leader-follower-up kafka " " + killport 3000 -s sigterm + killport 3001 -s sigterm sleep 10 -rm -r e2e_logs -rm utils/deploy/deploy_01.log @@ -551,6 +551,8 @@ stratus-test-coverage output="": -rm -r temp_3000-rocksdb -rm -r temp_3001-rocksdb just e2e-leader-follower-up deploy " " + killport 3000 -s sigterm + killport 3001 -s sigterm sleep 10 -rm -r e2e_logs -rm utils/deploy/deploy_01.log @@ -559,6 +561,8 @@ stratus-test-coverage output="": -rm -r temp_3000-rocksdb -rm -r temp_3001-rocksdb just e2e-leader-follower-up brlc " " + killport 3000 -s sigterm + killport 3001 -s sigterm sleep 10 -rm -r e2e_logs -rm utils/deploy/deploy_01.log @@ -567,6 +571,8 @@ stratus-test-coverage output="": -rm -r temp_3000-rocksdb -rm -r temp_3001-rocksdb just e2e-leader-follower-up change " " + killport 3000 -s sigterm + killport 3001 -s sigterm sleep 10 -rm -r e2e_logs -rm utils/deploy/deploy_01.log @@ -575,6 +581,8 @@ stratus-test-coverage output="": -rm -r temp_3000-rocksdb -rm -r temp_3001-rocksdb just e2e-leader-follower-up miner " " + killport 3000 -s sigterm + killport 3001 -s sigterm sleep 10 -rm -r e2e_logs -rm utils/deploy/deploy_01.log @@ -583,6 +591,8 @@ stratus-test-coverage output="": -rm -r temp_3000-rocksdb -rm -r temp_3001-rocksdb just e2e-leader-follower-up importer " " + killport 3000 -s sigterm + killport 3001 -s sigterm sleep 10 -rm -r e2e_logs -rm utils/deploy/deploy_01.log diff --git a/src/bin/historic_events_processor.rs b/src/bin/historic_events_processor.rs index a9156a010..319d976d2 100644 --- a/src/bin/historic_events_processor.rs +++ b/src/bin/historic_events_processor.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::time::Duration; use anyhow::Context; @@ -6,7 +7,10 @@ use chrono::TimeZone; use chrono::Timelike; use indicatif::ProgressBar; use rocksdb::properties::ESTIMATE_NUM_KEYS; +use stratus::eth::primitives::TransactionMined; +use stratus::eth::storage::permanent::rocks::types::BlockNumberRocksdb; use stratus::eth::storage::permanent::rocks::types::BlockRocksdb; +use stratus::eth::storage::permanent::rocks::types::HashRocksdb; use stratus::eth::storage::permanent::rocks::types::TransactionMinedRocksdb; use stratus::eth::storage::permanent::rocks::types::UnixTimeRocksdb; use stratus::eth::storage::permanent::rocks::RocksStorageState; @@ -18,8 +22,14 @@ use stratus::ledger::events::Event; const TIMEOUT: Duration = Duration::from_secs(5); /// Converts a mined transaction from RocksDB to account transfer events -fn transaction_mined_rocks_db_to_events(block_timestamp: UnixTimeRocksdb, tx: TransactionMinedRocksdb) -> Vec { - transaction_to_events(block_timestamp.into(), std::borrow::Cow::Owned(tx.into())) +fn transaction_mined_rocks_db_to_events( + block_timestamp: UnixTimeRocksdb, + tx: TransactionMinedRocksdb, + block_number: BlockNumberRocksdb, + block_hash: HashRocksdb, +) -> Vec { + let tx = TransactionMined::from_rocks_primitives(tx, block_number, block_hash); + transaction_to_events(block_timestamp.into(), Cow::Owned(tx)) } /// Returns total count of blocks and transactions from RocksDB state @@ -72,7 +82,7 @@ fn process_block_events(block: BlockRocksdb) -> Vec { block .transactions .into_iter() - .flat_map(|tx| transaction_mined_rocks_db_to_events(timestamp, tx)) + .flat_map(|tx| transaction_mined_rocks_db_to_events(timestamp, tx, block.header.number, block.header.hash)) .map(|event| event.event_payload().unwrap()) .collect() } @@ -87,13 +97,13 @@ fn main() -> Result<(), anyhow::Error> { // Load last processed block number from file tracing::info!("loading last processed block"); let start_block = std::fs::read_to_string("last_processed_block") - .map(|s| s.trim().parse::().unwrap()) + .map(|s| s.trim().parse::().unwrap()) .unwrap_or(0); tracing::info!(?start_block); tracing::info!("creating rocksdb iterator"); let iter = if start_block > 0 { - b_pb.inc(start_block); + b_pb.inc(start_block.into()); state.blocks_by_number.iter_from(start_block.into(), rocksdb::Direction::Forward)? } else { state.blocks_by_number.iter_start() diff --git a/src/bin/importer_offline.rs b/src/bin/importer_offline.rs index 34d2abd52..095ab741d 100644 --- a/src/bin/importer_offline.rs +++ b/src/bin/importer_offline.rs @@ -291,7 +291,35 @@ fn run_block_saver(miner: Arc, from_executor_rx: mpsc::Receiver, block_start: BlockNumber, block_end: BlockNumber) -> anyhow::Result { tracing::info!(parent: None, %block_start, %block_end, "fetching blocks and receipts"); - rpc_storage.read_block_and_receipts_in_range(block_start, block_end).await + let mut blocks = rpc_storage.read_block_and_receipts_in_range(block_start, block_end).await?; + for (block, receipts) in blocks.iter_mut() { + // Stably sort transactions and receipts by transaction_index + block.transactions.sort_by(|a, b| a.transaction_index.cmp(&b.transaction_index)); + receipts.sort_by(|a, b| a.transaction_index.cmp(&b.transaction_index)); + + // perform additional checks on the transaction index + for window in block.transactions.windows(2) { + let tx_index = window[0].transaction_index.map_or(u32::MAX, |index| index.as_u32()); + let next_tx_index = window[1].transaction_index.map_or(u32::MAX, |index| index.as_u32()); + assert!( + tx_index + 1 == next_tx_index, + "two consecutive transactions must have consecutive indices: {} and {}", + tx_index, + next_tx_index, + ); + } + for window in receipts.windows(2) { + let tx_index = window[0].transaction_index.as_u32(); + let next_tx_index = window[1].transaction_index.as_u32(); + assert!( + tx_index + 1 == next_tx_index, + "two consecutive receipts must have consecutive indices: {} and {}", + tx_index, + next_tx_index, + ); + } + } + Ok(blocks) } async fn block_number_to_stop(rpc_storage: &Arc) -> anyhow::Result { diff --git a/src/eth/executor/evm.rs b/src/eth/executor/evm.rs index e15d518f3..ce202afe4 100644 --- a/src/eth/executor/evm.rs +++ b/src/eth/executor/evm.rs @@ -88,7 +88,7 @@ impl Evm { let cfg_env = evm.cfg_mut(); cfg_env.chain_id = chain_id; cfg_env.limit_contract_code_size = Some(usize::MAX); - cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Raw; + cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse; // global block config let block_env = evm.block_mut(); diff --git a/src/eth/executor/evm_input.rs b/src/eth/executor/evm_input.rs index 54a3e80d2..4a8bc6294 100644 --- a/src/eth/executor/evm_input.rs +++ b/src/eth/executor/evm_input.rs @@ -157,3 +157,16 @@ impl EvmInput { self.to.is_some() && not(self.data.is_empty()) } } + +impl PartialEq<(&TransactionInput, &PendingBlockHeader)> for EvmInput { + fn eq(&self, other: &(&TransactionInput, &PendingBlockHeader)) -> bool { + self.block_number == other.1.number + && self.block_timestamp == *other.1.timestamp + && self.chain_id == other.0.chain_id + && self.data == other.0.input + && self.from == other.0.signer + && self.nonce.is_some_and(|inner| inner == other.0.nonce) + && self.value == other.0.value + && self.to == other.0.to + } +} diff --git a/src/eth/follower/importer/importer.rs b/src/eth/follower/importer/importer.rs index 97a264e3a..4409c3780 100644 --- a/src/eth/follower/importer/importer.rs +++ b/src/eth/follower/importer/importer.rs @@ -30,7 +30,6 @@ use crate::ext::traced_sleep; use crate::ext::DisplayExt; use crate::ext::SleepReason; use crate::globals::IMPORTER_ONLINE_TASKS_SEMAPHORE; -use crate::if_else; use crate::infra::kafka::KafkaConnector; #[cfg(feature = "metrics")] use crate::infra::metrics; @@ -62,9 +61,8 @@ static EXTERNAL_RPC_CURRENT_BLOCK: AtomicU64 = AtomicU64::new(0); /// Only sets the external RPC current block number if it is equals or greater than the current one. fn set_external_rpc_current_block(new_number: BlockNumber) { - let new_number_u64 = new_number.as_u64(); let _ = EXTERNAL_RPC_CURRENT_BLOCK.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current_number| { - if_else!(new_number_u64 >= current_number, Some(new_number_u64), None) + Some(current_number.max(new_number.as_u64())) }); } @@ -440,7 +438,27 @@ impl Importer { // keep fetching in order let mut tasks = futures::stream::iter(tasks).buffered(PARALLEL_BLOCKS); - while let Some((block, receipts)) = tasks.next().await { + while let Some((mut block, mut receipts)) = tasks.next().await { + // Stably sort transactions and receipts by transaction_index + block.transactions.sort_by(|a, b| a.transaction_index.cmp(&b.transaction_index)); + receipts.sort_by(|a, b| a.transaction_index.cmp(&b.transaction_index)); + + // perform additional checks on the transaction index + for window in block.transactions.windows(2) { + let tx_index = window[0].transaction_index.map_or(u32::MAX, |index| index.as_u32()); + let next_tx_index = window[1].transaction_index.map_or(u32::MAX, |index| index.as_u32()); + if tx_index + 1 != next_tx_index { + tracing::error!(tx_index, next_tx_index, "two consecutive transactions must have consecutive indices"); + } + } + for window in receipts.windows(2) { + let tx_index = window[0].transaction_index.as_u32(); + let next_tx_index = window[1].transaction_index.as_u32(); + if tx_index + 1 != next_tx_index { + tracing::error!(tx_index, next_tx_index, "two consecutive receipts must have consecutive indices"); + } + } + if backlog_tx.send((block, receipts)).is_err() { warn_task_rx_closed(TASK_NAME); return Ok(()); diff --git a/src/eth/primitives/account.rs b/src/eth/primitives/account.rs index d4e1ffa25..edb4d764f 100644 --- a/src/eth/primitives/account.rs +++ b/src/eth/primitives/account.rs @@ -1,13 +1,13 @@ use display_json::DebugAsJson; +use revm::interpreter::analysis::to_analysed; +use revm::primitives::Bytecode; use crate::alias::RevmAccountInfo; use crate::alias::RevmAddress; use crate::eth::primitives::Address; -use crate::eth::primitives::Bytes; use crate::eth::primitives::CodeHash; use crate::eth::primitives::Nonce; use crate::eth::primitives::Wei; -use crate::ext::OptionExt; /// Ethereum account (wallet or contract). /// @@ -24,7 +24,8 @@ pub struct Account { pub balance: Wei, /// Contract bytecode. Present only if the account is a contract. - pub bytecode: Option, + #[dummy(default)] + pub bytecode: Option, /// Keccak256 Hash of the bytecode. If bytecode is null, then the hash of empty string. pub code_hash: CodeHash, @@ -57,7 +58,7 @@ impl Account { /// Checks the current account is a contract. pub fn is_contract(&self) -> bool { match self.bytecode { - Some(ref bytecode) => !bytecode.is_empty(), + Some(ref bytecode) => !bytecode.bytecode().is_empty(), None => false, } } @@ -70,11 +71,12 @@ impl From<(RevmAddress, RevmAccountInfo)> for Account { fn from(value: (RevmAddress, RevmAccountInfo)) -> Self { let (address, info) = value; + let code = info.code.map(to_analysed); Self { address: address.into(), nonce: info.nonce.into(), balance: info.balance.into(), - bytecode: info.code.map_into(), + bytecode: code, code_hash: info.code_hash.into(), } } @@ -90,7 +92,7 @@ impl From<&Account> for RevmAccountInfo { nonce: value.nonce.into(), balance: value.balance.into(), code_hash: value.code_hash.0 .0.into(), - code: value.bytecode.as_ref().cloned().map_into(), + code: value.bytecode.as_ref().cloned(), } } } diff --git a/src/eth/primitives/block_number.rs b/src/eth/primitives/block_number.rs index 5002b169c..0f722ad51 100644 --- a/src/eth/primitives/block_number.rs +++ b/src/eth/primitives/block_number.rs @@ -77,15 +77,17 @@ impl BlockNumber { } } - /// Converts itself to i64. pub fn as_i64(&self) -> i64 { self.0.as_u64() as i64 } - /// Converts itself to u64. pub fn as_u64(&self) -> u64 { self.0.as_u64() } + + pub fn as_u32(&self) -> u32 { + self.0.as_u64() as u32 + } } impl Dummy for BlockNumber { diff --git a/src/eth/primitives/bytes.rs b/src/eth/primitives/bytes.rs index 4e258c150..a76ae9e4d 100644 --- a/src/eth/primitives/bytes.rs +++ b/src/eth/primitives/bytes.rs @@ -62,12 +62,6 @@ impl From for Bytes { } } -impl From for Bytes { - fn from(value: RevmBytecode) -> Self { - Self(value.bytecode().clone().into()) - } -} - impl From for Bytes { fn from(value: RevmBytes) -> Self { Self(value.0.into()) diff --git a/src/eth/primitives/execution_account_changes.rs b/src/eth/primitives/execution_account_changes.rs index 9a009a475..47fe4c846 100644 --- a/src/eth/primitives/execution_account_changes.rs +++ b/src/eth/primitives/execution_account_changes.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; use display_json::DebugAsJson; +use revm::primitives::Bytecode; use super::CodeHash; use crate::eth::primitives::Account; use crate::eth::primitives::Address; -use crate::eth::primitives::Bytes; use crate::eth::primitives::ExecutionValueChange; use crate::eth::primitives::Nonce; use crate::eth::primitives::Slot; @@ -23,7 +23,8 @@ pub struct ExecutionAccountChanges { pub balance: ExecutionValueChange, // TODO: bytecode related information should be grouped in a Bytecode struct - pub bytecode: ExecutionValueChange>, + #[dummy(default)] + pub bytecode: ExecutionValueChange>, pub code_hash: CodeHash, // TODO: should be wrapped in a ExecutionValueChange #[cfg_attr(test, serde(serialize_with = "ordered_map"))] pub slots: HashMap>, diff --git a/src/eth/primitives/execution_value_change.rs b/src/eth/primitives/execution_value_change.rs index 71cd03ff8..be02d828b 100644 --- a/src/eth/primitives/execution_value_change.rs +++ b/src/eth/primitives/execution_value_change.rs @@ -9,7 +9,7 @@ use display_json::DebugAsJson; use crate::ext::to_json_string; /// Changes that happened to an account value during a transaction. -#[derive(Clone, PartialEq, Eq, fake::Dummy, serde::Serialize, serde::Deserialize)] +#[derive(Clone, PartialEq, Eq, fake::Dummy, serde::Serialize, serde::Deserialize, Default)] pub struct ExecutionValueChange where T: PartialEq + serde::Serialize, @@ -97,10 +97,11 @@ where // Value State // ----------------------------------------------------------------------------- -#[derive(DebugAsJson, Clone, PartialEq, Eq, fake::Dummy, serde::Serialize, serde::Deserialize)] +#[derive(DebugAsJson, Clone, PartialEq, Eq, fake::Dummy, serde::Serialize, serde::Deserialize, Default)] #[serde(rename_all = "snake_case")] pub enum ValueState { Set(T), + #[default] NotSet, } diff --git a/src/eth/rpc/rpc_server.rs b/src/eth/rpc/rpc_server.rs index 65ad2f8a8..8991f2269 100644 --- a/src/eth/rpc/rpc_server.rs +++ b/src/eth/rpc/rpc_server.rs @@ -1061,7 +1061,7 @@ fn eth_get_code(params: Params<'_>, ctx: Arc, ext: &Extensions) -> R let point_in_time = ctx.storage.translate_to_point_in_time(filter)?; let account = ctx.storage.read_account(address, point_in_time)?; - Ok(account.bytecode.map(hex_data).unwrap_or_else(hex_null)) + Ok(account.bytecode.map(|bytecode| hex_data(bytecode.original_bytes())).unwrap_or_else(hex_null)) } // ----------------------------------------------------------------------------- diff --git a/src/eth/storage/permanent/inmemory.rs b/src/eth/storage/permanent/inmemory.rs index 6115c6d70..465c600a2 100644 --- a/src/eth/storage/permanent/inmemory.rs +++ b/src/eth/storage/permanent/inmemory.rs @@ -12,13 +12,13 @@ use nonempty::NonEmpty; use parking_lot::RwLock; use parking_lot::RwLockReadGuard; use parking_lot::RwLockWriteGuard; +use revm::primitives::Bytecode; use crate::eth::primitives::Account; use crate::eth::primitives::Address; use crate::eth::primitives::Block; use crate::eth::primitives::BlockFilter; use crate::eth::primitives::BlockNumber; -use crate::eth::primitives::Bytes; use crate::eth::primitives::CodeHash; use crate::eth::primitives::Hash; use crate::eth::primitives::LogFilter; @@ -255,7 +255,7 @@ struct InMemoryPermanentAccount { pub address: Address, pub balance: InMemoryHistory, pub nonce: InMemoryHistory, - pub bytecode: InMemoryHistory>, + pub bytecode: InMemoryHistory>, pub code_hash: InMemoryHistory, pub slots: HashMap, hash_hasher::HashBuildHasher>, } diff --git a/src/eth/storage/permanent/mod.rs b/src/eth/storage/permanent/mod.rs index d33c91cc9..9ad3a5dd0 100644 --- a/src/eth/storage/permanent/mod.rs +++ b/src/eth/storage/permanent/mod.rs @@ -1,10 +1,8 @@ pub use self::inmemory::InMemoryPermanentStorage; -pub use self::redis::RedisPermanentStorage; pub use self::rocks::RocksPermanentStorage; pub use self::rocks::RocksStorageState; mod inmemory; -mod redis; pub mod rocks; use std::str::FromStr; @@ -27,7 +25,6 @@ use crate::eth::primitives::Slot; use crate::eth::primitives::SlotIndex; use crate::eth::primitives::TransactionMined; use crate::ext::parse_duration; -use crate::log_and_err; /// Permanent (committed) storage operations. pub trait PermanentStorage: Send + Sync + 'static { @@ -121,9 +118,6 @@ pub enum PermanentStorageKind { #[serde(rename = "inmemory")] InMemory, - #[serde(rename = "redis")] - Redis, - #[serde(rename = "rocks")] Rocks, } @@ -136,13 +130,6 @@ impl PermanentStorageConfig { let perm: Box = match self.perm_storage_kind { PermanentStorageKind::InMemory => Box::::default(), - PermanentStorageKind::Redis => { - let Some(url) = self.perm_storage_url.as_deref() else { - return log_and_err!("redis connection url not provided when it was expected to be present"); - }; - Box::new(RedisPermanentStorage::new(url)?) - } - PermanentStorageKind::Rocks => Box::new(RocksPermanentStorage::new( self.rocks_path_prefix.clone(), self.rocks_shutdown_timeout, @@ -160,7 +147,6 @@ impl FromStr for PermanentStorageKind { fn from_str(s: &str) -> anyhow::Result { match s { "inmemory" => Ok(Self::InMemory), - "redis" => Ok(Self::Redis), "rocks" => Ok(Self::Rocks), s => Err(anyhow!("unknown permanent storage: {}", s)), } diff --git a/src/eth/storage/permanent/redis.rs b/src/eth/storage/permanent/redis.rs deleted file mode 100644 index 8b6df0f4f..000000000 --- a/src/eth/storage/permanent/redis.rs +++ /dev/null @@ -1,402 +0,0 @@ -use itertools::Itertools; -use redis::Client as RedisClient; -use redis::Commands; -use redis::Connection as RedisConnection; -use redis::RedisResult; - -use crate::eth::primitives::Account; -use crate::eth::primitives::Address; -use crate::eth::primitives::Block; -use crate::eth::primitives::BlockFilter; -use crate::eth::primitives::BlockNumber; -use crate::eth::primitives::Hash; -use crate::eth::primitives::LogFilter; -use crate::eth::primitives::LogMined; -use crate::eth::primitives::PointInTime; -use crate::eth::primitives::Slot; -use crate::eth::primitives::SlotIndex; -use crate::eth::primitives::TransactionMined; -use crate::eth::storage::PermanentStorage; -use crate::ext::from_json_str; -use crate::ext::to_json_object; -use crate::ext::to_json_string; -use crate::ext::to_json_value; -use crate::log_and_err; - -type RedisVecOptString = RedisResult>>; -type RedisVecString = RedisResult>; -type RedisOptString = RedisResult>; -type RedisOptUsize = RedisResult>; -type RedisVoid = RedisResult<()>; - -pub struct RedisPermanentStorage { - client: redis::Client, -} - -impl RedisPermanentStorage { - pub fn new(url: &str) -> anyhow::Result { - let client = match RedisClient::open(url) { - Ok(client) => client, - Err(e) => return log_and_err!(reason = e, "failed to create redis client"), - }; - Ok(Self { client }) - } - - fn conn(&self) -> anyhow::Result { - match self.client.get_connection() { - Ok(conn) => Ok(conn), - Err(e) => log_and_err!(reason = e, "failed to get redis connection"), - } - } -} - -impl PermanentStorage for RedisPermanentStorage { - fn set_mined_block_number(&self, number: BlockNumber) -> anyhow::Result<()> { - // execute command - let mut conn = self.conn()?; - let set: RedisVoid = conn.set("number::mined", number.to_string()); - - // parse - match set { - Ok(_) => Ok(()), - Err(e) => log_and_err!(reason = e, "failed to write mined number to redis"), - } - } - - fn read_mined_block_number(&self) -> anyhow::Result { - // execute command - let mut conn = self.conn()?; - let value: RedisOptUsize = conn.get("number::mined"); - - // parse - match value { - Ok(Some(value)) => Ok(value.into()), - Ok(None) => Ok(BlockNumber::ZERO), - Err(e) => log_and_err!(reason = e, "failed to read miner block number from redis"), - } - } - - fn save_block(&self, block: Block) -> anyhow::Result<()> { - // generate block keys - let key_block_number = key_block_by_number(block.number()); - let key_block_hash = key_block_by_hash(block.hash()); - - // generate values - let block_json = to_json_string(&block); - - // blocks - let mut mset_values = vec![ - (key_block_number, block_json.clone()), - (key_block_hash, block_json.clone()), - ("block::latest".to_owned(), block_json), - ]; - let mut zadd_values = vec![]; - - // transactions - for tx in &block.transactions { - let tx_key = key_tx(tx.input.hash); - let tx_value = to_json_string(&tx); - mset_values.push((tx_key, tx_value)); - } - - // changes - for changes in block.compact_account_changes() { - // account - if changes.is_account_modified() { - let mut account = Account { - address: changes.address, - ..Account::default() - }; - if let Some(nonce) = changes.nonce.take() { - account.nonce = nonce; - } - if let Some(balance) = changes.balance.take() { - account.balance = balance; - } - if let Some(bytecode) = changes.bytecode.take() { - account.bytecode = bytecode; - } - - // add block number to force slot modification - let mut account_value = to_json_object(&account); - account_value.insert("block".to_owned(), to_json_value(block.number())); - let account_value = to_json_string(&account_value); - - mset_values.push((key_account(account.address), account_value.clone())); - zadd_values.push((key_account_history(account.address), account_value, block.number().as_u64())); - } - - // slots - for slot in changes.slots.into_values() { - if let Some(slot) = slot.take() { - // add block number to force slot modification - let mut slot_value = to_json_value(slot); - slot_value.as_object_mut().unwrap().insert("block".to_owned(), to_json_value(block.number())); - let slot_value = to_json_string(&slot_value); - - mset_values.push((key_slot(changes.address, slot.index), slot_value.clone())); - zadd_values.push((key_slot_history(changes.address, slot.index), slot_value, block.number().as_u64())); - } - } - } - - // execute mset command - let mut conn = self.conn()?; - let set: RedisVoid = conn.mset(&mset_values); - if let Err(e) = set { - return log_and_err!(reason = e, "failed to write block mset to redis"); - } - - // execute zadd commands - for (key, value, score) in zadd_values { - let mut cmd = redis::cmd("ZADD"); - cmd.arg(key).arg("NX").arg(score).arg(value); - - let zadd: RedisVoid = cmd.exec(&mut conn); - if let Err(e) = zadd { - return log_and_err!(reason = e, "failed to write block zadd to redis"); - } - } - - Ok(()) - } - - fn read_block(&self, block_filter: BlockFilter) -> anyhow::Result> { - // prepare keys - let block_key = match block_filter { - BlockFilter::Latest | BlockFilter::Pending => "block::latest".to_owned(), - BlockFilter::Earliest => "block::earliest".to_owned(), - BlockFilter::Hash(hash) => key_block_by_hash(hash), - BlockFilter::Number(number) => key_block_by_number(number), - }; - - // execute command - let mut conn = self.conn()?; - let redis_block: RedisOptString = conn.get(block_key); - - // parse - match redis_block { - Ok(Some(json)) => Ok(from_json_str(&json)), - Ok(None) => Ok(None), - Err(e) => log_and_err!(reason = e, "failed to read block from redis"), - } - } - - fn read_transaction(&self, hash: Hash) -> anyhow::Result> { - // prepare keys - let tx_key = key_tx(hash); - - // execute command - let mut conn = self.conn()?; - let redis_transaction: RedisOptString = conn.get(tx_key); - - // parse - match redis_transaction { - Ok(Some(json)) => Ok(from_json_str(&json)), - Ok(None) => Ok(None), - Err(e) => log_and_err!(reason = e, "failed to read transaction from redis"), - } - } - - fn read_logs(&self, filter: &LogFilter) -> anyhow::Result> { - // prepare keys - let from_block = filter.from_block.as_u64(); - let to_block = match filter.to_block { - Some(number) => number.as_u64(), - None => self.read_mined_block_number()?.as_u64(), - }; - let block_keys = (from_block..=to_block).map(key_block_by_number).collect_vec(); - - // exit if no keys - if block_keys.is_empty() { - return Ok(vec![]); - } - - // execute command - let mut conn = self.conn()?; - let blocks: RedisVecOptString = conn.mget(block_keys); - - // parse - let blocks: Vec = match blocks { - Ok(vec_json) => vec_json.into_iter().flatten().map(|json| from_json_str(&json)).collect_vec(), - Err(e) => return log_and_err!(reason = e, "failed to read logs from redis"), - }; - - // filter - let logs = blocks - .into_iter() - .flat_map(|b| b.transactions) - .flat_map(|t| t.logs) - .filter(|log| filter.matches(log)) - .collect_vec(); - - Ok(logs) - } - - fn save_accounts(&self, accounts: Vec) -> anyhow::Result<()> { - // exit if no accounts - if accounts.is_empty() { - return Ok(()); - } - - // prepare values - let redis_accounts = accounts - .into_iter() - .map(|acc| { - let account_key = key_account(acc.address); - let account_value = to_json_string(&acc); - (account_key, account_value) - }) - .collect_vec(); - - // execute command - let mut conn = self.conn()?; - let set: RedisVoid = conn.mset(&redis_accounts); - - // parse - match set { - Ok(_) => Ok(()), - Err(e) => log_and_err!(reason = e, "failed to write accounts to redis"), - } - } - - fn read_account(&self, address: Address, point_in_time: PointInTime) -> anyhow::Result> { - let mut conn = self.conn()?; - match point_in_time { - PointInTime::Mined | PointInTime::Pending => { - // prepare key - let account_key = key_account(address); - - // execute - let redis_account: RedisOptString = conn.get(account_key); - - // parse - match redis_account { - Ok(Some(json)) => Ok(Some(from_json_str(&json))), - Ok(None) => Ok(None), - Err(e) => log_and_err!(reason = e, "failed to read account from redis current value"), - } - } - PointInTime::MinedPast(number) => { - // prepare key - let account_key = key_account_history(address); - - // execute - let mut cmd = redis::cmd("ZRANGE"); - cmd.arg(account_key) - .arg(number.as_u64()) - .arg(0) - .arg("BYSCORE") - .arg("REV") - .arg("LIMIT") - .arg(0) - .arg(1); - let redis_account: RedisVecString = cmd.query(&mut conn); - - // parse - match redis_account { - Ok(vec_json) => match vec_json.first() { - Some(json) => Ok(Some(from_json_str(json))), - None => Ok(None), - }, - Err(e) => log_and_err!(reason = e, "failed to read account from redis historical value"), - } - } - } - } - - fn read_slot(&self, address: Address, index: SlotIndex, point_in_time: PointInTime) -> anyhow::Result> { - // execute command and parse - let mut conn = self.conn()?; - match point_in_time { - PointInTime::Mined | PointInTime::Pending => { - // prepare key - let slot_key = key_slot(address, index); - - // execute - let redis_slot: RedisOptString = conn.get(slot_key); - - // parse - match redis_slot { - Ok(Some(json)) => Ok(Some(from_json_str(&json))), - Ok(None) => Ok(None), - Err(e) => log_and_err!(reason = e, "failed to read slot from redis current value"), - } - } - PointInTime::MinedPast(number) => { - // prepare key - let slot_key = key_slot_history(address, index); - - // execute - let mut cmd = redis::cmd("ZRANGE"); - cmd.arg(slot_key) - .arg(number.as_u64()) - .arg(0) - .arg("BYSCORE") - .arg("REV") - .arg("LIMIT") - .arg(0) - .arg(1); - let redis_account: RedisVecString = cmd.query(&mut conn); - - // parse - match redis_account { - Ok(vec_json) => match vec_json.first() { - Some(json) => Ok(Some(from_json_str(json))), - None => Ok(None), - }, - Err(e) => log_and_err!(reason = e, "failed to read account from redis historical value"), - } - } - } - } - - #[cfg(feature = "dev")] - fn reset(&self) -> anyhow::Result<()> { - let mut conn = self.conn()?; - let flush: RedisVoid = redis::cmd("FLUSHDB").exec(&mut conn); - match flush { - Ok(_) => Ok(()), - Err(e) => log_and_err!(reason = e, "failed to clear all redis keys"), - } - } -} - -// ----------------------------------------------------------------------------- -// Keys helpers -// ----------------------------------------------------------------------------- - -/// Generates a key for accessing a block by number. -fn key_block_by_number(number: impl Into) -> String { - format!("block::number::{}", number.into()) -} - -/// Generates a key for accessing a block by hash. -fn key_block_by_hash(hash: Hash) -> String { - format!("block::hash::{}", hash) -} - -/// Generates a key for accessing an account. -fn key_account(address: Address) -> String { - format!("account::{}", address) -} - -/// Generates a key for accessing an account history. -fn key_account_history(address: Address) -> String { - format!("account_history::{}", address) -} - -/// Generates a key for accessing a slot. -fn key_slot(address: Address, index: SlotIndex) -> String { - format!("slot::{}::{}", address, index) -} - -/// Generates a key for accessing a slot history. -fn key_slot_history(address: Address, index: SlotIndex) -> String { - format!("slot_history::{}::{}", address, index) -} - -/// Generates a key for accessing a transaction. -fn key_tx(hash: Hash) -> String { - format!("tx::{}", hash) -} diff --git a/src/eth/storage/permanent/rocks/cf_versions.rs b/src/eth/storage/permanent/rocks/cf_versions.rs index a067814af..1f689f4b1 100644 --- a/src/eth/storage/permanent/rocks/cf_versions.rs +++ b/src/eth/storage/permanent/rocks/cf_versions.rs @@ -243,7 +243,7 @@ mod tests { fs::create_dir_all(&snapshot_parent_path)?; fs::write(snapshot_path, serialized)?; } else { - bail!("snapshot file at '{snapshot_path:?}' doesn't exist and GEN_NEW_VARIANT_SNAPSHOT is not set"); + bail!("snapshot file at '{snapshot_path:?}' doesn't exist and DANGEROUS_UPDATE_SNAPSHOTS is not set"); } } diff --git a/src/eth/storage/permanent/rocks/rocks_permanent.rs b/src/eth/storage/permanent/rocks/rocks_permanent.rs index 8c2377e8c..6eb40ab3d 100644 --- a/src/eth/storage/permanent/rocks/rocks_permanent.rs +++ b/src/eth/storage/permanent/rocks/rocks_permanent.rs @@ -1,5 +1,5 @@ use std::path::Path; -use std::sync::atomic::AtomicU64; +use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering; use std::time::Duration; @@ -23,7 +23,7 @@ use crate::eth::storage::PermanentStorage; #[derive(Debug)] pub struct RocksPermanentStorage { pub state: RocksStorageState, - block_number: AtomicU64, + block_number: AtomicU32, } impl RocksPermanentStorage { @@ -82,7 +82,7 @@ impl PermanentStorage for RocksPermanentStorage { } fn set_mined_block_number(&self, number: BlockNumber) -> anyhow::Result<()> { - self.block_number.store(number.as_u64(), Ordering::SeqCst); + self.block_number.store(number.as_u32(), Ordering::SeqCst); Ok(()) } @@ -144,7 +144,7 @@ impl PermanentStorage for RocksPermanentStorage { #[cfg(feature = "dev")] fn reset(&self) -> anyhow::Result<()> { - self.block_number.store(0u64, Ordering::SeqCst); + self.block_number.store(0u32, Ordering::SeqCst); self.state.reset().inspect_err(|e| { tracing::error!(reason = ?e, "failed to reset in RocksPermanent"); }) diff --git a/src/eth/storage/permanent/rocks/rocks_state.rs b/src/eth/storage/permanent/rocks/rocks_state.rs index 416c9bc97..93722011f 100644 --- a/src/eth/storage/permanent/rocks/rocks_state.rs +++ b/src/eth/storage/permanent/rocks/rocks_state.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::fmt; use std::fmt::Debug; -use std::sync::atomic::AtomicU64; +use std::sync::atomic::AtomicU32; use std::sync::Arc; use std::time::Duration; use std::time::Instant; @@ -180,10 +180,10 @@ impl RocksStorageState { self.db_path.rsplit('/').next().unwrap_or(&self.db_path) } - pub fn preload_block_number(&self) -> Result { - let block_number = self.blocks_by_number.last_key()?.unwrap_or_default(); + pub fn preload_block_number(&self) -> Result { + let block_number = self.blocks_by_number.last_key()?.unwrap_or_default().0; tracing::info!(%block_number, "preloaded block_number"); - Ok((u64::from(block_number)).into()) + Ok(AtomicU32::new(block_number)) } #[cfg(feature = "dev")] @@ -251,13 +251,14 @@ impl RocksStorageState { return log_and_err!("the block that the transaction was supposed to be in was not found") .with_context(|| format!("block_number = {:?} tx_hash = {}", block_number, tx_hash)); }; + let block = block.into_inner(); - let transaction = block.into_inner().transactions.into_iter().find(|tx| Hash::from(tx.input.hash) == tx_hash); + let transaction = block.transactions.into_iter().find(|tx| Hash::from(tx.input.hash) == tx_hash); match transaction { Some(tx) => { tracing::trace!(%tx_hash, "transaction found"); - Ok(Some(tx.into())) + Ok(Some(TransactionMined::from_rocks_primitives(tx, block_number.into_inner(), block.header.hash))) } None => log_and_err!("rocks error, transaction wasn't found in block where the index pointed at") .with_context(|| format!("block_number = {:?} tx_hash = {}", block_number, tx_hash)), @@ -283,12 +284,12 @@ impl RocksStorageState { break; } - let logs = block - .into_inner() - .transactions - .into_iter() - .flat_map(|transaction| transaction.logs) - .map(LogMined::from); + let block = block.into_inner(); + let logs = block.transactions.into_iter().enumerate().flat_map(|(tx_index, transaction)| { + transaction.logs.into_iter().enumerate().map(move |(log_index, log)| { + LogMined::from_rocks_primitives(log, block.header.number, block.header.hash, tx_index, transaction.input.hash, log_index) + }) + }); let filtered_logs = logs.filter(|log| filter.matches(log)); logs_result.extend(filtered_logs); @@ -400,7 +401,7 @@ impl RocksStorageState { self.accounts_history.prepare_batch_insertion( accounts.iter().cloned().map(|acc| { let tup = <(AddressRocksdb, AccountRocksdb)>::from(acc); - ((tup.0, 0u64.into()), tup.1.into()) + ((tup.0, 0u32.into()), tup.1.into()) }), &mut write_batch, )?; @@ -728,7 +729,7 @@ mod tests { address: Faker.fake(), nonce: ExecutionValueChange::from_original(Faker.fake()), balance: ExecutionValueChange::from_original(Faker.fake()), - bytecode: ExecutionValueChange::from_original(Faker.fake()), + bytecode: ExecutionValueChange::from_original(Some(revm::primitives::Bytecode::new_raw(Faker.fake::>().into()))), code_hash: Faker.fake(), slots: HashMap::new(), }; @@ -745,7 +746,7 @@ mod tests { ..change_base.clone() }, ExecutionAccountChanges { - bytecode: ExecutionValueChange::from_modified(Faker.fake()), + bytecode: ExecutionValueChange::from_modified(Some(revm::primitives::Bytecode::new_raw(Faker.fake::>().into()))), ..change_base }, ]; diff --git a/src/eth/storage/permanent/rocks/types/account.rs b/src/eth/storage/permanent/rocks/types/account.rs index f33fccac8..a1dcce94f 100644 --- a/src/eth/storage/permanent/rocks/types/account.rs +++ b/src/eth/storage/permanent/rocks/types/account.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use revm::primitives::KECCAK_EMPTY; use super::address::AddressRocksdb; -use super::bytes::BytesRocksdb; +use super::bytecode::BytecodeRocksdb; use super::nonce::NonceRocksdb; use super::wei::WeiRocksdb; use crate::eth::primitives::Account; @@ -14,7 +14,7 @@ use crate::ext::OptionExt; pub struct AccountRocksdb { pub balance: WeiRocksdb, pub nonce: NonceRocksdb, - pub bytecode: Option, + pub bytecode: Option, } impl AccountRocksdb { diff --git a/src/eth/storage/permanent/rocks/types/block.rs b/src/eth/storage/permanent/rocks/types/block.rs index aa1e20bac..6aea8cfa7 100644 --- a/src/eth/storage/permanent/rocks/types/block.rs +++ b/src/eth/storage/permanent/rocks/types/block.rs @@ -48,28 +48,31 @@ impl From for BlockRocksdb { impl From for Block { fn from(item: BlockRocksdb) -> Self { - Block { - header: BlockHeader { - number: BlockNumber::from(item.header.number), - hash: Hash::from(item.header.hash), - transactions_root: Hash::from(item.header.transactions_root), - gas_used: item.header.gas_used.into(), - gas_limit: item.header.gas_limit.into(), - bloom: item.header.bloom.into(), - timestamp: item.header.timestamp.into(), - parent_hash: Hash::from(item.header.parent_hash), - author: Address::from(item.header.author), - extra_data: item.header.extra_data.into(), - miner: Address::from(item.header.miner), - difficulty: item.header.difficulty.into(), - receipts_root: Hash::from(item.header.receipts_root), - uncle_hash: Hash::from(item.header.uncle_hash), - size: item.header.size.into(), - state_root: Hash::from(item.header.state_root), - total_difficulty: item.header.total_difficulty.into(), - nonce: item.header.nonce.into(), - }, - transactions: item.transactions.into_iter().map(TransactionMined::from).collect(), - } + let header = BlockHeader { + number: BlockNumber::from(item.header.number), + hash: Hash::from(item.header.hash), + transactions_root: Hash::from(item.header.transactions_root), + gas_used: item.header.gas_used.into(), + gas_limit: item.header.gas_limit.into(), + bloom: item.header.bloom.into(), + timestamp: item.header.timestamp.into(), + parent_hash: Hash::from(item.header.parent_hash), + author: Address::from(item.header.author), + extra_data: item.header.extra_data.into(), + miner: Address::from(item.header.miner), + difficulty: item.header.difficulty.into(), + receipts_root: Hash::from(item.header.receipts_root), + uncle_hash: Hash::from(item.header.uncle_hash), + size: item.header.size.into(), + state_root: Hash::from(item.header.state_root), + total_difficulty: item.header.total_difficulty.into(), + nonce: item.header.nonce.into(), + }; + let transactions = item + .transactions + .into_iter() + .map(|tx| TransactionMined::from_rocks_primitives(tx, header.number.into(), header.hash.into())) + .collect(); + Block { header, transactions } } } diff --git a/src/eth/storage/permanent/rocks/types/block_number.rs b/src/eth/storage/permanent/rocks/types/block_number.rs index 6c15ab796..2cc67c428 100644 --- a/src/eth/storage/permanent/rocks/types/block_number.rs +++ b/src/eth/storage/permanent/rocks/types/block_number.rs @@ -5,13 +5,13 @@ use crate::eth::primitives::BlockNumber; use crate::gen_newtype_from; #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Ord, PartialOrd, Hash, derive_more::Display, fake::Dummy)] -pub struct BlockNumberRocksdb(pub u64); +pub struct BlockNumberRocksdb(pub u32); -gen_newtype_from!(self = BlockNumberRocksdb, other = u8, u16, u32, u64); +gen_newtype_from!(self = BlockNumberRocksdb, other = u8, u16, u32); impl From for BlockNumberRocksdb { fn from(item: BlockNumber) -> Self { - item.0.as_u64().into() + Self(item.as_u32()) } } @@ -21,7 +21,7 @@ impl From for BlockNumber { } } -impl From for u64 { +impl From for u32 { fn from(value: BlockNumberRocksdb) -> Self { value.0 } @@ -35,14 +35,14 @@ impl serde::Serialize for BlockNumberRocksdb { impl<'de> serde::Deserialize<'de> for BlockNumberRocksdb { fn deserialize>(deserializer: D) -> Result { - u64::deserialize(deserializer).map(|v| Self(u64::from_be(v))) + u32::deserialize(deserializer).map(|v| Self(u32::from_be(v))) } } -impl Add for BlockNumberRocksdb { +impl Add for BlockNumberRocksdb { type Output = Self; - fn add(self, other: u64) -> Self { + fn add(self, other: u32) -> Self { BlockNumberRocksdb(self.0 + other) } } diff --git a/src/eth/storage/permanent/rocks/types/bytecode.rs b/src/eth/storage/permanent/rocks/types/bytecode.rs new file mode 100644 index 000000000..e66cb6db5 --- /dev/null +++ b/src/eth/storage/permanent/rocks/types/bytecode.rs @@ -0,0 +1,138 @@ +use std::ops::Deref; + +use revm::primitives::eof::TypesSection; +use revm::primitives::Bytecode; + +use super::bytes::BytesRocksdb; + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)] +pub enum BytecodeRocksdb { + LegacyRaw(BytesRocksdb), + LegacyAnalyzed(LegacyAnalyzedBytecodeRocksdb), + Eof(EofRocksdb), +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)] +pub struct LegacyAnalyzedBytecodeRocksdb { + bytecode: BytesRocksdb, + original_len: usize, + jump_table: Vec, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)] +pub struct EofHeaderRocksdb { + pub types_size: u16, + pub code_sizes: Vec, + pub container_sizes: Vec, + pub data_size: u16, + pub sum_code_sizes: usize, + pub sum_container_sizes: usize, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)] +pub struct EofBodyRocksdb { + pub types_section: Vec, + pub code_section: Vec, + pub container_section: Vec, + pub data_section: BytesRocksdb, + pub is_data_filled: bool, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)] +pub struct TypesSectionRocksdb { + pub inputs: u8, + pub outputs: u8, + pub max_stack_size: u16, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)] +pub struct EofRocksdb { + pub header: EofHeaderRocksdb, + pub body: EofBodyRocksdb, + pub raw: BytesRocksdb, +} + +impl From for TypesSectionRocksdb { + fn from(value: TypesSection) -> Self { + Self { + inputs: value.inputs, + outputs: value.outputs, + max_stack_size: value.max_stack_size, + } + } +} + +impl From for BytecodeRocksdb { + fn from(value: Bytecode) -> Self { + match value { + Bytecode::LegacyRaw(bytes) => BytecodeRocksdb::LegacyRaw(bytes.to_vec().into()), + Bytecode::LegacyAnalyzed(analyzed) => BytecodeRocksdb::LegacyAnalyzed(LegacyAnalyzedBytecodeRocksdb { + bytecode: analyzed.bytecode().clone().into(), + original_len: analyzed.original_len(), + jump_table: analyzed.jump_table().0.deref().clone().into_vec(), + }), + Bytecode::Eof(eof) => BytecodeRocksdb::Eof(EofRocksdb { + header: EofHeaderRocksdb { + types_size: eof.header.types_size, + code_sizes: eof.header.code_sizes, + container_sizes: eof.header.container_sizes, + data_size: eof.header.data_size, + sum_code_sizes: eof.header.sum_code_sizes, + sum_container_sizes: eof.header.sum_container_sizes, + }, + body: EofBodyRocksdb { + types_section: eof.body.types_section.into_iter().map(Into::into).collect(), + code_section: eof.body.code_section.into_iter().map(Into::into).collect(), + container_section: eof.body.container_section.into_iter().map(Into::into).collect(), + data_section: eof.body.data_section.into(), + is_data_filled: eof.body.is_data_filled, + }, + raw: eof.raw.into(), + }), + } + } +} + +impl From for Bytecode { + fn from(value: BytecodeRocksdb) -> Self { + match value { + BytecodeRocksdb::LegacyRaw(bytes) => Bytecode::LegacyRaw(bytes.to_vec().into()), + BytecodeRocksdb::LegacyAnalyzed(analyzed) => Bytecode::LegacyAnalyzed(revm::primitives::LegacyAnalyzedBytecode::new( + analyzed.bytecode.into(), + analyzed.original_len, + revm::primitives::JumpTable::from_slice(&analyzed.jump_table), + )), + BytecodeRocksdb::Eof(eof) => { + let header = revm::primitives::eof::EofHeader { + types_size: eof.header.types_size, + code_sizes: eof.header.code_sizes, + container_sizes: eof.header.container_sizes, + data_size: eof.header.data_size, + sum_code_sizes: eof.header.sum_code_sizes, + sum_container_sizes: eof.header.sum_container_sizes, + }; + let body = revm::primitives::eof::EofBody { + types_section: eof + .body + .types_section + .into_iter() + .map(|t| TypesSection { + inputs: t.inputs, + outputs: t.outputs, + max_stack_size: t.max_stack_size, + }) + .collect(), + code_section: eof.body.code_section.into_iter().map(Into::into).collect(), + container_section: eof.body.container_section.into_iter().map(Into::into).collect(), + data_section: eof.body.data_section.into(), + is_data_filled: eof.body.is_data_filled, + }; + Bytecode::Eof(revm::primitives::eof::Eof { + header, + body, + raw: eof.raw.into(), + }) + } + } + } +} diff --git a/src/eth/storage/permanent/rocks/types/bytes.rs b/src/eth/storage/permanent/rocks/types/bytes.rs index 730f1e70c..996359ca2 100644 --- a/src/eth/storage/permanent/rocks/types/bytes.rs +++ b/src/eth/storage/permanent/rocks/types/bytes.rs @@ -2,6 +2,8 @@ use std::fmt::Debug; use std::fmt::Display; use std::ops::Deref; +use revm::primitives::Bytes as RevmBytes; + use crate::eth::primitives::Bytes; #[derive(Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)] @@ -42,3 +44,21 @@ impl From for Bytes { Self(value.0) } } + +impl From> for BytesRocksdb { + fn from(value: Vec) -> Self { + Self(value) + } +} + +impl From for BytesRocksdb { + fn from(value: RevmBytes) -> Self { + value.to_vec().into() + } +} + +impl From for RevmBytes { + fn from(value: BytesRocksdb) -> Self { + value.to_vec().into() + } +} diff --git a/src/eth/storage/permanent/rocks/types/index.rs b/src/eth/storage/permanent/rocks/types/index.rs index b1500a19b..1e515a49b 100644 --- a/src/eth/storage/permanent/rocks/types/index.rs +++ b/src/eth/storage/permanent/rocks/types/index.rs @@ -3,22 +3,22 @@ use std::fmt::Debug; use crate::eth::primitives::Index; #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, derive_more::Add, Copy, Hash, fake::Dummy)] -pub struct IndexRocksdb(u64); +pub struct IndexRocksdb(pub(self) u32); impl IndexRocksdb { - pub fn inner_value(&self) -> u64 { - self.0 + pub fn as_usize(&self) -> usize { + self.0 as usize } } impl From for IndexRocksdb { fn from(item: Index) -> Self { - IndexRocksdb(item.0) + IndexRocksdb(item.0 as u32) } } impl From for Index { fn from(item: IndexRocksdb) -> Self { - Index::new(item.inner_value()) + Index::new(item.0 as u64) } } diff --git a/src/eth/storage/permanent/rocks/types/log_mined.rs b/src/eth/storage/permanent/rocks/types/log_mined.rs index c3e88b2b8..c5db8d235 100644 --- a/src/eth/storage/permanent/rocks/types/log_mined.rs +++ b/src/eth/storage/permanent/rocks/types/log_mined.rs @@ -2,42 +2,37 @@ use std::fmt::Debug; use super::block_number::BlockNumberRocksdb; use super::hash::HashRocksdb; -use super::index::IndexRocksdb; use super::log::LogRocksdb; +use crate::eth::primitives::Index; use crate::eth::primitives::LogMined; #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)] -pub struct LogMinedRockdb { +pub struct LogMinedRocksdb { pub log: LogRocksdb, - pub transaction_hash: HashRocksdb, - pub transaction_index: IndexRocksdb, - pub log_index: IndexRocksdb, - pub block_number: BlockNumberRocksdb, - pub block_hash: HashRocksdb, } -impl From for LogMinedRockdb { +impl From for LogMinedRocksdb { fn from(item: LogMined) -> Self { - Self { - log: item.log.into(), - transaction_hash: item.transaction_hash.into(), - transaction_index: item.transaction_index.into(), - log_index: item.log_index.into(), - block_number: item.block_number.into(), - block_hash: item.block_hash.into(), - } + Self { log: item.log.into() } } } -impl From for LogMined { - fn from(item: LogMinedRockdb) -> Self { +impl LogMined { + pub fn from_rocks_primitives( + other: LogMinedRocksdb, + block_number: BlockNumberRocksdb, + block_hash: HashRocksdb, + tx_index: usize, + tx_hash: HashRocksdb, + log_index: usize, + ) -> Self { Self { - log: item.log.into(), - transaction_hash: item.transaction_hash.into(), - transaction_index: item.transaction_index.into(), - log_index: item.log_index.into(), - block_number: item.block_number.into(), - block_hash: item.block_hash.into(), + block_number: block_number.into(), + block_hash: block_hash.into(), + log: other.log.into(), + transaction_hash: tx_hash.into(), + transaction_index: Index::from(tx_index as u64), + log_index: Index::from(log_index as u64), } } } diff --git a/src/eth/storage/permanent/rocks/types/mod.rs b/src/eth/storage/permanent/rocks/types/mod.rs index 851175590..caaf138c7 100644 --- a/src/eth/storage/permanent/rocks/types/mod.rs +++ b/src/eth/storage/permanent/rocks/types/mod.rs @@ -3,6 +3,7 @@ mod address; mod block; mod block_header; mod block_number; +mod bytecode; mod bytes; mod chain_id; mod difficulty; @@ -43,7 +44,7 @@ mod tests { use execution::ExecutionRocksdb; use execution_result::ExecutionResultRocksdb; use gas::GasRocksdb; - use log_mined::LogMinedRockdb; + use log_mined::LogMinedRocksdb; use logs_bloom::LogsBloomRocksdb; use miner_nonce::MinerNonceRocksdb; use nonce::NonceRocksdb; @@ -70,7 +71,7 @@ mod tests { gen_test_bincode!(GasRocksdb); gen_test_bincode!(HashRocksdb); gen_test_bincode!(IndexRocksdb); - gen_test_bincode!(LogMinedRockdb); + gen_test_bincode!(LogMinedRocksdb); gen_test_bincode!(LogRocksdb); gen_test_bincode!(LogsBloomRocksdb); gen_test_bincode!(MinerNonceRocksdb); diff --git a/src/eth/storage/permanent/rocks/types/transaction_input.rs b/src/eth/storage/permanent/rocks/types/transaction_input.rs index 5339c8c87..a1368105c 100644 --- a/src/eth/storage/permanent/rocks/types/transaction_input.rs +++ b/src/eth/storage/permanent/rocks/types/transaction_input.rs @@ -14,7 +14,7 @@ use crate::ext::OptionExt; #[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, fake::Dummy)] pub struct TransactionInputRocksdb { - pub tx_type: Option, + pub tx_type: Option, pub chain_id: Option, pub hash: HashRocksdb, pub nonce: NonceRocksdb, @@ -33,7 +33,7 @@ pub struct TransactionInputRocksdb { impl From for TransactionInputRocksdb { fn from(item: TransactionInput) -> Self { Self { - tx_type: item.tx_type.map(|inner| inner.as_u64()), + tx_type: item.tx_type.map(|inner| inner.as_u64() as u8), chain_id: item.chain_id.map_into(), hash: HashRocksdb::from(item.hash), nonce: NonceRocksdb::from(item.nonce), diff --git a/src/eth/storage/permanent/rocks/types/transaction_mined.rs b/src/eth/storage/permanent/rocks/types/transaction_mined.rs index 2ef9b579c..a2f948800 100644 --- a/src/eth/storage/permanent/rocks/types/transaction_mined.rs +++ b/src/eth/storage/permanent/rocks/types/transaction_mined.rs @@ -4,7 +4,7 @@ use super::block_number::BlockNumberRocksdb; use super::execution::ExecutionRocksdb; use super::hash::HashRocksdb; use super::index::IndexRocksdb; -use super::log_mined::LogMinedRockdb; +use super::log_mined::LogMinedRocksdb; use super::transaction_input::TransactionInputRocksdb; use crate::eth::primitives::LogMined; use crate::eth::primitives::TransactionMined; @@ -13,10 +13,8 @@ use crate::eth::primitives::TransactionMined; pub struct TransactionMinedRocksdb { pub input: TransactionInputRocksdb, pub execution: ExecutionRocksdb, - pub logs: Vec, + pub logs: Vec, pub transaction_index: IndexRocksdb, - pub block_number: BlockNumberRocksdb, - pub block_hash: HashRocksdb, } impl From for TransactionMinedRocksdb { @@ -24,23 +22,29 @@ impl From for TransactionMinedRocksdb { Self { input: item.input.into(), execution: item.execution.into(), - logs: item.logs.into_iter().map(LogMinedRockdb::from).collect(), + logs: item.logs.into_iter().map(LogMinedRocksdb::from).collect(), transaction_index: IndexRocksdb::from(item.transaction_index), - block_number: BlockNumberRocksdb::from(item.block_number), - block_hash: HashRocksdb::from(item.block_hash), } } } -impl From for TransactionMined { - fn from(item: TransactionMinedRocksdb) -> Self { +impl TransactionMined { + pub fn from_rocks_primitives(other: TransactionMinedRocksdb, block_number: BlockNumberRocksdb, block_hash: HashRocksdb) -> Self { + let logs = other + .logs + .into_iter() + .enumerate() + .map(|(log_index, log)| { + LogMined::from_rocks_primitives(log, block_number, block_hash, other.transaction_index.as_usize(), other.input.hash, log_index) + }) + .collect(); Self { - input: item.input.into(), - execution: item.execution.into(), - logs: item.logs.into_iter().map(LogMined::from).collect(), - transaction_index: item.transaction_index.into(), - block_number: item.block_number.into(), - block_hash: item.block_hash.into(), + block_number: block_number.into(), + block_hash: block_hash.into(), + input: other.input.into(), + execution: other.execution.into(), + transaction_index: other.transaction_index.into(), + logs, } } } diff --git a/src/eth/storage/stratus_storage.rs b/src/eth/storage/stratus_storage.rs index 2dc7793da..503b2f1a0 100644 --- a/src/eth/storage/stratus_storage.rs +++ b/src/eth/storage/stratus_storage.rs @@ -29,6 +29,7 @@ use crate::infra::tracing::SpanExt; mod label { pub(super) const TEMP: &str = "temporary"; pub(super) const PERM: &str = "permanent"; + pub(super) const CACHE: &str = "cache"; } /// Proxy that simplifies interaction with permanent and temporary storages. @@ -151,7 +152,10 @@ impl Storage for StratusStorage { let account = 'query: { if point_in_time.is_pending() { - if let Some(account) = self.cache.get_account(address) { + if let Some(account) = timed(|| self.cache.get_account(address)).with(|m| { + metrics::inc_storage_read_account(m.elapsed, label::CACHE, point_in_time, true); + }) { + tracing::debug!(storage = %label::CACHE, %address, ?account, "account found in cache"); return Ok(account); }; @@ -200,7 +204,10 @@ impl Storage for StratusStorage { let slot = 'query: { if point_in_time.is_pending() { - if let Some(slot) = self.cache.get_slot(address, index) { + if let Some(slot) = timed(|| self.cache.get_slot(address, index)).with(|m| { + metrics::inc_storage_read_slot(m.elapsed, label::CACHE, point_in_time, true); + }) { + tracing::debug!(storage = %label::CACHE, %address, %index, value = %slot.value, "slot found in cache"); return Ok(slot); }; diff --git a/src/eth/storage/temporary/inmemory.rs b/src/eth/storage/temporary/inmemory.rs index 015628eef..7492fdaac 100644 --- a/src/eth/storage/temporary/inmemory.rs +++ b/src/eth/storage/temporary/inmemory.rs @@ -3,6 +3,9 @@ use std::collections::HashMap; use parking_lot::RwLock; +use parking_lot::RwLockUpgradableReadGuard; +#[cfg(not(feature = "dev"))] +use parking_lot::RwLockWriteGuard; use crate::eth::executor::EvmInput; use crate::eth::primitives::Account; @@ -121,11 +124,10 @@ impl TemporaryStorage for InMemoryTemporaryStorage { fn save_pending_execution(&self, tx: TransactionExecution, check_conflicts: bool) -> Result<(), StratusError> { // check conflicts - let mut pending_block = self.pending_block.write(); + let pending_block = self.pending_block.upgradable_read(); if let TransactionExecution::Local(tx) = &tx { - let expected_input = EvmInput::from_eth_transaction(&tx.input, &pending_block.block.header); - - if expected_input != tx.evm_input { + if tx.evm_input != (&tx.input, &pending_block.block.header) { + let expected_input = EvmInput::from_eth_transaction(&tx.input, &pending_block.block.header); return Err(StratusError::TransactionEvmInputMismatch { expected: Box::new(expected_input), actual: Box::new(tx.evm_input.clone()), @@ -133,6 +135,8 @@ impl TemporaryStorage for InMemoryTemporaryStorage { } } + let mut pending_block = RwLockUpgradableReadGuard::::upgrade(pending_block); + if check_conflicts { if let Some(conflicts) = self.check_conflicts(tx.execution())? { return Err(StratusError::TransactionConflict(conflicts.into())); @@ -179,27 +183,34 @@ impl TemporaryStorage for InMemoryTemporaryStorage { } fn finish_pending_block(&self) -> anyhow::Result { - let mut pending_block = self.pending_block.write(); - - #[cfg(feature = "dev")] - let mut finished_block = pending_block.block.clone(); - #[cfg(not(feature = "dev"))] - let finished_block = pending_block.block.clone(); + let pending_block = self.pending_block.upgradable_read(); + // This has to happen BEFORE creating the new state, because UnixTimeNow::default() may change the offset. #[cfg(feature = "dev")] - { + let finished_block = { + let mut finished_block = pending_block.block.clone(); // Update block timestamp only if evm_setNextBlockTimestamp was called, // otherwise keep the original timestamp from pending block creation if UnixTime::evm_set_next_block_timestamp_was_called() { finished_block.header.timestamp = UnixTimeNow::default(); } - } + finished_block + }; + let next_state = InMemoryTemporaryStorageState::new(pending_block.block.header.number.next_block_number()); + + let mut pending_block = RwLockUpgradableReadGuard::::upgrade(pending_block); let mut latest = self.latest_block.write(); - *latest = Some(std::mem::replace( - &mut *pending_block, - InMemoryTemporaryStorageState::new(finished_block.header.number.next_block_number()), - )); + + *latest = Some(std::mem::replace(&mut *pending_block, next_state)); + + drop(pending_block); + + #[cfg(not(feature = "dev"))] + let finished_block = { + let latest = RwLockWriteGuard::>::downgrade(latest); + latest.as_ref().expect("latest should be Some after finishing the pending block").block.clone() + }; Ok(finished_block) } diff --git a/src/ledger/events.rs b/src/ledger/events.rs index 8d92bc1d0..9deb1260d 100644 --- a/src/ledger/events.rs +++ b/src/ledger/events.rs @@ -11,6 +11,7 @@ use ethereum_types::U256; use hex_literal::hex; use itertools::Itertools; use serde::ser::SerializeStruct; +use serde::Deserialize; use serde::Serialize; use uuid::Uuid; @@ -128,7 +129,8 @@ pub struct AccountTransfer { } /// Direction of a transfer relative to the primary account address. -#[derive(DebugAsJson, strum::EnumIs)] +#[derive(DebugAsJson, strum::EnumIs, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] pub enum AccountTransferDirection { /// `account_address` is being credited. Credit, @@ -178,18 +180,6 @@ impl Serialize for AccountTransfer { } } -impl Serialize for AccountTransferDirection { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self { - Self::Credit => serializer.serialize_str("credit"), - Self::Debit => serializer.serialize_str("debit"), - } - } -} - // ----------------------------------------------------------------------------- // Marker Trait // ----------------------------------------------------------------------------- diff --git a/static/contracts-deployments/contracts-production.csv b/static/contracts-deployments/contracts-production.csv index e005616ac..94ee91684 100644 --- a/static/contracts-deployments/contracts-production.csv +++ b/static/contracts-deployments/contracts-production.csv @@ -1,7 +1,8 @@ -0x88EC3491f763f4cDCF2a8F9Edd4b752AE5B8C9Fb,YieldStreamer 0x61A0B4D1A0876BD3861F756198D79A81F01E9C8A,BalanceTracker +0xfdc76e496bEB8b77fB1fFe95413e3dbFc9C2A93A,BalanceFreezer 0xA9a55a81a4C085EC0C31585Aed4cFB09D78dfD53,BRLCToken 0x7907A11948226348beDE63887e27c3F3a00AA6A9,USJIMToken +0x597F6899E7BB0077f156ED64fd14352c2576651b,Dispatcher 0x01507D7fB0f11d6b6786DF1FdBB69Fb5758eC47e,CreditAgent 0x1F94A163C329bEc14C73Ca46c66150E3c47dbEDC,Cashier_BRLC_v2 0xB2aEa43F8aEfc78A2eb558118F8A606d6d9073D8,Cashier_USJIM_v2 @@ -12,9 +13,13 @@ 0xeB6922ae58b79035E2288f9163a0e4Bb953d6a7e,Cashier_USJIM_v4 0xd306E1CeA5f2D9E8a525D1F2468c748f92540BB0,Cashier_BRLC_Receivables_v4 0x613Ce630536ddd32859D1f2fc785c65C40AC8184,Cashier_BRLC_TED_v4 -0x66CA4827747D7065DAc910845A46a82F94851be2,LendingMarketUUPS -0xc30b1A05cEC8C7cBb8E0476789D6Ab3A9A57aAf4,CreditLineConfigurableUUPS -0x9316770BcE40cBB6AFa3bEe4961023ada71cf2e0,LiquidityPoolAccountableUUPS +0x66CA4827747D7065DAc910845A46a82F94851be2,LendingMarket +0xc30b1A05cEC8C7cBb8E0476789D6Ab3A9A57aAf4,CreditLine_1 +0x9316770BcE40cBB6AFa3bEe4961023ada71cf2e0,LiquidityPool_1 +0xF510D843700b6e87628DACBFA4e028173347Dbd8,CreditLine_2 +0x201f958ED561fD35845A0088CB7A5dEFf834F098,LiquidityPool_2 +0x2EeA7710DAAAC9DA79D81DB88baa38b781810b97,CreditLine_3 +0x16b18353a91522b999FF5d88baC53225b3ed704d,LiquidityPool_3 0xc10dB4941fB486b2d88839775802FA03BAc6dE31,CPP_BRLC_v1 0xE3845d98DFb62172B0C8E49BfCc3290890e40a05,CashbackDistributor_v1 0x06aAAACCE7E224b402E749135C1dF616435BBb9E,CPP_USJIM_v1 @@ -22,12 +27,6 @@ 0x10D71aCE2B4B1Ba26f27F4FDd1105CB1b90a98cF,CPP_USJIM_v2 0xDf669070CDa52E80Ae82AAb951c4111b52FF30C1,Cashier_USJIM_v4_deprecated 0x81FA55BeC91af38d6bcd69E65F2698C2ADF70E61,Cashier_BRLC_TED_deprecated -0xD4220c4A3a6eD01D3592B48e80A1311473874a01,Multisig_Wallet_7 -0x5Acd9ed22d5d14BC2AD932574E4bC17A2AC37d15,Multisig_Wallet_8 -0x51fda8b52CFAd8AbEdBdc4095B04828ea22673d9,Multisig_Wallet_9 -0x27315161F8084E759b2786c1d1ED9e150820E3Bf,Multisig_Wallet_10 -0x35cE99bc63472A34c6436D72f9bAcE332cD3D83a,Multisig_Wallet_11 -0xc116Ad4C23AD430aF7B55b7aA464A63C82a9674f,Multisig_Wallet_12 0x9146bD9af43B7CEee82d54e5ff6c5BFD69fD143f,Compound_Comptroller 0x0Ce03Edf9eD2b40d82bfc803416a4e3Ef5b992E7,Compound_Market_1 0x3fDbb1c253a01B9344b30865494C90E6F585100C,Compound_Market_2 @@ -43,3 +42,20 @@ 0x79339c994453AD8832Ff9DDAc9b78373AB1831F8,Compound_Agent_5 0x18f7259eaF0d0C409126C06e895da222738816B8,Compound_Agent_6 0xf888a28599bb671E1b037DA6116032e689e816cA,Compound_Agent_7 +0x194D943B5aC2102d5757d8f279EBfc1852C2067a,Multisig_Wallet_1 +0xF720ca0Be8b4C16B0Ef33ac5E59599a74F5d7932,Multisig_Wallet_2 +0x83C5bE678FE705C2866dFD0911caD27f6fd12A91,Multisig_Wallet_3 +0xD64D48BA2647b8dfD5924F47B5aC705443f7F664,Multisig_Wallet_4 +0x579C412AcdeC26FafD0F61A2254830491C237544,Multisig_Wallet_5 +0xB592E7E9C58259eAb005c58b73BBb0B9945fa426,Multisig_Wallet_6 +0xD4220c4A3a6eD01D3592B48e80A1311473874a01,Multisig_Wallet_7 +0x5Acd9ed22d5d14BC2AD932574E4bC17A2AC37d15,Multisig_Wallet_8 +0x51fda8b52CFAd8AbEdBdc4095B04828ea22673d9,Multisig_Wallet_9 +0x6535B947607311F395C0FFe52CD2F2DB0BFC2099,Multisig_Wallet_10 +0x35cE99bc63472A34c6436D72f9bAcE332cD3D83a,Multisig_Wallet_11 +0x27315161F8084E759b2786c1d1ED9e150820E3Bf,Multisig_Wallet_12 +0xc116Ad4C23AD430aF7B55b7aA464A63C82a9674f,Multisig_Wallet_13 +0x0B4E40d73eea7c9cC7c0c85EC8762575c49E0882,Multisig_Wallet_14 +0x0a7D297D752376fd403DE13778DFbE56b8762cfA,Multisig_Wallet_15 +0x88EC3491f763f4cDCF2a8F9Edd4b752AE5B8C9Fb,YieldStreamer +0xf1Db417ec9F5f10F45dD1205d5e0Bf7f3E66b71e,YieldStreamer_v2 diff --git a/static/contracts-deployments/contracts-staging.csv b/static/contracts-deployments/contracts-staging.csv index 2009e7f71..ead0ee5b6 100644 --- a/static/contracts-deployments/contracts-staging.csv +++ b/static/contracts-deployments/contracts-staging.csv @@ -1,5 +1,5 @@ -0xe66681cD29F07c1C4c056B46B7d37007eF493486,YieldStreamer 0xB1f571b3254C99A0A562124738f0193dE2B2b2A9,BalanceTracker +0x36F511784C59FB84098e9522761359BCb3ccf5d8,BalanceFreezer 0xC6d1eFd908ef6B69dA0749600F553923C465c812,BRLCToken 0x6d8Da3C039D1D78622F27D4739e1E00B324aFAAa,USJIMToken 0x135Ad34643C902906960Ea8F9F470B1Cc5160200,CreditAgent @@ -12,9 +12,13 @@ 0x3c7c6DA9439B3E410B89cB02Ce6BD315cCe622d5,Cashier_USJIM_v4 0x038501B9a2aA059Eb2FA17DC79A9454d6c18dF75,Cashier_BRLC_Receivables_v4 0x27868AA4b98Eda8e1C13A294e36606d01Bba6332,Cashier_BRLC_TED_v4 -0xCd73739C815C5eD6071D094051C0bD6C06bc394c,LendingMarketUUPS -0xAad8dEf94A9B71E53E563024f2a7cC714A0195d7,CreditLineConfigurableUUPS -0x92Ad16Fd2c713Fa02066466D3308476b58b5EF46,LiquidityPoolAccountableUUPS +0xCd73739C815C5eD6071D094051C0bD6C06bc394c,LendingMarket +0xAad8dEf94A9B71E53E563024f2a7cC714A0195d7,CreditLine_1 +0x92Ad16Fd2c713Fa02066466D3308476b58b5EF46,LiquidityPool_1 +0x30c3b89EF62069eE7cc4A327FB74bB9c687092B9,CreditLine_2 +0x3602482Ff44C79C688F3458a4E7e27e74a5075A5,LiquidityPool_2 +0x21CF0089a39F93A92Ec0B0279d8422ffAaBB942A,CreditLine_3 +0x95E781D66Ea3471180e00e0fe42eD596843C7C47,LiquidityPool_3 0xe938b69d9AFA593FFE55CF01738AbfD62466DEa7,CPP_BRLC_v1 0xFe57a8CE8f8428688Aa6D58B4707ED3586da6E46,CashbackDistributor_v1 0x160e794bAd1503968D316A8300D2a4E8F435Bf3e,CPP_USJIM_v1 @@ -31,3 +35,7 @@ 0xfe6316368cb40870cC068667a2469035Ad8668aD,Compound_Agent_3 0xae47B1ecF0ebA42572a16e449052849451edf851,Compound_Agent_4 0xE23dc96fAe16E0bf33F510459249dc2f4eE3B031,Compound_Agent_5 +0xa9b796cCDbbbe6B0BDBf2A96E5cb484465482030,CompoundRelayer +0x0d9B2195a7f39583e8257dCbE6BaC5bD7F56b73B,Multisig_Wallet +0xe66681cD29F07c1C4c056B46B7d37007eF493486,YieldStreamer +0x8D7b7CE41b63920B931A4e59e1852117ba6eeC22,YieldStreamer_v2 diff --git a/tests/fixtures/cf_versions/accounts/V1.bincode b/tests/fixtures/cf_versions/accounts/V1.bincode index bea74c91d..f4a59dee2 100644 Binary files a/tests/fixtures/cf_versions/accounts/V1.bincode and b/tests/fixtures/cf_versions/accounts/V1.bincode differ diff --git a/tests/fixtures/cf_versions/accounts_history/V1.bincode b/tests/fixtures/cf_versions/accounts_history/V1.bincode index bea74c91d..f4a59dee2 100644 Binary files a/tests/fixtures/cf_versions/accounts_history/V1.bincode and b/tests/fixtures/cf_versions/accounts_history/V1.bincode differ diff --git a/tests/fixtures/cf_versions/blocks_by_hash/V1.bincode b/tests/fixtures/cf_versions/blocks_by_hash/V1.bincode index b1cdd68d4..49f778b65 100644 Binary files a/tests/fixtures/cf_versions/blocks_by_hash/V1.bincode and b/tests/fixtures/cf_versions/blocks_by_hash/V1.bincode differ diff --git a/tests/fixtures/cf_versions/blocks_by_number/V1.bincode b/tests/fixtures/cf_versions/blocks_by_number/V1.bincode index 6bfafe4e0..8f5cf4bc3 100644 Binary files a/tests/fixtures/cf_versions/blocks_by_number/V1.bincode and b/tests/fixtures/cf_versions/blocks_by_number/V1.bincode differ diff --git a/tests/fixtures/cf_versions/logs/V1.bincode b/tests/fixtures/cf_versions/logs/V1.bincode index b1cdd68d4..49f778b65 100644 Binary files a/tests/fixtures/cf_versions/logs/V1.bincode and b/tests/fixtures/cf_versions/logs/V1.bincode differ diff --git a/tests/fixtures/cf_versions/transactions/V1.bincode b/tests/fixtures/cf_versions/transactions/V1.bincode index b1cdd68d4..49f778b65 100644 Binary files a/tests/fixtures/cf_versions/transactions/V1.bincode and b/tests/fixtures/cf_versions/transactions/V1.bincode differ