mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-18 22:35:39 +01:00
Switch CCoinsView and chainstate db from per-txid to per-txout
This patch makes several related changes: * Changes the CCoinsView virtual methods (GetCoins, HaveCoins, ...) to be COutPoint/Coin-based rather than txid/CCoins-based. * Changes the chainstate db to a new incompatible format that is also COutPoint/Coin based. * Implements reconstruction code for hash_serialized_2. * Adapts the coins_tests unit tests (thanks to Russell Yanofsky). A side effect of the new CCoinsView model is that we can no longer use the (unreliable) test for transaction outputs in the UTXO set to determine whether we already have a particular transaction.
This commit is contained in:
@@ -524,9 +524,9 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
|
||||
indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
|
||||
if (it2 != mapTx.end())
|
||||
continue;
|
||||
const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash);
|
||||
if (nCheckFrequency != 0) assert(coins);
|
||||
if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) {
|
||||
const Coin &coin = pcoins->AccessCoin(txin.prevout);
|
||||
if (nCheckFrequency != 0) assert(!coin.IsPruned());
|
||||
if (coin.IsPruned() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) {
|
||||
txToRemove.insert(it);
|
||||
break;
|
||||
}
|
||||
@@ -654,8 +654,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
||||
parentSigOpCost += it2->GetSigOpCost();
|
||||
}
|
||||
} else {
|
||||
const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash);
|
||||
assert(coins && coins->IsAvailable(txin.prevout.n));
|
||||
assert(pcoins->HaveCoins(txin.prevout));
|
||||
}
|
||||
// Check whether its inputs are marked in mapNextTx.
|
||||
auto it3 = mapNextTx.find(txin.prevout);
|
||||
@@ -891,20 +890,24 @@ bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
|
||||
|
||||
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
|
||||
|
||||
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
|
||||
bool CCoinsViewMemPool::GetCoins(const COutPoint &outpoint, Coin &coin) const {
|
||||
// If an entry in the mempool exists, always return that one, as it's guaranteed to never
|
||||
// conflict with the underlying cache, and it cannot have pruned entries (as it contains full)
|
||||
// transactions. First checking the underlying cache risks returning a pruned entry instead.
|
||||
CTransactionRef ptx = mempool.get(txid);
|
||||
CTransactionRef ptx = mempool.get(outpoint.hash);
|
||||
if (ptx) {
|
||||
coins = CCoins(*ptx, MEMPOOL_HEIGHT);
|
||||
return true;
|
||||
if (outpoint.n < ptx->vout.size()) {
|
||||
coin = Coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (base->GetCoins(txid, coins) && !coins.IsPruned());
|
||||
return (base->GetCoins(outpoint, coin) && !coin.IsPruned());
|
||||
}
|
||||
|
||||
bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const {
|
||||
return mempool.exists(txid) || base->HaveCoins(txid);
|
||||
bool CCoinsViewMemPool::HaveCoins(const COutPoint &outpoint) const {
|
||||
return mempool.exists(outpoint) || base->HaveCoins(outpoint);
|
||||
}
|
||||
|
||||
size_t CTxMemPool::DynamicMemoryUsage() const {
|
||||
@@ -1015,7 +1018,7 @@ void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
|
||||
}
|
||||
}
|
||||
|
||||
void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRemaining) {
|
||||
void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining) {
|
||||
LOCK(cs);
|
||||
|
||||
unsigned nTxnRemoved = 0;
|
||||
@@ -1046,11 +1049,10 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe
|
||||
if (pvNoSpendsRemaining) {
|
||||
BOOST_FOREACH(const CTransaction& tx, txn) {
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
|
||||
if (exists(txin.prevout.hash))
|
||||
continue;
|
||||
auto iter = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0));
|
||||
if (iter == mapNextTx.end() || iter->first->hash != txin.prevout.hash)
|
||||
pvNoSpendsRemaining->push_back(txin.prevout.hash);
|
||||
if (exists(txin.prevout.hash)) continue;
|
||||
if (!mapNextTx.count(txin.prevout)) {
|
||||
pvNoSpendsRemaining->push_back(txin.prevout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1067,3 +1069,5 @@ bool CTxMemPool::TransactionWithinChainLimit(const uint256& txid, size_t chainLi
|
||||
return it == mapTx.end() || (it->GetCountWithAncestors() < chainLimit &&
|
||||
it->GetCountWithDescendants() < chainLimit);
|
||||
}
|
||||
|
||||
SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
|
||||
|
||||
Reference in New Issue
Block a user