[WIP] txpool (tx validation) using block sums for full validation (#1567)
tx validation (txpool) rework/simplify
This commit is contained in:
@@ -27,12 +27,8 @@ pub mod common;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use core::core::{Block, BlockHeader};
|
||||
|
||||
use chain::txhashset;
|
||||
use chain::types::Tip;
|
||||
use core::core::hash::Hashed;
|
||||
use core::core::verifier_cache::LruVerifierCache;
|
||||
use core::core::{Block, BlockHeader, Transaction};
|
||||
use core::pow::Difficulty;
|
||||
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
@@ -47,53 +43,35 @@ fn test_transaction_pool_block_building() {
|
||||
|
||||
let db_root = ".grin_block_building".to_string();
|
||||
clean_output_dir(db_root.clone());
|
||||
let chain = ChainAdapter::init(db_root.clone()).unwrap();
|
||||
let mut chain = ChainAdapter::init(db_root.clone()).unwrap();
|
||||
|
||||
let verifier_cache = Arc::new(RwLock::new(LruVerifierCache::new()));
|
||||
|
||||
// Initialize the chain/txhashset with an initial block
|
||||
// so we have a non-empty UTXO set.
|
||||
let add_block = |height, txs| {
|
||||
let add_block = |prev_header: BlockHeader, txs: Vec<Transaction>, chain: &mut ChainAdapter| {
|
||||
let height = prev_header.height + 1;
|
||||
let key_id = keychain.derive_key_id(height as u32).unwrap();
|
||||
let reward = libtx::reward::output(&keychain, &key_id, 0, height).unwrap();
|
||||
let mut block =
|
||||
Block::new(&BlockHeader::default(), txs, Difficulty::one(), reward).unwrap();
|
||||
let fee = txs.iter().map(|x| x.fee()).sum();
|
||||
let reward = libtx::reward::output(&keychain, &key_id, fee, height).unwrap();
|
||||
let block = Block::new(&prev_header, txs, Difficulty::one(), reward).unwrap();
|
||||
|
||||
let mut txhashset = chain.txhashset.write().unwrap();
|
||||
let mut batch = chain.store.batch().unwrap();
|
||||
txhashset::extending(&mut txhashset, &mut batch, |extension| {
|
||||
extension.apply_block(&block)?;
|
||||
|
||||
// Now set the roots and sizes as necessary on the block header.
|
||||
let roots = extension.roots();
|
||||
block.header.output_root = roots.output_root;
|
||||
block.header.range_proof_root = roots.rproof_root;
|
||||
block.header.kernel_root = roots.kernel_root;
|
||||
let sizes = extension.sizes();
|
||||
block.header.output_mmr_size = sizes.0;
|
||||
block.header.kernel_mmr_size = sizes.2;
|
||||
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
|
||||
let tip = Tip::from_block(&block.header);
|
||||
batch.save_block_header(&block.header).unwrap();
|
||||
batch.save_head(&tip).unwrap();
|
||||
batch.commit().unwrap();
|
||||
chain.update_db_for_block(&block);
|
||||
|
||||
block.header
|
||||
};
|
||||
let header = add_block(1, vec![]);
|
||||
|
||||
// Initialize a new pool with our chain adapter.
|
||||
let pool = RwLock::new(test_setup(Arc::new(chain.clone()), verifier_cache));
|
||||
let header = add_block(BlockHeader::default(), vec![], &mut chain);
|
||||
|
||||
// Now create tx to spend that first coinbase (now matured).
|
||||
// Provides us with some useful outputs to test with.
|
||||
let initial_tx = test_transaction_spending_coinbase(&keychain, &header, vec![10, 20, 30, 40]);
|
||||
|
||||
// Mine that initial tx so we can spend it with multiple txs
|
||||
let header = add_block(2, vec![initial_tx]);
|
||||
let header = add_block(header, vec![initial_tx], &mut chain);
|
||||
|
||||
// Initialize a new pool with our chain adapter.
|
||||
let pool = RwLock::new(test_setup(Arc::new(chain.clone()), verifier_cache));
|
||||
|
||||
let root_tx_1 = test_transaction(&keychain, vec![10, 20], vec![24]);
|
||||
let root_tx_2 = test_transaction(&keychain, vec![30], vec![28]);
|
||||
@@ -107,21 +85,21 @@ fn test_transaction_pool_block_building() {
|
||||
|
||||
// Add the three root txs to the pool.
|
||||
write_pool
|
||||
.add_to_pool(test_source(), root_tx_1, false, &header.hash())
|
||||
.add_to_pool(test_source(), root_tx_1, false, &header)
|
||||
.unwrap();
|
||||
write_pool
|
||||
.add_to_pool(test_source(), root_tx_2, false, &header.hash())
|
||||
.add_to_pool(test_source(), root_tx_2, false, &header)
|
||||
.unwrap();
|
||||
write_pool
|
||||
.add_to_pool(test_source(), root_tx_3, false, &header.hash())
|
||||
.add_to_pool(test_source(), root_tx_3, false, &header)
|
||||
.unwrap();
|
||||
|
||||
// Now add the two child txs to the pool.
|
||||
write_pool
|
||||
.add_to_pool(test_source(), child_tx_1.clone(), false, &header.hash())
|
||||
.add_to_pool(test_source(), child_tx_1.clone(), false, &header)
|
||||
.unwrap();
|
||||
write_pool
|
||||
.add_to_pool(test_source(), child_tx_2.clone(), false, &header.hash())
|
||||
.add_to_pool(test_source(), child_tx_2.clone(), false, &header)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(write_pool.total_size(), 5);
|
||||
@@ -129,41 +107,19 @@ fn test_transaction_pool_block_building() {
|
||||
|
||||
let txs = {
|
||||
let read_pool = pool.read().unwrap();
|
||||
read_pool.prepare_mineable_transactions()
|
||||
read_pool.prepare_mineable_transactions().unwrap()
|
||||
};
|
||||
// children should have been aggregated into parents
|
||||
assert_eq!(txs.len(), 3);
|
||||
|
||||
let mut block = {
|
||||
let block = {
|
||||
let key_id = keychain.derive_key_id(2).unwrap();
|
||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||
let reward = libtx::reward::output(&keychain, &key_id, fees, 0).unwrap();
|
||||
Block::new(&header, txs, Difficulty::one(), reward)
|
||||
}.unwrap();
|
||||
|
||||
{
|
||||
let mut batch = chain.store.batch().unwrap();
|
||||
let mut txhashset = chain.txhashset.write().unwrap();
|
||||
txhashset::extending(&mut txhashset, &mut batch, |extension| {
|
||||
extension.apply_block(&block)?;
|
||||
|
||||
// Now set the roots and sizes as necessary on the block header.
|
||||
let roots = extension.roots();
|
||||
block.header.output_root = roots.output_root;
|
||||
block.header.range_proof_root = roots.rproof_root;
|
||||
block.header.kernel_root = roots.kernel_root;
|
||||
let sizes = extension.sizes();
|
||||
block.header.output_mmr_size = sizes.0;
|
||||
block.header.kernel_mmr_size = sizes.2;
|
||||
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
|
||||
let tip = Tip::from_block(&block.header);
|
||||
batch.save_block_header(&block.header).unwrap();
|
||||
batch.save_head(&tip).unwrap();
|
||||
batch.commit().unwrap();
|
||||
}
|
||||
chain.update_db_for_block(&block);
|
||||
|
||||
// Now reconcile the transaction pool with the new block
|
||||
// and check the resulting contents of the pool are what we expect.
|
||||
|
||||
@@ -27,15 +27,9 @@ pub mod common;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use core::core::hash::Hashed;
|
||||
use core::core::{Block, BlockHeader};
|
||||
|
||||
use chain::txhashset;
|
||||
use chain::types::Tip;
|
||||
use common::{
|
||||
clean_output_dir, test_setup, test_source, test_transaction,
|
||||
test_transaction_spending_coinbase, ChainAdapter,
|
||||
};
|
||||
use common::*;
|
||||
use core::core::verifier_cache::LruVerifierCache;
|
||||
use core::pow::Difficulty;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
@@ -47,84 +41,41 @@ fn test_transaction_pool_block_reconciliation() {
|
||||
|
||||
let db_root = ".grin_block_reconciliation".to_string();
|
||||
clean_output_dir(db_root.clone());
|
||||
let chain = ChainAdapter::init(db_root.clone()).unwrap();
|
||||
let chain = Arc::new(ChainAdapter::init(db_root.clone()).unwrap());
|
||||
|
||||
let verifier_cache = Arc::new(RwLock::new(LruVerifierCache::new()));
|
||||
|
||||
// Initialize the chain/txhashset with an initial block
|
||||
// so we have a non-empty UTXO set.
|
||||
// Initialize a new pool with our chain adapter.
|
||||
let pool = RwLock::new(test_setup(chain.clone(), verifier_cache.clone()));
|
||||
|
||||
let header = {
|
||||
let height = 1;
|
||||
let key_id = keychain.derive_key_id(height as u32).unwrap();
|
||||
let reward = libtx::reward::output(&keychain, &key_id, 0, height).unwrap();
|
||||
let mut block =
|
||||
Block::new(&BlockHeader::default(), vec![], Difficulty::one(), reward).unwrap();
|
||||
let block = Block::new(&BlockHeader::default(), vec![], Difficulty::one(), reward).unwrap();
|
||||
|
||||
let mut batch = chain.store.batch().unwrap();
|
||||
let mut txhashset = chain.txhashset.write().unwrap();
|
||||
txhashset::extending(&mut txhashset, &mut batch, |extension| {
|
||||
extension.apply_block(&block)?;
|
||||
|
||||
// Now set the roots and sizes as necessary on the block header.
|
||||
let roots = extension.roots();
|
||||
block.header.output_root = roots.output_root;
|
||||
block.header.range_proof_root = roots.rproof_root;
|
||||
block.header.kernel_root = roots.kernel_root;
|
||||
let sizes = extension.sizes();
|
||||
block.header.output_mmr_size = sizes.0;
|
||||
block.header.kernel_mmr_size = sizes.2;
|
||||
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
|
||||
let tip = Tip::from_block(&block.header);
|
||||
batch.save_block_header(&block.header).unwrap();
|
||||
batch.save_head(&tip).unwrap();
|
||||
batch.commit().unwrap();
|
||||
chain.update_db_for_block(&block);
|
||||
|
||||
block.header
|
||||
};
|
||||
|
||||
// Initialize a new pool with our chain adapter.
|
||||
let pool = RwLock::new(test_setup(Arc::new(chain.clone()), verifier_cache.clone()));
|
||||
|
||||
// Now create tx to spend that first coinbase (now matured).
|
||||
// Provides us with some useful outputs to test with.
|
||||
let initial_tx = test_transaction_spending_coinbase(&keychain, &header, vec![10, 20, 30, 40]);
|
||||
|
||||
let header = {
|
||||
let block = {
|
||||
let key_id = keychain.derive_key_id(2).unwrap();
|
||||
let fees = initial_tx.fee();
|
||||
let reward = libtx::reward::output(&keychain, &key_id, fees, 0).unwrap();
|
||||
let mut block = Block::new(&header, vec![initial_tx], Difficulty::one(), reward).unwrap();
|
||||
let block = Block::new(&header, vec![initial_tx], Difficulty::one(), reward).unwrap();
|
||||
|
||||
let mut batch = chain.store.batch().unwrap();
|
||||
{
|
||||
let mut txhashset = chain.txhashset.write().unwrap();
|
||||
txhashset::extending(&mut txhashset, &mut batch, |extension| {
|
||||
extension.apply_block(&block)?;
|
||||
chain.update_db_for_block(&block);
|
||||
|
||||
// Now set the roots and sizes as necessary on the block header.
|
||||
let roots = extension.roots();
|
||||
block.header.output_root = roots.output_root;
|
||||
block.header.range_proof_root = roots.rproof_root;
|
||||
block.header.kernel_root = roots.kernel_root;
|
||||
let sizes = extension.sizes();
|
||||
block.header.output_mmr_size = sizes.0;
|
||||
block.header.kernel_mmr_size = sizes.2;
|
||||
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
let tip = Tip::from_block(&block.header);
|
||||
batch.save_block_header(&block.header).unwrap();
|
||||
batch.save_head(&tip).unwrap();
|
||||
batch.commit().unwrap();
|
||||
|
||||
block.header
|
||||
block
|
||||
};
|
||||
|
||||
let header = block.header;
|
||||
|
||||
// Preparation: We will introduce three root pool transactions.
|
||||
// 1. A transaction that should be invalidated because it is exactly
|
||||
// contained in the block.
|
||||
@@ -181,7 +132,7 @@ fn test_transaction_pool_block_reconciliation() {
|
||||
|
||||
for tx in &txs_to_add {
|
||||
write_pool
|
||||
.add_to_pool(test_source(), tx.clone(), false, &header.hash())
|
||||
.add_to_pool(test_source(), tx.clone(), false, &header)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -198,6 +149,7 @@ fn test_transaction_pool_block_reconciliation() {
|
||||
let block_tx_3 = test_transaction(&keychain, vec![8], vec![5, 1]);
|
||||
// - Output conflict w/ 8
|
||||
let block_tx_4 = test_transaction(&keychain, vec![40], vec![9, 31]);
|
||||
|
||||
let block_txs = vec![block_tx_1, block_tx_2, block_tx_3, block_tx_4];
|
||||
|
||||
// Now apply this block.
|
||||
@@ -205,34 +157,9 @@ fn test_transaction_pool_block_reconciliation() {
|
||||
let key_id = keychain.derive_key_id(3).unwrap();
|
||||
let fees = block_txs.iter().map(|tx| tx.fee()).sum();
|
||||
let reward = libtx::reward::output(&keychain, &key_id, fees, 0).unwrap();
|
||||
let mut block = Block::new(&header, block_txs, Difficulty::one(), reward).unwrap();
|
||||
|
||||
{
|
||||
let mut batch = chain.store.batch().unwrap();
|
||||
let mut txhashset = chain.txhashset.write().unwrap();
|
||||
txhashset::extending(&mut txhashset, &mut batch, |extension| {
|
||||
extension.apply_block(&block)?;
|
||||
|
||||
// Now set the roots and sizes as necessary on the block header.
|
||||
let roots = extension.roots();
|
||||
block.header.output_root = roots.output_root;
|
||||
block.header.range_proof_root = roots.rproof_root;
|
||||
block.header.kernel_root = roots.kernel_root;
|
||||
let sizes = extension.sizes();
|
||||
block.header.output_mmr_size = sizes.0;
|
||||
block.header.kernel_mmr_size = sizes.2;
|
||||
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
batch.commit().unwrap();
|
||||
}
|
||||
|
||||
let tip = Tip::from_block(&block.header);
|
||||
let batch = chain.store.batch().unwrap();
|
||||
batch.save_block_header(&block.header).unwrap();
|
||||
batch.save_head(&tip).unwrap();
|
||||
batch.commit().unwrap();
|
||||
let block = Block::new(&header, block_txs, Difficulty::one(), reward).unwrap();
|
||||
|
||||
chain.update_db_for_block(&block);
|
||||
block
|
||||
};
|
||||
|
||||
|
||||
@@ -27,10 +27,10 @@ pub mod common;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use common::{test_setup, test_source, test_transaction};
|
||||
use common::*;
|
||||
use core::core::hash::Hash;
|
||||
use core::core::verifier_cache::LruVerifierCache;
|
||||
use core::core::{BlockHeader, Transaction};
|
||||
use core::core::{BlockHeader, BlockSums, Transaction};
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use pool::types::{BlockChain, PoolError};
|
||||
|
||||
@@ -48,12 +48,15 @@ impl BlockChain for CoinbaseMaturityErrorChainAdapter {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn validate_raw_txs(
|
||||
&self,
|
||||
_txs: Vec<Transaction>,
|
||||
_pre_tx: Option<Transaction>,
|
||||
_block_hash: &Hash,
|
||||
) -> Result<Vec<Transaction>, PoolError> {
|
||||
fn get_block_header(&self, _hash: &Hash) -> Result<BlockHeader, PoolError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn get_block_sums(&self, _hash: &Hash) -> Result<BlockSums, PoolError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn validate_tx(&self, _tx: &Transaction, _header: &BlockHeader) -> Result<(), PoolError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
@@ -82,7 +85,7 @@ fn test_coinbase_maturity() {
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let tx = test_transaction(&keychain, vec![50], vec![49]);
|
||||
match write_pool.add_to_pool(test_source(), tx.clone(), true, &Hash::default()) {
|
||||
match write_pool.add_to_pool(test_source(), tx.clone(), true, &BlockHeader::default()) {
|
||||
Err(PoolError::ImmatureCoinbase) => {}
|
||||
_ => panic!("Expected an immature coinbase error here."),
|
||||
}
|
||||
|
||||
+80
-28
@@ -26,16 +26,16 @@ extern crate grin_wallet as wallet;
|
||||
extern crate chrono;
|
||||
extern crate rand;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use core::core::hash::Hash;
|
||||
use core::core::hash::{Hash, Hashed};
|
||||
use core::core::verifier_cache::VerifierCache;
|
||||
use core::core::{BlockHeader, Transaction};
|
||||
use core::core::{Block, BlockHeader, BlockSums, Committed, Transaction};
|
||||
|
||||
use chain::store::ChainStore;
|
||||
use chain::txhashset;
|
||||
use chain::txhashset::TxHashSet;
|
||||
use chain::types::Tip;
|
||||
use pool::*;
|
||||
|
||||
use keychain::Keychain;
|
||||
@@ -43,11 +43,12 @@ use wallet::libtx;
|
||||
|
||||
use pool::types::*;
|
||||
use pool::TransactionPool;
|
||||
use util::secp::pedersen::Commitment;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ChainAdapter {
|
||||
pub txhashset: Arc<RwLock<TxHashSet>>,
|
||||
pub store: Arc<ChainStore>,
|
||||
pub utxo: Arc<RwLock<HashSet<Commitment>>>,
|
||||
}
|
||||
|
||||
impl ChainAdapter {
|
||||
@@ -57,13 +58,54 @@ impl ChainAdapter {
|
||||
let chain_store =
|
||||
ChainStore::new(db_env).map_err(|e| format!("failed to init chain_store, {:?}", e))?;
|
||||
let store = Arc::new(chain_store);
|
||||
let txhashset = TxHashSet::open(target_dir.clone(), store.clone(), None)
|
||||
.map_err(|e| format!("failed to init txhashset, {}", e))?;
|
||||
let utxo = Arc::new(RwLock::new(HashSet::new()));
|
||||
|
||||
Ok(ChainAdapter {
|
||||
txhashset: Arc::new(RwLock::new(txhashset)),
|
||||
store: store.clone(),
|
||||
})
|
||||
Ok(ChainAdapter { store, utxo })
|
||||
}
|
||||
|
||||
pub fn update_db_for_block(&self, block: &Block) {
|
||||
let header = &block.header;
|
||||
let batch = self.store.batch().unwrap();
|
||||
let tip = Tip::from_block(&header);
|
||||
batch.save_block_header(&header).unwrap();
|
||||
batch.save_head(&tip).unwrap();
|
||||
|
||||
// Retrieve previous block_sums from the db.
|
||||
let prev_sums = if let Ok(prev_sums) = batch.get_block_sums(&header.previous) {
|
||||
prev_sums
|
||||
} else {
|
||||
BlockSums::default()
|
||||
};
|
||||
|
||||
// Overage is based purely on the new block.
|
||||
// Previous block_sums have taken all previous overage into account.
|
||||
let overage = header.overage();
|
||||
|
||||
// Offset on the other hand is the total kernel offset from the new block.
|
||||
let offset = header.total_kernel_offset();
|
||||
|
||||
// Verify the kernel sums for the block_sums with the new block applied.
|
||||
let (utxo_sum, kernel_sum) = (prev_sums, block as &Committed)
|
||||
.verify_kernel_sums(overage, offset)
|
||||
.unwrap();
|
||||
|
||||
let block_sums = BlockSums {
|
||||
utxo_sum,
|
||||
kernel_sum,
|
||||
};
|
||||
batch.save_block_sums(&header.hash(), &block_sums).unwrap();
|
||||
|
||||
batch.commit().unwrap();
|
||||
|
||||
{
|
||||
let mut utxo = self.utxo.write().unwrap();
|
||||
for x in block.inputs() {
|
||||
utxo.remove(&x.commitment());
|
||||
}
|
||||
for x in block.outputs() {
|
||||
utxo.insert(x.commitment());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,24 +116,34 @@ impl BlockChain for ChainAdapter {
|
||||
.map_err(|_| PoolError::Other(format!("failed to get chain head")))
|
||||
}
|
||||
|
||||
fn validate_raw_txs(
|
||||
&self,
|
||||
txs: Vec<Transaction>,
|
||||
pre_tx: Option<Transaction>,
|
||||
block_hash: &Hash,
|
||||
) -> Result<Vec<Transaction>, PoolError> {
|
||||
let header = self
|
||||
.store
|
||||
.get_block_header(&block_hash)
|
||||
.map_err(|_| PoolError::Other(format!("failed to get header")))?;
|
||||
fn get_block_header(&self, hash: &Hash) -> Result<BlockHeader, PoolError> {
|
||||
self.store
|
||||
.get_block_header(hash)
|
||||
.map_err(|_| PoolError::Other(format!("failed to get block header")))
|
||||
}
|
||||
|
||||
let mut txhashset = self.txhashset.write().unwrap();
|
||||
let res = txhashset::extending_readonly(&mut txhashset, |extension| {
|
||||
extension.rewind(&header)?;
|
||||
let valid_txs = extension.validate_raw_txs(txs, pre_tx)?;
|
||||
Ok(valid_txs)
|
||||
}).map_err(|e| PoolError::Other(format!("Error: test chain adapter: {:?}", e)))?;
|
||||
Ok(res)
|
||||
fn get_block_sums(&self, hash: &Hash) -> Result<BlockSums, PoolError> {
|
||||
self.store
|
||||
.get_block_sums(hash)
|
||||
.map_err(|_| PoolError::Other(format!("failed to get block sums")))
|
||||
}
|
||||
|
||||
fn validate_tx(&self, tx: &Transaction, _header: &BlockHeader) -> Result<(), pool::PoolError> {
|
||||
let utxo = self.utxo.read().unwrap();
|
||||
|
||||
for x in tx.outputs() {
|
||||
if utxo.contains(&x.commitment()) {
|
||||
return Err(PoolError::Other(format!("output commitment not unique")));
|
||||
}
|
||||
}
|
||||
|
||||
for x in tx.inputs() {
|
||||
if !utxo.contains(&x.commitment()) {
|
||||
return Err(PoolError::Other(format!("not in utxo set")));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Mocking this check out for these tests.
|
||||
|
||||
@@ -27,13 +27,7 @@ pub mod common;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use chain::txhashset;
|
||||
use chain::types::Tip;
|
||||
use common::{
|
||||
clean_output_dir, test_setup, test_source, test_transaction,
|
||||
test_transaction_spending_coinbase, ChainAdapter,
|
||||
};
|
||||
use core::core::hash::Hashed;
|
||||
use common::*;
|
||||
use core::core::verifier_cache::LruVerifierCache;
|
||||
use core::core::{transaction, Block, BlockHeader};
|
||||
use core::pow::Difficulty;
|
||||
@@ -47,12 +41,13 @@ fn test_the_transaction_pool() {
|
||||
|
||||
let db_root = ".grin_transaction_pool".to_string();
|
||||
clean_output_dir(db_root.clone());
|
||||
let chain = ChainAdapter::init(db_root.clone()).unwrap();
|
||||
let chain = Arc::new(ChainAdapter::init(db_root.clone()).unwrap());
|
||||
|
||||
let verifier_cache = Arc::new(RwLock::new(LruVerifierCache::new()));
|
||||
|
||||
// Initialize the chain/txhashset with a few blocks,
|
||||
// so we have a non-empty UTXO set.
|
||||
// Initialize a new pool with our chain adapter.
|
||||
let pool = RwLock::new(test_setup(chain.clone(), verifier_cache.clone()));
|
||||
|
||||
let header = {
|
||||
let height = 1;
|
||||
let key_id = keychain.derive_key_id(height as u32).unwrap();
|
||||
@@ -60,34 +55,11 @@ fn test_the_transaction_pool() {
|
||||
let mut block =
|
||||
Block::new(&BlockHeader::default(), vec![], Difficulty::one(), reward).unwrap();
|
||||
|
||||
let mut txhashset = chain.txhashset.write().unwrap();
|
||||
let mut batch = chain.store.batch().unwrap();
|
||||
txhashset::extending(&mut txhashset, &mut batch, |extension| {
|
||||
extension.apply_block(&block)?;
|
||||
|
||||
// Now set the roots and sizes as necessary on the block header.
|
||||
let roots = extension.roots();
|
||||
block.header.output_root = roots.output_root;
|
||||
block.header.range_proof_root = roots.rproof_root;
|
||||
block.header.kernel_root = roots.kernel_root;
|
||||
let sizes = extension.sizes();
|
||||
block.header.output_mmr_size = sizes.0;
|
||||
block.header.kernel_mmr_size = sizes.2;
|
||||
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
|
||||
let tip = Tip::from_block(&block.header);
|
||||
batch.save_block_header(&block.header).unwrap();
|
||||
batch.save_head(&tip).unwrap();
|
||||
batch.commit().unwrap();
|
||||
chain.update_db_for_block(&block);
|
||||
|
||||
block.header
|
||||
};
|
||||
|
||||
// Initialize a new pool with our chain adapter.
|
||||
let pool = RwLock::new(test_setup(Arc::new(chain.clone()), verifier_cache.clone()));
|
||||
|
||||
// Now create tx to spend a coinbase, giving us some useful outputs for testing
|
||||
// with.
|
||||
let initial_tx = {
|
||||
@@ -102,7 +74,7 @@ fn test_the_transaction_pool() {
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
write_pool
|
||||
.add_to_pool(test_source(), initial_tx, false, &header.hash())
|
||||
.add_to_pool(test_source(), initial_tx, false, &header)
|
||||
.unwrap();
|
||||
assert_eq!(write_pool.total_size(), 1);
|
||||
}
|
||||
@@ -121,14 +93,14 @@ fn test_the_transaction_pool() {
|
||||
|
||||
// First, add a simple tx to the pool in "stem" mode.
|
||||
write_pool
|
||||
.add_to_pool(test_source(), tx1.clone(), true, &header.hash())
|
||||
.add_to_pool(test_source(), tx1.clone(), true, &header)
|
||||
.unwrap();
|
||||
assert_eq!(write_pool.total_size(), 1);
|
||||
assert_eq!(write_pool.stempool.size(), 1);
|
||||
|
||||
// Add another tx spending outputs from the previous tx.
|
||||
write_pool
|
||||
.add_to_pool(test_source(), tx2.clone(), true, &header.hash())
|
||||
.add_to_pool(test_source(), tx2.clone(), true, &header)
|
||||
.unwrap();
|
||||
assert_eq!(write_pool.total_size(), 1);
|
||||
assert_eq!(write_pool.stempool.size(), 2);
|
||||
@@ -141,7 +113,7 @@ fn test_the_transaction_pool() {
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
assert!(
|
||||
write_pool
|
||||
.add_to_pool(test_source(), tx1.clone(), true, &header.hash())
|
||||
.add_to_pool(test_source(), tx1.clone(), true, &header)
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
@@ -153,7 +125,7 @@ fn test_the_transaction_pool() {
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
assert!(
|
||||
write_pool
|
||||
.add_to_pool(test_source(), tx1a, true, &header.hash())
|
||||
.add_to_pool(test_source(), tx1a, true, &header)
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
@@ -164,7 +136,7 @@ fn test_the_transaction_pool() {
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
assert!(
|
||||
write_pool
|
||||
.add_to_pool(test_source(), bad_tx, true, &header.hash())
|
||||
.add_to_pool(test_source(), bad_tx, true, &header)
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
@@ -178,7 +150,7 @@ fn test_the_transaction_pool() {
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
assert!(
|
||||
write_pool
|
||||
.add_to_pool(test_source(), tx, true, &header.hash())
|
||||
.add_to_pool(test_source(), tx, true, &header)
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
@@ -189,7 +161,7 @@ fn test_the_transaction_pool() {
|
||||
let tx3 = test_transaction(&keychain, vec![500], vec![497]);
|
||||
assert!(
|
||||
write_pool
|
||||
.add_to_pool(test_source(), tx3, true, &header.hash())
|
||||
.add_to_pool(test_source(), tx3, true, &header)
|
||||
.is_err()
|
||||
);
|
||||
assert_eq!(write_pool.total_size(), 1);
|
||||
@@ -207,7 +179,7 @@ fn test_the_transaction_pool() {
|
||||
.unwrap();
|
||||
assert_eq!(agg_tx.kernels().len(), 2);
|
||||
write_pool
|
||||
.add_to_pool(test_source(), agg_tx, false, &header.hash())
|
||||
.add_to_pool(test_source(), agg_tx, false, &header)
|
||||
.unwrap();
|
||||
assert_eq!(write_pool.total_size(), 2);
|
||||
}
|
||||
@@ -222,11 +194,12 @@ fn test_the_transaction_pool() {
|
||||
let tx4 = test_transaction(&keychain, vec![800], vec![799]);
|
||||
// tx1 and tx2 are already in the txpool (in aggregated form)
|
||||
// tx4 is the "new" part of this aggregated tx that we care about
|
||||
let agg_tx =
|
||||
transaction::aggregate(vec![tx1.clone(), tx2.clone(), tx4], verifier_cache.clone())
|
||||
.unwrap();
|
||||
let agg_tx = transaction::aggregate(vec![tx1.clone(), tx2.clone(), tx4]).unwrap();
|
||||
|
||||
agg_tx.validate(verifier_cache.clone()).unwrap();
|
||||
|
||||
write_pool
|
||||
.add_to_pool(test_source(), agg_tx, false, &header.hash())
|
||||
.add_to_pool(test_source(), agg_tx, false, &header)
|
||||
.unwrap();
|
||||
assert_eq!(write_pool.total_size(), 3);
|
||||
let entry = write_pool.txpool.entries.last().unwrap();
|
||||
@@ -245,19 +218,14 @@ fn test_the_transaction_pool() {
|
||||
// check we cannot add a double spend to the stempool
|
||||
assert!(
|
||||
write_pool
|
||||
.add_to_pool(test_source(), double_spend_tx.clone(), true, &header.hash())
|
||||
.add_to_pool(test_source(), double_spend_tx.clone(), true, &header)
|
||||
.is_err()
|
||||
);
|
||||
|
||||
// check we cannot add a double spend to the txpool
|
||||
assert!(
|
||||
write_pool
|
||||
.add_to_pool(
|
||||
test_source(),
|
||||
double_spend_tx.clone(),
|
||||
false,
|
||||
&header.hash()
|
||||
)
|
||||
.add_to_pool(test_source(), double_spend_tx.clone(), false, &header)
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user