diff --git a/crates/astria-sequencer/src/app/test_utils.rs b/crates/astria-sequencer/src/app/test_utils.rs index 508c6003c6..03d7d9704a 100644 --- a/crates/astria-sequencer/src/app/test_utils.rs +++ b/crates/astria-sequencer/src/app/test_utils.rs @@ -257,26 +257,65 @@ pub(crate) async fn initialize_app( reason = "allow is only necessary when benchmark isn't enabled" )] #[cfg_attr(feature = "benchmark", allow(dead_code))] -pub(crate) fn mock_tx( +pub(crate) struct MockTxBuilder { nonce: u32, - signer: &SigningKey, - rollup_name: &str, -) -> Arc { - let tx = UnsignedTransaction::builder() - .actions(vec![ - SequenceAction { - rollup_id: RollupId::from_unhashed_bytes(rollup_name.as_bytes()), - data: Bytes::from_static(&[0x99]), - fee_asset: denom_0(), - } - .into(), - ]) - .chain_id("test") - .nonce(nonce) - .try_build() - .unwrap(); + signer: SigningKey, + chain_id: String, +} + +#[expect( + clippy::allow_attributes, + clippy::allow_attributes_without_reason, + reason = "allow is only necessary when benchmark isn't enabled" +)] +#[cfg_attr(feature = "benchmark", allow(dead_code))] +impl MockTxBuilder { + pub(crate) fn new() -> Self { + Self { + chain_id: "test".to_string(), + nonce: 0, + signer: get_alice_signing_key(), + } + } - Arc::new(tx.into_signed(signer)) + pub(crate) fn nonce(self, nonce: u32) -> Self { + Self { + nonce, + ..self + } + } + + pub(crate) fn signer(self, signer: SigningKey) -> Self { + Self { + signer, + ..self + } + } + + pub(crate) fn chain_id(self, chain_id: &str) -> Self { + Self { + chain_id: chain_id.to_string(), + ..self + } + } + + pub(crate) fn build(self) -> Arc { + let tx = UnsignedTransaction::builder() + .actions(vec![ + SequenceAction { + rollup_id: RollupId::from_unhashed_bytes("rollup-id"), + data: Bytes::from_static(&[0x99]), + fee_asset: denom_0(), + } + .into(), + ]) + .chain_id(self.chain_id) + .nonce(self.nonce) + .try_build() + .unwrap(); + + Arc::new(tx.into_signed(&self.signer)) + } } pub(crate) const MOCK_SEQUENCE_FEE: u128 = 10; diff --git a/crates/astria-sequencer/src/grpc/sequencer.rs b/crates/astria-sequencer/src/grpc/sequencer.rs index f7ddf660c4..4a649a4e6b 100644 --- a/crates/astria-sequencer/src/grpc/sequencer.rs +++ b/crates/astria-sequencer/src/grpc/sequencer.rs @@ -270,7 +270,9 @@ mod tests { let alice_address = astria_address(&alice.address_bytes()); // insert a transaction with a nonce gap let gapped_nonce = 99; - let tx = crate::app::test_utils::mock_tx(gapped_nonce, &get_alice_signing_key(), "test"); + let tx = crate::app::test_utils::MockTxBuilder::new() + .nonce(gapped_nonce) + .build(); mempool .insert(tx, 0, mock_balances(0, 0), mock_tx_cost(0, 0, 0)) .await @@ -278,7 +280,10 @@ mod tests { // insert a transaction at the current nonce let account_nonce = 0; - let tx = crate::app::test_utils::mock_tx(account_nonce, &get_alice_signing_key(), "test"); + let tx = crate::app::test_utils::MockTxBuilder::new() + .nonce(account_nonce) + .build(); + mempool .insert(tx, 0, mock_balances(0, 0), mock_tx_cost(0, 0, 0)) .await @@ -287,7 +292,9 @@ mod tests { // insert a transactions one above account nonce (not gapped) let sequential_nonce = 1; let tx: Arc = - crate::app::test_utils::mock_tx(sequential_nonce, &get_alice_signing_key(), "test"); + crate::app::test_utils::MockTxBuilder::new() + .nonce(sequential_nonce) + .build(); mempool .insert(tx, 0, mock_balances(0, 0), mock_tx_cost(0, 0, 0)) .await diff --git a/crates/astria-sequencer/src/mempool/mod.rs b/crates/astria-sequencer/src/mempool/mod.rs index 5916b85123..d0aaaa270c 100644 --- a/crates/astria-sequencer/src/mempool/mod.rs +++ b/crates/astria-sequencer/src/mempool/mod.rs @@ -410,27 +410,31 @@ impl Mempool { #[cfg(test)] mod tests { - use astria_core::crypto::SigningKey; - use super::*; - use crate::app::test_utils::{ - mock_balances, - mock_state_getter, - mock_state_put_account_balances, - mock_state_put_account_nonce, - mock_tx, - mock_tx_cost, + use crate::{ + app::test_utils::{ + get_bob_signing_key, + mock_balances, + mock_state_getter, + mock_state_put_account_balances, + mock_state_put_account_nonce, + mock_tx_cost, + MockTxBuilder, + ALICE_ADDRESS, + BOB_ADDRESS, + CAROL_ADDRESS, + }, + test_utils::astria_address_from_hex_string, }; #[tokio::test] async fn insert() { let mempool = Mempool::new(); - let signing_key = SigningKey::from([1; 32]); let account_balances = mock_balances(100, 100); let tx_cost = mock_tx_cost(10, 10, 0); // sign and insert nonce 1 - let tx1 = mock_tx(1, &signing_key, "test"); + let tx1 = MockTxBuilder::new().nonce(1).build(); assert!( mempool .insert(tx1.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -450,7 +454,10 @@ mod tests { ); // try to replace nonce - let tx1_replacement = mock_tx(1, &signing_key, "test_0"); + let tx1_replacement = MockTxBuilder::new() + .nonce(1) + .chain_id("test-chain-id") + .build(); assert_eq!( mempool .insert( @@ -466,7 +473,7 @@ mod tests { ); // add too low nonce - let tx0 = mock_tx(0, &signing_key, "test"); + let tx0 = MockTxBuilder::new().nonce(0).build(); assert_eq!( mempool .insert(tx0.clone(), 1, account_balances, tx_cost) @@ -486,14 +493,12 @@ mod tests { // some transactions that other nodes include into their proposed blocks. let mempool = Mempool::new(); - let signing_key = SigningKey::from([1; 32]); - let signing_address = signing_key.verification_key().address_bytes(); let account_balances = mock_balances(100, 100); let tx_cost = mock_tx_cost(10, 10, 0); // add nonces in odd order to trigger insertion promotion logic // sign and insert nonce 1 - let tx1 = mock_tx(1, &signing_key, "test"); + let tx1 = MockTxBuilder::new().nonce(1).build(); assert!( mempool .insert(tx1.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -503,7 +508,7 @@ mod tests { ); // sign and insert nonce 2 - let tx2 = mock_tx(2, &signing_key, "test"); + let tx2 = MockTxBuilder::new().nonce(2).build(); assert!( mempool .insert(tx2.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -513,7 +518,7 @@ mod tests { ); // sign and insert nonce 0 - let tx0 = mock_tx(0, &signing_key, "test"); + let tx0 = MockTxBuilder::new().nonce(0).build(); assert!( mempool .insert(tx0.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -523,7 +528,7 @@ mod tests { ); // sign and insert nonce 4 - let tx4 = mock_tx(4, &signing_key, "test"); + let tx4 = MockTxBuilder::new().nonce(4).build(); assert!( mempool .insert(tx4.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -537,7 +542,11 @@ mod tests { // mock state with nonce at 1 let mut mock_state = mock_state_getter().await; - mock_state_put_account_nonce(&mut mock_state, signing_address, 1); + mock_state_put_account_nonce( + &mut mock_state, + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + 1, + ); // grab building queue, should return transactions [1,2] since [0] was below and [4] is // gapped @@ -557,8 +566,16 @@ mod tests { // to pending // setup state - mock_state_put_account_nonce(&mut mock_state, signing_address, 4); - mock_state_put_account_balances(&mut mock_state, signing_address, mock_balances(100, 100)); + mock_state_put_account_nonce( + &mut mock_state, + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + 4, + ); + mock_state_put_account_balances( + &mut mock_state, + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + mock_balances(100, 100), + ); mempool.run_maintenance(&mock_state, false).await; @@ -577,18 +594,16 @@ mod tests { #[tokio::test] async fn run_maintenance_promotion() { let mempool = Mempool::new(); - let signing_key = SigningKey::from([1; 32]); - let signing_address = signing_key.verification_key().address_bytes(); // create transaction setup to trigger promotions // // initially pending has single transaction let initial_balances = mock_balances(1, 0); let tx_cost = mock_tx_cost(1, 0, 0); - let tx1 = mock_tx(1, &signing_key, "test"); - let tx2 = mock_tx(2, &signing_key, "test"); - let tx3 = mock_tx(3, &signing_key, "test"); - let tx4 = mock_tx(4, &signing_key, "test"); + let tx1 = MockTxBuilder::new().nonce(1).build(); + let tx2 = MockTxBuilder::new().nonce(2).build(); + let tx3 = MockTxBuilder::new().nonce(3).build(); + let tx4 = MockTxBuilder::new().nonce(4).build(); mempool .insert(tx1.clone(), 1, initial_balances.clone(), tx_cost.clone()) @@ -609,7 +624,11 @@ mod tests { // see pending only has one transaction let mut mock_state = mock_state_getter().await; - mock_state_put_account_nonce(&mut mock_state, signing_address, 1); + mock_state_put_account_nonce( + &mut mock_state, + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + 1, + ); let builder_queue = mempool .builder_queue(&mock_state) @@ -624,7 +643,11 @@ mod tests { // run maintenance with account containing balance for two more transactions // setup state - mock_state_put_account_balances(&mut mock_state, signing_address, mock_balances(3, 0)); + mock_state_put_account_balances( + &mut mock_state, + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + mock_balances(3, 0), + ); mempool.run_maintenance(&mock_state, false).await; @@ -643,18 +666,16 @@ mod tests { #[tokio::test] async fn run_maintenance_demotion() { let mempool = Mempool::new(); - let signing_key = SigningKey::from([1; 32]); - let signing_address = signing_key.verification_key().address_bytes(); // create transaction setup to trigger demotions // // initially pending has four transactions let initial_balances = mock_balances(4, 0); let tx_cost = mock_tx_cost(1, 0, 0); - let tx1 = mock_tx(1, &signing_key, "test"); - let tx2 = mock_tx(2, &signing_key, "test"); - let tx3 = mock_tx(3, &signing_key, "test"); - let tx4 = mock_tx(4, &signing_key, "test"); + let tx1 = MockTxBuilder::new().nonce(1).build(); + let tx2 = MockTxBuilder::new().nonce(2).build(); + let tx3 = MockTxBuilder::new().nonce(3).build(); + let tx4 = MockTxBuilder::new().nonce(4).build(); mempool .insert(tx1.clone(), 1, initial_balances.clone(), tx_cost.clone()) @@ -676,7 +697,11 @@ mod tests { // see pending only has all transactions let mut mock_state = mock_state_getter().await; - mock_state_put_account_nonce(&mut mock_state, signing_address, 1); + mock_state_put_account_nonce( + &mut mock_state, + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + 1, + ); let builder_queue = mempool .builder_queue(&mock_state) @@ -689,7 +714,11 @@ mod tests { ); // setup state - mock_state_put_account_balances(&mut mock_state, signing_address, mock_balances(1, 0)); + mock_state_put_account_balances( + &mut mock_state, + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + mock_balances(1, 0), + ); mempool.run_maintenance(&mock_state, false).await; @@ -704,8 +733,16 @@ mod tests { "builder queue should contain single transaction" ); - mock_state_put_account_nonce(&mut mock_state, signing_address, 1); - mock_state_put_account_balances(&mut mock_state, signing_address, mock_balances(3, 0)); + mock_state_put_account_nonce( + &mut mock_state, + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + 1, + ); + mock_state_put_account_balances( + &mut mock_state, + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + mock_balances(3, 0), + ); mempool.run_maintenance(&mock_state, false).await; @@ -723,12 +760,11 @@ mod tests { #[tokio::test] async fn remove_invalid() { let mempool = Mempool::new(); - let signing_key = SigningKey::from([1; 32]); let account_balances = mock_balances(100, 100); let tx_cost = mock_tx_cost(10, 10, 10); // sign and insert nonces 0,1 and 3,4,5 - let tx0 = mock_tx(0, &signing_key, "test"); + let tx0 = MockTxBuilder::new().nonce(0).build(); assert!( mempool .insert(tx0.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -736,7 +772,7 @@ mod tests { .is_ok(), "should be able to insert nonce 0 transaction into mempool" ); - let tx1 = mock_tx(1, &signing_key, "test"); + let tx1 = MockTxBuilder::new().nonce(1).build(); assert!( mempool .insert(tx1.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -744,7 +780,7 @@ mod tests { .is_ok(), "should be able to insert nonce 1 transaction into mempool" ); - let tx3 = mock_tx(3, &signing_key, "test"); + let tx3 = MockTxBuilder::new().nonce(3).build(); assert!( mempool .insert(tx3.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -752,7 +788,7 @@ mod tests { .is_ok(), "should be able to insert nonce 3 transaction into mempool" ); - let tx4 = mock_tx(4, &signing_key, "test"); + let tx4 = MockTxBuilder::new().nonce(4).build(); assert!( mempool .insert(tx4.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -760,7 +796,7 @@ mod tests { .is_ok(), "should be able to insert nonce 4 transaction into mempool" ); - let tx5 = mock_tx(5, &signing_key, "test"); + let tx5 = MockTxBuilder::new().nonce(5).build(); assert!( mempool .insert(tx5.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -826,17 +862,12 @@ mod tests { #[tokio::test] async fn should_get_pending_nonce() { let mempool = Mempool::new(); - let signing_key_0 = SigningKey::from([1; 32]); - let signing_key_1 = SigningKey::from([2; 32]); - let signing_key_2 = SigningKey::from([3; 32]); - let signing_address_0 = signing_key_0.verification_key().address_bytes(); - let signing_address_1 = signing_key_1.verification_key().address_bytes(); - let signing_address_2 = signing_key_2.verification_key().address_bytes(); + let account_balances = mock_balances(100, 100); let tx_cost = mock_tx_cost(10, 10, 0); // sign and insert nonces 0,1 - let tx0 = mock_tx(0, &signing_key_0, "test"); + let tx0 = MockTxBuilder::new().nonce(0).build(); assert!( mempool .insert(tx0.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -844,7 +875,7 @@ mod tests { .is_ok(), "should be able to insert nonce 0 transaction into mempool" ); - let tx1 = mock_tx(1, &signing_key_0, "test"); + let tx1 = MockTxBuilder::new().nonce(1).build(); assert!( mempool .insert(tx1.clone(), 0, account_balances.clone(), tx_cost.clone()) @@ -854,7 +885,10 @@ mod tests { ); // sign and insert nonces 100, 101 - let tx100 = mock_tx(100, &signing_key_1, "test"); + let tx100 = MockTxBuilder::new() + .nonce(100) + .signer(get_bob_signing_key()) + .build(); assert!( mempool .insert( @@ -867,7 +901,10 @@ mod tests { .is_ok(), "should be able to insert nonce 100 transaction into mempool" ); - let tx101 = mock_tx(101, &signing_key_1, "test"); + let tx101 = MockTxBuilder::new() + .nonce(101) + .signer(get_bob_signing_key()) + .build(); assert!( mempool .insert( @@ -884,11 +921,28 @@ mod tests { assert_eq!(mempool.len().await, 4); // Check the pending nonces - assert_eq!(mempool.pending_nonce(signing_address_0).await.unwrap(), 1); - assert_eq!(mempool.pending_nonce(signing_address_1).await.unwrap(), 101); + assert_eq!( + mempool + .pending_nonce(astria_address_from_hex_string(ALICE_ADDRESS).bytes()) + .await + .unwrap(), + 1 + ); + assert_eq!( + mempool + .pending_nonce(astria_address_from_hex_string(BOB_ADDRESS).bytes()) + .await + .unwrap(), + 101 + ); // Check the pending nonce for an address with no txs is `None`. - assert!(mempool.pending_nonce(signing_address_2).await.is_none()); + assert!( + mempool + .pending_nonce(astria_address_from_hex_string(CAROL_ADDRESS).bytes()) + .await + .is_none() + ); } #[tokio::test] diff --git a/crates/astria-sequencer/src/mempool/transactions_container.rs b/crates/astria-sequencer/src/mempool/transactions_container.rs index 25d5cad27e..be079d712a 100644 --- a/crates/astria-sequencer/src/mempool/transactions_container.rs +++ b/crates/astria-sequencer/src/mempool/transactions_container.rs @@ -783,38 +783,89 @@ mod tests { use astria_core::crypto::SigningKey; use super::*; - use crate::app::test_utils::{ - denom_0, - denom_1, - denom_3, - mock_balances, - mock_state_getter, - mock_state_put_account_nonce, - mock_tx, - mock_tx_cost, - MOCK_SEQUENCE_FEE, + use crate::{ + app::test_utils::{ + denom_0, + denom_1, + denom_3, + get_alice_signing_key, + get_bob_signing_key, + get_carol_signing_key, + mock_balances, + mock_state_getter, + mock_state_put_account_nonce, + mock_tx_cost, + MockTxBuilder, + ALICE_ADDRESS, + BOB_ADDRESS, + CAROL_ADDRESS, + MOCK_SEQUENCE_FEE, + }, + test_utils::astria_address_from_hex_string, }; const MAX_PARKED_TXS_PER_ACCOUNT: usize = 15; const TX_TTL: Duration = Duration::from_secs(2); - fn mock_ttx( + struct MockTTXBuilder { nonce: u32, - signer: &SigningKey, - denom_0_cost: u128, - denom_1_cost: u128, - denom_2_cost: u128, - ) -> TimemarkedTransaction { - TimemarkedTransaction::new( - mock_tx(nonce, signer, "test"), - mock_tx_cost(denom_0_cost, denom_1_cost, denom_2_cost), - ) + signer: SigningKey, + chain_id: String, + cost_map: HashMap, + } + + impl MockTTXBuilder { + fn build(self) -> TimemarkedTransaction { + let tx = MockTxBuilder::new() + .nonce(self.nonce) + .signer(self.signer) + .chain_id(&self.chain_id) + .build(); + + TimemarkedTransaction::new(tx, self.cost_map) + } + + fn chain_id(self, chain_id: &str) -> Self { + Self { + chain_id: chain_id.to_string(), + ..self + } + } + + fn new() -> Self { + Self { + nonce: 0, + signer: get_alice_signing_key(), + chain_id: "test".to_string(), + cost_map: mock_tx_cost(0, 0, 0), + } + } + + fn nonce(self, nonce: u32) -> Self { + Self { + nonce, + ..self + } + } + + fn signer(self, signer: SigningKey) -> Self { + Self { + signer, + ..self + } + } + + fn cost_map(self, cost: HashMap) -> Self { + Self { + cost_map: cost, + ..self + } + } } #[test] fn transaction_priority_should_error_if_invalid() { - let ttx = - TimemarkedTransaction::new(mock_tx(0, &[1; 32].into(), "test"), mock_tx_cost(0, 0, 0)); + let ttx = MockTTXBuilder::new().nonce(0).build(); let priority = ttx.priority(1); assert!( @@ -935,9 +986,18 @@ mod tests { let mut parked_txs = ParkedTransactionsForAccount::::new(); // transactions to add - let ttx_1 = mock_ttx(1, &[1; 32].into(), 10, 0, 0); - let ttx_3 = mock_ttx(3, &[1; 32].into(), 0, 10, 0); - let ttx_5 = mock_ttx(5, &[1; 32].into(), 0, 0, 100); + let ttx_1 = MockTTXBuilder::new() + .nonce(1) + .cost_map(mock_tx_cost(10, 0, 0)) + .build(); + let ttx_3 = MockTTXBuilder::new() + .nonce(3) + .cost_map(mock_tx_cost(0, 10, 0)) + .build(); + let ttx_5 = MockTTXBuilder::new() + .nonce(5) + .cost_map(mock_tx_cost(0, 0, 100)) + .build(); // note account doesn't have balance to cover any of them let account_balances = mock_balances(1, 1); @@ -973,9 +1033,9 @@ mod tests { let mut parked_txs = ParkedTransactionsForAccount::<2>::new(); // transactions to add - let ttx_1 = mock_ttx(1, &[1; 32].into(), 0, 0, 0); - let ttx_3 = mock_ttx(3, &[1; 32].into(), 0, 0, 0); - let ttx_5 = mock_ttx(5, &[1; 32].into(), 0, 0, 0); + let ttx_1 = MockTTXBuilder::new().nonce(1).build(); + let ttx_3 = MockTTXBuilder::new().nonce(3).build(); + let ttx_5 = MockTTXBuilder::new().nonce(5).build(); let account_balances = mock_balances(1, 1); let current_account_nonce = 0; @@ -1000,10 +1060,10 @@ mod tests { let mut pending_txs = PendingTransactionsForAccount::new(); // transactions to add, not testing balances in this unit test - let ttx_0 = mock_ttx(0, &[1; 32].into(), 0, 0, 0); - let ttx_1 = mock_ttx(1, &[1; 32].into(), 0, 0, 0); - let ttx_2 = mock_ttx(2, &[1; 32].into(), 0, 0, 0); - let ttx_3 = mock_ttx(3, &[1; 32].into(), 0, 0, 0); + let ttx_0 = MockTTXBuilder::new().nonce(0).build(); + let ttx_1 = MockTTXBuilder::new().nonce(1).build(); + let ttx_2 = MockTTXBuilder::new().nonce(2).build(); + let ttx_3 = MockTTXBuilder::new().nonce(3).build(); let account_balances = mock_balances(1, 1); @@ -1057,13 +1117,34 @@ mod tests { let mut pending_txs = PendingTransactionsForAccount::new(); // transactions to add, testing balances - let ttx_0_too_expensive_0 = mock_ttx(0, &[1; 32].into(), 11, 0, 0); - let ttx_0_too_expensive_1 = mock_ttx(0, &[1; 32].into(), 0, 0, 1); - let ttx_0 = mock_ttx(0, &[1; 32].into(), 10, 0, 0); - let ttx_1 = mock_ttx(1, &[1; 32].into(), 0, 10, 0); - let ttx_2 = mock_ttx(2, &[1; 32].into(), 0, 8, 0); - let ttx_3 = mock_ttx(3, &[1; 32].into(), 0, 2, 0); - let ttx_4 = mock_ttx(4, &[1; 32].into(), 1, 0, 0); + let ttx_0_too_expensive_0 = MockTTXBuilder::new() + .nonce(0) + .cost_map(mock_tx_cost(11, 0, 0)) + .build(); + let ttx_0_too_expensive_1 = MockTTXBuilder::new() + .nonce(0) + .cost_map(mock_tx_cost(0, 0, 1)) + .build(); + let ttx_0 = MockTTXBuilder::new() + .nonce(0) + .cost_map(mock_tx_cost(10, 0, 0)) + .build(); + let ttx_1 = MockTTXBuilder::new() + .nonce(1) + .cost_map(mock_tx_cost(0, 10, 0)) + .build(); + let ttx_2 = MockTTXBuilder::new() + .nonce(2) + .cost_map(mock_tx_cost(0, 8, 0)) + .build(); + let ttx_3 = MockTTXBuilder::new() + .nonce(3) + .cost_map(mock_tx_cost(0, 2, 0)) + .build(); + let ttx_4 = MockTTXBuilder::new() + .nonce(4) + .cost_map(mock_tx_cost(0, 0, 1)) + .build(); let account_balances = mock_balances(10, 20); let current_account_nonce = 0; @@ -1134,10 +1215,10 @@ mod tests { let mut account_txs = PendingTransactionsForAccount::new(); // transactions to add - let ttx_0 = mock_ttx(0, &[1; 32].into(), 0, 0, 0); - let ttx_1 = mock_ttx(1, &[1; 32].into(), 0, 0, 0); - let ttx_2 = mock_ttx(2, &[1; 32].into(), 0, 0, 0); - let ttx_3 = mock_ttx(3, &[1; 32].into(), 0, 0, 0); + let ttx_0 = MockTTXBuilder::new().nonce(0).build(); + let ttx_1 = MockTTXBuilder::new().nonce(1).build(); + let ttx_2 = MockTTXBuilder::new().nonce(2).build(); + let ttx_3 = MockTTXBuilder::new().nonce(3).build(); let account_balances = mock_balances(1, 1); account_txs @@ -1189,9 +1270,9 @@ mod tests { ); // transactions to add - let ttx_0 = mock_ttx(0, &[1; 32].into(), 0, 0, 0); - let ttx_1 = mock_ttx(1, &[1; 32].into(), 0, 0, 0); - let ttx_2 = mock_ttx(2, &[1; 32].into(), 0, 0, 0); + let ttx_0 = MockTTXBuilder::new().nonce(0).build(); + let ttx_1 = MockTTXBuilder::new().nonce(1).build(); + let ttx_2 = MockTTXBuilder::new().nonce(2).build(); let account_balances = mock_balances(1, 1); pending_txs.add(ttx_0, 0, &account_balances).unwrap(); @@ -1209,20 +1290,18 @@ mod tests { #[test] fn transactions_container_add() { let mut pending_txs = PendingTransactions::new(TX_TTL); - - let signing_key_0 = SigningKey::from([1; 32]); - let signing_address_0 = signing_key_0.address_bytes(); - - let signing_key_1 = SigningKey::from([2; 32]); - let signing_address_1 = signing_key_1.address_bytes(); - // transactions to add to accounts - let ttx_s0_0_0 = mock_ttx(0, &signing_key_0, 0, 0, 0); - // Same nonce and signer as `ttx_s0_0_0`, but different rollup name, hence different tx. - let ttx_s0_0_1 = - TimemarkedTransaction::new(mock_tx(0, &signing_key_0, "other"), mock_tx_cost(0, 0, 0)); - let ttx_s0_2_0 = mock_ttx(2, &signing_key_0, 0, 0, 0); - let ttx_s1_0_0 = mock_ttx(0, &signing_key_1, 0, 0, 0); + let ttx_s0_0_0 = MockTTXBuilder::new().nonce(0).build(); + // Same nonce and signer as `ttx_s0_0_0`, but different chain id. + let ttx_s0_0_1 = MockTTXBuilder::new() + .nonce(0) + .chain_id("different-chain-id") + .build(); + let ttx_s0_2_0 = MockTTXBuilder::new().nonce(2).build(); + let ttx_s1_0_0 = MockTTXBuilder::new() + .nonce(0) + .signer(get_bob_signing_key()) + .build(); let account_balances = mock_balances(1, 1); // transactions to add for account 1 @@ -1285,12 +1364,22 @@ mod tests { // check internal structures assert_eq!(pending_txs.txs.len(), 2, "two accounts should exist"); assert_eq!( - pending_txs.txs.get(&signing_address_0).unwrap().txs().len(), + pending_txs + .txs + .get(&astria_address_from_hex_string(ALICE_ADDRESS).bytes()) + .unwrap() + .txs() + .len(), 1, "one transaction should be in the original account" ); assert_eq!( - pending_txs.txs.get(&signing_address_1).unwrap().txs().len(), + pending_txs + .txs + .get(&astria_address_from_hex_string(BOB_ADDRESS).bytes()) + .unwrap() + .txs() + .len(), 1, "one transaction should be in the second account" ); @@ -1304,14 +1393,18 @@ mod tests { #[test] fn transactions_container_remove() { let mut pending_txs = PendingTransactions::new(TX_TTL); - let signing_key_0 = SigningKey::from([1; 32]); - let signing_key_1 = SigningKey::from([2; 32]); // transactions to add to accounts - let ttx_s0_0 = mock_ttx(0, &signing_key_0, 0, 0, 0); - let ttx_s0_1 = mock_ttx(1, &signing_key_0, 0, 0, 0); - let ttx_s1_0 = mock_ttx(0, &signing_key_1, 0, 0, 0); - let ttx_s1_1 = mock_ttx(1, &signing_key_1, 0, 0, 0); + let ttx_s0_0 = MockTTXBuilder::new().nonce(0).build(); + let ttx_s0_1 = MockTTXBuilder::new().nonce(1).build(); + let ttx_s1_0 = MockTTXBuilder::new() + .nonce(0) + .signer(get_bob_signing_key()) + .build(); + let ttx_s1_1 = MockTTXBuilder::new() + .nonce(1) + .signer(get_bob_signing_key()) + .build(); let account_balances = mock_balances(1, 1); // remove on empty returns the tx in Err variant. @@ -1359,20 +1452,21 @@ mod tests { #[test] fn transactions_container_clear_account() { let mut pending_txs = PendingTransactions::new(TX_TTL); - let signing_key_0 = SigningKey::from([1; 32]); - let signing_address_0 = signing_key_0.address_bytes(); - - let signing_key_1 = SigningKey::from([2; 32]); // transactions to add to accounts - let ttx_s0_0 = mock_ttx(0, &signing_key_0, 0, 0, 0); - let ttx_s0_1 = mock_ttx(1, &signing_key_0, 0, 0, 0); - let ttx_s1_0 = mock_ttx(0, &signing_key_1, 0, 0, 0); + let ttx_s0_0 = MockTTXBuilder::new().nonce(0).build(); + let ttx_s0_1 = MockTTXBuilder::new().nonce(1).build(); + let ttx_s1_0 = MockTTXBuilder::new() + .nonce(0) + .signer(get_bob_signing_key()) + .build(); let account_balances = mock_balances(1, 1); // clear all on empty returns zero assert!( - pending_txs.clear_account(&signing_address_0).is_empty(), + pending_txs + .clear_account(&astria_address_from_hex_string(ALICE_ADDRESS).bytes()) + .is_empty(), "zero transactions should be removed from clearing non existing accounts" ); @@ -1389,7 +1483,7 @@ mod tests { // clear should return all transactions assert_eq!( - pending_txs.clear_account(&signing_address_0), + pending_txs.clear_account(&astria_address_from_hex_string(ALICE_ADDRESS).bytes()), vec![ttx_s0_0.tx_hash, ttx_s0_1.tx_hash], "all transactions should be returned from clearing account" ); @@ -1409,17 +1503,15 @@ mod tests { #[tokio::test] async fn transactions_container_recost_transactions() { let mut pending_txs = PendingTransactions::new(TX_TTL); - let signing_key = SigningKey::from([1; 32]); - let signing_address = signing_key.address_bytes(); let account_balances = mock_balances(1, 1); // transaction to add to account - let ttx = mock_ttx(0, &signing_key, 0, 0, 0); + let ttx = MockTTXBuilder::new().nonce(0).build(); pending_txs.add(ttx.clone(), 0, &account_balances).unwrap(); assert_eq!( pending_txs .txs - .get(&signing_address) + .get(&astria_address_from_hex_string(ALICE_ADDRESS).bytes()) .unwrap() .txs .get(&0) @@ -1434,14 +1526,17 @@ mod tests { // recost transactions with mock state's tx costs let state = mock_state_getter().await; pending_txs - .recost_transactions(signing_address, &state) + .recost_transactions( + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + &state, + ) .await; // transaction should have been recosted assert_eq!( pending_txs .txs - .get(&signing_address) + .get(&astria_address_from_hex_string(ALICE_ADDRESS).bytes()) .unwrap() .txs .get(&0) @@ -1455,25 +1550,38 @@ mod tests { } #[tokio::test] + #[expect(clippy::too_many_lines, reason = "it's a test")] async fn transactions_container_clean_account_stale_expired() { let mut pending_txs = PendingTransactions::new(TX_TTL); - let signing_key_0 = SigningKey::from([1; 32]); - let signing_address_0 = signing_key_0.address_bytes(); - let signing_key_1 = SigningKey::from([2; 32]); - let signing_address_1 = signing_key_1.address_bytes(); - let signing_key_2 = SigningKey::from([3; 32]); - let signing_address_2 = signing_key_2.address_bytes(); // transactions to add to accounts - let ttx_s0_0 = mock_ttx(0, &signing_key_0, 0, 0, 0); - let ttx_s0_1 = mock_ttx(1, &signing_key_0, 0, 0, 0); - let ttx_s0_2 = mock_ttx(2, &signing_key_0, 0, 0, 0); - let ttx_s1_0 = mock_ttx(0, &signing_key_1, 0, 0, 0); - let ttx_s1_1 = mock_ttx(1, &signing_key_1, 0, 0, 0); - let ttx_s1_2 = mock_ttx(2, &signing_key_1, 0, 0, 0); - let ttx_s2_0 = mock_ttx(0, &signing_key_2, 0, 0, 0); - let ttx_s2_1 = mock_ttx(1, &signing_key_2, 0, 0, 0); - let ttx_s2_2 = mock_ttx(2, &signing_key_2, 0, 0, 0); + let ttx_s0_0 = MockTTXBuilder::new().nonce(0).build(); + let ttx_s0_1 = MockTTXBuilder::new().nonce(1).build(); + let ttx_s0_2 = MockTTXBuilder::new().nonce(2).build(); + let ttx_s1_0 = MockTTXBuilder::new() + .nonce(0) + .signer(get_bob_signing_key()) + .build(); + let ttx_s1_1 = MockTTXBuilder::new() + .nonce(1) + .signer(get_bob_signing_key()) + .build(); + let ttx_s1_2 = MockTTXBuilder::new() + .nonce(2) + .signer(get_bob_signing_key()) + .build(); + let ttx_s2_0 = MockTTXBuilder::new() + .nonce(0) + .signer(get_carol_signing_key()) + .build(); + let ttx_s2_1 = MockTTXBuilder::new() + .nonce(1) + .signer(get_carol_signing_key()) + .build(); + let ttx_s2_2 = MockTTXBuilder::new() + .nonce(2) + .signer(get_carol_signing_key()) + .build(); let account_balances = mock_balances(1, 1); // add transactions @@ -1508,9 +1616,20 @@ mod tests { // clean accounts // should pop none from signing_address_0, one from signing_address_1, and all from // signing_address_2 - let mut removed_txs = pending_txs.clean_account_stale_expired(signing_address_0, 0); - removed_txs.extend(pending_txs.clean_account_stale_expired(signing_address_1, 1)); - removed_txs.extend(pending_txs.clean_account_stale_expired(signing_address_2, 4)); + let mut removed_txs = pending_txs + .clean_account_stale_expired(astria_address_from_hex_string(ALICE_ADDRESS).bytes(), 0); + removed_txs.extend( + pending_txs.clean_account_stale_expired( + astria_address_from_hex_string(BOB_ADDRESS).bytes(), + 1, + ), + ); + removed_txs.extend( + pending_txs.clean_account_stale_expired( + astria_address_from_hex_string(CAROL_ADDRESS).bytes(), + 4, + ), + ); assert_eq!( removed_txs.len(), @@ -1530,11 +1649,21 @@ mod tests { assert!(pending_txs.contains_tx(&ttx_s1_2.tx_hash)); assert_eq!( - pending_txs.txs.get(&signing_address_0).unwrap().txs().len(), + pending_txs + .txs + .get(&astria_address_from_hex_string(ALICE_ADDRESS).bytes()) + .unwrap() + .txs() + .len(), 3 ); assert_eq!( - pending_txs.txs.get(&signing_address_1).unwrap().txs().len(), + pending_txs + .txs + .get(&astria_address_from_hex_string(BOB_ADDRESS).bytes()) + .unwrap() + .txs() + .len(), 2 ); for (_, reason) in removed_txs { @@ -1548,20 +1677,19 @@ mod tests { #[tokio::test(start_paused = true)] async fn transactions_container_clean_accounts_expired_transactions() { let mut pending_txs = PendingTransactions::new(TX_TTL); - let signing_key_0 = SigningKey::from([1; 32]); - let signing_address_0 = signing_key_0.address_bytes(); - let signing_key_1 = SigningKey::from([2; 32]); - let signing_address_1 = signing_key_1.address_bytes(); let account_balances = mock_balances(1, 1); // transactions to add to accounts - let ttx_s0_0 = mock_ttx(0, &signing_key_0, 0, 0, 0); + let ttx_s0_0 = MockTTXBuilder::new().nonce(0).build(); // pass time to make first transaction stale tokio::time::advance(TX_TTL.saturating_add(Duration::from_nanos(1))).await; - let ttx_s0_1 = mock_ttx(1, &signing_key_0, 0, 0, 0); - let ttx_s1_0 = mock_ttx(0, &signing_key_1, 0, 0, 0); + let ttx_s0_1 = MockTTXBuilder::new().nonce(1).build(); + let ttx_s1_0 = MockTTXBuilder::new() + .nonce(0) + .signer(get_bob_signing_key()) + .build(); // add transactions pending_txs @@ -1575,8 +1703,14 @@ mod tests { .unwrap(); // clean accounts, all nonces should be valid - let mut removed_txs = pending_txs.clean_account_stale_expired(signing_address_0, 0); - removed_txs.extend(pending_txs.clean_account_stale_expired(signing_address_1, 0)); + let mut removed_txs = pending_txs + .clean_account_stale_expired(astria_address_from_hex_string(ALICE_ADDRESS).bytes(), 0); + removed_txs.extend( + pending_txs.clean_account_stale_expired( + astria_address_from_hex_string(BOB_ADDRESS).bytes(), + 0, + ), + ); assert_eq!( removed_txs.len(), @@ -1610,29 +1744,26 @@ mod tests { #[test] fn pending_transactions_pending_nonce() { let mut pending_txs = PendingTransactions::new(TX_TTL); - let signing_key_0 = SigningKey::from([1; 32]); - let signing_address_0 = signing_key_0.address_bytes(); - - let signing_key_1 = SigningKey::from([2; 32]); - let signing_address_1 = signing_key_1.address_bytes(); let account_balances = mock_balances(1, 1); // transactions to add for account 0 - let ttx_s0_0 = mock_ttx(0, &signing_key_0, 0, 0, 0); - let ttx_s0_1 = mock_ttx(1, &signing_key_0, 0, 0, 0); + let ttx_s0_0 = MockTTXBuilder::new().nonce(0).build(); + let ttx_s0_1 = MockTTXBuilder::new().nonce(1).build(); pending_txs.add(ttx_s0_0, 0, &account_balances).unwrap(); pending_txs.add(ttx_s0_1, 0, &account_balances).unwrap(); // empty account returns zero assert!( - pending_txs.pending_nonce(signing_address_1).is_none(), + pending_txs + .pending_nonce(astria_address_from_hex_string(BOB_ADDRESS).bytes()) + .is_none(), "empty account should return None" ); // non empty account returns highest nonce assert_eq!( - pending_txs.pending_nonce(signing_address_0), + pending_txs.pending_nonce(astria_address_from_hex_string(ALICE_ADDRESS).bytes()), Some(1), "should return highest nonce" ); @@ -1641,16 +1772,21 @@ mod tests { #[tokio::test] async fn pending_transactions_builder_queue() { let mut pending_txs = PendingTransactions::new(TX_TTL); - let signing_key_0 = SigningKey::from([1; 32]); - let signing_address_0 = signing_key_0.address_bytes(); - let signing_key_1 = SigningKey::from([2; 32]); - let signing_address_1 = signing_key_1.address_bytes(); // transactions to add to accounts - let ttx_s0_1 = mock_ttx(1, &signing_key_0, 0, 0, 0); - let ttx_s1_1 = mock_ttx(1, &signing_key_1, 0, 0, 0); - let ttx_s1_2 = mock_ttx(2, &signing_key_1, 0, 0, 0); - let ttx_s1_3 = mock_ttx(3, &signing_key_1, 0, 0, 0); + let ttx_s0_1 = MockTTXBuilder::new().nonce(1).build(); + let ttx_s1_1 = MockTTXBuilder::new() + .nonce(1) + .signer(get_bob_signing_key()) + .build(); + let ttx_s1_2 = MockTTXBuilder::new() + .nonce(2) + .signer(get_bob_signing_key()) + .build(); + let ttx_s1_3 = MockTTXBuilder::new() + .nonce(3) + .signer(get_bob_signing_key()) + .build(); let account_balances = mock_balances(1, 1); // add transactions @@ -1667,10 +1803,18 @@ mod tests { .add(ttx_s1_3.clone(), 1, &account_balances) .unwrap(); - // should return all transactions from signing_key_0 and last two from signing_key_1 + // should return all transactions from Alice and last two from Bob let mut mock_state = mock_state_getter().await; - mock_state_put_account_nonce(&mut mock_state, signing_address_0, 1); - mock_state_put_account_nonce(&mut mock_state, signing_address_1, 2); + mock_state_put_account_nonce( + &mut mock_state, + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + 1, + ); + mock_state_put_account_nonce( + &mut mock_state, + astria_address_from_hex_string(BOB_ADDRESS).bytes(), + 2, + ); // get builder queue let builder_queue = pending_txs @@ -1711,13 +1855,20 @@ mod tests { #[tokio::test] async fn parked_transactions_find_promotables() { let mut parked_txs = ParkedTransactions::::new(TX_TTL); - let signing_key = SigningKey::from([1; 32]); - let signing_address = signing_key.address_bytes(); // transactions to add to accounts - let ttx_1 = mock_ttx(1, &signing_key, 10, 0, 0); - let ttx_2 = mock_ttx(2, &signing_key, 5, 2, 0); - let ttx_3 = mock_ttx(3, &signing_key, 1, 0, 0); + let ttx_1 = MockTTXBuilder::new() + .nonce(1) + .cost_map(mock_tx_cost(10, 0, 0)) + .build(); + let ttx_2 = MockTTXBuilder::new() + .nonce(2) + .cost_map(mock_tx_cost(5, 2, 0)) + .build(); + let ttx_3 = MockTTXBuilder::new() + .nonce(3) + .cost_map(mock_tx_cost(1, 0, 0)) + .build(); let remaining_balances = mock_balances(15, 2); // add transactions @@ -1732,11 +1883,19 @@ mod tests { .unwrap(); // none should be returned on nonce gap - let promotables = parked_txs.find_promotables(&signing_address, 0, &remaining_balances); + let promotables = parked_txs.find_promotables( + &astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + 0, + &remaining_balances, + ); assert_eq!(promotables.len(), 0); // only first two transactions should be returned - let promotables = parked_txs.find_promotables(&signing_address, 1, &remaining_balances); + let promotables = parked_txs.find_promotables( + &astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + 1, + &remaining_balances, + ); assert_eq!(promotables.len(), 2); assert_eq!(promotables[0].nonce(), 1); assert_eq!(promotables[1].nonce(), 2); @@ -1748,7 +1907,11 @@ mod tests { // empty account should be removed // remove last - parked_txs.find_promotables(&signing_address, 3, &remaining_balances); + parked_txs.find_promotables( + &astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + 3, + &remaining_balances, + ); assert_eq!( parked_txs.addresses().len(), 0, @@ -1759,14 +1922,24 @@ mod tests { #[tokio::test] async fn pending_transactions_find_demotables() { let mut pending_txs = PendingTransactions::new(TX_TTL); - let signing_key = SigningKey::from([1; 32]); - let signing_address = signing_key.address_bytes(); // transactions to add to account - let ttx_1 = mock_ttx(1, &signing_key, 5, 0, 0); - let ttx_2 = mock_ttx(2, &signing_key, 0, 5, 0); - let ttx_3 = mock_ttx(3, &signing_key, 5, 0, 0); - let ttx_4 = mock_ttx(4, &signing_key, 0, 5, 0); + let ttx_1 = MockTTXBuilder::new() + .nonce(1) + .cost_map(mock_tx_cost(5, 0, 0)) + .build(); + let ttx_2 = MockTTXBuilder::new() + .nonce(2) + .cost_map(mock_tx_cost(0, 5, 0)) + .build(); + let ttx_3 = MockTTXBuilder::new() + .nonce(3) + .cost_map(mock_tx_cost(5, 0, 0)) + .build(); + let ttx_4 = MockTTXBuilder::new() + .nonce(4) + .cost_map(mock_tx_cost(0, 5, 0)) + .build(); let account_balances_full = mock_balances(100, 100); // add transactions @@ -1784,25 +1957,36 @@ mod tests { .unwrap(); // demote none - let demotables: Vec = - pending_txs.find_demotables(signing_address, &account_balances_full); + let demotables: Vec = pending_txs.find_demotables( + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + &account_balances_full, + ); assert_eq!(demotables.len(), 0); // demote last let account_balances_demotion = mock_balances(100, 9); - let demotables = pending_txs.find_demotables(signing_address, &account_balances_demotion); + let demotables = pending_txs.find_demotables( + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + &account_balances_demotion, + ); assert_eq!(demotables.len(), 1); assert_eq!(demotables[0].nonce(), 4); // demote multiple let account_balances_demotion = mock_balances(100, 4); - let demotables = pending_txs.find_demotables(signing_address, &account_balances_demotion); + let demotables = pending_txs.find_demotables( + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + &account_balances_demotion, + ); assert_eq!(demotables.len(), 2); assert_eq!(demotables[0].nonce(), 2); // demote rest let account_balances_demotion = mock_balances(0, 5); - let demotables = pending_txs.find_demotables(signing_address, &account_balances_demotion); + let demotables = pending_txs.find_demotables( + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + &account_balances_demotion, + ); assert_eq!(demotables.len(), 1); assert_eq!(demotables[0].nonce(), 1); @@ -1817,14 +2001,24 @@ mod tests { #[tokio::test] async fn pending_transactions_remaining_account_balances() { let mut pending_txs = PendingTransactions::new(TX_TTL); - let signing_key = SigningKey::from([1; 32]); - let signing_address = signing_key.address_bytes(); // transactions to add to account - let ttx_1 = mock_ttx(1, &signing_key, 6, 0, 0); - let ttx_2 = mock_ttx(2, &signing_key, 0, 5, 0); - let ttx_3 = mock_ttx(3, &signing_key, 6, 0, 0); - let ttx_4 = mock_ttx(4, &signing_key, 0, 5, 0); + let ttx_1 = MockTTXBuilder::new() + .nonce(1) + .cost_map(mock_tx_cost(6, 0, 0)) + .build(); + let ttx_2 = MockTTXBuilder::new() + .nonce(2) + .cost_map(mock_tx_cost(0, 5, 0)) + .build(); + let ttx_3 = MockTTXBuilder::new() + .nonce(3) + .cost_map(mock_tx_cost(6, 0, 0)) + .build(); + let ttx_4 = MockTTXBuilder::new() + .nonce(4) + .cost_map(mock_tx_cost(0, 5, 0)) + .build(); let account_balances_full = mock_balances(100, 100); // add transactions @@ -1842,8 +2036,10 @@ mod tests { .unwrap(); // get balances - let remaining_balances = - pending_txs.subtract_contained_costs(signing_address, account_balances_full); + let remaining_balances = pending_txs.subtract_contained_costs( + astria_address_from_hex_string(ALICE_ADDRESS).bytes(), + account_balances_full, + ); assert_eq!( remaining_balances .get(&denom_0().to_ibc_prefixed())