aboutsummaryrefslogtreecommitdiff
path: root/src/miner.h
diff options
context:
space:
mode:
authorSuhas Daftuar <sdaftuar@chaincode.com>2016-02-20 21:02:44 -0500
committerSuhas Daftuar <sdaftuar@gmail.com>2016-06-16 12:35:37 -0400
commitc82a4e9a63a28fc8c482c7c8e5b7bfcc51a6805a (patch)
tree3cd3545c0f596ece7043bf414e8f09143a97ca77 /src/miner.h
parent44c1b1c9bb54082625c7ad76af25473abf79f866 (diff)
downloadbitcoin-c82a4e9a63a28fc8c482c7c8e5b7bfcc51a6805a.tar.xz
Use ancestor-feerate based transaction selection for mining
Includes changes by Pieter Wuille
Diffstat (limited to 'src/miner.h')
-rw-r--r--src/miner.h118
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 */