mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 18:49:30 +01:00
Track coinbase spends in CTxMemPoolEntry
This allows us to optimize CTxMemPool::removeForReorg.
This commit is contained in:
parent
bb8ea1f630
commit
7e49f5f8b4
13
src/main.cpp
13
src/main.cpp
@ -953,7 +953,18 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||||||
CAmount inChainInputValue;
|
CAmount inChainInputValue;
|
||||||
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
|
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
|
||||||
|
|
||||||
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue);
|
// 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(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase);
|
||||||
unsigned int nSize = entry.GetTxSize();
|
unsigned int nSize = entry.GetTxSize();
|
||||||
|
|
||||||
// Don't accept it if it can't get into a block
|
// Don't accept it if it can't get into a block
|
||||||
|
@ -119,7 +119,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||||||
{
|
{
|
||||||
tx.vout[0].nValue -= 1000000;
|
tx.vout[0].nValue -= 1000000;
|
||||||
hash = tx.GetHash();
|
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;
|
tx.vin[0].prevout.hash = hash;
|
||||||
}
|
}
|
||||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
|
||||||
@ -139,7 +140,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||||||
{
|
{
|
||||||
tx.vout[0].nValue -= 10000000;
|
tx.vout[0].nValue -= 10000000;
|
||||||
hash = tx.GetHash();
|
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;
|
tx.vin[0].prevout.hash = hash;
|
||||||
}
|
}
|
||||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
|
||||||
@ -158,7 +160,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||||||
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
|
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
|
||||||
tx.vout[0].nValue = 4900000000LL;
|
tx.vout[0].nValue = 4900000000LL;
|
||||||
hash = tx.GetHash();
|
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].prevout.hash = hash;
|
||||||
tx.vin.resize(2);
|
tx.vin.resize(2);
|
||||||
tx.vin[1].scriptSig = CScript() << OP_1;
|
tx.vin[1].scriptSig = CScript() << OP_1;
|
||||||
@ -166,7 +168,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||||||
tx.vin[1].prevout.n = 0;
|
tx.vin[1].prevout.n = 0;
|
||||||
tx.vout[0].nValue = 5900000000LL;
|
tx.vout[0].nValue = 5900000000LL;
|
||||||
hash = tx.GetHash();
|
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(chainparams, scriptPubKey));
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
|
||||||
delete pblocktemplate;
|
delete pblocktemplate;
|
||||||
mempool.clear();
|
mempool.clear();
|
||||||
@ -177,7 +179,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||||||
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
|
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
|
||||||
tx.vout[0].nValue = 0;
|
tx.vout[0].nValue = 0;
|
||||||
hash = tx.GetHash();
|
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(chainparams, scriptPubKey));
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
|
||||||
delete pblocktemplate;
|
delete pblocktemplate;
|
||||||
mempool.clear();
|
mempool.clear();
|
||||||
@ -190,12 +192,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||||||
script = CScript() << OP_0;
|
script = CScript() << OP_0;
|
||||||
tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
|
tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
|
||||||
hash = tx.GetHash();
|
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].prevout.hash = hash;
|
||||||
tx.vin[0].scriptSig = CScript() << (std::vector<unsigned char>)script;
|
tx.vin[0].scriptSig = CScript() << (std::vector<unsigned char>)script;
|
||||||
tx.vout[0].nValue -= 1000000;
|
tx.vout[0].nValue -= 1000000;
|
||||||
hash = tx.GetHash();
|
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(chainparams, scriptPubKey));
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
|
||||||
delete pblocktemplate;
|
delete pblocktemplate;
|
||||||
mempool.clear();
|
mempool.clear();
|
||||||
@ -206,10 +208,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||||||
tx.vout[0].nValue = 4900000000LL;
|
tx.vout[0].nValue = 4900000000LL;
|
||||||
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
||||||
hash = tx.GetHash();
|
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;
|
tx.vout[0].scriptPubKey = CScript() << OP_2;
|
||||||
hash = tx.GetHash();
|
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(chainparams, scriptPubKey));
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
|
||||||
delete pblocktemplate;
|
delete pblocktemplate;
|
||||||
mempool.clear();
|
mempool.clear();
|
||||||
@ -235,7 +237,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||||||
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
tx.vout[0].scriptPubKey = CScript() << OP_1;
|
||||||
tx.nLockTime = chainActive.Tip()->nHeight+1;
|
tx.nLockTime = chainActive.Tip()->nHeight+1;
|
||||||
hash = tx.GetHash();
|
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));
|
BOOST_CHECK(!CheckFinalTx(tx, LOCKTIME_MEDIAN_TIME_PAST));
|
||||||
|
|
||||||
// time locked
|
// time locked
|
||||||
@ -249,7 +251,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||||||
tx2.vout[0].scriptPubKey = CScript() << OP_1;
|
tx2.vout[0].scriptPubKey = CScript() << OP_1;
|
||||||
tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1;
|
tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1;
|
||||||
hash = tx2.GetHash();
|
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(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST));
|
||||||
|
|
||||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
|
||||||
|
@ -150,7 +150,7 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPo
|
|||||||
CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0;
|
CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0;
|
||||||
|
|
||||||
return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight,
|
return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight,
|
||||||
hasNoDependencies, inChainValue);
|
hasNoDependencies, inChainValue, spendsCoinbase);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown(void* parg)
|
void Shutdown(void* parg)
|
||||||
|
@ -65,10 +65,11 @@ struct TestMemPoolEntryHelper
|
|||||||
double dPriority;
|
double dPriority;
|
||||||
unsigned int nHeight;
|
unsigned int nHeight;
|
||||||
bool hadNoDependencies;
|
bool hadNoDependencies;
|
||||||
|
bool spendsCoinbase;
|
||||||
|
|
||||||
TestMemPoolEntryHelper() :
|
TestMemPoolEntryHelper() :
|
||||||
nFee(0), nTime(0), dPriority(0.0), nHeight(1),
|
nFee(0), nTime(0), dPriority(0.0), nHeight(1),
|
||||||
hadNoDependencies(false) { }
|
hadNoDependencies(false), spendsCoinbase(false) { }
|
||||||
|
|
||||||
CTxMemPoolEntry FromTx(CMutableTransaction &tx, CTxMemPool *pool = NULL);
|
CTxMemPoolEntry FromTx(CMutableTransaction &tx, CTxMemPool *pool = NULL);
|
||||||
|
|
||||||
@ -78,5 +79,6 @@ struct TestMemPoolEntryHelper
|
|||||||
TestMemPoolEntryHelper &Priority(double _priority) { dPriority = _priority; return *this; }
|
TestMemPoolEntryHelper &Priority(double _priority) { dPriority = _priority; return *this; }
|
||||||
TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; }
|
TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; }
|
||||||
TestMemPoolEntryHelper &HadNoDependencies(bool _hnd) { hadNoDependencies = _hnd; return *this; }
|
TestMemPoolEntryHelper &HadNoDependencies(bool _hnd) { hadNoDependencies = _hnd; return *this; }
|
||||||
|
TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,9 +21,11 @@ using namespace std;
|
|||||||
|
|
||||||
CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
||||||
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
|
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
|
||||||
bool poolHasNoInputsOf, CAmount _inChainInputValue):
|
bool poolHasNoInputsOf, CAmount _inChainInputValue,
|
||||||
|
bool _spendsCoinbase):
|
||||||
tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
|
tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
|
||||||
hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue)
|
hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue),
|
||||||
|
spendsCoinbase(_spendsCoinbase)
|
||||||
{
|
{
|
||||||
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
nModSize = tx.CalculateModifiedSize(nTxSize);
|
nModSize = tx.CalculateModifiedSize(nTxSize);
|
||||||
@ -488,7 +490,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
|
|||||||
const CTransaction& tx = it->GetTx();
|
const CTransaction& tx = it->GetTx();
|
||||||
if (!IsFinalTx(tx, nMemPoolHeight, GetAdjustedTime())) {
|
if (!IsFinalTx(tx, nMemPoolHeight, GetAdjustedTime())) {
|
||||||
transactionsToRemove.push_back(tx);
|
transactionsToRemove.push_back(tx);
|
||||||
} else {
|
} else if (it->GetSpendsCoinbase()) {
|
||||||
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
||||||
indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
|
indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
|
||||||
if (it2 != mapTx.end())
|
if (it2 != mapTx.end())
|
||||||
|
@ -67,6 +67,7 @@ private:
|
|||||||
unsigned int entryHeight; //! Chain height when entering the mempool
|
unsigned int entryHeight; //! Chain height when entering the mempool
|
||||||
bool hadNoDependencies; //! Not dependent on any other txs when it entered the mempool
|
bool hadNoDependencies; //! Not dependent on any other txs when it entered the mempool
|
||||||
CAmount inChainInputValue; //! Sum of all txin values that are already in blockchain
|
CAmount inChainInputValue; //! Sum of all txin values that are already in blockchain
|
||||||
|
bool spendsCoinbase; //! keep track of transactions that spend a coinbase
|
||||||
|
|
||||||
// Information about descendants of this transaction that are in the
|
// Information about descendants of this transaction that are in the
|
||||||
// mempool; if we remove this transaction we must remove all of these
|
// mempool; if we remove this transaction we must remove all of these
|
||||||
@ -80,7 +81,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
||||||
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
|
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
|
||||||
bool poolHasNoInputsOf, CAmount _inChainInputValue);
|
bool poolHasNoInputsOf, CAmount _inChainInputValue, bool spendsCoinbase);
|
||||||
CTxMemPoolEntry(const CTxMemPoolEntry& other);
|
CTxMemPoolEntry(const CTxMemPoolEntry& other);
|
||||||
|
|
||||||
const CTransaction& GetTx() const { return this->tx; }
|
const CTransaction& GetTx() const { return this->tx; }
|
||||||
@ -109,6 +110,8 @@ public:
|
|||||||
uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
|
uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
|
||||||
uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
|
uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
|
||||||
CAmount GetFeesWithDescendants() const { return nFeesWithDescendants; }
|
CAmount GetFeesWithDescendants() const { return nFeesWithDescendants; }
|
||||||
|
|
||||||
|
bool GetSpendsCoinbase() const { return spendsCoinbase; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.
|
// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.
|
||||||
|
Loading…
Reference in New Issue
Block a user