From e8d46fe9bdb4ef5746effa01ab216704f06ee616 Mon Sep 17 00:00:00 2001 From: zeroXbrock <2791467+zeroXbrock@users.noreply.github.com> Date: Fri, 27 Sep 2024 06:02:05 -0700 Subject: [PATCH 1/9] fix spam cache bug --- src/spammer/blockwise.rs | 2 +- src/spammer/tx_actor.rs | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/spammer/blockwise.rs b/src/spammer/blockwise.rs index 464272e..aedef0d 100644 --- a/src/spammer/blockwise.rs +++ b/src/spammer/blockwise.rs @@ -119,7 +119,7 @@ where .await .map_err(|e| ContenderError::with_err(e, "failed to get block"))? .ok_or(ContenderError::SpamError("no block found", None))?; - last_block_number = block.header.number + 1; + last_block_number = block.header.number; // get gas price let gas_price = self diff --git a/src/spammer/tx_actor.rs b/src/spammer/tx_actor.rs index b43e12c..cf9b161 100644 --- a/src/spammer/tx_actor.rs +++ b/src/spammer/tx_actor.rs @@ -89,12 +89,6 @@ where target_block_num, } => { println!("unconfirmed txs: {}", self.cache.len()); - let receipts = self - .rpc - .get_block_receipts(target_block_num.into()) - .await? - .unwrap_or_default(); - println!("found {} receipts", receipts.len()); let mut maybe_block; loop { maybe_block = self @@ -104,15 +98,26 @@ where if maybe_block.is_some() { break; } + println!("waiting for block {}", target_block_num); std::thread::sleep(Duration::from_secs(1)); } let target_block = maybe_block.expect("this should never happen"); + let receipts = self + .rpc + .get_block_receipts(target_block_num.into()) + .await? + .unwrap_or_default(); + println!( + "found {} receipts for block #{}", + receipts.len(), + target_block_num + ); // filter for txs that were included in the block let receipt_tx_hashes = receipts .iter() .map(|r| r.transaction_hash) .collect::>(); - let pending_txs = self + let confirmed_txs = self .cache .iter() .filter(|tx| receipt_tx_hashes.contains(&tx.tx_hash)) @@ -123,13 +128,13 @@ where let new_txs = &self .cache .iter() - .filter(|tx| !pending_txs.contains(tx)) + .filter(|tx| !confirmed_txs.contains(tx)) .map(|tx| tx.to_owned()) .collect::>(); self.cache = new_txs.to_vec(); // ready to go to the DB - let run_txs = pending_txs + let run_txs = confirmed_txs .into_iter() .map(|pending_tx| { let receipt = receipts From 9dd972e41a968b2b867beae3aeb56a08a7a3462c Mon Sep 17 00:00:00 2001 From: zeroXbrock <2791467+zeroXbrock@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:07:51 -0700 Subject: [PATCH 2/9] fix redundant scan --- src/spammer/blockwise.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/spammer/blockwise.rs b/src/spammer/blockwise.rs index aedef0d..8c575a0 100644 --- a/src/spammer/blockwise.rs +++ b/src/spammer/blockwise.rs @@ -71,7 +71,7 @@ where .map(|slice| slice.to_vec()) .collect(); let mut block_offset = 0; - let mut last_block_number; + let mut last_block_number = 0; // get chain id before we start spamming let chain_id = self @@ -93,11 +93,7 @@ where let mut tasks = vec![]; let mut gas_limits = HashMap::, u128>::new(); - let first_block_number = self - .rpc_client - .get_block_number() - .await - .map_err(|e| ContenderError::with_err(e, "failed to get block number"))?; + // get nonce for each signer and put it into a hashmap let mut nonces = HashMap::new(); for (addr, _) in self.scenario.wallet_map.iter() { @@ -245,8 +241,7 @@ where let _ = task.await; } - // re-iterate through target block range in case there are any txs left in the cache - last_block_number = first_block_number; + // wait until there are no txs left in the cache, or until we time out let mut timeout_counter = 0; if let Some(run_id) = run_id { loop { From b092d931a23041bb1035971abbb2898e86ec6490 Mon Sep 17 00:00:00 2001 From: zeroXbrock <2791467+zeroXbrock@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:38:32 -0700 Subject: [PATCH 3/9] add NamedTx struct, remove singular insert functions (favor plural versions) --- sqlite_db/src/lib.rs | 66 ++++++-------------------------------------- src/db/mod.rs | 49 ++++++++++++++++---------------- src/test_scenario.rs | 20 +++++++++----- testfile/src/lib.rs | 2 +- 4 files changed, 48 insertions(+), 89 deletions(-) diff --git a/sqlite_db/src/lib.rs b/sqlite_db/src/lib.rs index 74262f0..e341204 100644 --- a/sqlite_db/src/lib.rs +++ b/sqlite_db/src/lib.rs @@ -2,7 +2,7 @@ use alloy::{ hex::{FromHex, ToHexExt}, primitives::{Address, TxHash}, }; -use contender_core::db::{DbOps, RunTx}; +use contender_core::db::{DbOps, NamedTx, RunTx}; use contender_core::{error::ContenderError, Result}; use r2d2::{Pool, PooledConnection}; use r2d2_sqlite::SqliteConnectionManager; @@ -180,30 +180,14 @@ impl DbOps for SqliteDb { Ok(res) } - fn insert_named_tx( - &self, - name: String, - tx_hash: TxHash, - contract_address: Option
, - ) -> Result<()> { - self.execute( - "INSERT INTO named_txs (name, tx_hash, contract_address) VALUES (?, ?, ?)", - params![ - name, - tx_hash.encode_hex(), - contract_address.map(|a| a.encode_hex()) - ], - ) - } - - fn insert_named_txs(&self, named_txs: Vec<(String, TxHash, Option
)>) -> Result<()> { + fn insert_named_txs(&self, named_txs: Vec) -> Result<()> { let pool = self.get_pool()?; - let stmts = named_txs.iter().map(|(name, tx_hash, contract_address)| { + let stmts = named_txs.iter().map(|tx| { format!( "INSERT INTO named_txs (name, tx_hash, contract_address) VALUES ('{}', '{}', '{}');", - name, - tx_hash.encode_hex(), - contract_address.map(|a| a.encode_hex()).unwrap_or_default() + tx.name, + tx.tx_hash.encode_hex(), + tx.address.map(|a| a.encode_hex()).unwrap_or_default() ) }); pool.execute_batch(&format!( @@ -245,20 +229,6 @@ impl DbOps for SqliteDb { Ok((tx_hash, contract_address)) } - fn insert_run_tx(&self, run_id: u64, run_tx: RunTx) -> Result<()> { - self.execute( - "INSERT INTO run_txs (run_id, tx_hash, start_timestamp, end_timestamp, block_number, gas_used) VALUES (?, ?, ?, ?, ?, ?)", - params![ - run_id, - run_tx.tx_hash.encode_hex(), - run_tx.start_timestamp, - run_tx.end_timestamp, - run_tx.block_number, - run_tx.gas_used.to_string() - ], - ) - } - fn insert_run_txs(&self, run_id: u64, run_txs: Vec) -> Result<()> { let pool = self.get_pool()?; let stmts = run_txs.iter().map(|tx| { @@ -309,32 +279,14 @@ mod tests { } #[test] - fn inserts_named_tx() { - let db = SqliteDb::new_memory(); - db.create_tables().unwrap(); - let tx_hash = TxHash::from_slice(&[0u8; 32]); - let contract_address = Some(Address::from_slice(&[0u8; 20])); - db.insert_named_tx("test_tx".to_string(), tx_hash, contract_address) - .unwrap(); - let count: i64 = db - .get_pool() - .unwrap() - .query_row("SELECT COUNT(*) FROM named_txs", params![], |row| { - row.get(0) - }) - .unwrap(); - assert_eq!(count, 1); - } - - #[test] - fn insert_named_txs() { + fn inserts_named_txs() { let db = SqliteDb::new_memory(); db.create_tables().unwrap(); let tx_hash = TxHash::from_slice(&[0u8; 32]); let contract_address = Some(Address::from_slice(&[0u8; 20])); db.insert_named_txs(vec![ - ("test_tx".to_string(), tx_hash, contract_address), - ("test_tx2".to_string(), tx_hash, contract_address), + NamedTx::new("test_tx".to_string(), tx_hash, contract_address), + NamedTx::new("test_tx2".to_string(), tx_hash, contract_address), ]) .unwrap(); let count: i64 = db diff --git a/src/db/mod.rs b/src/db/mod.rs index 0fca8f6..07daab3 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -14,6 +14,29 @@ pub struct RunTx { pub gas_used: u128, } +#[derive(Debug, Serialize, Clone)] +pub struct NamedTx { + pub name: String, + pub tx_hash: TxHash, + pub address: Option
, +} + +impl NamedTx { + pub fn new(name: String, tx_hash: TxHash, address: Option
) -> Self { + Self { + name, + tx_hash, + address, + } + } +} + +impl From for Vec { + fn from(named_tx: NamedTx) -> Self { + vec![named_tx] + } +} + pub trait DbOps { fn create_tables(&self) -> Result<()>; @@ -22,19 +45,10 @@ pub trait DbOps { fn num_runs(&self) -> Result; - fn insert_named_tx( - &self, - name: String, - tx_hash: TxHash, - contract_address: Option
, - ) -> Result<()>; - - fn insert_named_txs(&self, named_txs: Vec<(String, TxHash, Option
)>) -> Result<()>; + fn insert_named_txs(&self, named_txs: Vec) -> Result<()>; fn get_named_tx(&self, name: &str) -> Result<(TxHash, Option
)>; - fn insert_run_tx(&self, run_id: u64, tx: RunTx) -> Result<()>; - fn insert_run_txs(&self, run_id: u64, run_txs: Vec) -> Result<()>; fn get_run_txs(&self, run_id: u64) -> Result>; @@ -55,16 +69,7 @@ impl DbOps for MockDb { Ok(0) } - fn insert_named_tx( - &self, - _name: String, - _tx_hash: TxHash, - _contract_address: Option
, - ) -> Result<()> { - Ok(()) - } - - fn insert_named_txs(&self, _named_txs: Vec<(String, TxHash, Option
)>) -> Result<()> { + fn insert_named_txs(&self, _named_txs: Vec) -> Result<()> { Ok(()) } @@ -72,10 +77,6 @@ impl DbOps for MockDb { Ok((TxHash::default(), None)) } - fn insert_run_tx(&self, _run_id: u64, _tx: RunTx) -> Result<()> { - Ok(()) - } - fn insert_run_txs(&self, _run_id: u64, _run_txs: Vec) -> Result<()> { Ok(()) } diff --git a/src/test_scenario.rs b/src/test_scenario.rs index cb4bc46..27abff2 100644 --- a/src/test_scenario.rs +++ b/src/test_scenario.rs @@ -1,4 +1,4 @@ -use crate::db::DbOps; +use crate::db::{DbOps, NamedTx}; use crate::error::ContenderError; use crate::generator::templater::Templater; use crate::generator::{seeder::Seeder, types::PlanType, Generator, PlanConfig}; @@ -112,10 +112,13 @@ where let receipt = res.get_receipt().await.expect("failed to get receipt"); println!("contract address: {:?}", receipt.contract_address); let contract_address = receipt.contract_address; - db.insert_named_tx( - tx_req.name.unwrap_or_default(), - receipt.transaction_hash, - contract_address, + db.insert_named_txs( + NamedTx::new( + tx_req.name.unwrap_or_default(), + receipt.transaction_hash, + contract_address, + ) + .into(), ) .expect("failed to insert tx into db"); }); @@ -174,8 +177,11 @@ where .expect("failed to send tx"); let receipt = res.get_receipt().await.expect("failed to get receipt"); if let Some(name) = tx_req.name { - db.insert_named_tx(name, receipt.transaction_hash, receipt.contract_address) - .expect("failed to insert tx into db"); + db.insert_named_txs( + NamedTx::new(name, receipt.transaction_hash, receipt.contract_address) + .into(), + ) + .expect("failed to insert tx into db"); } }); Ok(Some(handle)) diff --git a/testfile/src/lib.rs b/testfile/src/lib.rs index bf09a99..f254a09 100644 --- a/testfile/src/lib.rs +++ b/testfile/src/lib.rs @@ -261,7 +261,7 @@ pub mod tests { #[test] fn parses_testconfig_toml() { - let test_file = TestConfig::from_file("univ2ConfigTest.toml").unwrap(); + let test_file = TestConfig::from_file("../cli/univ2ConfigTest.toml").unwrap(); assert!(test_file.env.is_some()); assert!(test_file.setup.is_some()); assert!(test_file.spam.is_some()); From 5309fab446a09ea15252c91e15d4135d4a13e080 Mon Sep 17 00:00:00 2001 From: zeroXbrock <2791467+zeroXbrock@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:00:52 -0700 Subject: [PATCH 4/9] return NamedTx from get_named_tx --- sqlite_db/src/lib.rs | 44 +++++++++++++++++++++++++------------- src/db/mod.rs | 6 +++--- src/generator/templater.rs | 2 +- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/sqlite_db/src/lib.rs b/sqlite_db/src/lib.rs index e341204..faf4ea1 100644 --- a/sqlite_db/src/lib.rs +++ b/sqlite_db/src/lib.rs @@ -65,6 +65,18 @@ struct NamedTxRow { contract_address: Option, } +impl From for NamedTx { + fn from(row: NamedTxRow) -> Self { + let tx_hash = TxHash::from_hex(&row.tx_hash).expect("invalid tx hash"); + let contract_address = row + .contract_address + .map(|a| Address::from_hex(&a)) + .transpose() + .expect("invalid address"); + NamedTx::new(row.name, tx_hash, contract_address) + } +} + impl NamedTxRow { fn from_row(row: &Row) -> rusqlite::Result { Ok(Self { @@ -202,7 +214,7 @@ impl DbOps for SqliteDb { Ok(()) } - fn get_named_tx(&self, name: &str) -> Result<(TxHash, Option
)> { + fn get_named_tx(&self, name: &str) -> Result { let pool = self.get_pool()?; let mut stmt = pool .prepare( @@ -218,15 +230,7 @@ impl DbOps for SqliteDb { .transpose() .map_err(|e| ContenderError::with_err(e, "no row found"))? .ok_or(ContenderError::DbError("no existing row", None))?; - - let tx_hash = TxHash::from_hex(&res.tx_hash) - .map_err(|e| ContenderError::with_err(e, "invalid tx hash"))?; - let contract_address = res - .contract_address - .map(|a| Address::from_hex(&a)) - .transpose() - .map_err(|e| ContenderError::with_err(e, "invalid address"))?; - Ok((tx_hash, contract_address)) + Ok(res.into()) } fn insert_run_txs(&self, run_id: u64, run_txs: Vec) -> Result<()> { @@ -279,14 +283,16 @@ mod tests { } #[test] - fn inserts_named_txs() { + fn inserts_and_gets_named_txs() { let db = SqliteDb::new_memory(); db.create_tables().unwrap(); let tx_hash = TxHash::from_slice(&[0u8; 32]); - let contract_address = Some(Address::from_slice(&[0u8; 20])); + let contract_address = Some(Address::from_slice(&[4u8; 20])); + let name1 = "test_tx".to_string(); + let name2 = "test_tx2"; db.insert_named_txs(vec![ - NamedTx::new("test_tx".to_string(), tx_hash, contract_address), - NamedTx::new("test_tx2".to_string(), tx_hash, contract_address), + NamedTx::new(name1.to_owned(), tx_hash, contract_address), + NamedTx::new(name2.to_string(), tx_hash, contract_address), ]) .unwrap(); let count: i64 = db @@ -297,10 +303,15 @@ mod tests { }) .unwrap(); assert_eq!(count, 2); + + let res1 = db.get_named_tx(&name1).unwrap(); + assert_eq!(res1.name, name1); + assert_eq!(res1.tx_hash, tx_hash); + assert_eq!(res1.address, contract_address); } #[test] - fn inserts_run_txs() { + fn inserts_and_gets_run_txs() { let db = SqliteDb::new_memory(); db.create_tables().unwrap(); let run_id = db.insert_run(100000, 100).unwrap(); @@ -327,5 +338,8 @@ mod tests { .query_row("SELECT COUNT(*) FROM run_txs", params![], |row| row.get(0)) .unwrap(); assert_eq!(count, 2); + + let res = db.get_run_txs(run_id as u64).unwrap(); + assert_eq!(res.len(), 2); } } diff --git a/src/db/mod.rs b/src/db/mod.rs index 07daab3..8b5bc67 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -47,7 +47,7 @@ pub trait DbOps { fn insert_named_txs(&self, named_txs: Vec) -> Result<()>; - fn get_named_tx(&self, name: &str) -> Result<(TxHash, Option
)>; + fn get_named_tx(&self, name: &str) -> Result; fn insert_run_txs(&self, run_id: u64, run_txs: Vec) -> Result<()>; @@ -73,8 +73,8 @@ impl DbOps for MockDb { Ok(()) } - fn get_named_tx(&self, _name: &str) -> Result<(TxHash, Option
)> { - Ok((TxHash::default(), None)) + fn get_named_tx(&self, _name: &str) -> Result { + Ok(NamedTx::new(String::default(), TxHash::default(), None)) } fn insert_run_txs(&self, _run_id: u64, _run_txs: Vec) -> Result<()> { diff --git a/src/generator/templater.rs b/src/generator/templater.rs index 7f4fd3e..055c214 100644 --- a/src/generator/templater.rs +++ b/src/generator/templater.rs @@ -61,7 +61,7 @@ where placeholder_map.insert( template_key, template_value - .1 + .address .map(|a| self.encode_contract_address(&a)) .unwrap_or_default(), ); From 8dfcd2b7a689df58d8dbea6428e0efcf698f38c9 Mon Sep 17 00:00:00 2001 From: brock smedley <2791467+zeroXbrock@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:13:30 -0700 Subject: [PATCH 5/9] create gh actions workflow --- .github/workflows/rust.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/rust.yml diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..12b7deb --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,22 @@ +name: Rust + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose --workspace From e250c4363d504b02a0a9026c8810bbeaaa61a4d3 Mon Sep 17 00:00:00 2001 From: zeroXbrock <2791467+zeroXbrock@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:15:44 -0700 Subject: [PATCH 6/9] build workspace in CI --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 12b7deb..39c5645 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -17,6 +17,6 @@ jobs: steps: - uses: actions/checkout@v4 - name: Build - run: cargo build --verbose + run: cargo build --verbose --workspace - name: Run tests run: cargo test --verbose --workspace From 9efe012a1fdb5fd17d3d8fb3585fd5a42b6545b2 Mon Sep 17 00:00:00 2001 From: zeroXbrock <2791467+zeroXbrock@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:23:21 -0700 Subject: [PATCH 7/9] add rust-toolchain & rust-cache to workflow --- .github/workflows/rust.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 39c5645..1110b86 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -16,6 +16,10 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true - name: Build run: cargo build --verbose --workspace - name: Run tests From 15d46815d555d771d63b5cfc907bcf7ae6b0ad2d Mon Sep 17 00:00:00 2001 From: zeroXbrock <2791467+zeroXbrock@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:28:39 -0700 Subject: [PATCH 8/9] install foundry in workflow --- .github/workflows/rust.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1110b86..62f5b5d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -16,6 +16,12 @@ jobs: steps: - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 with: From f8086eae0c65db5b41f652bc4eca8fbded464f88 Mon Sep 17 00:00:00 2001 From: zeroXbrock <2791467+zeroXbrock@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:38:23 -0700 Subject: [PATCH 9/9] separate build & test steps --- .github/workflows/rust.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 62f5b5d..85cf504 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -16,17 +16,25 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 with: - submodules: recursive + cache-on-failure: true + - name: Build + run: cargo build --verbose --workspace + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 - - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - - name: Build - run: cargo build --verbose --workspace - name: Run tests run: cargo test --verbose --workspace