diff options
author | Suhas Daftuar <sdaftuar@chaincode.com> | 2016-02-20 21:02:44 -0500 |
---|---|---|
committer | Suhas Daftuar <sdaftuar@gmail.com> | 2016-06-16 12:35:37 -0400 |
commit | c82a4e9a63a28fc8c482c7c8e5b7bfcc51a6805a (patch) | |
tree | 3cd3545c0f596ece7043bf414e8f09143a97ca77 /src/miner.h | |
parent | 44c1b1c9bb54082625c7ad76af25473abf79f866 (diff) |
Use ancestor-feerate based transaction selection for mining
Includes changes by Pieter Wuille
Diffstat (limited to 'src/miner.h')
-rw-r--r-- | src/miner.h | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/src/miner.h b/src/miner.h index 74f19693c4..a9fea85304 100644 --- a/src/miner.h +++ b/src/miner.h @@ -11,6 +11,8 @@ #include <stdint.h> #include <memory> +#include "boost/multi_index_container.hpp" +#include "boost/multi_index/ordered_index.hpp" class CBlockIndex; class CChainParams; @@ -29,6 +31,104 @@ struct CBlockTemplate std::vector<int64_t> vTxSigOps; }; +// Container for tracking updates to ancestor feerate as we include (parent) +// transactions in a block +struct CTxMemPoolModifiedEntry { + CTxMemPoolModifiedEntry(CTxMemPool::txiter entry) + { + iter = entry; + nSizeWithAncestors = entry->GetSizeWithAncestors(); + nModFeesWithAncestors = entry->GetModFeesWithAncestors(); + nSigOpCountWithAncestors = entry->GetSigOpCountWithAncestors(); + } + + CTxMemPool::txiter iter; + uint64_t nSizeWithAncestors; + CAmount nModFeesWithAncestors; + unsigned int nSigOpCountWithAncestors; +}; + +/** Comparator for CTxMemPool::txiter objects. + * It simply compares the internal memory address of the CTxMemPoolEntry object + * pointed to. This means it has no meaning, and is only useful for using them + * as key in other indexes. + */ +struct CompareCTxMemPoolIter { + bool operator()(const CTxMemPool::txiter& a, const CTxMemPool::txiter& b) const + { + return &(*a) < &(*b); + } +}; + +struct modifiedentry_iter { + typedef CTxMemPool::txiter result_type; + result_type operator() (const CTxMemPoolModifiedEntry &entry) const + { + return entry.iter; + } +}; + +// This matches the calculation in CompareTxMemPoolEntryByAncestorFee, +// except operating on CTxMemPoolModifiedEntry. +// TODO: refactor to avoid duplication of this logic. +struct CompareModifiedEntry { + bool operator()(const CTxMemPoolModifiedEntry &a, const CTxMemPoolModifiedEntry &b) + { + double f1 = (double)a.nModFeesWithAncestors * b.nSizeWithAncestors; + double f2 = (double)b.nModFeesWithAncestors * a.nSizeWithAncestors; + if (f1 == f2) { + return CTxMemPool::CompareIteratorByHash()(a.iter, b.iter); + } + return f1 > f2; + } +}; + +// A comparator that sorts transactions based on number of ancestors. +// This is sufficient to sort an ancestor package in an order that is valid +// to appear in a block. +struct CompareTxIterByAncestorCount { + bool operator()(const CTxMemPool::txiter &a, const CTxMemPool::txiter &b) + { + if (a->GetCountWithAncestors() != b->GetCountWithAncestors()) + return a->GetCountWithAncestors() < b->GetCountWithAncestors(); + return CTxMemPool::CompareIteratorByHash()(a, b); + } +}; + +typedef boost::multi_index_container< + CTxMemPoolModifiedEntry, + boost::multi_index::indexed_by< + boost::multi_index::ordered_unique< + modifiedentry_iter, + CompareCTxMemPoolIter + >, + // sorted by modified ancestor fee rate + boost::multi_index::ordered_non_unique< + // Reuse same tag from CTxMemPool's similar index + boost::multi_index::tag<ancestor_score>, + boost::multi_index::identity<CTxMemPoolModifiedEntry>, + CompareModifiedEntry + > + > +> indexed_modified_transaction_set; + +typedef indexed_modified_transaction_set::nth_index<0>::type::iterator modtxiter; +typedef indexed_modified_transaction_set::index<ancestor_score>::type::iterator modtxscoreiter; + +struct update_for_parent_inclusion +{ + update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {} + + void operator() (CTxMemPoolModifiedEntry &e) + { + e.nModFeesWithAncestors -= iter->GetFee(); + e.nSizeWithAncestors -= iter->GetTxSize(); + e.nSigOpCountWithAncestors -= iter->GetSigOpCount(); + } + + CTxMemPool::txiter iter; +}; + /** Generate a new block, without valid proof-of-work */ class BlockAssembler { @@ -74,12 +174,30 @@ private: void addScoreTxs(); /** Add transactions based on tx "priority" */ void addPriorityTxs(); + /** Add transactions based on feerate including unconfirmed ancestors */ + void addPackageTxs(); // helper function for addScoreTxs and addPriorityTxs /** Test if tx will still "fit" in the block */ bool TestForBlock(CTxMemPool::txiter iter); /** Test if tx still has unconfirmed parents not yet in block */ bool isStillDependent(CTxMemPool::txiter iter); + + // helper functions for addPackageTxs() + /** Remove confirmed (inBlock) entries from given set */ + void onlyUnconfirmed(CTxMemPool::setEntries& testSet); + /** Test if a new package would "fit" in the block */ + bool TestPackage(uint64_t packageSize, unsigned int packageSigOps); + /** Test if a set of transactions are all final */ + bool TestPackageFinality(const CTxMemPool::setEntries& package); + /** Return true if given transaction from mapTx has already been evaluated, + * or if the transaction's cached data in mapTx is incorrect. */ + bool SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, CTxMemPool::setEntries &failedTx); + /** Sort the package in an order that is valid to appear in a block */ + void SortForBlock(const CTxMemPool::setEntries& package, CTxMemPool::txiter entry, std::vector<CTxMemPool::txiter>& sortedEntries); + /** Add descendants of given transactions to mapModifiedTx with ancestor + * state updated assuming given transactions are inBlock. */ + void UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set &mapModifiedTx); }; /** Modify the extranonce in a block */ |