Browse Source

scripted-diff: various renames for per-utxo consistency

Thanks to John Newberry for pointing these out.

-BEGIN VERIFY SCRIPT-
sed -i 's/\<GetCoins\>/GetCoin/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<HaveCoins\>/HaveCoin/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<HaveCoinsInCache\>/HaveCoinInCache/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<IsPruned\>/IsSpent/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<FetchCoins\>/FetchCoin/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<CoinsEntry\>/CoinEntry/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<vHashTxnToUncache\>/coins_to_uncache/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<vHashTxToUncache\>/coins_to_uncache/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<fHadTxInCache\>/had_coin_in_cache/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<coinbaseids\>/coinbase_coins/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<disconnectedids\>/disconnected_coins/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<duplicateids\>/duplicate_coins/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
sed -i 's/\<oldcoins\>/old_coin/g' src/test/coins_tests.cpp
sed -i 's/\<origcoins\>/orig_coin/g' src/*.cpp src/*.h src/*/*.cpp src/*/*.h
-END VERIFY SCRIPT-
0.15
Pieter Wuille 8 years ago
parent
commit
589827975f
  1. 4
      src/bitcoin-tx.cpp
  2. 44
      src/coins.cpp
  3. 24
      src/coins.h
  4. 2
      src/consensus/tx_verify.cpp
  5. 4
      src/init.cpp
  6. 4
      src/net_processing.cpp
  7. 2
      src/qt/transactiondesc.cpp
  8. 2
      src/rest.cpp
  9. 4
      src/rpc/blockchain.cpp
  10. 8
      src/rpc/rawtransaction.cpp
  11. 90
      src/test/coins_tests.cpp
  12. 20
      src/txdb.cpp
  13. 4
      src/txdb.h
  14. 14
      src/txmempool.cpp
  15. 4
      src/txmempool.h
  16. 34
      src/validation.cpp

4
src/bitcoin-tx.cpp

@ -562,7 +562,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
{ {
const Coin& coin = view.AccessCoin(out); const Coin& coin = view.AccessCoin(out);
if (!coin.IsPruned() && coin.out.scriptPubKey != scriptPubKey) { if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {
std::string err("Previous output scriptPubKey mismatch:\n"); std::string err("Previous output scriptPubKey mismatch:\n");
err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+ err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
ScriptToAsmStr(scriptPubKey); ScriptToAsmStr(scriptPubKey);
@ -598,7 +598,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i]; CTxIn& txin = mergedTx.vin[i];
const Coin& coin = view.AccessCoin(txin.prevout); const Coin& coin = view.AccessCoin(txin.prevout);
if (coin.IsPruned()) { if (coin.IsSpent()) {
fComplete = false; fComplete = false;
continue; continue;
} }

44
src/coins.cpp

@ -10,16 +10,16 @@
#include <assert.h> #include <assert.h>
bool CCoinsView::GetCoins(const COutPoint &outpoint, Coin &coin) const { return false; } bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
bool CCoinsView::HaveCoins(const COutPoint &outpoint) const { return false; } bool CCoinsView::HaveCoin(const COutPoint &outpoint) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); } uint256 CCoinsView::GetBestBlock() const { return uint256(); }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; } bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
CCoinsViewCursor *CCoinsView::Cursor() const { return 0; } CCoinsViewCursor *CCoinsView::Cursor() const { return 0; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { } CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetCoins(const COutPoint &outpoint, Coin &coin) const { return base->GetCoins(outpoint, coin); } bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { return base->GetCoin(outpoint, coin); }
bool CCoinsViewBacked::HaveCoins(const COutPoint &outpoint) const { return base->HaveCoins(outpoint); } bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); } uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
@ -34,15 +34,15 @@ size_t CCoinsViewCache::DynamicMemoryUsage() const {
return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage; return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage;
} }
CCoinsMap::iterator CCoinsViewCache::FetchCoins(const COutPoint &outpoint) const { CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const {
CCoinsMap::iterator it = cacheCoins.find(outpoint); CCoinsMap::iterator it = cacheCoins.find(outpoint);
if (it != cacheCoins.end()) if (it != cacheCoins.end())
return it; return it;
Coin tmp; Coin tmp;
if (!base->GetCoins(outpoint, tmp)) if (!base->GetCoin(outpoint, tmp))
return cacheCoins.end(); return cacheCoins.end();
CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first; CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
if (ret->second.coin.IsPruned()) { if (ret->second.coin.IsSpent()) {
// The parent only has an empty entry for this outpoint; we can consider our // The parent only has an empty entry for this outpoint; we can consider our
// version as fresh. // version as fresh.
ret->second.flags = CCoinsCacheEntry::FRESH; ret->second.flags = CCoinsCacheEntry::FRESH;
@ -51,8 +51,8 @@ CCoinsMap::iterator CCoinsViewCache::FetchCoins(const COutPoint &outpoint) const
return ret; return ret;
} }
bool CCoinsViewCache::GetCoins(const COutPoint &outpoint, Coin &coin) const { bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const {
CCoinsMap::const_iterator it = FetchCoins(outpoint); CCoinsMap::const_iterator it = FetchCoin(outpoint);
if (it != cacheCoins.end()) { if (it != cacheCoins.end()) {
coin = it->second.coin; coin = it->second.coin;
return true; return true;
@ -61,7 +61,7 @@ bool CCoinsViewCache::GetCoins(const COutPoint &outpoint, Coin &coin) const {
} }
void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) { void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) {
assert(!coin.IsPruned()); assert(!coin.IsSpent());
if (coin.out.scriptPubKey.IsUnspendable()) return; if (coin.out.scriptPubKey.IsUnspendable()) return;
CCoinsMap::iterator it; CCoinsMap::iterator it;
bool inserted; bool inserted;
@ -71,7 +71,7 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
} }
if (!possible_overwrite) { if (!possible_overwrite) {
if (!it->second.coin.IsPruned()) { if (!it->second.coin.IsSpent()) {
throw std::logic_error("Adding new coin that replaces non-pruned entry"); throw std::logic_error("Adding new coin that replaces non-pruned entry");
} }
fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY); fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
@ -92,7 +92,7 @@ void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight) {
} }
void CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) { void CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
CCoinsMap::iterator it = FetchCoins(outpoint); CCoinsMap::iterator it = FetchCoin(outpoint);
if (it == cacheCoins.end()) return; if (it == cacheCoins.end()) return;
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
if (moveout) { if (moveout) {
@ -109,7 +109,7 @@ void CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
static const Coin coinEmpty; static const Coin coinEmpty;
const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const { const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
CCoinsMap::const_iterator it = FetchCoins(outpoint); CCoinsMap::const_iterator it = FetchCoin(outpoint);
if (it == cacheCoins.end()) { if (it == cacheCoins.end()) {
return coinEmpty; return coinEmpty;
} else { } else {
@ -117,12 +117,12 @@ const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
} }
} }
bool CCoinsViewCache::HaveCoins(const COutPoint &outpoint) const { bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const {
CCoinsMap::const_iterator it = FetchCoins(outpoint); CCoinsMap::const_iterator it = FetchCoin(outpoint);
return (it != cacheCoins.end() && !it->second.coin.IsPruned()); return (it != cacheCoins.end() && !it->second.coin.IsSpent());
} }
bool CCoinsViewCache::HaveCoinsInCache(const COutPoint &outpoint) const { bool CCoinsViewCache::HaveCoinInCache(const COutPoint &outpoint) const {
CCoinsMap::const_iterator it = cacheCoins.find(outpoint); CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
return it != cacheCoins.end(); return it != cacheCoins.end();
} }
@ -144,7 +144,7 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
if (itUs == cacheCoins.end()) { if (itUs == cacheCoins.end()) {
// The parent cache does not have an entry, while the child does // The parent cache does not have an entry, while the child does
// We can ignore it if it's both FRESH and pruned in the child // We can ignore it if it's both FRESH and pruned in the child
if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsPruned())) { if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
// Otherwise we will need to create it in the parent // Otherwise we will need to create it in the parent
// and move the data up and mark it as dirty // and move the data up and mark it as dirty
CCoinsCacheEntry& entry = cacheCoins[it->first]; CCoinsCacheEntry& entry = cacheCoins[it->first];
@ -162,11 +162,11 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
// parent cache entry has unspent outputs. If this ever happens, // parent cache entry has unspent outputs. If this ever happens,
// it means the FRESH flag was misapplied and there is a logic // it means the FRESH flag was misapplied and there is a logic
// error in the calling code. // error in the calling code.
if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsPruned()) if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent())
throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs"); throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");
// Found the entry in the parent cache // Found the entry in the parent cache
if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsPruned()) { if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
// The grandparent does not have an entry, and the child is // The grandparent does not have an entry, and the child is
// modified and being pruned. This means we can just delete // modified and being pruned. This means we can just delete
// it from the parent. // it from the parent.
@ -229,7 +229,7 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
{ {
if (!tx.IsCoinBase()) { if (!tx.IsCoinBase()) {
for (unsigned int i = 0; i < tx.vin.size(); i++) { for (unsigned int i = 0; i < tx.vin.size(); i++) {
if (!HaveCoins(tx.vin[i].prevout)) { if (!HaveCoin(tx.vin[i].prevout)) {
return false; return false;
} }
} }
@ -244,7 +244,7 @@ const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
COutPoint iter(txid, 0); COutPoint iter(txid, 0);
while (iter.n < MAX_OUTPUTS_PER_BLOCK) { while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
const Coin& alternate = view.AccessCoin(iter); const Coin& alternate = view.AccessCoin(iter);
if (!alternate.IsPruned()) return alternate; if (!alternate.IsSpent()) return alternate;
++iter.n; ++iter.n;
} }
return coinEmpty; return coinEmpty;

24
src/coins.h

@ -58,7 +58,7 @@ public:
template<typename Stream> template<typename Stream>
void Serialize(Stream &s) const { void Serialize(Stream &s) const {
assert(!IsPruned()); assert(!IsSpent());
uint32_t code = nHeight * 2 + fCoinBase; uint32_t code = nHeight * 2 + fCoinBase;
::Serialize(s, VARINT(code)); ::Serialize(s, VARINT(code));
::Serialize(s, CTxOutCompressor(REF(out))); ::Serialize(s, CTxOutCompressor(REF(out)));
@ -73,7 +73,7 @@ public:
::Unserialize(s, REF(CTxOutCompressor(out))); ::Unserialize(s, REF(CTxOutCompressor(out)));
} }
bool IsPruned() const { bool IsSpent() const {
return out.IsNull(); return out.IsNull();
} }
@ -147,11 +147,11 @@ class CCoinsView
{ {
public: public:
//! Retrieve the Coin (unspent transaction output) for a given outpoint. //! Retrieve the Coin (unspent transaction output) for a given outpoint.
virtual bool GetCoins(const COutPoint &outpoint, Coin &coin) const; virtual bool GetCoin(const COutPoint &outpoint, Coin &coin) const;
//! Just check whether we have data for a given outpoint. //! Just check whether we have data for a given outpoint.
//! This may (but cannot always) return true for spent outputs. //! This may (but cannot always) return true for spent outputs.
virtual bool HaveCoins(const COutPoint &outpoint) const; virtual bool HaveCoin(const COutPoint &outpoint) const;
//! Retrieve the block hash whose state this CCoinsView currently represents //! Retrieve the block hash whose state this CCoinsView currently represents
virtual uint256 GetBestBlock() const; virtual uint256 GetBestBlock() const;
@ -179,8 +179,8 @@ protected:
public: public:
CCoinsViewBacked(CCoinsView *viewIn); CCoinsViewBacked(CCoinsView *viewIn);
bool GetCoins(const COutPoint &outpoint, Coin &coin) const override; bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
bool HaveCoins(const COutPoint &outpoint) const override; bool HaveCoin(const COutPoint &outpoint) const override;
uint256 GetBestBlock() const override; uint256 GetBestBlock() const override;
void SetBackend(CCoinsView &viewIn); void SetBackend(CCoinsView &viewIn);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override; bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
@ -207,22 +207,22 @@ public:
CCoinsViewCache(CCoinsView *baseIn); CCoinsViewCache(CCoinsView *baseIn);
// Standard CCoinsView methods // Standard CCoinsView methods
bool GetCoins(const COutPoint &outpoint, Coin &coin) const; bool GetCoin(const COutPoint &outpoint, Coin &coin) const;
bool HaveCoins(const COutPoint &outpoint) const; bool HaveCoin(const COutPoint &outpoint) const;
uint256 GetBestBlock() const; uint256 GetBestBlock() const;
void SetBestBlock(const uint256 &hashBlock); void SetBestBlock(const uint256 &hashBlock);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
/** /**
* Check if we have the given utxo already loaded in this cache. * Check if we have the given utxo already loaded in this cache.
* The semantics are the same as HaveCoins(), but no calls to * The semantics are the same as HaveCoin(), but no calls to
* the backing CCoinsView are made. * the backing CCoinsView are made.
*/ */
bool HaveCoinsInCache(const COutPoint &outpoint) const; bool HaveCoinInCache(const COutPoint &outpoint) const;
/** /**
* Return a reference to Coin in the cache, or a pruned one if not found. This is * Return a reference to Coin in the cache, or a pruned one if not found. This is
* more efficient than GetCoins. Modifications to other cache entries are * more efficient than GetCoin. Modifications to other cache entries are
* allowed while accessing the returned pointer. * allowed while accessing the returned pointer.
*/ */
const Coin& AccessCoin(const COutPoint &output) const; const Coin& AccessCoin(const COutPoint &output) const;
@ -273,7 +273,7 @@ public:
bool HaveInputs(const CTransaction& tx) const; bool HaveInputs(const CTransaction& tx) const;
private: private:
CCoinsMap::iterator FetchCoins(const COutPoint &outpoint) const; CCoinsMap::iterator FetchCoin(const COutPoint &outpoint) const;
/** /**
* By making the copy constructor private, we prevent accidentally using it when one intends to create a cache on top of a base cache. * By making the copy constructor private, we prevent accidentally using it when one intends to create a cache on top of a base cache.

2
src/consensus/tx_verify.cpp

@ -214,7 +214,7 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
{ {
const COutPoint &prevout = tx.vin[i].prevout; const COutPoint &prevout = tx.vin[i].prevout;
const Coin& coin = inputs.AccessCoin(prevout); const Coin& coin = inputs.AccessCoin(prevout);
assert(!coin.IsPruned()); assert(!coin.IsSpent());
// If prev is coinbase, check that it's matured // If prev is coinbase, check that it's matured
if (coin.IsCoinBase()) { if (coin.IsCoinBase()) {

4
src/init.cpp

@ -146,9 +146,9 @@ class CCoinsViewErrorCatcher : public CCoinsViewBacked
{ {
public: public:
CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {} CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
bool GetCoins(const COutPoint &outpoint, Coin &coin) const override { bool GetCoin(const COutPoint &outpoint, Coin &coin) const override {
try { try {
return CCoinsViewBacked::GetCoins(outpoint, coin); return CCoinsViewBacked::GetCoin(outpoint, coin);
} catch(const std::runtime_error& e) { } catch(const std::runtime_error& e) {
uiInterface.ThreadSafeMessageBox(_("Error reading from database, shutting down."), "", CClientUIInterface::MSG_ERROR); uiInterface.ThreadSafeMessageBox(_("Error reading from database, shutting down."), "", CClientUIInterface::MSG_ERROR);
LogPrintf("Error reading from database: %s\n", e.what()); LogPrintf("Error reading from database: %s\n", e.what());

4
src/net_processing.cpp

@ -914,8 +914,8 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
return recentRejects->contains(inv.hash) || return recentRejects->contains(inv.hash) ||
mempool.exists(inv.hash) || mempool.exists(inv.hash) ||
mapOrphanTransactions.count(inv.hash) || mapOrphanTransactions.count(inv.hash) ||
pcoinsTip->HaveCoinsInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1 pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1
pcoinsTip->HaveCoinsInCache(COutPoint(inv.hash, 1)); pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1));
} }
case MSG_BLOCK: case MSG_BLOCK:
case MSG_WITNESS_BLOCK: case MSG_WITNESS_BLOCK:

2
src/qt/transactiondesc.cpp

@ -294,7 +294,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
COutPoint prevout = txin.prevout; COutPoint prevout = txin.prevout;
Coin prev; Coin prev;
if(pcoinsTip->GetCoins(prevout, prev)) if(pcoinsTip->GetCoin(prevout, prev))
{ {
{ {
strHTML += "<li>"; strHTML += "<li>";

2
src/rest.cpp

@ -514,7 +514,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
for (size_t i = 0; i < vOutPoints.size(); i++) { for (size_t i = 0; i < vOutPoints.size(); i++) {
bool hit = false; bool hit = false;
Coin coin; Coin coin;
if (view.GetCoins(vOutPoints[i], coin) && !mempool.isSpent(vOutPoints[i])) { if (view.GetCoin(vOutPoints[i], coin) && !mempool.isSpent(vOutPoints[i])) {
hit = true; hit = true;
outs.emplace_back(std::move(coin)); outs.emplace_back(std::move(coin));
} }

4
src/rpc/blockchain.cpp

@ -985,11 +985,11 @@ UniValue gettxout(const JSONRPCRequest& request)
if (fMempool) { if (fMempool) {
LOCK(mempool.cs); LOCK(mempool.cs);
CCoinsViewMemPool view(pcoinsTip, mempool); CCoinsViewMemPool view(pcoinsTip, mempool);
if (!view.GetCoins(out, coin) || mempool.isSpent(out)) { // TODO: filtering spent coins should be done by the CCoinsViewMemPool if (!view.GetCoin(out, coin) || mempool.isSpent(out)) { // TODO: filtering spent coins should be done by the CCoinsViewMemPool
return NullUniValue; return NullUniValue;
} }
} else { } else {
if (!pcoinsTip->GetCoins(out, coin)) { if (!pcoinsTip->GetCoin(out, coin)) {
return NullUniValue; return NullUniValue;
} }
} }

8
src/rpc/rawtransaction.cpp

@ -220,7 +220,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
pblockindex = mapBlockIndex[hashBlock]; pblockindex = mapBlockIndex[hashBlock];
} else { } else {
const Coin& coin = AccessByTxid(*pcoinsTip, oneTxid); const Coin& coin = AccessByTxid(*pcoinsTip, oneTxid);
if (!coin.IsPruned() && coin.nHeight > 0 && coin.nHeight <= chainActive.Height()) { if (!coin.IsSpent() && coin.nHeight > 0 && coin.nHeight <= chainActive.Height()) {
pblockindex = chainActive[coin.nHeight]; pblockindex = chainActive[coin.nHeight];
} }
} }
@ -696,7 +696,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
{ {
const Coin& coin = view.AccessCoin(out); const Coin& coin = view.AccessCoin(out);
if (!coin.IsPruned() && coin.out.scriptPubKey != scriptPubKey) { if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {
std::string err("Previous output scriptPubKey mismatch:\n"); std::string err("Previous output scriptPubKey mismatch:\n");
err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+ err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
ScriptToAsmStr(scriptPubKey); ScriptToAsmStr(scriptPubKey);
@ -768,7 +768,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i]; CTxIn& txin = mergedTx.vin[i];
const Coin& coin = view.AccessCoin(txin.prevout); const Coin& coin = view.AccessCoin(txin.prevout);
if (coin.IsPruned()) { if (coin.IsSpent()) {
TxInErrorToJSON(txin, vErrors, "Input not found or already spent"); TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
continue; continue;
} }
@ -848,7 +848,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
bool fHaveChain = false; bool fHaveChain = false;
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) { for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o)); const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
fHaveChain = !existingCoin.IsPruned(); fHaveChain = !existingCoin.IsSpent();
} }
bool fHaveMempool = mempool.exists(hashTx); bool fHaveMempool = mempool.exists(hashTx);
if (!fHaveMempool && !fHaveChain) { if (!fHaveMempool && !fHaveChain) {

90
src/test/coins_tests.cpp

@ -25,7 +25,7 @@ namespace
//! equality test //! equality test
bool operator==(const Coin &a, const Coin &b) { bool operator==(const Coin &a, const Coin &b) {
// Empty Coin objects are always equal. // Empty Coin objects are always equal.
if (a.IsPruned() && b.IsPruned()) return true; if (a.IsSpent() && b.IsSpent()) return true;
return a.fCoinBase == b.fCoinBase && return a.fCoinBase == b.fCoinBase &&
a.nHeight == b.nHeight && a.nHeight == b.nHeight &&
a.out == b.out; a.out == b.out;
@ -37,24 +37,24 @@ class CCoinsViewTest : public CCoinsView
std::map<COutPoint, Coin> map_; std::map<COutPoint, Coin> map_;
public: public:
bool GetCoins(const COutPoint& outpoint, Coin& coin) const bool GetCoin(const COutPoint& outpoint, Coin& coin) const
{ {
std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint); std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint);
if (it == map_.end()) { if (it == map_.end()) {
return false; return false;
} }
coin = it->second; coin = it->second;
if (coin.IsPruned() && insecure_rand() % 2 == 0) { if (coin.IsSpent() && insecure_rand() % 2 == 0) {
// Randomly return false in case of an empty entry. // Randomly return false in case of an empty entry.
return false; return false;
} }
return true; return true;
} }
bool HaveCoins(const COutPoint& outpoint) const bool HaveCoin(const COutPoint& outpoint) const
{ {
Coin coin; Coin coin;
return GetCoins(outpoint, coin); return GetCoin(outpoint, coin);
} }
uint256 GetBestBlock() const { return hashBestBlock_; } uint256 GetBestBlock() const { return hashBestBlock_; }
@ -65,7 +65,7 @@ public:
if (it->second.flags & CCoinsCacheEntry::DIRTY) { if (it->second.flags & CCoinsCacheEntry::DIRTY) {
// Same optimization used in CCoinsViewDB is to only write dirty entries. // Same optimization used in CCoinsViewDB is to only write dirty entries.
map_[it->first] = it->second.coin; map_[it->first] = it->second.coin;
if (it->second.coin.IsPruned() && insecure_rand() % 3 == 0) { if (it->second.coin.IsSpent() && insecure_rand() % 3 == 0) {
// Randomly delete empty entries on write. // Randomly delete empty entries on write.
map_.erase(it->first); map_.erase(it->first);
} }
@ -151,20 +151,20 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
const Coin& entry = (insecure_rand() % 500 == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0)); const Coin& entry = (insecure_rand() % 500 == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0));
BOOST_CHECK(coin == entry); BOOST_CHECK(coin == entry);
if (insecure_rand() % 5 == 0 || coin.IsPruned()) { if (insecure_rand() % 5 == 0 || coin.IsSpent()) {
Coin newcoin; Coin newcoin;
newcoin.out.nValue = insecure_rand(); newcoin.out.nValue = insecure_rand();
newcoin.nHeight = 1; newcoin.nHeight = 1;
if (insecure_rand() % 16 == 0 && coin.IsPruned()) { if (insecure_rand() % 16 == 0 && coin.IsSpent()) {
newcoin.out.scriptPubKey.assign(1 + (insecure_rand() & 0x3F), OP_RETURN); newcoin.out.scriptPubKey.assign(1 + (insecure_rand() & 0x3F), OP_RETURN);
BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable()); BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable());
added_an_unspendable_entry = true; added_an_unspendable_entry = true;
} else { } else {
newcoin.out.scriptPubKey.assign(insecure_rand() & 0x3F, 0); // Random sizes so we can test memory usage accounting newcoin.out.scriptPubKey.assign(insecure_rand() & 0x3F, 0); // Random sizes so we can test memory usage accounting
(coin.IsPruned() ? added_an_entry : updated_an_entry) = true; (coin.IsSpent() ? added_an_entry : updated_an_entry) = true;
coin = newcoin; coin = newcoin;
} }
stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), !coin.IsPruned() || insecure_rand() & 1); stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), !coin.IsSpent() || insecure_rand() & 1);
} else { } else {
removed_an_entry = true; removed_an_entry = true;
coin.Clear(); coin.Clear();
@ -177,20 +177,20 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
COutPoint out(txids[insecure_rand() % txids.size()], 0); COutPoint out(txids[insecure_rand() % txids.size()], 0);
int cacheid = insecure_rand() % stack.size(); int cacheid = insecure_rand() % stack.size();
stack[cacheid]->Uncache(out); stack[cacheid]->Uncache(out);
uncached_an_entry |= !stack[cacheid]->HaveCoinsInCache(out); uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out);
} }
// Once every 1000 iterations and at the end, verify the full cache. // Once every 1000 iterations and at the end, verify the full cache.
if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
for (auto it = result.begin(); it != result.end(); it++) { for (auto it = result.begin(); it != result.end(); it++) {
bool have = stack.back()->HaveCoins(it->first); bool have = stack.back()->HaveCoin(it->first);
const Coin& coin = stack.back()->AccessCoin(it->first); const Coin& coin = stack.back()->AccessCoin(it->first);
BOOST_CHECK(have == !coin.IsPruned()); BOOST_CHECK(have == !coin.IsSpent());
BOOST_CHECK(coin == it->second); BOOST_CHECK(coin == it->second);
if (coin.IsPruned()) { if (coin.IsSpent()) {
missed_an_entry = true; missed_an_entry = true;
} else { } else {
BOOST_CHECK(stack.back()->HaveCoinsInCache(it->first)); BOOST_CHECK(stack.back()->HaveCoinInCache(it->first));
found_an_entry = true; found_an_entry = true;
} }
} }
@ -281,9 +281,9 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache. stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache.
// Track the txids we've used in various sets // Track the txids we've used in various sets
std::set<COutPoint> coinbaseids; std::set<COutPoint> coinbase_coins;
std::set<COutPoint> disconnectedids; std::set<COutPoint> disconnected_coins;
std::set<COutPoint> duplicateids; std::set<COutPoint> duplicate_coins;
std::set<COutPoint> utxoset; std::set<COutPoint> utxoset;
for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) {
@ -297,22 +297,22 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate
tx.vout[0].scriptPubKey.assign(insecure_rand() & 0x3F, 0); // Random sizes so we can test memory usage accounting tx.vout[0].scriptPubKey.assign(insecure_rand() & 0x3F, 0); // Random sizes so we can test memory usage accounting
unsigned int height = insecure_rand(); unsigned int height = insecure_rand();
Coin oldcoins; Coin old_coin;
// 2/20 times create a new coinbase // 2/20 times create a new coinbase
if (randiter % 20 < 2 || coinbaseids.size() < 10) { if (randiter % 20 < 2 || coinbase_coins.size() < 10) {
// 1/10 of those times create a duplicate coinbase // 1/10 of those times create a duplicate coinbase
if (insecure_rand() % 10 == 0 && coinbaseids.size()) { if (insecure_rand() % 10 == 0 && coinbase_coins.size()) {
auto utxod = FindRandomFrom(coinbaseids); auto utxod = FindRandomFrom(coinbase_coins);
// Reuse the exact same coinbase // Reuse the exact same coinbase
tx = std::get<0>(utxod->second); tx = std::get<0>(utxod->second);
// shouldn't be available for reconnection if its been duplicated // shouldn't be available for reconnection if its been duplicated
disconnectedids.erase(utxod->first); disconnected_coins.erase(utxod->first);
duplicateids.insert(utxod->first); duplicate_coins.insert(utxod->first);
} }
else { else {
coinbaseids.insert(COutPoint(tx.GetHash(), 0)); coinbase_coins.insert(COutPoint(tx.GetHash(), 0));
} }
assert(CTransaction(tx).IsCoinBase()); assert(CTransaction(tx).IsCoinBase());
} }
@ -322,21 +322,21 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
COutPoint prevout; COutPoint prevout;
// 1/20 times reconnect a previously disconnected tx // 1/20 times reconnect a previously disconnected tx
if (randiter % 20 == 2 && disconnectedids.size()) { if (randiter % 20 == 2 && disconnected_coins.size()) {
auto utxod = FindRandomFrom(disconnectedids); auto utxod = FindRandomFrom(disconnected_coins);
tx = std::get<0>(utxod->second); tx = std::get<0>(utxod->second);
prevout = tx.vin[0].prevout; prevout = tx.vin[0].prevout;
if (!CTransaction(tx).IsCoinBase() && !utxoset.count(prevout)) { if (!CTransaction(tx).IsCoinBase() && !utxoset.count(prevout)) {
disconnectedids.erase(utxod->first); disconnected_coins.erase(utxod->first);
continue; continue;
} }
// If this tx is already IN the UTXO, then it must be a coinbase, and it must be a duplicate // If this tx is already IN the UTXO, then it must be a coinbase, and it must be a duplicate
if (utxoset.count(utxod->first)) { if (utxoset.count(utxod->first)) {
assert(CTransaction(tx).IsCoinBase()); assert(CTransaction(tx).IsCoinBase());
assert(duplicateids.count(utxod->first)); assert(duplicate_coins.count(utxod->first));
} }
disconnectedids.erase(utxod->first); disconnected_coins.erase(utxod->first);
} }
// 16/20 times create a regular tx // 16/20 times create a regular tx
@ -349,7 +349,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
assert(!CTransaction(tx).IsCoinBase()); assert(!CTransaction(tx).IsCoinBase());
} }
// In this simple test coins only have two states, spent or unspent, save the unspent state to restore // In this simple test coins only have two states, spent or unspent, save the unspent state to restore
oldcoins = result[prevout]; old_coin = result[prevout];
// Update the expected result of prevouthash to know these coins are spent // Update the expected result of prevouthash to know these coins are spent
result[prevout].Clear(); result[prevout].Clear();
@ -357,7 +357,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// The test is designed to ensure spending a duplicate coinbase will work properly // The test is designed to ensure spending a duplicate coinbase will work properly
// if that ever happens and not resurrect the previously overwritten coinbase // if that ever happens and not resurrect the previously overwritten coinbase
if (duplicateids.count(prevout)) { if (duplicate_coins.count(prevout)) {
spent_a_duplicate_coinbase = true; spent_a_duplicate_coinbase = true;
} }
@ -375,21 +375,21 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
utxoset.insert(outpoint); utxoset.insert(outpoint);
// Track this tx and undo info to use later // Track this tx and undo info to use later
utxoData.emplace(outpoint, std::make_tuple(tx,undo,oldcoins)); utxoData.emplace(outpoint, std::make_tuple(tx,undo,old_coin));
} else if (utxoset.size()) { } else if (utxoset.size()) {
//1/20 times undo a previous transaction //1/20 times undo a previous transaction
auto utxod = FindRandomFrom(utxoset); auto utxod = FindRandomFrom(utxoset);
CTransaction &tx = std::get<0>(utxod->second); CTransaction &tx = std::get<0>(utxod->second);
CTxUndo &undo = std::get<1>(utxod->second); CTxUndo &undo = std::get<1>(utxod->second);
Coin &origcoins = std::get<2>(utxod->second); Coin &orig_coin = std::get<2>(utxod->second);
// Update the expected result // Update the expected result
// Remove new outputs // Remove new outputs
result[utxod->first].Clear(); result[utxod->first].Clear();
// If not coinbase restore prevout // If not coinbase restore prevout
if (!tx.IsCoinBase()) { if (!tx.IsCoinBase()) {
result[tx.vin[0].prevout] = origcoins; result[tx.vin[0].prevout] = orig_coin;
} }
// Disconnect the tx from the current UTXO // Disconnect the tx from the current UTXO
@ -403,7 +403,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
ApplyTxInUndo(std::move(coin), *(stack.back()), out); ApplyTxInUndo(std::move(coin), *(stack.back()), out);
} }
// Store as a candidate for reconnection // Store as a candidate for reconnection
disconnectedids.insert(utxod->first); disconnected_coins.insert(utxod->first);
// Update the utxoset // Update the utxoset
utxoset.erase(utxod->first); utxoset.erase(utxod->first);
@ -414,9 +414,9 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// Once every 1000 iterations and at the end, verify the full cache. // Once every 1000 iterations and at the end, verify the full cache.
if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
for (auto it = result.begin(); it != result.end(); it++) { for (auto it = result.begin(); it != result.end(); it++) {
bool have = stack.back()->HaveCoins(it->first); bool have = stack.back()->HaveCoin(it->first);
const Coin& coin = stack.back()->AccessCoin(it->first); const Coin& coin = stack.back()->AccessCoin(it->first);
BOOST_CHECK(have == !coin.IsPruned()); BOOST_CHECK(have == !coin.IsSpent());
BOOST_CHECK(coin == it->second); BOOST_CHECK(coin == it->second);
} }
} }
@ -425,11 +425,11 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
if (utxoset.size() > 1 && insecure_rand() % 30) { if (utxoset.size() > 1 && insecure_rand() % 30) {
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first); stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first);
} }
if (disconnectedids.size() > 1 && insecure_rand() % 30) { if (disconnected_coins.size() > 1 && insecure_rand() % 30) {
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(disconnectedids)->first); stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first);
} }
if (duplicateids.size() > 1 && insecure_rand() % 30) { if (duplicate_coins.size() > 1 && insecure_rand() % 30) {
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(duplicateids)->first); stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(duplicate_coins)->first);
} }
if (insecure_rand() % 100 == 0) { if (insecure_rand() % 100 == 0) {
@ -537,11 +537,11 @@ void SetCoinsValue(CAmount value, Coin& coin)
{ {
assert(value != ABSENT); assert(value != ABSENT);
coin.Clear(); coin.Clear();
assert(coin.IsPruned()); assert(coin.IsSpent());
if (value != PRUNED) { if (value != PRUNED) {
coin.out.nValue = value; coin.out.nValue = value;
coin.nHeight = 1; coin.nHeight = 1;
assert(!coin.IsPruned()); assert(!coin.IsSpent());
} }
} }
@ -567,7 +567,7 @@ void GetCoinsMapEntry(const CCoinsMap& map, CAmount& value, char& flags)
value = ABSENT; value = ABSENT;
flags = NO_ENTRY; flags = NO_ENTRY;
} else { } else {
if (it->second.coin.IsPruned()) { if (it->second.coin.IsSpent()) {
value = PRUNED; value = PRUNED;
} else { } else {
value = it->second.coin.out.nValue; value = it->second.coin.out.nValue;

20
src/txdb.cpp

@ -27,10 +27,10 @@ static const char DB_LAST_BLOCK = 'l';
namespace { namespace {
struct CoinsEntry { struct CoinEntry {
COutPoint* outpoint; COutPoint* outpoint;
char key; char key;
CoinsEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {} CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
template<typename Stream> template<typename Stream>
void Serialize(Stream &s) const { void Serialize(Stream &s) const {
@ -53,12 +53,12 @@ CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(Get
{ {
} }
bool CCoinsViewDB::GetCoins(const COutPoint &outpoint, Coin &coin) const { bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
return db.Read(CoinsEntry(&outpoint), coin); return db.Read(CoinEntry(&outpoint), coin);
} }
bool CCoinsViewDB::HaveCoins(const COutPoint &outpoint) const { bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
return db.Exists(CoinsEntry(&outpoint)); return db.Exists(CoinEntry(&outpoint));
} }
uint256 CCoinsViewDB::GetBestBlock() const { uint256 CCoinsViewDB::GetBestBlock() const {
@ -74,8 +74,8 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
size_t changed = 0; size_t changed = 0;
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) { if (it->second.flags & CCoinsCacheEntry::DIRTY) {
CoinsEntry entry(&it->first); CoinEntry entry(&it->first);
if (it->second.coin.IsPruned()) if (it->second.coin.IsSpent())
batch.Erase(entry); batch.Erase(entry);
else else
batch.Write(entry, it->second.coin); batch.Write(entry, it->second.coin);
@ -130,7 +130,7 @@ CCoinsViewCursor *CCoinsViewDB::Cursor() const
i->pcursor->Seek(DB_COIN); i->pcursor->Seek(DB_COIN);
// Cache key of first record // Cache key of first record
if (i->pcursor->Valid()) { if (i->pcursor->Valid()) {
CoinsEntry entry(&i->keyTmp.second); CoinEntry entry(&i->keyTmp.second);
i->pcursor->GetKey(entry); i->pcursor->GetKey(entry);
i->keyTmp.first = entry.key; i->keyTmp.first = entry.key;
} else { } else {
@ -167,7 +167,7 @@ bool CCoinsViewDBCursor::Valid() const
void CCoinsViewDBCursor::Next() void CCoinsViewDBCursor::Next()
{ {
pcursor->Next(); pcursor->Next();
CoinsEntry entry(&keyTmp.second); CoinEntry entry(&keyTmp.second);
if (!pcursor->Valid() || !pcursor->GetKey(entry)) { if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
} else { } else {

4
src/txdb.h

@ -71,8 +71,8 @@ protected:
public: public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
bool GetCoins(const COutPoint &outpoint, Coin &coin) const override; bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
bool HaveCoins(const COutPoint &outpoint) const override; bool HaveCoin(const COutPoint &outpoint) const override;
uint256 GetBestBlock() const override; uint256 GetBestBlock() const override;
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override; bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
CCoinsViewCursor *Cursor() const override; CCoinsViewCursor *Cursor() const override;

14
src/txmempool.cpp

@ -525,8 +525,8 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
if (it2 != mapTx.end()) if (it2 != mapTx.end())
continue; continue;
const Coin &coin = pcoins->AccessCoin(txin.prevout); const Coin &coin = pcoins->AccessCoin(txin.prevout);
if (nCheckFrequency != 0) assert(!coin.IsPruned()); if (nCheckFrequency != 0) assert(!coin.IsSpent());
if (coin.IsPruned() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) { if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) {
txToRemove.insert(it); txToRemove.insert(it);
break; break;
} }
@ -654,7 +654,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
parentSigOpCost += it2->GetSigOpCost(); parentSigOpCost += it2->GetSigOpCost();
} }
} else { } else {
assert(pcoins->HaveCoins(txin.prevout)); assert(pcoins->HaveCoin(txin.prevout));
} }
// Check whether its inputs are marked in mapNextTx. // Check whether its inputs are marked in mapNextTx.
auto it3 = mapNextTx.find(txin.prevout); auto it3 = mapNextTx.find(txin.prevout);
@ -890,7 +890,7 @@ bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
bool CCoinsViewMemPool::GetCoins(const COutPoint &outpoint, Coin &coin) const { bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const {
// If an entry in the mempool exists, always return that one, as it's guaranteed to never // 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) // 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. // transactions. First checking the underlying cache risks returning a pruned entry instead.
@ -903,11 +903,11 @@ bool CCoinsViewMemPool::GetCoins(const COutPoint &outpoint, Coin &coin) const {
return false; return false;
} }
} }
return (base->GetCoins(outpoint, coin) && !coin.IsPruned()); return (base->GetCoin(outpoint, coin) && !coin.IsSpent());
} }
bool CCoinsViewMemPool::HaveCoins(const COutPoint &outpoint) const { bool CCoinsViewMemPool::HaveCoin(const COutPoint &outpoint) const {
return mempool.exists(outpoint) || base->HaveCoins(outpoint); return mempool.exists(outpoint) || base->HaveCoin(outpoint);
} }
size_t CTxMemPool::DynamicMemoryUsage() const { size_t CTxMemPool::DynamicMemoryUsage() const {

4
src/txmempool.h

@ -679,8 +679,8 @@ protected:
public: public:
CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn); CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn);
bool GetCoins(const COutPoint &outpoint, Coin &coin) const; bool GetCoin(const COutPoint &outpoint, Coin &coin) const;
bool HaveCoins(const COutPoint &outpoint) const; bool HaveCoin(const COutPoint &outpoint) const;
}; };
#endif // BITCOIN_TXMEMPOOL_H #endif // BITCOIN_TXMEMPOOL_H

34
src/validation.cpp

@ -269,7 +269,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
const CTxIn& txin = tx.vin[txinIndex]; const CTxIn& txin = tx.vin[txinIndex];
Coin coin; Coin coin;
if (!viewMemPool.GetCoins(txin.prevout, coin)) { if (!viewMemPool.GetCoin(txin.prevout, coin)) {
return error("%s: Missing input", __func__); return error("%s: Missing input", __func__);
} }
if (coin.nHeight == MEMPOOL_HEIGHT) { if (coin.nHeight == MEMPOOL_HEIGHT) {
@ -344,7 +344,7 @@ static bool IsCurrentForFeeEstimation()
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, bool fLimitFree, bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, bool fLimitFree,
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced, bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, std::vector<COutPoint>& vHashTxnToUncache) bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache)
{ {
const CTransaction& tx = *ptx; const CTransaction& tx = *ptx;
const uint256 hash = tx.GetHash(); const uint256 hash = tx.GetHash();
@ -439,10 +439,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// do we already have it? // do we already have it?
for (size_t out = 0; out < tx.vout.size(); out++) { for (size_t out = 0; out < tx.vout.size(); out++) {
COutPoint outpoint(hash, out); COutPoint outpoint(hash, out);
bool fHadTxInCache = pcoinsTip->HaveCoinsInCache(outpoint); bool had_coin_in_cache = pcoinsTip->HaveCoinInCache(outpoint);
if (view.HaveCoins(outpoint)) { if (view.HaveCoin(outpoint)) {
if (!fHadTxInCache) { if (!had_coin_in_cache) {
vHashTxnToUncache.push_back(outpoint); coins_to_uncache.push_back(outpoint);
} }
return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-known"); return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-known");
} }
@ -450,10 +450,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// do all inputs exist? // do all inputs exist?
BOOST_FOREACH(const CTxIn txin, tx.vin) { BOOST_FOREACH(const CTxIn txin, tx.vin) {
if (!pcoinsTip->HaveCoinsInCache(txin.prevout)) { if (!pcoinsTip->HaveCoinInCache(txin.prevout)) {
vHashTxnToUncache.push_back(txin.prevout); coins_to_uncache.push_back(txin.prevout);
} }
if (!view.HaveCoins(txin.prevout)) { if (!view.HaveCoin(txin.prevout)) {
if (pfMissingInputs) { if (pfMissingInputs) {
*pfMissingInputs = true; *pfMissingInputs = true;
} }
@ -763,10 +763,10 @@ bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced, bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
bool fOverrideMempoolLimit, const CAmount nAbsurdFee) bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
{ {
std::vector<COutPoint> vHashTxToUncache; std::vector<COutPoint> coins_to_uncache;
bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache); bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache);
if (!res) { if (!res) {
BOOST_FOREACH(const COutPoint& hashTx, vHashTxToUncache) BOOST_FOREACH(const COutPoint& hashTx, coins_to_uncache)
pcoinsTip->Uncache(hashTx); pcoinsTip->Uncache(hashTx);
} }
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits // After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
@ -819,7 +819,7 @@ bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
const Coin& coin = AccessByTxid(*pcoinsTip, hash); const Coin& coin = AccessByTxid(*pcoinsTip, hash);
if (!coin.IsPruned()) pindexSlow = chainActive[coin.nHeight]; if (!coin.IsSpent()) pindexSlow = chainActive[coin.nHeight];
} }
if (pindexSlow) { if (pindexSlow) {
@ -1117,7 +1117,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
for (unsigned int i = 0; i < tx.vin.size(); i++) { for (unsigned int i = 0; i < tx.vin.size(); i++) {
const COutPoint &prevout = tx.vin[i].prevout; const COutPoint &prevout = tx.vin[i].prevout;
const Coin& coin = inputs.AccessCoin(prevout); const Coin& coin = inputs.AccessCoin(prevout);
assert(!coin.IsPruned()); assert(!coin.IsSpent());
// We very carefully only pass in things to CScriptCheck which // We very carefully only pass in things to CScriptCheck which
// are clearly committed to by tx' witness hash. This provides // are clearly committed to by tx' witness hash. This provides
@ -1254,14 +1254,14 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
{ {
bool fClean = true; bool fClean = true;
if (view.HaveCoins(out)) fClean = false; // overwriting transaction output if (view.HaveCoin(out)) fClean = false; // overwriting transaction output
if (undo.nHeight == 0) { if (undo.nHeight == 0) {
// Missing undo metadata (height and coinbase). Older versions included this // Missing undo metadata (height and coinbase). Older versions included this
// information only in undo records for the last spend of a transactions' // information only in undo records for the last spend of a transactions'
// outputs. This implies that it must be present for some other output of the same tx. // outputs. This implies that it must be present for some other output of the same tx.
const Coin& alternate = AccessByTxid(view, out.hash); const Coin& alternate = AccessByTxid(view, out.hash);
if (!alternate.IsPruned()) { if (!alternate.IsSpent()) {
undo.nHeight = alternate.nHeight; undo.nHeight = alternate.nHeight;
undo.fCoinBase = alternate.fCoinBase; undo.fCoinBase = alternate.fCoinBase;
} else { } else {
@ -1510,7 +1510,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
if (fEnforceBIP30) { if (fEnforceBIP30) {
for (const auto& tx : block.vtx) { for (const auto& tx : block.vtx) {
for (size_t o = 0; o < tx->vout.size(); o++) { for (size_t o = 0; o < tx->vout.size(); o++) {
if (view.HaveCoins(COutPoint(tx->GetHash(), o))) { if (view.HaveCoin(COutPoint(tx->GetHash(), o))) {
return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"), return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"),
REJECT_INVALID, "bad-txns-BIP30"); REJECT_INVALID, "bad-txns-BIP30");
} }

Loading…
Cancel
Save