Skip to content

Commit

Permalink
feat: add unit tests for the mempool in send_raw_transaction (#1354)
Browse files Browse the repository at this point in the history
* feat: mempool send_raw_transaction test

* fix: insufficient_balance tx value

* fix: test name and insufficient_balance test

* feat: new test
  • Loading branch information
eugypalu authored Aug 30, 2024
1 parent 1a677d0 commit dcdd396
Showing 1 changed file with 317 additions and 0 deletions.
317 changes: 317 additions & 0 deletions tests/tests/eth_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use reth_rpc_types::{
request::TransactionInput, serde_helpers::JsonStorageKey, state::AccountOverride, Filter, FilterBlockOption,
FilterChanges, Log, RpcBlockHash, Topic, TransactionRequest,
};
use reth_transaction_pool::TransactionPool;
use rstest::*;
use starknet::core::types::{BlockTag, Felt};
use std::{collections::HashMap, sync::Arc};
Expand Down Expand Up @@ -725,6 +726,12 @@ async fn test_send_raw_transaction(#[future] katana: Katana, _setup: ()) {
let signature = sign_message(katana.eoa().private_key(), transaction.signature_hash()).unwrap();
let transaction_signed = TransactionSigned::from_transaction_and_signature(transaction, signature);

// Retrieve the current size of the mempool
let mempool_size = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending and total transactions in the mempool is 0
assert_eq!(mempool_size.pending, 0);
assert_eq!(mempool_size.total, 0);

// Send the transaction
let _ = eth_provider
.send_raw_transaction(transaction_signed.envelope_encoded())
Expand All @@ -743,6 +750,214 @@ async fn test_send_raw_transaction(#[future] katana: Katana, _setup: ()) {
// Assert the transaction hash and block number
assert_eq!(tx.hash, transaction_signed.hash());
assert!(tx.block_number.is_none());

// Retrieve the current size of the mempool
let mempool_size_after_send = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending transactions in the mempool is 1
assert_eq!(mempool_size_after_send.pending, 1);
assert_eq!(mempool_size_after_send.total, 1);
let tx_in_mempool = eth_provider.mempool().unwrap().get(&tx.hash);
// Assert that the transaction in the mempool exists
assert!(tx_in_mempool.is_some());
// Verify that the hash of the transaction in the mempool matches the expected hash
assert_eq!(tx_in_mempool.unwrap().hash(), *tx.hash);
}

#[rstest]
#[awt]
#[tokio::test(flavor = "multi_thread")]
async fn test_send_raw_transaction_wrong_nonce(#[future] katana: Katana, _setup: ()) {
// Given
let eth_provider = katana.eth_provider();
let chain_id = eth_provider.chain_id().await.unwrap_or_default().unwrap_or_default().to();

// Create a sample transaction
let transaction = Transaction::Eip1559(TxEip1559 {
chain_id,
nonce: 0,
gas_limit: 21000,
to: TxKind::Call(Address::random()),
value: U256::from(1000),
input: Bytes::default(),
max_fee_per_gas: 875_000_000,
max_priority_fee_per_gas: 0,
access_list: Default::default(),
});

// Sign the transaction
let signature = sign_message(katana.eoa().private_key(), transaction.signature_hash()).unwrap();
let transaction_signed = TransactionSigned::from_transaction_and_signature(transaction, signature);

// Retrieve the current size of the mempool
let mempool_size = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending and total transactions in the mempool is 0
assert_eq!(mempool_size.pending, 0);
assert_eq!(mempool_size.total, 0);

// Send the transaction
let _ = eth_provider
.send_raw_transaction(transaction_signed.envelope_encoded())
.await
.expect("failed to send transaction");

// Assert that the number of pending transactions in the mempool is 1
assert_eq!(eth_provider.mempool().unwrap().pool_size().pending, 1);

// Create a sample transaction with nonce 0 instead of 1
let wrong_transaction = Transaction::Eip1559(TxEip1559 {
chain_id,
nonce: 0,
gas_limit: 21000,
to: TxKind::Call(Address::random()),
value: U256::from(1000),
input: Bytes::default(),
max_fee_per_gas: 875_000_000,
max_priority_fee_per_gas: 0,
access_list: Default::default(),
});

// Sign the transaction
let wrong_signature = sign_message(katana.eoa().private_key(), wrong_transaction.signature_hash()).unwrap();
let wrong_transaction_signed =
TransactionSigned::from_transaction_and_signature(wrong_transaction, wrong_signature);

// Retrieve the current size of the mempool
let mempool_size_after_send = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending transactions in the mempool is 1
assert_eq!(mempool_size_after_send.pending, 1);
assert_eq!(mempool_size_after_send.total, 1);

// Send the transaction
let _ = eth_provider
.send_raw_transaction(wrong_transaction_signed.envelope_encoded())
.await
.expect("failed to send transaction");

// Retrieve the current size of the mempool
let mempool_size_after_wrong_send = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending transactions in the mempool is still 1 (wrong_transaction was not added to the mempool)
assert_eq!(mempool_size_after_wrong_send.pending, 1);
assert_eq!(mempool_size_after_wrong_send.total, 1);
}

#[rstest]
#[awt]
#[tokio::test(flavor = "multi_thread")]
async fn test_send_raw_transaction_exceed_size_limit(#[future] katana: Katana, _setup: ()) {
// Given
let eth_provider = katana.eth_provider();
let chain_id = eth_provider.chain_id().await.unwrap_or_default().unwrap_or_default().to();

// Create a sample transaction
let transaction = Transaction::Eip1559(TxEip1559 {
chain_id,
nonce: 0,
gas_limit: 21000,
to: TxKind::Call(Address::random()),
value: U256::from(1000),
input: Bytes::from(vec![0; 200 * 1024]),
max_fee_per_gas: 875_000_000,
max_priority_fee_per_gas: 0,
access_list: Default::default(),
});

// Sign the transaction
let signature = sign_message(katana.eoa().private_key(), transaction.signature_hash()).unwrap();
let transaction_signed = TransactionSigned::from_transaction_and_signature(transaction, signature);

// Retrieve the current size of the mempool
let mempool_size = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending and total transactions in the mempool is 0
assert_eq!(mempool_size.pending, 0);
assert_eq!(mempool_size.total, 0);

let _ = eth_provider.send_raw_transaction(transaction_signed.envelope_encoded()).await;

// Retrieve the current size of the mempool
let mempool_size_after_send = eth_provider.mempool().unwrap().pool_size();
// Verify that the number of pending transactions in the mempool remains unchanged (0 tx)
assert_eq!(mempool_size_after_send.pending, 0);
assert_eq!(mempool_size_after_send.total, 0);
}

#[rstest]
#[awt]
#[tokio::test(flavor = "multi_thread")]
async fn test_send_raw_transaction_exceed_max_priority_fee_per_gas(#[future] katana: Katana, _setup: ()) {
// Given
let eth_provider = katana.eth_provider();
let chain_id = eth_provider.chain_id().await.unwrap_or_default().unwrap_or_default().to();

// Create a sample transaction
let transaction = Transaction::Eip1559(TxEip1559 {
chain_id,
nonce: 0,
gas_limit: 21000,
to: TxKind::Call(Address::random()),
value: U256::from(1000),
input: Bytes::default(),
max_fee_per_gas: 875_000_000,
max_priority_fee_per_gas: u128::MAX,
access_list: Default::default(),
});

// Sign the transaction
let signature = sign_message(katana.eoa().private_key(), transaction.signature_hash()).unwrap();
let transaction_signed = TransactionSigned::from_transaction_and_signature(transaction, signature);

// Retrieve the current size of the mempool
let mempool_size = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending and total transactions in the mempool is 0
assert_eq!(mempool_size.pending, 0);
assert_eq!(mempool_size.total, 0);

let _ = eth_provider.send_raw_transaction(transaction_signed.envelope_encoded()).await;

// Retrieve the current size of the mempool
let mempool_size_after_send = eth_provider.mempool().unwrap().pool_size();
// Verify that the number of pending transactions in the mempool remains unchanged (0 tx)
assert_eq!(mempool_size_after_send.pending, 0);
assert_eq!(mempool_size_after_send.total, 0);
}

#[rstest]
#[awt]
#[tokio::test(flavor = "multi_thread")]
async fn test_send_raw_transaction_exceed_gas_limit(#[future] katana: Katana, _setup: ()) {
// Given
let eth_provider = katana.eth_provider();
let chain_id = eth_provider.chain_id().await.unwrap_or_default().unwrap_or_default().to();

// Create a sample transaction
let transaction = Transaction::Eip1559(TxEip1559 {
chain_id,
nonce: 0,
gas_limit: u64::MAX,
to: TxKind::Call(Address::random()),
value: U256::from(1000),
input: Bytes::default(),
max_fee_per_gas: 875_000_000,
max_priority_fee_per_gas: 0,
access_list: Default::default(),
});

// Sign the transaction
let signature = sign_message(katana.eoa().private_key(), transaction.signature_hash()).unwrap();
let transaction_signed = TransactionSigned::from_transaction_and_signature(transaction, signature);

// Retrieve the current size of the mempool
let mempool_size = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending and total transactions in the mempool is 0
assert_eq!(mempool_size.pending, 0);
assert_eq!(mempool_size.total, 0);

let _ = eth_provider.send_raw_transaction(transaction_signed.envelope_encoded()).await;

// Retrieve the current size of the mempool
let mempool_size_after_send = eth_provider.mempool().unwrap().pool_size();
// Verify that the number of pending transactions in the mempool remains unchanged (0 tx)
assert_eq!(mempool_size_after_send.pending, 0);
assert_eq!(mempool_size_after_send.total, 0);
}

#[rstest]
Expand All @@ -767,6 +982,11 @@ async fn test_send_raw_transaction_pre_eip_155(#[future] katana: Katana, _setup:
let random_hash = B256::random();
std::env::set_var("WHITE_LISTED_EIP_155_TRANSACTION_HASHES", format!("{hash}, {random_hash}"));

let mempool_size = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending and total transactions in the mempool is 0
assert_eq!(mempool_size.pending, 0);
assert_eq!(mempool_size.total, 0);

// Send the transaction
let tx_hash = eth_provider
.send_raw_transaction(transaction_signed.envelope_encoded())
Expand All @@ -776,6 +996,11 @@ async fn test_send_raw_transaction_pre_eip_155(#[future] katana: Katana, _setup:
let bytes = tx_hash.0;
let starknet_tx_hash = Felt::from_bytes_be(&bytes);

let mempool_size_after_send = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending transactions in the mempool is 1
assert_eq!(mempool_size_after_send.pending, 1);
assert_eq!(mempool_size_after_send.total, 1);

watch_tx(eth_provider.starknet_provider(), starknet_tx_hash, std::time::Duration::from_millis(300), 60)
.await
.expect("Tx polling failed");
Expand Down Expand Up @@ -810,6 +1035,11 @@ async fn test_send_raw_transaction_wrong_signature(#[future] katana: Katana, _se
// Set an incorrect signature
transaction_signed.signature = Signature::default();

let mempool_size = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending and total transactions in the mempool is 0
assert_eq!(mempool_size.pending, 0);
assert_eq!(mempool_size.total, 0);

// Send the transaction
let _ = eth_provider.send_raw_transaction(transaction_signed.envelope_encoded()).await;

Expand All @@ -819,6 +1049,93 @@ async fn test_send_raw_transaction_wrong_signature(#[future] katana: Katana, _se

// Assert that no transaction is found
assert!(tx.is_none());

let mempool_size_after_send = eth_provider.mempool().unwrap().pool_size();
// Verify that the number of pending transactions in the mempool remains unchanged (0 tx)
assert_eq!(mempool_size_after_send.pending, 0);
assert_eq!(mempool_size_after_send.total, 0);
}

#[rstest]
#[awt]
#[tokio::test(flavor = "multi_thread")]
async fn test_send_raw_transaction_wrong_chain_id(#[future] katana: Katana, _setup: ()) {
// Given
let eth_provider = katana.eth_provider();
let wrong_chain_id = 999; // An arbitrary wrong chain ID

// Create a transaction with the wrong chain ID
let transaction = Transaction::Eip1559(TxEip1559 {
chain_id: wrong_chain_id,
nonce: 0,
gas_limit: 21000,
to: TxKind::Call(Address::random()),
value: U256::from(1000),
max_fee_per_gas: 875_000_000,
max_priority_fee_per_gas: 0,
input: Bytes::default(),
access_list: Default::default(),
});

// Sign the transaction
let signature = sign_message(katana.eoa().private_key(), transaction.signature_hash()).unwrap();
let transaction_signed = TransactionSigned::from_transaction_and_signature(transaction, signature);

let mempool_size = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending and total transactions in the mempool is 0
assert_eq!(mempool_size.pending, 0);
assert_eq!(mempool_size.total, 0);

// Attempt to send the transaction
let result = eth_provider.send_raw_transaction(transaction_signed.envelope_encoded()).await;

// Then
assert!(result.is_err()); // Ensure the transaction is rejected

let mempool_size_after_send = eth_provider.mempool().unwrap().pool_size();
// Verify that the number of pending transactions in the mempool remains unchanged (0 tx)
assert_eq!(mempool_size_after_send.pending, 0);
assert_eq!(mempool_size_after_send.total, 0);
}

#[rstest]
#[awt]
#[tokio::test(flavor = "multi_thread")]
async fn test_send_raw_transaction_insufficient_balance(#[future] katana: Katana, _setup: ()) {
// Given
let eth_provider = katana.eth_provider();
let eoa = katana.eoa();
let chain_id = eth_provider.chain_id().await.unwrap().unwrap_or_default().to();

// Create a transaction with a value greater than the balance
let transaction = Transaction::Eip1559(TxEip1559 {
chain_id,
nonce: 0,
gas_limit: 21000,
to: TxKind::Call(Address::random()),
value: U256::MAX,
max_fee_per_gas: 875_000_000,
max_priority_fee_per_gas: 0,
input: Bytes::default(),
access_list: Default::default(),
});

// Sign the transaction
let signature = sign_message(eoa.private_key(), transaction.signature_hash()).unwrap();
let transaction_signed = TransactionSigned::from_transaction_and_signature(transaction, signature);

let mempool_size = eth_provider.mempool().unwrap().pool_size();
// Assert that the number of pending and total transactions in the mempool is 0
assert_eq!(mempool_size.pending, 0);
assert_eq!(mempool_size.total, 0);

// Attempt to send the transaction
let _ = eth_provider.send_raw_transaction(transaction_signed.envelope_encoded()).await;

let mempool_size_after_send = eth_provider.mempool().unwrap().pool_size();
// Verify that the number of pending transactions in the mempool remains unchanged (0 tx)
assert_eq!(mempool_size_after_send.pending, 0);
assert_eq!(mempool_size_after_send.total, 0);
}

#[rstest]
Expand Down

0 comments on commit dcdd396

Please sign in to comment.