Newer
Older
#[test]
fn memory_pool_transactions_are_reverified_after_reorganization() {
let b0 = test_data::block_builder()
.header().build()
.transaction().coinbase().output().value(100_000).build().build()
.build();
let b1 = test_data::block_builder().header().nonce(1).parent(b0.hash()).build().build();
let b2 = test_data::block_builder().header().nonce(2).parent(b0.hash()).build().build();
let b3 = test_data::block_builder().header().parent(b2.hash()).build().build();
let input_tx = b0.transactions[0].clone();
let tx1: Transaction = test_data::TransactionBuilder::with_version(1).set_input(&input_tx, 0).into();
let tx1_hash = tx1.hash();
let tx2: Transaction = test_data::TransactionBuilder::with_input(&input_tx, 0).into();
let tx2_hash = tx2.hash();
let db = Arc::new(BlockChainDatabase::init_test_chain(vec![b0.into()]));
let mut chain = Chain::new(db, ConsensusParams::new(Network::Unitest, ConsensusFork::BitcoinCore), Arc::new(RwLock::new(MemoryPool::new())));
chain.verify_transaction(tx1.into());
chain.insert_verified_transaction(tx2.into());
// no reorg
let result = chain.insert_best_block(b1.into()).expect("no error");
assert_eq!(result.transactions_to_reverify.len(), 0);
// no reorg
let result = chain.insert_best_block(b2.into()).expect("no error");
assert_eq!(result.transactions_to_reverify.len(), 0);
// reorg
let result = chain.insert_best_block(b3.into()).expect("no error");
assert_eq!(result.transactions_to_reverify.len(), 2);
assert!(result.transactions_to_reverify.iter().any(|ref tx| &tx.hash == &tx1_hash));
assert!(result.transactions_to_reverify.iter().any(|ref tx| &tx.hash == &tx2_hash));
}
#[test]
fn fork_chain_block_transaction_is_removed_from_on_block_insert() {
let genesis = test_data::genesis();
let input_tx = genesis.transactions[0].clone();
let b0 = test_data::block_builder().header().parent(genesis.hash()).build().build(); // genesis -> b0
let b1 = test_data::block_builder().header().nonce(1).parent(b0.hash()).build()
.transaction().output().value(10).build().build()
.build(); // genesis -> b0 -> b1[tx1]
let b2 = test_data::block_builder().header().parent(b1.hash()).build()
.transaction().output().value(20).build().build()
.build(); // genesis -> b0 -> b1[tx1] -> b2[tx2]
let b3 = test_data::block_builder().header().nonce(2).parent(b0.hash()).build()
.transaction().input().hash(input_tx.hash()).index(0).build()
.output().value(50).build().build()
.build(); // genesis -> b0 -> b3[tx3]
let b4 = test_data::block_builder().header().parent(b3.hash()).build()
.transaction().input().hash(b3.transactions[0].hash()).index(0).build()
.output().value(40).build().build()
.build(); // genesis -> b0 -> b3[tx3] -> b4[tx4]
let b5 = test_data::block_builder().header().parent(b4.hash()).build()
.transaction().input().hash(b4.transactions[0].hash()).index(0).build()
.output().value(30).build().build()
.build(); // genesis -> b0 -> b3[tx3] -> b4[tx4] -> b5[tx5]
let tx1 = b1.transactions[0].clone();
let tx1_hash = tx1.hash();
let tx2 = b2.transactions[0].clone();
let tx2_hash = tx2.hash();
let tx3 = b3.transactions[0].clone();
let tx4 = b4.transactions[0].clone();
let tx5 = b5.transactions[0].clone();
let db = Arc::new(BlockChainDatabase::init_test_chain(vec![genesis.into()]));
let mut chain = Chain::new(db, ConsensusParams::new(Network::Unitest, ConsensusFork::BitcoinCore), Arc::new(RwLock::new(MemoryPool::new())));
chain.insert_verified_transaction(tx3.into());
chain.insert_verified_transaction(tx4.into());
chain.insert_verified_transaction(tx5.into());
assert_eq!(chain.insert_best_block(b0.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b0.hash()]));
assert_eq!(chain.information().transactions.transactions_count, 3);
assert_eq!(chain.insert_best_block(b1.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b1.hash()]));
assert_eq!(chain.information().transactions.transactions_count, 3);
assert_eq!(chain.insert_best_block(b2.clone().into()).expect("block accepted"), BlockInsertionResult::with_canonized_blocks(vec![b2.hash()]));
assert_eq!(chain.information().transactions.transactions_count, 3);
assert_eq!(chain.insert_best_block(b3.clone().into()).expect("block accepted"), BlockInsertionResult::default());
assert_eq!(chain.information().transactions.transactions_count, 3);
assert_eq!(chain.insert_best_block(b4.clone().into()).expect("block accepted"), BlockInsertionResult::default());
assert_eq!(chain.information().transactions.transactions_count, 3);
// order matters
let insert_result = chain.insert_best_block(b5.clone().into()).expect("block accepted");
let transactions_to_reverify_hashes: Vec<_> = insert_result
.transactions_to_reverify
.into_iter()
.collect();
assert_eq!(transactions_to_reverify_hashes, vec![tx1_hash, tx2_hash]);
assert_eq!(insert_result.canonized_blocks_hashes, vec![b3.hash(), b4.hash(), b5.hash()]);
assert_eq!(chain.information().transactions.transactions_count, 0); // tx3, tx4, tx5 are added to the database
}
#[test]
fn double_spend_transaction_is_removed_from_memory_pool_when_output_is_spent_in_block_transaction() {
let genesis = test_data::genesis();
let tx0 = genesis.transactions[0].clone();
let b0 = test_data::block_builder().header().nonce(1).parent(genesis.hash()).build()
.transaction()
.lock_time(1)
.input().hash(tx0.hash()).index(0).build()
.build()
.build(); // genesis -> b0[tx1]
// tx from b0 && tx2 are spending same output
let tx2: Transaction = test_data::TransactionBuilder::with_output(20).add_input(&tx0, 0).into();
// insert tx2 to memory pool
let db = Arc::new(BlockChainDatabase::init_test_chain(vec![test_data::genesis().into()]));
let mut chain = Chain::new(db, ConsensusParams::new(Network::Unitest, ConsensusFork::BitcoinCore), Arc::new(RwLock::new(MemoryPool::new())));
// insert verified block with tx1
chain.insert_best_block(b0.into()).expect("no error");
// => tx2 is removed from memory pool, but tx3 remains
assert_eq!(chain.information().transactions.transactions_count, 0);
#[test]
fn update_memory_pool_transaction() {
use self::test_data::{ChainBuilder, TransactionBuilder};
let input_tx = test_data::genesis().transactions[0].clone();
let data_chain = &mut ChainBuilder::new();
TransactionBuilder::with_input(&input_tx, 0).set_output(100).store(data_chain) // transaction0
.reset().set_input(&data_chain.at(0), 0).add_output(20).lock().store(data_chain) // transaction0 -> transaction1
.reset().set_input(&data_chain.at(0), 0).add_output(30).store(data_chain); // transaction0 -> transaction2
let db = Arc::new(BlockChainDatabase::init_test_chain(vec![test_data::genesis().into()]));
let mut chain = Chain::new(db, ConsensusParams::new(Network::Unitest, ConsensusFork::BitcoinCore), Arc::new(RwLock::new(MemoryPool::new())));
chain.insert_verified_transaction(data_chain.at(0).into());
chain.insert_verified_transaction(data_chain.at(1).into());
assert_eq!(chain.information().transactions.transactions_count, 2);
chain.insert_verified_transaction(data_chain.at(2).into());
assert_eq!(chain.information().transactions.transactions_count, 2); // tx was replaced