mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-02-19 03:04:27 -05:00
test: handle reorg event properly by pool maintaining (#16155)
This commit is contained in:
@@ -1 +1 @@
|
||||
{"config":{"chainId":1,"homesteadBlock":0,"daoForkSupport":true,"eip150Block":0,"eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0,"istanbulBlock":0,"muirGlacierBlock":0,"berlinBlock":0,"londonBlock":0,"arrowGlacierBlock":0,"grayGlacierBlock":0,"shanghaiTime":0,"cancunTime":0,"terminalTotalDifficulty":"0x0","terminalTotalDifficultyPassed":true},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x1c9c380","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"balance":"0xd3c21bcecceda1000000"},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"balance":"0xd3c21bcecceda1000000"},"0x1cbd3b2770909d4e10f157cabc84c7264073c9ec":{"balance":"0xd3c21bcecceda1000000"},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"balance":"0xd3c21bcecceda1000000"},"0x2546bcd3c84621e976d8185a91a922ae77ecec30":{"balance":"0xd3c21bcecceda1000000"},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"balance":"0xd3c21bcecceda1000000"},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"balance":"0xd3c21bcecceda1000000"},"0x71be63f3384f5fb98995898a86b02fb2426c5788":{"balance":"0xd3c21bcecceda1000000"},"0x8626f6940e2eb28930efb4cef49b2d1f2c9c1199":{"balance":"0xd3c21bcecceda1000000"},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"balance":"0xd3c21bcecceda1000000"},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"balance":"0xd3c21bcecceda1000000"},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"balance":"0xd3c21bcecceda1000000"},"0x9c41de96b2088cdc640c6182dfcf5491dc574a57":{"balance":"0xd3c21bcecceda1000000"},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"balance":"0xd3c21bcecceda1000000"},"0xbcd4042de499d14e55001ccbb24a551f3b954096":{"balance":"0xd3c21bcecceda1000000"},"0xbda5747bfd65f08deb54cb465eb87d40e51b197e":{"balance":"0xd3c21bcecceda1000000"},"0xcd3b766ccdd6ae721141f452c550ca635964ce71":{"balance":"0xd3c21bcecceda1000000"},"0xdd2fd4581271e230360230f9337d5c0430bf44c0":{"balance":"0xd3c21bcecceda1000000"},"0xdf3e18d64bc6a983f673ab319ccae4f1a57c7097":{"balance":"0xd3c21bcecceda1000000"},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"balance":"0xd3c21bcecceda1000000"},"0xfabb0ac9d68b0b445fb7357272ff202c5651694a":{"balance":"0xd3c21bcecceda1000000"}},"number":"0x0"}
|
||||
{"config":{"chainId":1,"homesteadBlock":0,"daoForkSupport":true,"eip150Block":0,"eip155Block":0,"eip158Block":0,"byzantiumBlock":0,"constantinopleBlock":0,"petersburgBlock":0,"istanbulBlock":0,"muirGlacierBlock":0,"berlinBlock":0,"londonBlock":0,"arrowGlacierBlock":0,"grayGlacierBlock":0,"shanghaiTime":0,"cancunTime":0,"terminalTotalDifficulty":"0x0","terminalTotalDifficultyPassed":true},"nonce":"0x0","timestamp":"0x0","extraData":"0x00","gasLimit":"0x1c9c380","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","alloc":{"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"balance":"0xd3c21bcecceda1000000"},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"balance":"0xd3c21bcecceda1000000"},"0x1cbd3b2770909d4e10f157cabc84c7264073c9ec":{"balance":"0xd3c21bcecceda1000000"},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"balance":"0xd3c21bcecceda1000000"},"0x2546bcd3c84621e976d8185a91a922ae77ecec30":{"balance":"0xd3c21bcecceda1000000"},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"balance":"0xd3c21bcecceda1000000"},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"balance":"0xd3c21bcecceda1000000"},"0x71be63f3384f5fb98995898a86b02fb2426c5788":{"balance":"0xd3c21bcecceda1000000"},"0x8626f6940e2eb28930efb4cef49b2d1f2c9c1199":{"balance":"0xd3c21bcecceda1000000"},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"balance":"0xd3c21bcecceda1000000"},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"balance":"0xd3c21bcecceda1000000"},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"balance":"0xd3c21bcecceda1000000"},"0x9c41de96b2088cdc640c6182dfcf5491dc574a57":{"balance":"0xd3c21bcecceda1000000"},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"balance":"0xd3c21bcecceda1000000"},"0xbcd4042de499d14e55001ccbb24a551f3b954096":{"balance":"0xd3c21bcecceda1000000"},"0xbda5747bfd65f08deb54cb465eb87d40e51b197e":{"balance":"0xd3c21bcecceda1000000"},"0xcd3b766ccdd6ae721141f452c550ca635964ce71":{"balance":"0xd3c21bcecceda1000000"},"0xdd2fd4581271e230360230f9337d5c0430bf44c0":{"balance":"0xd3c21bcecceda1000000"},"0xdf3e18d64bc6a983f673ab319ccae4f1a57c7097":{"balance":"0xd3c21bcecceda1000000"},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"balance":"0xd3c21bcecceda1000000"},"0xfabb0ac9d68b0b445fb7357272ff202c5651694a":{"balance":"0xd3c21bcecceda1000000"}},"number":"0x0"}
|
||||
|
||||
@@ -15,10 +15,143 @@ use reth_provider::CanonStateSubscriptions;
|
||||
use reth_tasks::TaskManager;
|
||||
use reth_transaction_pool::{
|
||||
blobstore::InMemoryBlobStore, test_utils::OkValidator, BlockInfo, CoinbaseTipOrdering,
|
||||
EthPooledTransaction, Pool, TransactionOrigin, TransactionPool, TransactionPoolExt,
|
||||
EthPooledTransaction, Pool, PoolTransaction, TransactionOrigin, TransactionPool,
|
||||
TransactionPoolExt,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
// Test that the pool's maintenance task can correctly handle `CanonStateNotification::Reorg` events
|
||||
#[tokio::test]
|
||||
async fn maintain_txpool_reorg() -> eyre::Result<()> {
|
||||
reth_tracing::init_test_tracing();
|
||||
let tasks = TaskManager::current();
|
||||
let executor = tasks.executor();
|
||||
|
||||
let txpool = Pool::new(
|
||||
OkValidator::default(),
|
||||
CoinbaseTipOrdering::default(),
|
||||
InMemoryBlobStore::default(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
// Directly generate a node to simulate various traits such as `StateProviderFactory` required
|
||||
// by the pool maintenance task
|
||||
let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap();
|
||||
let chain_spec = Arc::new(
|
||||
ChainSpecBuilder::default()
|
||||
.chain(MAINNET.chain)
|
||||
.genesis(genesis)
|
||||
.cancun_activated()
|
||||
.build(),
|
||||
);
|
||||
let genesis_hash = chain_spec.genesis_hash();
|
||||
let node_config = NodeConfig::test()
|
||||
.with_chain(chain_spec)
|
||||
.with_unused_ports()
|
||||
.with_rpc(RpcServerArgs::default().with_unused_ports().with_http());
|
||||
let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config.clone())
|
||||
.testing_node(executor.clone())
|
||||
.node(EthereumNode::default())
|
||||
.launch()
|
||||
.await?;
|
||||
|
||||
let mut node = NodeTestContext::new(node, eth_payload_attributes).await?;
|
||||
|
||||
let wallets = Wallet::new(2).wallet_gen();
|
||||
let w1 = wallets.first().unwrap();
|
||||
let w2 = wallets.last().unwrap();
|
||||
|
||||
executor.spawn_critical(
|
||||
"txpool maintenance task",
|
||||
reth_transaction_pool::maintain::maintain_transaction_pool_future(
|
||||
node.inner.provider.clone(),
|
||||
txpool.clone(),
|
||||
node.inner.provider.clone().canonical_state_stream(),
|
||||
executor.clone(),
|
||||
reth_transaction_pool::maintain::MaintainPoolConfig::default(),
|
||||
),
|
||||
);
|
||||
|
||||
// build tx1 from wallet1
|
||||
let envelop1 = TransactionTestContext::transfer_tx(1, w1.clone()).await;
|
||||
let tx1 = Recovered::new_unchecked(
|
||||
EthereumTxEnvelope::<TxEip4844>::from(envelop1.clone()),
|
||||
w1.address(),
|
||||
);
|
||||
let pooled_tx1 = EthPooledTransaction::new(tx1.clone(), 200);
|
||||
let tx_hash1 = *pooled_tx1.clone().hash();
|
||||
|
||||
// build tx2 from wallet2
|
||||
let envelop2 = TransactionTestContext::transfer_tx(1, w2.clone()).await;
|
||||
let tx2 = Recovered::new_unchecked(
|
||||
EthereumTxEnvelope::<TxEip4844>::from(envelop2.clone()),
|
||||
w2.address(),
|
||||
);
|
||||
let pooled_tx2 = EthPooledTransaction::new(tx2.clone(), 200);
|
||||
let tx_hash2 = *pooled_tx2.clone().hash();
|
||||
|
||||
let block_info = BlockInfo {
|
||||
block_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT_30M,
|
||||
last_seen_block_hash: B256::ZERO,
|
||||
last_seen_block_number: 0,
|
||||
pending_basefee: 10,
|
||||
pending_blob_fee: Some(10),
|
||||
};
|
||||
|
||||
txpool.set_block_info(block_info);
|
||||
|
||||
// add two txs to the pool
|
||||
txpool.add_transaction(TransactionOrigin::External, pooled_tx1).await.unwrap();
|
||||
txpool.add_transaction(TransactionOrigin::External, pooled_tx2).await.unwrap();
|
||||
|
||||
// inject tx1, make the node advance and eventually generate `CanonStateNotification::Commit`
|
||||
// event to propagate to the pool
|
||||
let _ = node.rpc.inject_tx(envelop1.encoded_2718().into()).await.unwrap();
|
||||
|
||||
// build a payload based on tx1
|
||||
let payload1 = node.new_payload().await?;
|
||||
|
||||
// clean up the internal pool of the provider node
|
||||
node.inner.pool.remove_transactions(vec![tx_hash1]);
|
||||
|
||||
// inject tx2, make the node reorg and eventually generate `CanonStateNotification::Reorg` event
|
||||
// to propagate to the pool
|
||||
let _ = node.rpc.inject_tx(envelop2.encoded_2718().into()).await.unwrap();
|
||||
|
||||
// build a payload based on tx2
|
||||
let payload2 = node.new_payload().await?;
|
||||
|
||||
// submit payload1
|
||||
let block_hash1 = node.submit_payload(payload1).await?;
|
||||
|
||||
node.update_forkchoice(genesis_hash, block_hash1).await?;
|
||||
|
||||
loop {
|
||||
// wait for pool to process `CanonStateNotification::Commit` event correctly, and finally
|
||||
// tx1 will be removed and tx2 is still in the pool
|
||||
tokio::time::sleep(std::time::Duration::from_millis(20)).await;
|
||||
if txpool.get(&tx_hash1).is_none() && txpool.get(&tx_hash2).is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// submit payload2
|
||||
let block_hash2 = node.submit_payload(payload2).await?;
|
||||
|
||||
node.update_forkchoice(genesis_hash, block_hash2).await?;
|
||||
|
||||
loop {
|
||||
// wait for pool to process `CanonStateNotification::Reorg` event properly, and finally tx1
|
||||
// will be added back to the pool and tx2 will be removed.
|
||||
tokio::time::sleep(std::time::Duration::from_millis(20)).await;
|
||||
if txpool.get(&tx_hash1).is_some() && txpool.get(&tx_hash2).is_none() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Test that the pool's maintenance task can correctly handle `CanonStateNotification::Commit`
|
||||
// events
|
||||
#[tokio::test]
|
||||
|
||||
Reference in New Issue
Block a user