Track coinbase spends in CTxMemPoolEntry
This allows us to optimize CTxMemPool::removeForReorg.
This commit is contained in:
parent
fe5cef0555
commit
a4b2518068
|
@ -83,7 +83,7 @@ TEST(Mempool, PriorityStatsDoNotCrash) {
|
|||
unsigned int nHeight = 92045;
|
||||
double dPriority = view.GetPriority(tx, nHeight);
|
||||
|
||||
CTxMemPoolEntry entry(tx, nFees, nTime, dPriority, nHeight, true);
|
||||
CTxMemPoolEntry entry(tx, nFees, nTime, dPriority, nHeight, true, false);
|
||||
|
||||
// Check it does not crash (ie. the death test fails)
|
||||
EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(testPool.addUnchecked(tx.GetHash(), entry), ""), "");
|
||||
|
|
13
src/main.cpp
13
src/main.cpp
|
@ -1188,7 +1188,18 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||
CAmount nFees = nValueIn-nValueOut;
|
||||
double dPriority = view.GetPriority(tx, chainActive.Height());
|
||||
|
||||
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx));
|
||||
// Keep track of transactions that spend a coinbase, which we re-scan
|
||||
// during reorgs to ensure COINBASE_MATURITY is still met.
|
||||
bool fSpendsCoinbase = false;
|
||||
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
|
||||
const CCoins *coins = view.AccessCoins(txin.prevout.hash);
|
||||
if (coins->IsCoinBase()) {
|
||||
fSpendsCoinbase = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx), fSpendsCoinbase);
|
||||
unsigned int nSize = entry.GetTxSize();
|
||||
|
||||
// Accept a tx if it contains joinsplits and has at least the default fee specified by z_sendmany.
|
||||
|
|
|
@ -285,7 +285,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
{
|
||||
tx.vout[0].nValue -= 10;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
|
||||
bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
|
||||
tx.vin[0].prevout.hash = hash;
|
||||
}
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
|
@ -305,7 +306,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
{
|
||||
tx.vout[0].nValue -= 350;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
|
||||
bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
|
||||
tx.vin[0].prevout.hash = hash;
|
||||
}
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
|
@ -324,7 +326,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
|
||||
tx.vout[0].nValue = 39000LL;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
|
||||
tx.vin[0].prevout.hash = hash;
|
||||
tx.vin.resize(2);
|
||||
tx.vin[1].scriptSig = CScript() << OP_1;
|
||||
|
@ -332,7 +334,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
tx.vin[1].prevout.n = 0;
|
||||
tx.vout[0].nValue = 49000LL;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
delete pblocktemplate;
|
||||
mempool.clear();
|
||||
|
@ -343,7 +345,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
|
||||
tx.vout[0].nValue = 0;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
delete pblocktemplate;
|
||||
mempool.clear();
|
||||
|
@ -356,12 +358,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
script = CScript() << OP_0;
|
||||
tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
|
||||
tx.vin[0].prevout.hash = hash;
|
||||
tx.vin[0].scriptSig = CScript() << (std::vector<unsigned char>)script;
|
||||
tx.vout[0].nValue -= 10000;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
delete pblocktemplate;
|
||||
mempool.clear();
|
||||
|
@ -372,10 +374,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
tx.vout[0].nValue = 49000LL;
|
||||
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
|
||||
tx.vout[0].scriptPubKey = CScript() << OP_2;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
delete pblocktemplate;
|
||||
mempool.clear();
|
||||
|
@ -401,7 +403,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
||||
tx.nLockTime = chainActive.Tip()->nHeight+1;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
|
||||
BOOST_CHECK(!CheckFinalTx(tx, LOCKTIME_MEDIAN_TIME_PAST));
|
||||
|
||||
// time locked
|
||||
|
@ -415,7 +417,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
tx2.vout[0].scriptPubKey = CScript() << OP_1;
|
||||
tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1;
|
||||
hash = tx2.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx2));
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx2));
|
||||
BOOST_CHECK(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST));
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||
|
|
|
@ -106,7 +106,7 @@ TestingSetup::~TestingSetup()
|
|||
|
||||
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) {
|
||||
return CTxMemPoolEntry(tx, nFee, nTime, dPriority, nHeight,
|
||||
pool ? pool->HasNoInputsOf(tx) : hadNoDependencies);
|
||||
pool ? pool->HasNoInputsOf(tx) : hadNoDependencies, spendsCoinbase);
|
||||
}
|
||||
|
||||
void Shutdown(void* parg)
|
||||
|
|
|
@ -47,10 +47,11 @@ struct TestMemPoolEntryHelper
|
|||
double dPriority;
|
||||
unsigned int nHeight;
|
||||
bool hadNoDependencies;
|
||||
bool spendsCoinbase;
|
||||
|
||||
TestMemPoolEntryHelper() :
|
||||
nFee(0), nTime(0), dPriority(0.0), nHeight(1),
|
||||
hadNoDependencies(false) { }
|
||||
hadNoDependencies(false), spendsCoinbase(false) { }
|
||||
|
||||
CTxMemPoolEntry FromTx(CMutableTransaction &tx, CTxMemPool *pool = NULL);
|
||||
|
||||
|
@ -60,5 +61,6 @@ struct TestMemPoolEntryHelper
|
|||
TestMemPoolEntryHelper &Priority(double _priority) { dPriority = _priority; return *this; }
|
||||
TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; }
|
||||
TestMemPoolEntryHelper &HadNoDependencies(bool _hnd) { hadNoDependencies = _hnd; return *this; }
|
||||
TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -19,16 +19,19 @@
|
|||
using namespace std;
|
||||
|
||||
CTxMemPoolEntry::CTxMemPoolEntry():
|
||||
nFee(0), nTxSize(0), nModSize(0), nUsageSize(0), nTime(0), dPriority(0.0), hadNoDependencies(false)
|
||||
nFee(0), nTxSize(0), nModSize(0), nUsageSize(0), nTime(0), dPriority(0.0),
|
||||
hadNoDependencies(false), spendsCoinbase(false)
|
||||
{
|
||||
nHeight = MEMPOOL_HEIGHT;
|
||||
}
|
||||
|
||||
CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
||||
int64_t _nTime, double _dPriority,
|
||||
unsigned int _nHeight, bool poolHasNoInputsOf):
|
||||
unsigned int _nHeight, bool poolHasNoInputsOf,
|
||||
bool _spendsCoinbase):
|
||||
tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight),
|
||||
hadNoDependencies(poolHasNoInputsOf)
|
||||
hadNoDependencies(poolHasNoInputsOf),
|
||||
spendsCoinbase(_spendsCoinbase)
|
||||
{
|
||||
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
nModSize = tx.CalculateModifiedSize(nTxSize);
|
||||
|
@ -177,7 +180,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
|
|||
const CTransaction& tx = it->GetTx();
|
||||
if (!IsFinalTx(tx, nMemPoolHeight, GetAdjustedTime())) {
|
||||
transactionsToRemove.push_back(tx);
|
||||
} else {
|
||||
} else if (it->GetSpendsCoinbase()) {
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
||||
indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
|
||||
if (it2 != mapTx.end())
|
||||
|
|
|
@ -50,10 +50,12 @@ private:
|
|||
double dPriority; //! Priority when entering the mempool
|
||||
unsigned int nHeight; //! Chain height when entering the mempool
|
||||
bool hadNoDependencies; //! Not dependent on any other txs when it entered the mempool
|
||||
bool spendsCoinbase; //! keep track of transactions that spend a coinbase
|
||||
|
||||
public:
|
||||
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
||||
int64_t _nTime, double _dPriority, unsigned int _nHeight, bool poolHasNoInputsOf = false);
|
||||
int64_t _nTime, double _dPriority, unsigned int _nHeight,
|
||||
bool poolHasNoInputsOf, bool spendsCoinbase);
|
||||
CTxMemPoolEntry();
|
||||
CTxMemPoolEntry(const CTxMemPoolEntry& other);
|
||||
|
||||
|
@ -66,6 +68,8 @@ public:
|
|||
unsigned int GetHeight() const { return nHeight; }
|
||||
bool WasClearAtEntry() const { return hadNoDependencies; }
|
||||
size_t DynamicMemoryUsage() const { return nUsageSize; }
|
||||
|
||||
bool GetSpendsCoinbase() const { return spendsCoinbase; }
|
||||
};
|
||||
|
||||
// extracts a TxMemPoolEntry's transaction hash
|
||||
|
|
Loading…
Reference in New Issue