synchronization_chain.rs 44.7 KiB
Newer Older
Svyatoslav Nikolsky's avatar
Svyatoslav Nikolsky committed
	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 tx2: Transaction = test_data::TransactionBuilder::with_input(&input_tx, 0).into();
Marek Kotewicz's avatar
Marek Kotewicz committed
		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())));
Svyatoslav Nikolsky's avatar
Svyatoslav Nikolsky committed
		chain.verify_transaction(tx1.into());
		chain.insert_verified_transaction(tx2.into());
Marek Kotewicz's avatar
Marek Kotewicz committed
		let result = chain.insert_best_block(b1.into()).expect("no error");
		assert_eq!(result.transactions_to_reverify.len(), 0);

		// no reorg
Marek Kotewicz's avatar
Marek Kotewicz committed
		let result = chain.insert_best_block(b2.into()).expect("no error");
		assert_eq!(result.transactions_to_reverify.len(), 0);

		// reorg
Marek Kotewicz's avatar
Marek Kotewicz committed
		let result = chain.insert_best_block(b3.into()).expect("no error");
		assert_eq!(result.transactions_to_reverify.len(), 2);
Svyatoslav Nikolsky's avatar
Svyatoslav Nikolsky committed
		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();

Marek Kotewicz's avatar
Marek Kotewicz committed
		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())));
Svyatoslav Nikolsky's avatar
Svyatoslav Nikolsky committed
		chain.insert_verified_transaction(tx3.into());
		chain.insert_verified_transaction(tx4.into());
		chain.insert_verified_transaction(tx5.into());
Marek Kotewicz's avatar
Marek Kotewicz committed
		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);
Marek Kotewicz's avatar
Marek Kotewicz committed
		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);
Marek Kotewicz's avatar
Marek Kotewicz committed
		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);
Marek Kotewicz's avatar
Marek Kotewicz committed
		assert_eq!(chain.insert_best_block(b3.clone().into()).expect("block accepted"), BlockInsertionResult::default());
		assert_eq!(chain.information().transactions.transactions_count, 3);
Marek Kotewicz's avatar
Marek Kotewicz committed
		assert_eq!(chain.insert_best_block(b4.clone().into()).expect("block accepted"), BlockInsertionResult::default());
		assert_eq!(chain.information().transactions.transactions_count, 3);
		// order matters
Marek Kotewicz's avatar
Marek Kotewicz committed
		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()
Svyatoslav Nikolsky's avatar
Svyatoslav Nikolsky committed
			.map(|tx| tx.hash)
			.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
Marek Kotewicz's avatar
Marek Kotewicz committed
		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())));
Svyatoslav Nikolsky's avatar
Svyatoslav Nikolsky committed
		chain.insert_verified_transaction(tx2.clone().into());
		// insert verified block with tx1
Marek Kotewicz's avatar
Marek Kotewicz committed
		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
Marek Kotewicz's avatar
Marek Kotewicz committed

		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());
Svyatoslav Nikolsky's avatar
Svyatoslav Nikolsky committed
		chain.insert_verified_transaction(data_chain.at(1).into());
		assert_eq!(chain.information().transactions.transactions_count, 2);
Svyatoslav Nikolsky's avatar
Svyatoslav Nikolsky committed
		chain.insert_verified_transaction(data_chain.at(2).into());
		assert_eq!(chain.information().transactions.transactions_count, 2); // tx was replaced