enhance tx gossip test coverage (#6578)

Co-authored-by: Emilia Hane <emiliaha95@gmail.com>
This commit is contained in:
Aditya Pandey
2024-02-16 10:02:21 +05:30
committed by GitHub
parent 3222be6460
commit e24eadf620
4 changed files with 127 additions and 3 deletions

View File

@@ -916,6 +916,11 @@ impl Peer {
Self { kind: PeerKind::Trusted, ..Self::new(addr) }
}
/// Returns the reputation of the peer
pub fn reputation(&self) -> i32 {
self.reputation
}
fn with_state(addr: SocketAddr, state: PeerConnectionState) -> Self {
Self {
addr,

View File

@@ -4,6 +4,7 @@ use crate::{
builder::ETH_REQUEST_CHANNEL_CAPACITY,
error::NetworkError,
eth_requests::EthRequestHandler,
peers::PeersHandle,
protocol::IntoRlpxSubProtocol,
transactions::{TransactionsHandle, TransactionsManager},
NetworkConfig, NetworkConfigBuilder, NetworkEvent, NetworkEvents, NetworkHandle,
@@ -475,6 +476,10 @@ impl<Pool> PeerHandle<Pool> {
self.network.peer_id()
}
pub fn peer_handle(&self) -> &PeersHandle {
self.network.peers_handle()
}
pub fn local_addr(&self) -> SocketAddr {
self.network.local_addr()
}

View File

@@ -2,9 +2,10 @@
use rand::thread_rng;
use reth_network::test_utils::Testnet;
use reth_primitives::U256;
use reth_primitives::{TransactionSigned, U256};
use reth_provider::test_utils::{ExtendedAccount, MockEthProvider};
use reth_transaction_pool::{test_utils::TransactionGenerator, PoolTransaction, TransactionPool};
use std::{sync::Arc, time::Duration};
#[tokio::test(flavor = "multi_thread")]
async fn test_tx_gossip() {
reth_tracing::init_test_tracing();
@@ -42,3 +43,85 @@ async fn test_tx_gossip() {
let received = peer1_tx_listener.recv().await.unwrap();
assert_eq!(received, hash);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_4844_tx_gossip_penalization() {
reth_tracing::init_test_tracing();
let provider = MockEthProvider::default();
let net = Testnet::create_with(2, provider.clone()).await;
// install request handlers
let net = net.with_eth_pool();
let handle = net.spawn();
let peer0 = &handle.peers()[0];
let peer1 = &handle.peers()[1];
// connect all the peers
handle.connect_peers().await;
let mut peer1_tx_listener = peer1.pool().unwrap().pending_transactions_listener();
let mut gen = TransactionGenerator::new(thread_rng());
// peer 0 will be penalised for sending txs[0] over gossip
let txs = vec![gen.gen_eip4844_pooled(), gen.gen_eip1559_pooled()];
txs.iter().for_each(|tx| {
let sender = tx.sender();
provider.add_account(sender, ExtendedAccount::new(0, U256::from(100_000_000)));
});
let signed_txs: Vec<Arc<TransactionSigned>> =
txs.iter().map(|tx| Arc::new(tx.transaction().clone().into_signed())).collect();
let network_handle = peer0.network();
let peer0_reputation_before =
peer1.peer_handle().peer_by_id(peer0.peer_id().clone()).await.unwrap().reputation();
// sends txs directly to peer1
network_handle.send_transactions(peer1.peer_id().clone(), signed_txs);
let received = peer1_tx_listener.recv().await.unwrap();
let peer0_reputation_after =
peer1.peer_handle().peer_by_id(peer0.peer_id().clone()).await.unwrap().reputation();
assert_ne!(peer0_reputation_before, peer0_reputation_after);
assert_eq!(received, txs[1].transaction().hash);
// this will return an [`Empty`] error because blob txs are disallowed to be broadcasted
assert!(peer1_tx_listener.try_recv().is_err());
}
#[tokio::test(flavor = "multi_thread")]
async fn test_sending_invalid_transactions() {
reth_tracing::init_test_tracing();
let provider = MockEthProvider::default();
let net = Testnet::create_with(2, provider.clone()).await;
// install request handlers
let net = net.with_eth_pool();
let handle = net.spawn();
let peer0 = &handle.peers()[0];
let peer1 = &handle.peers()[1];
// connect all the peers
handle.connect_peers().await;
let mut peer1_tx_listener = peer1.pool().unwrap().pending_transactions_listener();
let invalid_txs: Vec<Arc<TransactionSigned>> = vec![Arc::new(TransactionSigned::default())];
let network_handle = peer0.network();
// sends txs directly to peer1
network_handle.send_transactions(peer1.peer_id().clone(), invalid_txs);
tokio::time::sleep(Duration::from_secs(1)).await;
// this will return an [`Empty`] error because bad txs are disallowed to be broadcasted
assert!(peer1_tx_listener.try_recv().is_err());
}

View File

@@ -2,8 +2,8 @@ use crate::EthPooledTransaction;
use rand::Rng;
use reth_primitives::{
constants::MIN_PROTOCOL_BASE_FEE, sign_message, AccessList, Address, Bytes,
FromRecoveredTransaction, Transaction, TransactionKind, TransactionSigned, TxEip1559, TxLegacy,
TxValue, B256, MAINNET,
FromRecoveredTransaction, Transaction, TransactionKind, TransactionSigned, TxEip1559,
TxEip4844, TxLegacy, TxValue, B256, MAINNET,
};
/// A generator for transactions for testing purposes.
@@ -91,12 +91,23 @@ impl<R: Rng> TransactionGenerator<R> {
self.transaction().into_eip1559()
}
/// Creates a new transaction with a random signer
pub fn gen_eip4844(&mut self) -> TransactionSigned {
self.transaction().into_eip4844()
}
/// Generates and returns a pooled EIP-1559 transaction with a random signer.
pub fn gen_eip1559_pooled(&mut self) -> EthPooledTransaction {
EthPooledTransaction::from_recovered_transaction(
self.gen_eip1559().into_ecrecovered().unwrap(),
)
}
/// Generates and returns a pooled EIP-4844 transaction with a random signer.
pub fn gen_eip4844_pooled(&mut self) -> EthPooledTransaction {
EthPooledTransaction::from_recovered_transaction(
self.gen_eip4844().into_ecrecovered().unwrap(),
)
}
}
/// A Builder type to configure and create a transaction.
@@ -162,6 +173,26 @@ impl TransactionBuilder {
self.signer,
)
}
/// Converts the transaction builder into a transaction format using EIP-4844.
pub fn into_eip4844(self) -> TransactionSigned {
TransactionBuilder::signed(
TxEip4844 {
chain_id: self.chain_id,
nonce: self.nonce,
gas_limit: self.gas_limit,
max_fee_per_gas: self.max_fee_per_gas,
max_priority_fee_per_gas: self.max_priority_fee_per_gas,
to: self.to,
value: self.value,
access_list: self.access_list,
input: self.input,
blob_versioned_hashes: Default::default(),
max_fee_per_blob_gas: Default::default(),
}
.into(),
self.signer,
)
}
/// Signs the provided transaction using the specified signer and returns a signed transaction.
fn signed(transaction: Transaction, signer: B256) -> TransactionSigned {