Merge branch 'master' into unitdiff
This commit is contained in:
+1
-1
@@ -10,7 +10,7 @@ blake2-rfc = "0.2"
|
||||
rand = "0.5"
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
slog = { version = "~2.3", features = ["max_level_trace", "release_max_level_trace"] }
|
||||
log = "0.4"
|
||||
chrono = "0.4.4"
|
||||
|
||||
grin_core = { path = "../core" }
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ extern crate serde;
|
||||
#[macro_use] // Needed for Serialize/Deserialize. The compiler complaining here is a bug.
|
||||
extern crate serde_derive;
|
||||
#[macro_use]
|
||||
extern crate slog;
|
||||
extern crate log;
|
||||
extern crate chrono;
|
||||
|
||||
mod pool;
|
||||
|
||||
+71
-83
@@ -16,7 +16,8 @@
|
||||
//! Used for both the txpool and stempool layers in the pool.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use util::RwLock;
|
||||
|
||||
use core::consensus;
|
||||
use core::core::hash::{Hash, Hashed};
|
||||
@@ -25,7 +26,6 @@ use core::core::transaction;
|
||||
use core::core::verifier_cache::VerifierCache;
|
||||
use core::core::{Block, BlockHeader, BlockSums, Committed, Transaction, TxKernel};
|
||||
use types::{BlockChain, PoolEntry, PoolEntryState, PoolError};
|
||||
use util::LOGGER;
|
||||
|
||||
// max weight leaving minimum space for a coinbase
|
||||
const MAX_MINEABLE_WEIGHT: usize =
|
||||
@@ -48,8 +48,8 @@ impl Pool {
|
||||
) -> Pool {
|
||||
Pool {
|
||||
entries: vec![],
|
||||
blockchain: chain.clone(),
|
||||
verifier_cache: verifier_cache.clone(),
|
||||
blockchain: chain,
|
||||
verifier_cache,
|
||||
name,
|
||||
}
|
||||
}
|
||||
@@ -74,34 +74,34 @@ impl Pool {
|
||||
&self,
|
||||
hash: Hash,
|
||||
nonce: u64,
|
||||
kern_ids: &Vec<ShortId>,
|
||||
kern_ids: &[ShortId],
|
||||
) -> (Vec<Transaction>, Vec<ShortId>) {
|
||||
let mut rehashed = HashMap::new();
|
||||
let mut txs = vec![];
|
||||
let mut found_ids = vec![];
|
||||
|
||||
// Rehash all entries in the pool using short_ids based on provided hash and nonce.
|
||||
for x in &self.entries {
|
||||
'outer: for x in &self.entries {
|
||||
for k in x.tx.kernels() {
|
||||
// rehash each kernel to calculate the block specific short_id
|
||||
let short_id = k.short_id(&hash, nonce);
|
||||
rehashed.insert(short_id, x.tx.hash());
|
||||
if kern_ids.contains(&short_id) {
|
||||
txs.push(x.tx.clone());
|
||||
found_ids.push(short_id);
|
||||
}
|
||||
if found_ids.len() == kern_ids.len() {
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retrive the txs from the pool by the set of unique hashes.
|
||||
let hashes: HashSet<_> = rehashed.values().collect();
|
||||
let txs = hashes.into_iter().filter_map(|x| self.get_tx(*x)).collect();
|
||||
|
||||
// Calculate the missing ids based on the ids passed in
|
||||
// and the ids that successfully matched txs.
|
||||
let matched_ids: HashSet<_> = rehashed.keys().collect();
|
||||
let all_ids: HashSet<_> = kern_ids.iter().collect();
|
||||
let missing_ids = all_ids
|
||||
.difference(&matched_ids)
|
||||
.map(|x| *x)
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
(txs, missing_ids)
|
||||
txs.dedup();
|
||||
(
|
||||
txs,
|
||||
kern_ids
|
||||
.into_iter()
|
||||
.filter(|id| !found_ids.contains(id))
|
||||
.cloned()
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Take pool transactions, filtering and ordering them in a way that's
|
||||
@@ -133,8 +133,7 @@ impl Pool {
|
||||
// Iteratively apply the txs to the current chain state,
|
||||
// rejecting any that do not result in a valid state.
|
||||
// Return a vec of all the valid txs.
|
||||
let block_sums = self.blockchain.get_block_sums(&header.hash())?;
|
||||
let txs = self.validate_raw_txs(flat_txs, None, &header, &block_sums)?;
|
||||
let txs = self.validate_raw_txs(flat_txs, None, &header)?;
|
||||
Ok(txs)
|
||||
}
|
||||
|
||||
@@ -159,8 +158,7 @@ impl Pool {
|
||||
extra_tx: Option<Transaction>,
|
||||
header: &BlockHeader,
|
||||
) -> Result<Vec<Transaction>, PoolError> {
|
||||
let block_sums = self.blockchain.get_block_sums(&header.hash())?;
|
||||
let valid_txs = self.validate_raw_txs(txs, extra_tx, header, &block_sums)?;
|
||||
let valid_txs = self.validate_raw_txs(txs, extra_tx, header)?;
|
||||
Ok(valid_txs)
|
||||
}
|
||||
|
||||
@@ -173,10 +171,10 @@ impl Pool {
|
||||
}
|
||||
|
||||
// Transition the specified pool entries to the new state.
|
||||
pub fn transition_to_state(&mut self, txs: &Vec<Transaction>, state: PoolEntryState) {
|
||||
for x in self.entries.iter_mut() {
|
||||
pub fn transition_to_state(&mut self, txs: &[Transaction], state: PoolEntryState) {
|
||||
for x in &mut self.entries {
|
||||
if txs.contains(&x.tx) {
|
||||
x.state = state.clone();
|
||||
x.state = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,18 +188,6 @@ impl Pool {
|
||||
extra_txs: Vec<Transaction>,
|
||||
header: &BlockHeader,
|
||||
) -> Result<(), PoolError> {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"pool [{}]: add_to_pool: {}, {:?}, inputs: {}, outputs: {}, kernels: {} (at block {})",
|
||||
self.name,
|
||||
entry.tx.hash(),
|
||||
entry.src,
|
||||
entry.tx.inputs().len(),
|
||||
entry.tx.outputs().len(),
|
||||
entry.tx.kernels().len(),
|
||||
header.hash(),
|
||||
);
|
||||
|
||||
// Combine all the txs from the pool with any extra txs provided.
|
||||
let mut txs = self.all_transactions();
|
||||
|
||||
@@ -228,6 +214,17 @@ impl Pool {
|
||||
// Validate aggregated tx against a known chain state.
|
||||
self.validate_raw_tx(&agg_tx, header)?;
|
||||
|
||||
debug!(
|
||||
"add_to_pool [{}]: {} ({}), in/out/kern: {}/{}/{}, pool: {} (at block {})",
|
||||
self.name,
|
||||
entry.tx.hash(),
|
||||
entry.src.debug_name,
|
||||
entry.tx.inputs().len(),
|
||||
entry.tx.outputs().len(),
|
||||
entry.tx.kernels().len(),
|
||||
self.size(),
|
||||
header.hash(),
|
||||
);
|
||||
// If we get here successfully then we can safely add the entry to the pool.
|
||||
self.entries.push(entry);
|
||||
|
||||
@@ -239,8 +236,14 @@ impl Pool {
|
||||
tx: &Transaction,
|
||||
header: &BlockHeader,
|
||||
) -> Result<BlockSums, PoolError> {
|
||||
let block_sums = self.blockchain.get_block_sums(&header.hash())?;
|
||||
let new_sums = self.apply_txs_to_block_sums(&block_sums, vec![tx.clone()], header)?;
|
||||
tx.validate(self.verifier_cache.clone())?;
|
||||
|
||||
// Validate the tx against current chain state.
|
||||
// Check all inputs are in the current UTXO set.
|
||||
// Check all outputs are unique in current UTXO set.
|
||||
self.blockchain.validate_tx(tx)?;
|
||||
|
||||
let new_sums = self.apply_tx_to_block_sums(tx, header)?;
|
||||
Ok(new_sums)
|
||||
}
|
||||
|
||||
@@ -249,7 +252,6 @@ impl Pool {
|
||||
txs: Vec<Transaction>,
|
||||
extra_tx: Option<Transaction>,
|
||||
header: &BlockHeader,
|
||||
block_sums: &BlockSums,
|
||||
) -> Result<Vec<Transaction>, PoolError> {
|
||||
let mut valid_txs = vec![];
|
||||
|
||||
@@ -260,10 +262,12 @@ impl Pool {
|
||||
};
|
||||
candidate_txs.extend(valid_txs.clone());
|
||||
candidate_txs.push(tx.clone());
|
||||
if self
|
||||
.apply_txs_to_block_sums(&block_sums, candidate_txs, header)
|
||||
.is_ok()
|
||||
{
|
||||
|
||||
// Build a single aggregate tx from candidate txs.
|
||||
let agg_tx = transaction::aggregate(candidate_txs)?;
|
||||
|
||||
// We know the tx is valid if the entire aggregate tx is valid.
|
||||
if self.validate_raw_tx(&agg_tx, header).is_ok() {
|
||||
valid_txs.push(tx);
|
||||
}
|
||||
}
|
||||
@@ -271,28 +275,20 @@ impl Pool {
|
||||
Ok(valid_txs)
|
||||
}
|
||||
|
||||
fn apply_txs_to_block_sums(
|
||||
fn apply_tx_to_block_sums(
|
||||
&self,
|
||||
block_sums: &BlockSums,
|
||||
txs: Vec<Transaction>,
|
||||
tx: &Transaction,
|
||||
header: &BlockHeader,
|
||||
) -> Result<BlockSums, PoolError> {
|
||||
// Build a single aggregate tx and validate it.
|
||||
let tx = transaction::aggregate(txs)?;
|
||||
tx.validate(self.verifier_cache.clone())?;
|
||||
|
||||
// Validate the tx against current chain state.
|
||||
// Check all inputs are in the current UTXO set.
|
||||
// Check all outputs are unique in current UTXO set.
|
||||
self.blockchain.validate_tx(&tx)?;
|
||||
|
||||
let overage = tx.overage();
|
||||
let offset = (header.total_kernel_offset() + tx.offset)?;
|
||||
|
||||
let block_sums = self.blockchain.get_block_sums(&header.hash())?;
|
||||
|
||||
// Verify the kernel sums for the block_sums with the new tx applied,
|
||||
// accounting for overage and offset.
|
||||
let (utxo_sum, kernel_sum) =
|
||||
(block_sums.clone(), &tx as &Committed).verify_kernel_sums(overage, offset)?;
|
||||
(block_sums, tx as &Committed).verify_kernel_sums(overage, offset)?;
|
||||
|
||||
Ok(BlockSums {
|
||||
utxo_sum,
|
||||
@@ -314,7 +310,7 @@ impl Pool {
|
||||
}
|
||||
|
||||
for x in existing_entries {
|
||||
let _ = self.add_to_pool(x.clone(), extra_txs.clone(), header);
|
||||
let _ = self.add_to_pool(x, extra_txs.clone(), header);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -355,20 +351,7 @@ impl Pool {
|
||||
tx_buckets
|
||||
}
|
||||
|
||||
// Filter txs in the pool based on the latest block.
|
||||
// Reject any txs where we see a matching tx kernel in the block.
|
||||
// Also reject any txs where we see a conflicting tx,
|
||||
// where an input is spent in a different tx.
|
||||
fn remaining_transactions(&self, block: &Block) -> Vec<Transaction> {
|
||||
self.entries
|
||||
.iter()
|
||||
.filter(|x| !x.tx.kernels().iter().any(|y| block.kernels().contains(y)))
|
||||
.filter(|x| !x.tx.inputs().iter().any(|y| block.inputs().contains(y)))
|
||||
.map(|x| x.tx.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn find_matching_transactions(&self, kernels: Vec<TxKernel>) -> Vec<Transaction> {
|
||||
pub fn find_matching_transactions(&self, kernels: &[TxKernel]) -> Vec<Transaction> {
|
||||
// While the inputs outputs can be cut-through the kernel will stay intact
|
||||
// In order to deaggregate tx we look for tx with the same kernel
|
||||
let mut found_txs = vec![];
|
||||
@@ -378,7 +361,7 @@ impl Pool {
|
||||
|
||||
// Check each transaction in the pool
|
||||
for entry in &self.entries {
|
||||
let entry_kernel_set = entry.tx.kernels().iter().cloned().collect::<HashSet<_>>();
|
||||
let entry_kernel_set = entry.tx.kernels().iter().collect::<HashSet<_>>();
|
||||
if entry_kernel_set.is_subset(&kernel_set) {
|
||||
found_txs.push(entry.tx.clone());
|
||||
}
|
||||
@@ -388,10 +371,15 @@ impl Pool {
|
||||
|
||||
/// Quick reconciliation step - we can evict any txs in the pool where
|
||||
/// inputs or kernels intersect with the block.
|
||||
pub fn reconcile_block(&mut self, block: &Block) -> Result<(), PoolError> {
|
||||
let candidate_txs = self.remaining_transactions(block);
|
||||
self.entries.retain(|x| candidate_txs.contains(&x.tx));
|
||||
Ok(())
|
||||
pub fn reconcile_block(&mut self, block: &Block) {
|
||||
// Filter txs in the pool based on the latest block.
|
||||
// Reject any txs where we see a matching tx kernel in the block.
|
||||
// Also reject any txs where we see a conflicting tx,
|
||||
// where an input is spent in a different tx.
|
||||
self.entries.retain(|x| {
|
||||
!x.tx.kernels().iter().any(|y| block.kernels().contains(y))
|
||||
&& !x.tx.inputs().iter().any(|y| block.inputs().contains(y))
|
||||
});
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
//! resulting tx pool can be added to the current chain state to produce a
|
||||
//! valid chain state.
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::Arc;
|
||||
use util::RwLock;
|
||||
|
||||
use chrono::prelude::Utc;
|
||||
|
||||
@@ -28,6 +30,9 @@ use core::core::{transaction, Block, BlockHeader, Transaction};
|
||||
use pool::Pool;
|
||||
use types::{BlockChain, PoolAdapter, PoolConfig, PoolEntry, PoolEntryState, PoolError, TxSource};
|
||||
|
||||
// Cache this many txs to handle a potential fork and re-org.
|
||||
const REORG_CACHE_SIZE: usize = 100;
|
||||
|
||||
/// Transaction pool implementation.
|
||||
pub struct TransactionPool {
|
||||
/// Pool Config
|
||||
@@ -36,6 +41,8 @@ pub struct TransactionPool {
|
||||
pub txpool: Pool,
|
||||
/// Our Dandelion "stempool".
|
||||
pub stempool: Pool,
|
||||
/// Cache of previous txs in case of a re-org.
|
||||
pub reorg_cache: Arc<RwLock<VecDeque<PoolEntry>>>,
|
||||
/// The blockchain
|
||||
pub blockchain: Arc<BlockChain>,
|
||||
pub verifier_cache: Arc<RwLock<VerifierCache>>,
|
||||
@@ -53,8 +60,13 @@ impl TransactionPool {
|
||||
) -> TransactionPool {
|
||||
TransactionPool {
|
||||
config,
|
||||
txpool: Pool::new(chain.clone(), verifier_cache.clone(), format!("txpool")),
|
||||
stempool: Pool::new(chain.clone(), verifier_cache.clone(), format!("stempool")),
|
||||
txpool: Pool::new(chain.clone(), verifier_cache.clone(), "txpool".to_string()),
|
||||
stempool: Pool::new(
|
||||
chain.clone(),
|
||||
verifier_cache.clone(),
|
||||
"stempool".to_string(),
|
||||
),
|
||||
reorg_cache: Arc::new(RwLock::new(VecDeque::new())),
|
||||
blockchain: chain,
|
||||
verifier_cache,
|
||||
adapter,
|
||||
@@ -68,13 +80,23 @@ impl TransactionPool {
|
||||
fn add_to_stempool(&mut self, entry: PoolEntry, header: &BlockHeader) -> Result<(), PoolError> {
|
||||
// Add tx to stempool (passing in all txs from txpool to validate against).
|
||||
self.stempool
|
||||
.add_to_pool(entry.clone(), self.txpool.all_transactions(), header)?;
|
||||
.add_to_pool(entry, self.txpool.all_transactions(), header)?;
|
||||
|
||||
// Note: we do not notify the adapter here,
|
||||
// we let the dandelion monitor handle this.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_to_reorg_cache(&mut self, entry: PoolEntry) -> Result<(), PoolError> {
|
||||
let mut cache = self.reorg_cache.write();
|
||||
cache.push_back(entry);
|
||||
if cache.len() > REORG_CACHE_SIZE {
|
||||
cache.pop_front();
|
||||
}
|
||||
debug!("added tx to reorg_cache: size now {}", cache.len());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_to_txpool(
|
||||
&mut self,
|
||||
mut entry: PoolEntry,
|
||||
@@ -82,9 +104,7 @@ impl TransactionPool {
|
||||
) -> Result<(), PoolError> {
|
||||
// First deaggregate the tx based on current txpool txs.
|
||||
if entry.tx.kernels().len() > 1 {
|
||||
let txs = self
|
||||
.txpool
|
||||
.find_matching_transactions(entry.tx.kernels().clone());
|
||||
let txs = self.txpool.find_matching_transactions(entry.tx.kernels());
|
||||
if !txs.is_empty() {
|
||||
let tx = transaction::deaggregate(entry.tx, txs)?;
|
||||
tx.validate(self.verifier_cache.clone())?;
|
||||
@@ -96,8 +116,10 @@ impl TransactionPool {
|
||||
|
||||
// We now need to reconcile the stempool based on the new state of the txpool.
|
||||
// Some stempool txs may no longer be valid and we need to evict them.
|
||||
let txpool_tx = self.txpool.aggregate_transaction()?;
|
||||
self.stempool.reconcile(txpool_tx, header)?;
|
||||
{
|
||||
let txpool_tx = self.txpool.aggregate_transaction()?;
|
||||
self.stempool.reconcile(txpool_tx, header)?;
|
||||
}
|
||||
|
||||
self.adapter.tx_accepted(&entry.tx);
|
||||
Ok(())
|
||||
@@ -123,7 +145,7 @@ impl TransactionPool {
|
||||
|
||||
// Make sure the transaction is valid before anything else.
|
||||
tx.validate(self.verifier_cache.clone())
|
||||
.map_err(|e| PoolError::InvalidTx(e))?;
|
||||
.map_err(PoolError::InvalidTx)?;
|
||||
|
||||
// Check the tx lock_time is valid based on current chain state.
|
||||
self.blockchain.verify_tx_lock_height(&tx)?;
|
||||
@@ -135,28 +157,46 @@ impl TransactionPool {
|
||||
state: PoolEntryState::Fresh,
|
||||
src,
|
||||
tx_at: Utc::now(),
|
||||
tx: tx.clone(),
|
||||
tx,
|
||||
};
|
||||
|
||||
if stem {
|
||||
// TODO - what happens to txs in the stempool in a re-org scenario?
|
||||
self.add_to_stempool(entry, header)?;
|
||||
} else {
|
||||
self.add_to_txpool(entry, header)?;
|
||||
self.add_to_txpool(entry.clone(), header)?;
|
||||
self.add_to_reorg_cache(entry)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reconcile_reorg_cache(&mut self, header: &BlockHeader) -> Result<(), PoolError> {
|
||||
let entries = self.reorg_cache.read().iter().cloned().collect::<Vec<_>>();
|
||||
debug!("reconcile_reorg_cache: size: {} ...", entries.len());
|
||||
for entry in entries {
|
||||
let _ = &self.add_to_txpool(entry.clone(), header);
|
||||
}
|
||||
debug!("reconcile_reorg_cache: ... done.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reconcile the transaction pool (both txpool and stempool) against the
|
||||
/// provided block.
|
||||
pub fn reconcile_block(&mut self, block: &Block) -> Result<(), PoolError> {
|
||||
// First reconcile the txpool.
|
||||
self.txpool.reconcile_block(block)?;
|
||||
self.txpool.reconcile_block(block);
|
||||
self.txpool.reconcile(None, &block.header)?;
|
||||
|
||||
// Then reconcile the stempool, accounting for the txpool txs.
|
||||
let txpool_tx = self.txpool.aggregate_transaction()?;
|
||||
self.stempool.reconcile_block(block)?;
|
||||
self.stempool.reconcile(txpool_tx, &block.header)?;
|
||||
// Take our "reorg_cache" and see if this block means
|
||||
// we need to (re)add old txs due to a fork and re-org.
|
||||
self.reconcile_reorg_cache(&block.header)?;
|
||||
|
||||
// Now reconcile our stempool, accounting for the updated txpool txs.
|
||||
self.stempool.reconcile_block(block);
|
||||
{
|
||||
let txpool_tx = self.txpool.aggregate_transaction()?;
|
||||
self.stempool.reconcile(txpool_tx, &block.header)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -168,7 +208,7 @@ impl TransactionPool {
|
||||
&self,
|
||||
hash: Hash,
|
||||
nonce: u64,
|
||||
kern_ids: &Vec<ShortId>,
|
||||
kern_ids: &[ShortId],
|
||||
) -> (Vec<Transaction>, Vec<ShortId>) {
|
||||
self.txpool.retrieve_transactions(hash, nonce, kern_ids)
|
||||
}
|
||||
|
||||
+10
-1
@@ -18,6 +18,7 @@
|
||||
use chrono::prelude::{DateTime, Utc};
|
||||
|
||||
use core::consensus;
|
||||
use core::core::block;
|
||||
use core::core::committed;
|
||||
use core::core::hash::Hash;
|
||||
use core::core::transaction::{self, Transaction};
|
||||
@@ -128,7 +129,7 @@ pub struct PoolEntry {
|
||||
}
|
||||
|
||||
/// The possible states a pool entry can be in.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum PoolEntryState {
|
||||
/// A new entry, not yet processed.
|
||||
Fresh,
|
||||
@@ -163,6 +164,8 @@ pub struct TxSource {
|
||||
pub enum PoolError {
|
||||
/// An invalid pool entry caused by underlying tx validation error
|
||||
InvalidTx(transaction::Error),
|
||||
/// An invalid pool entry caused by underlying block validation error
|
||||
InvalidBlock(block::Error),
|
||||
/// Underlying keychain error.
|
||||
Keychain(keychain::Error),
|
||||
/// Underlying "committed" error.
|
||||
@@ -192,6 +195,12 @@ impl From<transaction::Error> for PoolError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<block::Error> for PoolError {
|
||||
fn from(e: block::Error) -> PoolError {
|
||||
PoolError::InvalidBlock(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<keychain::Error> for PoolError {
|
||||
fn from(e: keychain::Error) -> PoolError {
|
||||
PoolError::Keychain(e)
|
||||
|
||||
@@ -25,7 +25,8 @@ extern crate rand;
|
||||
|
||||
pub mod common;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use util::RwLock;
|
||||
|
||||
use core::core::verifier_cache::LruVerifierCache;
|
||||
use core::core::{Block, BlockHeader, Transaction};
|
||||
@@ -80,7 +81,7 @@ fn test_transaction_pool_block_building() {
|
||||
let child_tx_2 = test_transaction(&keychain, vec![38], vec![32]);
|
||||
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
|
||||
// Add the three root txs to the pool.
|
||||
write_pool
|
||||
@@ -105,7 +106,7 @@ fn test_transaction_pool_block_building() {
|
||||
}
|
||||
|
||||
let txs = {
|
||||
let read_pool = pool.read().unwrap();
|
||||
let read_pool = pool.read();
|
||||
read_pool.prepare_mineable_transactions().unwrap()
|
||||
};
|
||||
// children should have been aggregated into parents
|
||||
@@ -123,7 +124,7 @@ fn test_transaction_pool_block_building() {
|
||||
// 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().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
write_pool.reconcile_block(&block).unwrap();
|
||||
|
||||
assert_eq!(write_pool.total_size(), 0);
|
||||
|
||||
@@ -25,7 +25,8 @@ extern crate rand;
|
||||
|
||||
pub mod common;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use util::RwLock;
|
||||
|
||||
use core::core::{Block, BlockHeader};
|
||||
|
||||
@@ -127,7 +128,7 @@ fn test_transaction_pool_block_reconciliation() {
|
||||
// First we add the above transactions to the pool.
|
||||
// All should be accepted.
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
assert_eq!(write_pool.total_size(), 0);
|
||||
|
||||
for tx in &txs_to_add {
|
||||
@@ -165,13 +166,13 @@ fn test_transaction_pool_block_reconciliation() {
|
||||
|
||||
// Check the pool still contains everything we expect at this point.
|
||||
{
|
||||
let write_pool = pool.write().unwrap();
|
||||
let write_pool = pool.write();
|
||||
assert_eq!(write_pool.total_size(), txs_to_add.len());
|
||||
}
|
||||
|
||||
// And reconcile the pool with this latest block.
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
write_pool.reconcile_block(&block).unwrap();
|
||||
|
||||
assert_eq!(write_pool.total_size(), 4);
|
||||
|
||||
@@ -25,7 +25,8 @@ extern crate rand;
|
||||
|
||||
pub mod common;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use util::RwLock;
|
||||
|
||||
use common::*;
|
||||
use core::core::hash::Hash;
|
||||
@@ -83,7 +84,7 @@ fn test_coinbase_maturity() {
|
||||
let pool = RwLock::new(test_setup(chain, verifier_cache));
|
||||
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
let tx = test_transaction(&keychain, vec![50], vec![49]);
|
||||
match write_pool.add_to_pool(test_source(), tx.clone(), true, &BlockHeader::default()) {
|
||||
Err(PoolError::ImmatureCoinbase) => {}
|
||||
|
||||
@@ -28,7 +28,8 @@ extern crate rand;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use util::RwLock;
|
||||
|
||||
use core::core::hash::{Hash, Hashed};
|
||||
use core::core::verifier_cache::VerifierCache;
|
||||
@@ -98,7 +99,7 @@ impl ChainAdapter {
|
||||
batch.commit().unwrap();
|
||||
|
||||
{
|
||||
let mut utxo = self.utxo.write().unwrap();
|
||||
let mut utxo = self.utxo.write();
|
||||
for x in block.inputs() {
|
||||
utxo.remove(&x.commitment());
|
||||
}
|
||||
@@ -129,7 +130,7 @@ impl BlockChain for ChainAdapter {
|
||||
}
|
||||
|
||||
fn validate_tx(&self, tx: &Transaction) -> Result<(), pool::PoolError> {
|
||||
let utxo = self.utxo.read().unwrap();
|
||||
let utxo = self.utxo.read();
|
||||
|
||||
for x in tx.outputs() {
|
||||
if utxo.contains(&x.commitment()) {
|
||||
|
||||
@@ -25,7 +25,8 @@ extern crate rand;
|
||||
|
||||
pub mod common;
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use util::RwLock;
|
||||
|
||||
use common::*;
|
||||
use core::core::verifier_cache::LruVerifierCache;
|
||||
@@ -72,7 +73,7 @@ fn test_the_transaction_pool() {
|
||||
|
||||
// Add this tx to the pool (stem=false, direct to txpool).
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
write_pool
|
||||
.add_to_pool(test_source(), initial_tx, false, &header)
|
||||
.unwrap();
|
||||
@@ -86,7 +87,7 @@ fn test_the_transaction_pool() {
|
||||
|
||||
// Take a write lock and add a couple of tx entries to the pool.
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
|
||||
// Check we have a single initial tx in the pool.
|
||||
assert_eq!(write_pool.total_size(), 1);
|
||||
@@ -110,7 +111,7 @@ fn test_the_transaction_pool() {
|
||||
// This will fail during tx aggregation due to duplicate outputs and duplicate
|
||||
// kernels.
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
assert!(
|
||||
write_pool
|
||||
.add_to_pool(test_source(), tx1.clone(), true, &header)
|
||||
@@ -122,7 +123,7 @@ fn test_the_transaction_pool() {
|
||||
// tx).
|
||||
{
|
||||
let tx1a = test_transaction(&keychain, vec![500, 600], vec![499, 599]);
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
assert!(
|
||||
write_pool
|
||||
.add_to_pool(test_source(), tx1a, true, &header)
|
||||
@@ -133,7 +134,7 @@ fn test_the_transaction_pool() {
|
||||
// Test adding a tx attempting to spend a non-existent output.
|
||||
{
|
||||
let bad_tx = test_transaction(&keychain, vec![10_001], vec![10_000]);
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
assert!(
|
||||
write_pool
|
||||
.add_to_pool(test_source(), bad_tx, true, &header)
|
||||
@@ -147,7 +148,7 @@ fn test_the_transaction_pool() {
|
||||
// to be immediately stolen via a "replay" tx.
|
||||
{
|
||||
let tx = test_transaction(&keychain, vec![900], vec![498]);
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
assert!(
|
||||
write_pool
|
||||
.add_to_pool(test_source(), tx, true, &header)
|
||||
@@ -157,7 +158,7 @@ fn test_the_transaction_pool() {
|
||||
|
||||
// Confirm the tx pool correctly identifies an invalid tx (already spent).
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
let tx3 = test_transaction(&keychain, vec![500], vec![497]);
|
||||
assert!(
|
||||
write_pool
|
||||
@@ -171,7 +172,7 @@ fn test_the_transaction_pool() {
|
||||
// Check we can take some entries from the stempool and "fluff" them into the
|
||||
// txpool. This also exercises multi-kernel txs.
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
let agg_tx = write_pool
|
||||
.stempool
|
||||
.aggregate_transaction()
|
||||
@@ -189,7 +190,7 @@ fn test_the_transaction_pool() {
|
||||
// We will do this be adding a new tx to the pool
|
||||
// that is a superset of a tx already in the pool.
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
|
||||
let tx4 = test_transaction(&keychain, vec![800], vec![799]);
|
||||
// tx1 and tx2 are already in the txpool (in aggregated form)
|
||||
@@ -210,7 +211,7 @@ fn test_the_transaction_pool() {
|
||||
// Check we cannot "double spend" an output spent in a previous block.
|
||||
// We use the initial coinbase output here for convenience.
|
||||
{
|
||||
let mut write_pool = pool.write().unwrap();
|
||||
let mut write_pool = pool.write();
|
||||
|
||||
let double_spend_tx =
|
||||
{ test_transaction_spending_coinbase(&keychain, &header, vec![1000]) };
|
||||
|
||||
Reference in New Issue
Block a user