Cleanup build warnings (#87)
* minor cleanup - unused imports * cleanup build warnings - unused vars * make structs pub to get rid of the private_in_public lint warning * missing docs on RangeProof * add missing docs to store delete function * cleaned up deprecation warning - tokio_core -> tokio_io complete() -> send()
This commit is contained in:
committed by
Ignotus Peverell
parent
131ea2f799
commit
3b4a48b2fd
@@ -1,7 +1,7 @@
|
||||
// This file is (hopefully) temporary.
|
||||
//
|
||||
// It contains a trait based on (but not exactly equal to) the trait defined
|
||||
// for the blockchain UTXO set, discussed at
|
||||
// for the blockchain UTXO set, discussed at
|
||||
// https://github.com/ignopeverell/grin/issues/29, and a dummy implementation
|
||||
// of said trait.
|
||||
// Notably, UtxoDiff has been left off, and the question of how to handle
|
||||
@@ -20,11 +20,12 @@ use std::sync::RwLock;
|
||||
|
||||
use types::BlockChain;
|
||||
|
||||
/// A DummyUtxoSet for mocking up the chain
|
||||
/// A DummyUtxoSet for mocking up the chain
|
||||
pub struct DummyUtxoSet {
|
||||
outputs : HashMap<Commitment, transaction::Output>
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl DummyUtxoSet {
|
||||
pub fn empty() -> DummyUtxoSet{
|
||||
DummyUtxoSet{outputs: HashMap::new()}
|
||||
@@ -50,7 +51,7 @@ impl DummyUtxoSet {
|
||||
self.outputs.insert(output.commitment(), output.clone());
|
||||
}
|
||||
}
|
||||
pub fn rewind(&self, b: &block::Block) -> DummyUtxoSet {
|
||||
pub fn rewind(&self, _: &block::Block) -> DummyUtxoSet {
|
||||
DummyUtxoSet{outputs: HashMap::new()}
|
||||
}
|
||||
pub fn get_output(&self, output_ref: &Commitment) -> Option<&transaction::Output> {
|
||||
@@ -75,10 +76,12 @@ impl DummyUtxoSet {
|
||||
|
||||
/// A DummyChain is the mocked chain for playing with what methods we would
|
||||
/// need
|
||||
#[allow(dead_code)]
|
||||
pub struct DummyChainImpl {
|
||||
utxo: RwLock<DummyUtxoSet>
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl DummyChainImpl {
|
||||
pub fn new() -> DummyChainImpl {
|
||||
DummyChainImpl{
|
||||
|
||||
+29
-16
@@ -15,15 +15,9 @@
|
||||
//! Base types for the transaction pool's Directed Acyclic Graphs
|
||||
|
||||
use std::vec::Vec;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
use std::sync::Weak;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use secp::pedersen::Commitment;
|
||||
use secp::{Secp256k1, ContextFlag};
|
||||
use secp::key;
|
||||
|
||||
use time;
|
||||
use rand;
|
||||
@@ -36,24 +30,28 @@ use core::core;
|
||||
/// These are the vertices of both of the graph structures
|
||||
pub struct PoolEntry {
|
||||
// Core data
|
||||
// Unique identifier of this pool entry and the corresponding transaction
|
||||
/// Unique identifier of this pool entry and the corresponding transaction
|
||||
pub transaction_hash: core::hash::Hash,
|
||||
|
||||
// Metadata
|
||||
size_estimate: u64,
|
||||
// Metadata
|
||||
/// Size estimate
|
||||
pub size_estimate: u64,
|
||||
/// Receive timestamp
|
||||
pub receive_ts: time::Tm,
|
||||
}
|
||||
|
||||
impl PoolEntry {
|
||||
/// Create new transaction pool entry
|
||||
pub fn new(tx: &core::transaction::Transaction) -> PoolEntry {
|
||||
PoolEntry{
|
||||
transaction_hash: transaction_identifier(tx),
|
||||
size_estimate : estimate_transaction_size(tx),
|
||||
receive_ts: time::now()}
|
||||
receive_ts: time::now()}
|
||||
}
|
||||
}
|
||||
|
||||
fn estimate_transaction_size(tx: &core::transaction::Transaction) -> u64 {
|
||||
/// TODO guessing this needs implementing
|
||||
fn estimate_transaction_size(_tx: &core::transaction::Transaction) -> u64 {
|
||||
0
|
||||
}
|
||||
|
||||
@@ -72,24 +70,32 @@ pub struct Edge {
|
||||
}
|
||||
|
||||
impl Edge{
|
||||
/// Create new edge
|
||||
pub fn new(source: Option<core::hash::Hash>, destination: Option<core::hash::Hash>, output: Commitment) -> Edge {
|
||||
Edge{source: source, destination: destination, output: output}
|
||||
}
|
||||
|
||||
/// Create new edge with a source
|
||||
pub fn with_source(&self, src: Option<core::hash::Hash>) -> Edge {
|
||||
Edge{source: src, destination: self.destination, output: self.output}
|
||||
}
|
||||
|
||||
/// Create new edge with destination
|
||||
pub fn with_destination(&self, dst: Option<core::hash::Hash>) -> Edge {
|
||||
Edge{source: self.source, destination: dst, output: self.output}
|
||||
}
|
||||
|
||||
/// The output commitment of the edge
|
||||
pub fn output_commitment(&self) -> Commitment {
|
||||
self.output
|
||||
}
|
||||
|
||||
/// The destination hash of the edge
|
||||
pub fn destination_hash(&self) -> Option<core::hash::Hash> {
|
||||
self.destination
|
||||
}
|
||||
|
||||
/// The source hash of the edge
|
||||
pub fn source_hash(&self) -> Option<core::hash::Hash> {
|
||||
self.source
|
||||
}
|
||||
@@ -108,13 +114,14 @@ pub struct DirectedGraph {
|
||||
edges: HashMap<Commitment, Edge>,
|
||||
vertices: Vec<PoolEntry>,
|
||||
|
||||
// A small optimization: keeping roots (vertices with in-degree 0) in a
|
||||
// A small optimization: keeping roots (vertices with in-degree 0) in a
|
||||
// separate list makes topological sort a bit faster. (This is true for
|
||||
// Kahn's, not sure about other implementations)
|
||||
roots: Vec<PoolEntry>,
|
||||
}
|
||||
|
||||
impl DirectedGraph {
|
||||
/// Create an empty directed graph
|
||||
pub fn empty() -> DirectedGraph {
|
||||
DirectedGraph{
|
||||
edges: HashMap::new(),
|
||||
@@ -123,14 +130,17 @@ impl DirectedGraph {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an edge by its commitment
|
||||
pub fn get_edge_by_commitment(&self, output_commitment: &Commitment) -> Option<&Edge> {
|
||||
self.edges.get(output_commitment)
|
||||
}
|
||||
|
||||
/// Remove an edge by its commitment
|
||||
pub fn remove_edge_by_commitment(&mut self, output_commitment: &Commitment) -> Option<Edge> {
|
||||
self.edges.remove(output_commitment)
|
||||
}
|
||||
|
||||
/// Remove a vertex by its hash
|
||||
pub fn remove_vertex(&mut self, tx_hash: core::hash::Hash) -> Option<PoolEntry> {
|
||||
match self.roots.iter().position(|x| x.transaction_hash == tx_hash) {
|
||||
Some(i) => Some(self.roots.swap_remove(i)),
|
||||
@@ -163,8 +173,8 @@ impl DirectedGraph {
|
||||
}
|
||||
}
|
||||
|
||||
// add_vertex_only adds a vertex, meant to be complemented by add_edge_only
|
||||
// in cases where delivering a vector of edges is not feasible or efficient
|
||||
/// add_vertex_only adds a vertex, meant to be complemented by add_edge_only
|
||||
/// in cases where delivering a vector of edges is not feasible or efficient
|
||||
pub fn add_vertex_only(&mut self, vertex: PoolEntry, is_root: bool) {
|
||||
if is_root {
|
||||
self.roots.push(vertex);
|
||||
@@ -173,6 +183,7 @@ impl DirectedGraph {
|
||||
}
|
||||
}
|
||||
|
||||
/// add_edge_only adds an edge
|
||||
pub fn add_edge_only(&mut self, edge: Edge) {
|
||||
self.edges.insert(edge.output_commitment(), edge);
|
||||
}
|
||||
@@ -181,7 +192,7 @@ impl DirectedGraph {
|
||||
pub fn len_vertices(&self) -> usize {
|
||||
self.vertices.len() + self.roots.len()
|
||||
}
|
||||
|
||||
|
||||
/// Number of root vertices only
|
||||
pub fn len_roots(&self) -> usize {
|
||||
self.roots.len()
|
||||
@@ -209,6 +220,8 @@ pub fn transaction_identifier(tx: &core::transaction::Transaction) -> core::hash
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use secp::{Secp256k1, ContextFlag};
|
||||
use secp::key;
|
||||
|
||||
#[test]
|
||||
fn test_add_entry() {
|
||||
@@ -243,7 +256,7 @@ mod tests {
|
||||
}
|
||||
|
||||
/// For testing/debugging: a random tx hash
|
||||
fn random_hash() -> core::hash::Hash {
|
||||
pub fn random_hash() -> core::hash::Hash {
|
||||
let hash_bytes: [u8;32]= rand::random();
|
||||
core::hash::Hash(hash_bytes)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ mod pool;
|
||||
|
||||
extern crate time;
|
||||
extern crate rand;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
extern crate grin_core as core;
|
||||
|
||||
+48
-44
@@ -20,22 +20,22 @@ pub use graph;
|
||||
use core::core::transaction;
|
||||
use core::core::block;
|
||||
use core::core::hash;
|
||||
// Temporary blockchain dummy impls
|
||||
use blockchain::{DummyChain, DummyChainImpl, DummyUtxoSet};
|
||||
|
||||
use secp;
|
||||
use secp::pedersen::Commitment;
|
||||
|
||||
use std::sync::{Arc, RwLock, Weak};
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// The pool itself.
|
||||
/// The transactions HashMap holds ownership of all transactions in the pool,
|
||||
/// keyed by their transaction hash.
|
||||
pub struct TransactionPool<T> {
|
||||
/// All transactions in the pool
|
||||
pub transactions: HashMap<hash::Hash, Box<transaction::Transaction>>,
|
||||
|
||||
/// The pool itself
|
||||
pub pool : Pool,
|
||||
/// Orphans in the pool
|
||||
pub orphans: Orphans,
|
||||
|
||||
// blockchain is a DummyChain, for now, which mimics what the future
|
||||
@@ -44,6 +44,7 @@ pub struct TransactionPool<T> {
|
||||
}
|
||||
|
||||
impl<T> TransactionPool<T> where T: BlockChain {
|
||||
/// Create a new transaction pool
|
||||
pub fn new(chain: Arc<T>) -> TransactionPool<T> {
|
||||
TransactionPool{
|
||||
transactions: HashMap::new(),
|
||||
@@ -53,15 +54,15 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
}
|
||||
}
|
||||
|
||||
/// Searches for an output, designated by its commitment, from the current
|
||||
/// Searches for an output, designated by its commitment, from the current
|
||||
/// best UTXO view, presented by taking the best blockchain UTXO set (as
|
||||
/// determined by the blockchain component) and rectifying pool spent and
|
||||
/// unspents.
|
||||
/// Detects double spends and unknown references from the pool and
|
||||
/// Detects double spends and unknown references from the pool and
|
||||
/// blockchain only; any conflicts with entries in the orphans set must
|
||||
/// be accounted for separately, if relevant.
|
||||
pub fn search_for_best_output(&self, output_commitment: &Commitment) -> Parent {
|
||||
// The current best unspent set is:
|
||||
// The current best unspent set is:
|
||||
// Pool unspent + (blockchain unspent - pool->blockchain spent)
|
||||
// Pool unspents are unconditional so we check those first
|
||||
self.pool.get_available_output(output_commitment).
|
||||
@@ -76,7 +77,7 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
// output designated by output_commitment.
|
||||
fn search_blockchain_unspents(&self, output_commitment: &Commitment) -> Option<Parent> {
|
||||
self.blockchain.get_unspent(output_commitment).
|
||||
map(|o| match self.pool.get_blockchain_spent(output_commitment) {
|
||||
map(|_| match self.pool.get_blockchain_spent(output_commitment) {
|
||||
Some(x) => Parent::AlreadySpent{other_tx: x.destination_hash().unwrap()},
|
||||
None => Parent::BlockTransaction,
|
||||
})
|
||||
@@ -96,10 +97,12 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
self.pool.num_transactions()
|
||||
}
|
||||
|
||||
/// Get the number of orphans in the pool
|
||||
pub fn orphans_size(&self) -> usize {
|
||||
self.orphans.num_transactions()
|
||||
}
|
||||
|
||||
/// Get the total size (transactions + orphans) of the pool
|
||||
pub fn total_size(&self) -> usize {
|
||||
self.pool.num_transactions() + self.orphans.num_transactions()
|
||||
}
|
||||
@@ -110,15 +113,15 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
/// if necessary, and performing any connection-related validity checks.
|
||||
/// Happens under an exclusive mutable reference gated by the write portion
|
||||
/// of a RWLock.
|
||||
pub fn add_to_memory_pool(&mut self, source: TxSource, tx: transaction::Transaction) -> Result<(), PoolError> {
|
||||
pub fn add_to_memory_pool(&mut self, _: TxSource, tx: transaction::Transaction) -> Result<(), PoolError> {
|
||||
// Making sure the transaction is valid before anything else.
|
||||
let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
|
||||
tx.validate(&secp).map_err(|_| PoolError::Invalid)?;
|
||||
|
||||
// The first check invovles ensuring that an identical transaction is
|
||||
// The first check invovles ensuring that an identical transaction is
|
||||
// not already in the pool's transaction set.
|
||||
// A non-authoritative similar check should be performed under the
|
||||
// pool's read lock before we get to this point, which would catch the
|
||||
// A non-authoritative similar check should be performed under the
|
||||
// pool's read lock before we get to this point, which would catch the
|
||||
// majority of duplicate cases. The race condition is caught here.
|
||||
// TODO: When the transaction identifier is finalized, the assumptions
|
||||
// here may change depending on the exact coverage of the identifier.
|
||||
@@ -156,7 +159,7 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
|
||||
// Next we examine the outputs this transaction creates and ensure
|
||||
// that they do not already exist.
|
||||
// I believe its worth preventing duplicate outputs from being
|
||||
// I believe its worth preventing duplicate outputs from being
|
||||
// accepted, even though it is possible for them to be mined
|
||||
// with strict ordering. In the future, if desirable, this could
|
||||
// be node policy config or more intelligent.
|
||||
@@ -182,8 +185,8 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
// output is unique. No further checks are necessary.
|
||||
self.pool.add_pool_transaction(pool_entry, blockchain_refs,
|
||||
pool_refs, new_unspents);
|
||||
|
||||
self.reconcile_orphans();
|
||||
|
||||
self.reconcile_orphans().unwrap();
|
||||
self.transactions.insert(tx_hash, Box::new(tx));
|
||||
Ok(())
|
||||
|
||||
@@ -194,11 +197,11 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
// checking above.
|
||||
// First, any references resolved to the pool need to be compared
|
||||
// against active orphan pool_connections.
|
||||
// Note that pool_connections here also does double duty to
|
||||
// Note that pool_connections here also does double duty to
|
||||
// account for blockchain connections.
|
||||
for pool_ref in pool_refs.iter().chain(blockchain_refs.iter()) {
|
||||
match self.orphans.get_external_spent_output(&pool_ref.output_commitment()){
|
||||
// Should the below err be subtyped to orphans somehow?
|
||||
// Should the below err be subtyped to orphans somehow?
|
||||
Some(x) => return Err(PoolError::DoubleSpend{other_tx: x.destination_hash().unwrap(), spent_output: x.output_commitment()}),
|
||||
None => {},
|
||||
}
|
||||
@@ -223,8 +226,8 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
/// Check the output for a conflict with an existing output.
|
||||
///
|
||||
/// Checks the output (by commitment) against outputs in the blockchain
|
||||
/// or in the pool. If the transaction is destined for orphans, the
|
||||
/// orphans set is checked as well.
|
||||
/// or in the pool. If the transaction is destined for orphans, the
|
||||
/// orphans set is checked as well.
|
||||
fn check_duplicate_outputs(&self, output : &transaction::Output, is_orphan: bool) -> Result<(), PoolError> {
|
||||
// Checking against current blockchain unspent outputs
|
||||
// We want outputs even if they're spent by pool txs, so we ignore
|
||||
@@ -249,7 +252,7 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
};
|
||||
|
||||
|
||||
// If the transaction might go into orphans, perform the same
|
||||
// If the transaction might go into orphans, perform the same
|
||||
// checks as above but against the orphan set instead.
|
||||
if is_orphan {
|
||||
// Checking against orphan outputs
|
||||
@@ -295,7 +298,7 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
None => {
|
||||
// The reference does not resolve to anything.
|
||||
// Make sure this missing_output has not already
|
||||
// been claimed, then add this entry to
|
||||
// been claimed, then add this entry to
|
||||
// missing_refs
|
||||
match self.orphans.get_unknown_output(&orphan_commitment) {
|
||||
Some(x) => return Err(PoolError::DoubleSpend{
|
||||
@@ -311,7 +314,7 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
Ok(missing_refs)
|
||||
}
|
||||
|
||||
/// The primary goal of the reconcile_orphans method is to eliminate any
|
||||
/// The primary goal of the reconcile_orphans method is to eliminate any
|
||||
/// orphans who conflict with the recently accepted pool transaction.
|
||||
/// TODO: How do we handle fishing orphans out that look like they could
|
||||
/// be freed? Current thought is to do so under a different lock domain
|
||||
@@ -332,9 +335,9 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
///
|
||||
/// Returns a list of transactions which have been evicted from the pool
|
||||
/// due to the recent block. Because transaction association information is
|
||||
/// irreversibly lost in the blockchain, we must keep track of these
|
||||
/// irreversibly lost in the blockchain, we must keep track of these
|
||||
/// evicted transactions elsewhere so that we can make a best effort at
|
||||
/// returning them to the pool in the event of a reorg that invalidates
|
||||
/// returning them to the pool in the event of a reorg that invalidates
|
||||
/// this block.
|
||||
pub fn reconcile_block(&mut self, block: &block::Block) -> Result<Vec<Box<transaction::Transaction>>, PoolError> {
|
||||
// If this pool has been kept in sync correctly, serializing all
|
||||
@@ -350,7 +353,7 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
// consumes the same blockchain output.
|
||||
// If one exists, we mark the transaction and then examine its
|
||||
// children. Recursively, we mark each child until a child is
|
||||
// fully satisfied by outputs in the updated utxo view (after
|
||||
// fully satisfied by outputs in the updated utxo view (after
|
||||
// reconciliation of the block), or there are no more children.
|
||||
//
|
||||
// Additionally, to protect our invariant dictating no duplicate
|
||||
@@ -358,11 +361,11 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
// against outputs generated by the pool and the corresponding
|
||||
// transactions are also marked.
|
||||
//
|
||||
// After marking concludes, sweeping begins. In order, the marked
|
||||
// After marking concludes, sweeping begins. In order, the marked
|
||||
// transactions are removed, the vertexes corresponding to the
|
||||
// transactions are removed, all the marked transactions' outputs are
|
||||
// removed, and all remaining non-blockchain inputs are returned to the
|
||||
// unspent_outputs set.
|
||||
// unspent_outputs set.
|
||||
//
|
||||
// After the pool has been successfully processed, an orphans
|
||||
// reconciliation job is triggered.
|
||||
@@ -389,7 +392,7 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
}
|
||||
let freed_txs = self.sweep_transactions(marked_transactions);
|
||||
|
||||
self.reconcile_orphans();
|
||||
self.reconcile_orphans().unwrap();
|
||||
|
||||
Ok(freed_txs)
|
||||
}
|
||||
@@ -397,9 +400,9 @@ impl<T> TransactionPool<T> where T: BlockChain {
|
||||
/// The mark portion of our mark-and-sweep pool cleanup.
|
||||
///
|
||||
/// The transaction designated by conflicting_tx is immediately marked.
|
||||
/// Each output of this transaction is then examined; if a transaction in
|
||||
/// the pool spends this output and the output is not replaced by an
|
||||
/// identical output included in the updated UTXO set, the child is marked
|
||||
/// Each output of this transaction is then examined; if a transaction in
|
||||
/// the pool spends this output and the output is not replaced by an
|
||||
/// identical output included in the updated UTXO set, the child is marked
|
||||
/// as well and the process continues recursively.
|
||||
///
|
||||
/// Marked transactions are added to the mutable marked_txs HashMap which
|
||||
@@ -466,6 +469,8 @@ mod tests {
|
||||
use secp::{Secp256k1, ContextFlag, constants};
|
||||
use secp::key;
|
||||
use core::core::build;
|
||||
use blockchain::{DummyChain, DummyChainImpl, DummyUtxoSet};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
macro_rules! expect_output_parent {
|
||||
($pool:expr, $expected:pat, $( $output:expr ),+ ) => {
|
||||
@@ -478,7 +483,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
/// A basic test; add a pair of transactions to the pool.
|
||||
fn test_basic_pool_add() {
|
||||
@@ -542,7 +546,8 @@ mod tests {
|
||||
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
|
||||
#[test]
|
||||
/// Testing various expected error conditions
|
||||
pub fn test_pool_add_error() {
|
||||
let mut dummy_chain = DummyChainImpl::new();
|
||||
@@ -595,7 +600,7 @@ mod tests {
|
||||
Ok(_) => panic!("Expected error when adding double spend, got Ok"),
|
||||
Err(x) => {
|
||||
match x {
|
||||
PoolError::DoubleSpend{other_tx, spent_output} => {
|
||||
PoolError::DoubleSpend{other_tx: _, spent_output} => {
|
||||
if spent_output != test_output(6).commitment() {
|
||||
panic!("Unexpected parameter in DoubleSpend: {:?}", x);
|
||||
}
|
||||
@@ -647,7 +652,7 @@ mod tests {
|
||||
let pool = RwLock::new(test_setup(&chain_ref));
|
||||
|
||||
// Preparation: We will introduce a three root pool transactions.
|
||||
// 1. A transaction that should be invalidated because it is exactly
|
||||
// 1. A transaction that should be invalidated because it is exactly
|
||||
// contained in the block.
|
||||
// 2. A transaction that should be invalidated because the input is
|
||||
// consumed in the block, although it is not exactly consumed.
|
||||
@@ -657,7 +662,7 @@ mod tests {
|
||||
let valid_transaction = test_transaction(vec![30], vec![14,15]);
|
||||
|
||||
// We will also introduce a few children:
|
||||
// 4. A transaction that descends from transaction 1, that is in
|
||||
// 4. A transaction that descends from transaction 1, that is in
|
||||
// turn exactly contained in the block.
|
||||
let block_child = test_transaction(vec![8], vec![4,3]);
|
||||
// 5. A transaction that descends from transaction 4, that is not
|
||||
@@ -681,9 +686,9 @@ mod tests {
|
||||
// transaction 9
|
||||
let mixed_child = test_transaction(vec![11,13], vec![2]);
|
||||
|
||||
// Add transactions.
|
||||
// Add transactions.
|
||||
// Note: There are some ordering constraints that must be followed here
|
||||
// until orphans is 100% implemented. Once the orphans process has
|
||||
// until orphans is 100% implemented. Once the orphans process has
|
||||
// stabilized, we can mix these up to exercise that path a bit.
|
||||
let mut txs_to_add = vec![block_transaction, conflict_transaction,
|
||||
valid_transaction, block_child, pool_child, conflict_child,
|
||||
@@ -755,7 +760,7 @@ mod tests {
|
||||
expect_output_parent!(read_pool,
|
||||
Parent::AlreadySpent{other_tx: _}, 15);
|
||||
|
||||
// We should have unspent pool references at 1, 13, 14
|
||||
// We should have unspent pool references at 1, 13, 14
|
||||
expect_output_parent!(read_pool,
|
||||
Parent::PoolTransaction{tx_ref: _}, 1, 13, 14);
|
||||
|
||||
@@ -765,9 +770,8 @@ mod tests {
|
||||
// Evicted transactions should have unknown outputs
|
||||
expect_output_parent!(read_pool, Parent::Unknown, 2, 11);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Test transaction selection and block building.
|
||||
fn test_block_building() {
|
||||
@@ -819,7 +823,7 @@ mod tests {
|
||||
txs = read_pool.prepare_mineable_transactions(3);
|
||||
assert_eq!(txs.len(), 3);
|
||||
// TODO: This is ugly, either make block::new take owned
|
||||
// txs instead of mut refs, or change
|
||||
// txs instead of mut refs, or change
|
||||
// prepare_mineable_transactions to return mut refs
|
||||
let block_txs: Vec<transaction::Transaction> = txs.drain(..).map(|x| *x).collect();
|
||||
let tx_refs = block_txs.iter().collect();
|
||||
@@ -840,7 +844,7 @@ mod tests {
|
||||
assert_eq!(write_pool.total_size(), 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -856,7 +860,7 @@ mod tests {
|
||||
/// Cobble together a test transaction for testing the transaction pool.
|
||||
///
|
||||
/// Connectivity here is the most important element.
|
||||
/// Every output is given a blinding key equal to its value, so that the
|
||||
/// Every output is given a blinding key equal to its value, so that the
|
||||
/// entire commitment can be derived deterministically from just the value.
|
||||
///
|
||||
/// Fees are the remainder between input and output values, so the numbers
|
||||
|
||||
+43
-33
@@ -16,10 +16,6 @@
|
||||
//! and its top-level members.
|
||||
|
||||
use std::vec::Vec;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
use std::sync::Weak;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::iter::Iterator;
|
||||
use std::fmt;
|
||||
@@ -28,19 +24,16 @@ use secp::pedersen::Commitment;
|
||||
|
||||
pub use graph;
|
||||
|
||||
use time;
|
||||
|
||||
use core::core::transaction;
|
||||
use core::core::block;
|
||||
use core::core::hash;
|
||||
|
||||
/// Placeholder: the data representing where we heard about a tx from.
|
||||
///
|
||||
/// Used to make decisions based on transaction acceptance priority from
|
||||
/// Used to make decisions based on transaction acceptance priority from
|
||||
/// various sources. For example, a node may want to bypass pool size
|
||||
/// restrictions when accepting a transaction from a local wallet.
|
||||
///
|
||||
/// Most likely this will evolve to contain some sort of network identifier,
|
||||
/// Most likely this will evolve to contain some sort of network identifier,
|
||||
/// once we get a better sense of what transaction building might look like.
|
||||
pub struct TxSource {
|
||||
/// Human-readable name used for logging and errors.
|
||||
@@ -71,14 +64,31 @@ impl fmt::Debug for Parent {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO document this enum more accurately
|
||||
/// Enum of errors
|
||||
#[derive(Debug)]
|
||||
pub enum PoolError {
|
||||
/// An invalid pool entry
|
||||
Invalid,
|
||||
/// An entry already in the pool
|
||||
AlreadyInPool,
|
||||
DuplicateOutput{other_tx: Option<hash::Hash>, in_chain: bool,
|
||||
output: Commitment},
|
||||
DoubleSpend{other_tx: hash::Hash, spent_output: Commitment},
|
||||
// An orphan successfully added to the orphans set
|
||||
/// A duplicate output
|
||||
DuplicateOutput{
|
||||
/// The other transaction
|
||||
other_tx: Option<hash::Hash>,
|
||||
/// Is in chain?
|
||||
in_chain: bool,
|
||||
/// The output
|
||||
output: Commitment
|
||||
},
|
||||
/// A double spend
|
||||
DoubleSpend{
|
||||
/// The other transaction
|
||||
other_tx: hash::Hash,
|
||||
/// The spent output
|
||||
spent_output: Commitment
|
||||
},
|
||||
/// An orphan successfully added to the orphans set
|
||||
OrphanTransaction,
|
||||
}
|
||||
|
||||
@@ -95,9 +105,9 @@ pub trait BlockChain {
|
||||
/// the blockchain.
|
||||
/// Reservations of outputs by orphan transactions (not fully connected) are
|
||||
/// not respected.
|
||||
/// Spending references (input -> output) exist in two structures: internal
|
||||
/// graph references are contained in the pool edge sets, while references
|
||||
/// sourced from the blockchain's UTXO set are contained in the
|
||||
/// Spending references (input -> output) exist in two structures: internal
|
||||
/// graph references are contained in the pool edge sets, while references
|
||||
/// sourced from the blockchain's UTXO set are contained in the
|
||||
/// blockchain_connections set.
|
||||
/// Spent by references (output-> input) exist in two structures: pool-pool
|
||||
/// connections are in the pool edge set, while unspent (dangling) references
|
||||
@@ -105,12 +115,12 @@ pub trait BlockChain {
|
||||
pub struct Pool {
|
||||
graph : graph::DirectedGraph,
|
||||
|
||||
// available_outputs are unspent outputs of the current pool set,
|
||||
// maintained as edges with empty destinations, keyed by the
|
||||
// available_outputs are unspent outputs of the current pool set,
|
||||
// maintained as edges with empty destinations, keyed by the
|
||||
// output's hash.
|
||||
available_outputs: HashMap<Commitment, graph::Edge>,
|
||||
|
||||
// Consumed blockchain utxo's are kept in a separate map.
|
||||
// Consumed blockchain utxo's are kept in a separate map.
|
||||
consumed_blockchain_outputs: HashMap<Commitment, graph::Edge>
|
||||
}
|
||||
|
||||
@@ -209,7 +219,7 @@ impl Pool {
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactionGraphContainer for Pool {
|
||||
impl TransactionGraphContainer for Pool {
|
||||
fn get_graph(&self) -> &graph::DirectedGraph {
|
||||
&self.graph
|
||||
}
|
||||
@@ -225,21 +235,21 @@ impl TransactionGraphContainer for Pool {
|
||||
}
|
||||
|
||||
/// Orphans contains the elements of the transaction graph that have not been
|
||||
/// connected in full to the blockchain.
|
||||
/// connected in full to the blockchain.
|
||||
pub struct Orphans {
|
||||
graph : graph::DirectedGraph,
|
||||
|
||||
// available_outputs are unspent outputs of the current orphan set,
|
||||
// available_outputs are unspent outputs of the current orphan set,
|
||||
// maintained as edges with empty destinations.
|
||||
available_outputs: HashMap<Commitment, graph::Edge>,
|
||||
|
||||
// missing_outputs are spending references (inputs) with missing
|
||||
// missing_outputs are spending references (inputs) with missing
|
||||
// corresponding outputs, maintained as edges with empty sources.
|
||||
missing_outputs: HashMap<Commitment, graph::Edge>,
|
||||
|
||||
// pool_connections are bidirectional edges which connect to the pool
|
||||
// graph. They should map one-to-one to pool graph available_outputs.
|
||||
// pool_connections should not be viewed authoritatively, they are
|
||||
// graph. They should map one-to-one to pool graph available_outputs.
|
||||
// pool_connections should not be viewed authoritatively, they are
|
||||
// merely informational until the transaction is officially connected to
|
||||
// the pool.
|
||||
pool_connections: HashMap<Commitment, graph::Edge>,
|
||||
@@ -255,12 +265,12 @@ impl Orphans {
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks for a double spent output, given the hash of the output,
|
||||
/// Checks for a double spent output, given the hash of the output,
|
||||
/// ONLY in the data maintained by the orphans set. This includes links
|
||||
/// to the pool as well as links internal to orphan transactions.
|
||||
/// Returns the transaction hash corresponding to the conflicting
|
||||
/// transaction.
|
||||
fn check_double_spend(&self, o: transaction::Output) -> Option<hash::Hash> {
|
||||
pub fn check_double_spend(&self, o: transaction::Output) -> Option<hash::Hash> {
|
||||
self.graph.get_edge_by_commitment(&o.commitment()).or(self.pool_connections.get(&o.commitment())).map(|x| x.destination_hash().unwrap())
|
||||
}
|
||||
|
||||
@@ -340,14 +350,14 @@ impl TransactionGraphContainer for Orphans {
|
||||
/// consumed by another transaction in this graph,
|
||||
/// 3) [External] Unspent: An output produced by a transaction in this graph
|
||||
/// that is not yet spent.
|
||||
///
|
||||
///
|
||||
/// There is no concept of an external "spent by" reference (output produced by
|
||||
/// a transaction in the graph spent by a transaction in another source), as
|
||||
/// a transaction in the graph spent by a transaction in another source), as
|
||||
/// these references are expected to be maintained by descendent graph. Outputs
|
||||
/// follow a heirarchy (Blockchain -> Pool -> Orphans) where each descendent
|
||||
/// exists at a lower priority than their parent. An output consumed by a
|
||||
/// follow a heirarchy (Blockchain -> Pool -> Orphans) where each descendent
|
||||
/// exists at a lower priority than their parent. An output consumed by a
|
||||
/// child graph is marked as unspent in the parent graph and an external spent
|
||||
/// in the child. This ensures that no descendent set must modify state in a
|
||||
/// in the child. This ensures that no descendent set must modify state in a
|
||||
/// set of higher priority.
|
||||
pub trait TransactionGraphContainer {
|
||||
/// Accessor for graph object
|
||||
@@ -365,7 +375,7 @@ pub trait TransactionGraphContainer {
|
||||
self.get_available_output(c).is_some()
|
||||
}
|
||||
|
||||
/// Checks if the pool has anything by this output already, between
|
||||
/// Checks if the pool has anything by this output already, between
|
||||
/// available outputs and internal ones.
|
||||
fn find_output(&self, c: &Commitment) -> Option<hash::Hash> {
|
||||
self.get_available_output(c).
|
||||
|
||||
Reference in New Issue
Block a user