From 3951ad06df4fa0ab76fd3db1822233388a3fa718 Mon Sep 17 00:00:00 2001 From: Vukasin Gostovic Date: Mon, 26 Jun 2023 14:54:38 +0200 Subject: [PATCH 1/8] Bump version --- Cargo.toml | 2 +- src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f156f8a..352faa9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sothis" -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["makemake "] license = "GPL-3.0-or-later" diff --git a/src/main.rs b/src/main.rs index 973a6fa..531be64 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,7 +32,7 @@ lazy_static! { #[tokio::main] async fn main() -> Result<(), Box> { let matches = Command::new("sothis") - .version("0.3.0") + .version("0.3.1") .author("makemake ") .about("Tool for replaying historical transactions. Designed to be used with anvil or hardhat.") .arg(Arg::new("source_rpc") From eb345af9d1b92d36535d7c86ede0c69ed80913f1 Mon Sep 17 00:00:00 2001 From: Vukasin Gostovic Date: Mon, 26 Jun 2023 14:54:58 +0200 Subject: [PATCH 2/8] Add contract address to tracker output --- src/tracker/tracker.rs | 1 + src/tracker/types.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tracker/tracker.rs b/src/tracker/tracker.rs index 345a044..681d10c 100644 --- a/src/tracker/tracker.rs +++ b/src/tracker/tracker.rs @@ -25,6 +25,7 @@ pub async fn track_state( })?; let mut storage = StateChangeList { + address: contract_address.clone(), storage_slot: storage_slot, state_changes: Vec::new(), }; diff --git a/src/tracker/types.rs b/src/tracker/types.rs index 825f4ec..6831c32 100644 --- a/src/tracker/types.rs +++ b/src/tracker/types.rs @@ -1,7 +1,6 @@ use serde::{Deserialize, Serialize}; use ethers::types::U256; -// #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] pub struct StateChange { pub block_number: U256, @@ -19,6 +18,7 @@ impl Default for StateChange { #[derive(Debug, Clone, Deserialize, Serialize)] pub struct StateChangeList { - pub storage_slot: U256, + pub address: String, + pub storage_slot: U256, pub state_changes: Vec, } From 61ae74d418461b0acc624c3b626019997fe8676a Mon Sep 17 00:00:00 2001 From: Vukasin Gostovic Date: Mon, 26 Jun 2023 15:27:31 +0200 Subject: [PATCH 3/8] version bump? --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index c0a6f87..62934a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2860,7 +2860,7 @@ dependencies = [ [[package]] name = "sothis" -version = "0.3.0" +version = "0.3.1" dependencies = [ "clap", "ctrlc", From 547d6efd120e95e13f59063a6fc8455d7fe16d53 Mon Sep 17 00:00:00 2001 From: Vukasin Gostovic Date: Mon, 26 Jun 2023 15:27:48 +0200 Subject: [PATCH 4/8] change behaviour of tracker to immediately read state --- src/tracker/tracker.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tracker/tracker.rs b/src/tracker/tracker.rs index 681d10c..5636938 100644 --- a/src/tracker/tracker.rs +++ b/src/tracker/tracker.rs @@ -1,4 +1,3 @@ -use crate::hex_to_decimal; use crate::APP_CONFIG; use crate::RpcConnection; use crate::tracker::types::*; @@ -41,17 +40,17 @@ pub async fn track_state( filename = app_config.filename.clone(); } + let mut block_number = source_rpc.block_number().await?; loop { if interrupted.load(Ordering::SeqCst) { break; } - let block_number = source_rpc.listen_for_blocks(block_time).await?; - let block_number = hex_to_decimal(&block_number)?; // FIXME: this returns a u64, change this + let block_number_u256: U256 = block_number.parse()?; let latest_slot = source_rpc.get_storage_at(contract_address.clone(), storage_slot.clone()).await?; let slot = StateChange { - block_number: block_number.into(), + block_number: block_number_u256, value: latest_slot, }; @@ -59,6 +58,8 @@ pub async fn track_state( println!("New storage slot value: {:?}", &slot.value); storage.state_changes.push(slot); } + + block_number = source_rpc.listen_for_blocks(block_time).await?; } let json = serde_json::to_string(&storage)?; From 9f54c544d232762407ee8f5db333b6af42b03b13 Mon Sep 17 00:00:00 2001 From: Vukasin Gostovic Date: Mon, 26 Jun 2023 15:58:04 +0200 Subject: [PATCH 5/8] add replay delay --- src/main.rs | 8 ++++++++ src/replay/replay.rs | 16 +++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 531be64..81a67db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ pub struct AppConfig { exit_on_tx_fail: bool, send_as_raw: bool, entropy_threshold: f32, + replay_delay: u64, block_listen_time: u64, path: String, filename: String, @@ -73,6 +74,12 @@ async fn main() -> Result<(), Box> { .num_args(1..) .default_value("0.07") .help("Set the percentage of failed transactions to trigger a warning")) + .arg(Arg::new("replay_delay") + .long("replay_delay") + .short('d') + .num_args(1..) + .default_value("0") + .help("Default delay for block replay in ms")) .arg(Arg::new("send_as_raw") .long("send_as_raw") .num_args(0..) @@ -112,6 +119,7 @@ async fn main() -> Result<(), Box> { app_config.exit_on_tx_fail = matches.get_occurrences::("exit_on_tx_fail").is_some(); app_config.send_as_raw = matches.get_occurrences::("send_as_raw").is_some(); app_config.entropy_threshold = matches.get_one::("entropy_threshold").expect("required").parse::()?; + app_config.replay_delay = matches.get_one::("replay_delay").expect("required").parse::()?; app_config.block_listen_time = matches.get_one::("block_listen_time").expect("required").parse::()?; app_config.path = matches.get_one::("path").expect("required").to_string(); app_config.filename = matches.get_one::("filename").expect("required").to_string(); diff --git a/src/replay/replay.rs b/src/replay/replay.rs index 7a25cde..5d5c6af 100644 --- a/src/replay/replay.rs +++ b/src/replay/replay.rs @@ -1,3 +1,6 @@ +use std::thread::sleep; +use tokio::time::Duration; + use crate::APP_CONFIG; use crate::replay::send_transaction::send_transactions; use crate::RpcConnection; @@ -37,7 +40,14 @@ pub async fn replay_historic_blocks( // set insanely high interval for the blocks replay_rpc.evm_set_interval_mining(std::u32::MAX.into()).await?; - while until > replay_block { + // Get the time we're delaying the replay for + let replay_delay; + { + let app_config = APP_CONFIG.lock()?; + replay_delay = app_config.replay_delay; + } + + loop { // we write a bit of illegible code let hex_block = decimal_to_hex(replay_block + 1); // get block from historical node @@ -60,6 +70,10 @@ pub async fn replay_historic_blocks( println!("Successfully replayed block {}", hex_to_decimal(&hex_block)?); replay_block = hex_to_decimal(&replay_rpc.block_number().await?)?; + if until < replay_block { + break; + } + sleep(Duration::from_millis(replay_delay)) } println!("Done replaying blocks"); Ok(()) From d87fc9f31209068ec5ccc97b8940ca0c3d275505 Mon Sep 17 00:00:00 2001 From: Vukasin Gostovic Date: Mon, 26 Jun 2023 16:01:01 +0200 Subject: [PATCH 6/8] Revert "add replay delay" This reverts commit 9f54c544d232762407ee8f5db333b6af42b03b13. --- src/main.rs | 8 -------- src/replay/replay.rs | 16 +--------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/main.rs b/src/main.rs index 81a67db..531be64 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,6 @@ pub struct AppConfig { exit_on_tx_fail: bool, send_as_raw: bool, entropy_threshold: f32, - replay_delay: u64, block_listen_time: u64, path: String, filename: String, @@ -74,12 +73,6 @@ async fn main() -> Result<(), Box> { .num_args(1..) .default_value("0.07") .help("Set the percentage of failed transactions to trigger a warning")) - .arg(Arg::new("replay_delay") - .long("replay_delay") - .short('d') - .num_args(1..) - .default_value("0") - .help("Default delay for block replay in ms")) .arg(Arg::new("send_as_raw") .long("send_as_raw") .num_args(0..) @@ -119,7 +112,6 @@ async fn main() -> Result<(), Box> { app_config.exit_on_tx_fail = matches.get_occurrences::("exit_on_tx_fail").is_some(); app_config.send_as_raw = matches.get_occurrences::("send_as_raw").is_some(); app_config.entropy_threshold = matches.get_one::("entropy_threshold").expect("required").parse::()?; - app_config.replay_delay = matches.get_one::("replay_delay").expect("required").parse::()?; app_config.block_listen_time = matches.get_one::("block_listen_time").expect("required").parse::()?; app_config.path = matches.get_one::("path").expect("required").to_string(); app_config.filename = matches.get_one::("filename").expect("required").to_string(); diff --git a/src/replay/replay.rs b/src/replay/replay.rs index 5d5c6af..7a25cde 100644 --- a/src/replay/replay.rs +++ b/src/replay/replay.rs @@ -1,6 +1,3 @@ -use std::thread::sleep; -use tokio::time::Duration; - use crate::APP_CONFIG; use crate::replay::send_transaction::send_transactions; use crate::RpcConnection; @@ -40,14 +37,7 @@ pub async fn replay_historic_blocks( // set insanely high interval for the blocks replay_rpc.evm_set_interval_mining(std::u32::MAX.into()).await?; - // Get the time we're delaying the replay for - let replay_delay; - { - let app_config = APP_CONFIG.lock()?; - replay_delay = app_config.replay_delay; - } - - loop { + while until > replay_block { // we write a bit of illegible code let hex_block = decimal_to_hex(replay_block + 1); // get block from historical node @@ -70,10 +60,6 @@ pub async fn replay_historic_blocks( println!("Successfully replayed block {}", hex_to_decimal(&hex_block)?); replay_block = hex_to_decimal(&replay_rpc.block_number().await?)?; - if until < replay_block { - break; - } - sleep(Duration::from_millis(replay_delay)) } println!("Done replaying blocks"); Ok(()) From cac811f84550e2de7f4e9aa30d97cd8a2eba7683 Mon Sep 17 00:00:00 2001 From: Vukasin Gostovic Date: Mon, 26 Jun 2023 16:07:49 +0200 Subject: [PATCH 7/8] Fix crashing on live mode by implementing a worse solution --- src/main.rs | 8 ++++++++ src/replay/replay.rs | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/main.rs b/src/main.rs index 531be64..81a67db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ pub struct AppConfig { exit_on_tx_fail: bool, send_as_raw: bool, entropy_threshold: f32, + replay_delay: u64, block_listen_time: u64, path: String, filename: String, @@ -73,6 +74,12 @@ async fn main() -> Result<(), Box> { .num_args(1..) .default_value("0.07") .help("Set the percentage of failed transactions to trigger a warning")) + .arg(Arg::new("replay_delay") + .long("replay_delay") + .short('d') + .num_args(1..) + .default_value("0") + .help("Default delay for block replay in ms")) .arg(Arg::new("send_as_raw") .long("send_as_raw") .num_args(0..) @@ -112,6 +119,7 @@ async fn main() -> Result<(), Box> { app_config.exit_on_tx_fail = matches.get_occurrences::("exit_on_tx_fail").is_some(); app_config.send_as_raw = matches.get_occurrences::("send_as_raw").is_some(); app_config.entropy_threshold = matches.get_one::("entropy_threshold").expect("required").parse::()?; + app_config.replay_delay = matches.get_one::("replay_delay").expect("required").parse::()?; app_config.block_listen_time = matches.get_one::("block_listen_time").expect("required").parse::()?; app_config.path = matches.get_one::("path").expect("required").to_string(); app_config.filename = matches.get_one::("filename").expect("required").to_string(); diff --git a/src/replay/replay.rs b/src/replay/replay.rs index 7a25cde..2c1deb5 100644 --- a/src/replay/replay.rs +++ b/src/replay/replay.rs @@ -1,3 +1,6 @@ +use std::thread::sleep; +use tokio::time::Duration; + use crate::APP_CONFIG; use crate::replay::send_transaction::send_transactions; use crate::RpcConnection; @@ -37,6 +40,13 @@ pub async fn replay_historic_blocks( // set insanely high interval for the blocks replay_rpc.evm_set_interval_mining(std::u32::MAX.into()).await?; + // Get the time we're delaying the replay for + let replay_delay; + { + let app_config = APP_CONFIG.lock()?; + replay_delay = app_config.replay_delay; + } + while until > replay_block { // we write a bit of illegible code let hex_block = decimal_to_hex(replay_block + 1); @@ -60,6 +70,10 @@ pub async fn replay_historic_blocks( println!("Successfully replayed block {}", hex_to_decimal(&hex_block)?); replay_block = hex_to_decimal(&replay_rpc.block_number().await?)?; + + // TODO: For some godforsaken reason i cannot do an infinite loop and break here or else it crashes. + // I feel dirty doing 2 checks for the same thing so you have to wait a bit ig. + sleep(Duration::from_millis(replay_delay)); } println!("Done replaying blocks"); Ok(()) From 21493babbbbbfe70eb62005acac9f023e7d1f15a Mon Sep 17 00:00:00 2001 From: Vukasin Gostovic Date: Mon, 26 Jun 2023 16:26:06 +0200 Subject: [PATCH 8/8] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index fd1e035..f44dda9 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ Options: Time in ms to check for new blocks. [default: 500] --entropy_threshold ... Set the percentage of failed transactions to trigger a warning [default: 0.07] + -d, --replay_delay ... + Default delay for block replay in ms [default: 0] --send_as_raw [...] Exit the program if a transaction fails -c, --contract_address ... @@ -86,6 +88,7 @@ The tracking mode is used to track the change in value of a storage slot for a c The result is saved to a JSON file that looks like this: ```json { + "address":"0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6", "storage_slot":"0x0", "state_changes":[ {"block_number":"0x10b7bbc","value":"0x00000000000000000000000000000000000000000000000000000000000e2b18"}