Skip to content

Commit

Permalink
Rework pool tests to use real chain (was mock chain) (#3342)
Browse files Browse the repository at this point in the history
* rework pool tests to use real chain (was mock chain) to better reflect reality (tx/block validation rules etc.)

* cleanup
  • Loading branch information
antiochp authored Jun 7, 2020
1 parent c7c9a32 commit c54568e
Show file tree
Hide file tree
Showing 11 changed files with 698 additions and 1,114 deletions.
2 changes: 1 addition & 1 deletion core/src/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub const TESTING_INITIAL_GRAPH_WEIGHT: u32 = 1;
pub const TESTING_INITIAL_DIFFICULTY: u64 = 1;

/// Testing max_block_weight (artifically low, just enough to support a few txs).
pub const TESTING_MAX_BLOCK_WEIGHT: usize = 150;
pub const TESTING_MAX_BLOCK_WEIGHT: usize = 250;

/// If a peer's last updated difficulty is 2 hours ago and its difficulty's lower than ours,
/// we're sure this peer is a stuck node, and we will kick out such kind of stuck peers.
Expand Down
4 changes: 2 additions & 2 deletions pool/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,9 @@ pub trait PoolAdapter: Send + Sync {

/// Dummy adapter used as a placeholder for real implementations
#[allow(dead_code)]
pub struct NoopAdapter {}
pub struct NoopPoolAdapter {}

impl PoolAdapter for NoopAdapter {
impl PoolAdapter for NoopPoolAdapter {
fn tx_accepted(&self, _entry: &PoolEntry) {}
fn stem_tx_accepted(&self, _entry: &PoolEntry) -> Result<(), PoolError> {
Ok(())
Expand Down
182 changes: 77 additions & 105 deletions pool/tests/block_building.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,126 +16,98 @@ pub mod common;

use self::core::core::hash::Hashed;
use self::core::core::verifier_cache::LruVerifierCache;
use self::core::core::{Block, BlockHeader, Transaction};
use self::core::pow::Difficulty;
use self::core::{global, libtx};
use self::core::global;
use self::keychain::{ExtKeychain, Keychain};
use self::pool::PoolError;
use self::util::RwLock;
use crate::common::*;
use grin_core as core;
use grin_keychain as keychain;
use grin_pool as pool;
use grin_util as util;
use std::sync::Arc;

#[test]
fn test_transaction_pool_block_building() {
fn test_transaction_pool_block_building() -> Result<(), PoolError> {
util::init_test_logger();
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let keychain: ExtKeychain = Keychain::from_random_seed(false).unwrap();

let db_root = ".grin_block_building".to_string();
clean_output_dir(db_root.clone());
let db_root = "target/.block_building";
clean_output_dir(db_root.into());

let genesis = genesis_block(&keychain);
let chain = Arc::new(init_chain(db_root, genesis));
let verifier_cache = Arc::new(RwLock::new(LruVerifierCache::new()));

// Initialize a new pool with our chain adapter.
let mut pool = init_transaction_pool(
Arc::new(ChainAdapter {
chain: chain.clone(),
}),
verifier_cache,
);

add_some_blocks(&chain, 3, &keychain);

let header_1 = chain.get_header_by_height(1).unwrap();

// Now create tx to spend an early coinbase (now matured).
// Provides us with some useful outputs to test with.
let initial_tx = test_transaction_spending_coinbase(&keychain, &header_1, vec![10, 20, 30, 40]);

// Mine that initial tx so we can spend it with multiple txs.
add_block(&chain, vec![initial_tx], &keychain);

let header = chain.head_header().unwrap();

let root_tx_1 = test_transaction(&keychain, vec![10, 20], vec![24]);
let root_tx_2 = test_transaction(&keychain, vec![30], vec![28]);
let root_tx_3 = test_transaction(&keychain, vec![40], vec![38]);

let child_tx_1 = test_transaction(&keychain, vec![24], vec![22]);
let child_tx_2 = test_transaction(&keychain, vec![38], vec![32]);

{
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 =
|prev_header: BlockHeader, txs: Vec<Transaction>, chain: &mut ChainAdapter| {
let height = prev_header.height + 1;
let key_id = ExtKeychain::derive_key_id(1, height as u32, 0, 0, 0);
let fee = txs.iter().map(|x| x.fee()).sum();
let reward = libtx::reward::output(
&keychain,
&libtx::ProofBuilder::new(&keychain),
&key_id,
fee,
false,
)
.unwrap();
let mut block = Block::new(&prev_header, txs, Difficulty::min(), reward).unwrap();

// Set the prev_root to the prev hash for testing purposes (no MMR to obtain a root from).
block.header.prev_root = prev_header.hash();

chain.update_db_for_block(&block);
block
};

let block = add_block(BlockHeader::default(), vec![], &mut chain);
let header = block.header;

// 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 block = add_block(header, vec![initial_tx], &mut chain);
let header = block.header;

// 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]);
let root_tx_3 = test_transaction(&keychain, vec![40], vec![38]);

let child_tx_1 = test_transaction(&keychain, vec![24], vec![22]);
let child_tx_2 = test_transaction(&keychain, vec![38], vec![32]);

{
let mut write_pool = pool.write();

// Add the three root txs to the pool.
write_pool
.add_to_pool(test_source(), root_tx_1.clone(), false, &header)
.unwrap();
write_pool
.add_to_pool(test_source(), root_tx_2.clone(), false, &header)
.unwrap();
write_pool
.add_to_pool(test_source(), root_tx_3.clone(), 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)
.unwrap();
write_pool
.add_to_pool(test_source(), child_tx_2.clone(), false, &header)
.unwrap();

assert_eq!(write_pool.total_size(), 5);
}

let txs = pool.read().prepare_mineable_transactions().unwrap();

let block = add_block(header, txs, &mut chain);

// Check the block contains what we expect.
assert_eq!(block.inputs().len(), 4);
assert_eq!(block.outputs().len(), 4);
assert_eq!(block.kernels().len(), 6);

assert!(block.kernels().contains(&root_tx_1.kernels()[0]));
assert!(block.kernels().contains(&root_tx_2.kernels()[0]));
assert!(block.kernels().contains(&root_tx_3.kernels()[0]));
assert!(block.kernels().contains(&child_tx_1.kernels()[0]));
assert!(block.kernels().contains(&child_tx_1.kernels()[0]));

// Now reconcile the transaction pool with the new block
// and check the resulting contents of the pool are what we expect.
{
let mut write_pool = pool.write();
write_pool.reconcile_block(&block).unwrap();

assert_eq!(write_pool.total_size(), 0);
}
// Add the three root txs to the pool.
pool.add_to_pool(test_source(), root_tx_1.clone(), false, &header)?;
pool.add_to_pool(test_source(), root_tx_2.clone(), false, &header)?;
pool.add_to_pool(test_source(), root_tx_3.clone(), false, &header)?;

// Now add the two child txs to the pool.
pool.add_to_pool(test_source(), child_tx_1.clone(), false, &header)?;
pool.add_to_pool(test_source(), child_tx_2.clone(), false, &header)?;

assert_eq!(pool.total_size(), 5);
}

let txs = pool.prepare_mineable_transactions()?;

add_block(&chain, txs, &keychain);

// Get full block from head of the chain (block we just processed).
let block = chain.get_block(&chain.head().unwrap().hash()).unwrap();

// Check the block contains what we expect.
assert_eq!(block.inputs().len(), 4);
assert_eq!(block.outputs().len(), 4);
assert_eq!(block.kernels().len(), 6);

assert!(block.kernels().contains(&root_tx_1.kernels()[0]));
assert!(block.kernels().contains(&root_tx_2.kernels()[0]));
assert!(block.kernels().contains(&root_tx_3.kernels()[0]));
assert!(block.kernels().contains(&child_tx_1.kernels()[0]));
assert!(block.kernels().contains(&child_tx_1.kernels()[0]));

// Now reconcile the transaction pool with the new block
// and check the resulting contents of the pool are what we expect.
{
pool.reconcile_block(&block)?;
assert_eq!(pool.total_size(), 0);
}

// Cleanup db directory
clean_output_dir(db_root.clone());
clean_output_dir(db_root.into());

Ok(())
}
Loading

0 comments on commit c54568e

Please sign in to comment.