mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
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-
This commit is contained in:
parent
a5e02bc7f8
commit
589827975f
@ -562,7 +562,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
|
||||
|
||||
{
|
||||
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");
|
||||
err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
|
||||
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++) {
|
||||
CTxIn& txin = mergedTx.vin[i];
|
||||
const Coin& coin = view.AccessCoin(txin.prevout);
|
||||
if (coin.IsPruned()) {
|
||||
if (coin.IsSpent()) {
|
||||
fComplete = false;
|
||||
continue;
|
||||
}
|
||||
|
@ -10,16 +10,16 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
bool CCoinsView::GetCoins(const COutPoint &outpoint, Coin &coin) const { return false; }
|
||||
bool CCoinsView::HaveCoins(const COutPoint &outpoint) const { return false; }
|
||||
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
|
||||
bool CCoinsView::HaveCoin(const COutPoint &outpoint) const { return false; }
|
||||
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
|
||||
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
|
||||
CCoinsViewCursor *CCoinsView::Cursor() const { return 0; }
|
||||
|
||||
|
||||
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
|
||||
bool CCoinsViewBacked::GetCoins(const COutPoint &outpoint, Coin &coin) const { return base->GetCoins(outpoint, coin); }
|
||||
bool CCoinsViewBacked::HaveCoins(const COutPoint &outpoint) const { return base->HaveCoins(outpoint); }
|
||||
bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { return base->GetCoin(outpoint, coin); }
|
||||
bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); }
|
||||
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
|
||||
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
|
||||
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;
|
||||
}
|
||||
|
||||
CCoinsMap::iterator CCoinsViewCache::FetchCoins(const COutPoint &outpoint) const {
|
||||
CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const {
|
||||
CCoinsMap::iterator it = cacheCoins.find(outpoint);
|
||||
if (it != cacheCoins.end())
|
||||
return it;
|
||||
Coin tmp;
|
||||
if (!base->GetCoins(outpoint, tmp))
|
||||
if (!base->GetCoin(outpoint, tmp))
|
||||
return cacheCoins.end();
|
||||
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
|
||||
// version as fresh.
|
||||
ret->second.flags = CCoinsCacheEntry::FRESH;
|
||||
@ -51,8 +51,8 @@ CCoinsMap::iterator CCoinsViewCache::FetchCoins(const COutPoint &outpoint) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::GetCoins(const COutPoint &outpoint, Coin &coin) const {
|
||||
CCoinsMap::const_iterator it = FetchCoins(outpoint);
|
||||
bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const {
|
||||
CCoinsMap::const_iterator it = FetchCoin(outpoint);
|
||||
if (it != cacheCoins.end()) {
|
||||
coin = it->second.coin;
|
||||
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) {
|
||||
assert(!coin.IsPruned());
|
||||
assert(!coin.IsSpent());
|
||||
if (coin.out.scriptPubKey.IsUnspendable()) return;
|
||||
CCoinsMap::iterator it;
|
||||
bool inserted;
|
||||
@ -71,7 +71,7 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
|
||||
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
|
||||
}
|
||||
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");
|
||||
}
|
||||
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) {
|
||||
CCoinsMap::iterator it = FetchCoins(outpoint);
|
||||
CCoinsMap::iterator it = FetchCoin(outpoint);
|
||||
if (it == cacheCoins.end()) return;
|
||||
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
|
||||
if (moveout) {
|
||||
@ -109,7 +109,7 @@ void CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
|
||||
static const Coin coinEmpty;
|
||||
|
||||
const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
|
||||
CCoinsMap::const_iterator it = FetchCoins(outpoint);
|
||||
CCoinsMap::const_iterator it = FetchCoin(outpoint);
|
||||
if (it == cacheCoins.end()) {
|
||||
return coinEmpty;
|
||||
} else {
|
||||
@ -117,12 +117,12 @@ const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::HaveCoins(const COutPoint &outpoint) const {
|
||||
CCoinsMap::const_iterator it = FetchCoins(outpoint);
|
||||
return (it != cacheCoins.end() && !it->second.coin.IsPruned());
|
||||
bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const {
|
||||
CCoinsMap::const_iterator it = FetchCoin(outpoint);
|
||||
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);
|
||||
return it != cacheCoins.end();
|
||||
}
|
||||
@ -144,7 +144,7 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
|
||||
if (itUs == cacheCoins.end()) {
|
||||
// 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
|
||||
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
|
||||
// and move the data up and mark it as dirty
|
||||
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,
|
||||
// it means the FRESH flag was misapplied and there is a logic
|
||||
// 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");
|
||||
|
||||
// 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
|
||||
// modified and being pruned. This means we can just delete
|
||||
// it from the parent.
|
||||
@ -229,7 +229,7 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
|
||||
{
|
||||
if (!tx.IsCoinBase()) {
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
if (!HaveCoins(tx.vin[i].prevout)) {
|
||||
if (!HaveCoin(tx.vin[i].prevout)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -244,7 +244,7 @@ const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
|
||||
COutPoint iter(txid, 0);
|
||||
while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
|
||||
const Coin& alternate = view.AccessCoin(iter);
|
||||
if (!alternate.IsPruned()) return alternate;
|
||||
if (!alternate.IsSpent()) return alternate;
|
||||
++iter.n;
|
||||
}
|
||||
return coinEmpty;
|
||||
|
24
src/coins.h
24
src/coins.h
@ -58,7 +58,7 @@ public:
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream &s) const {
|
||||
assert(!IsPruned());
|
||||
assert(!IsSpent());
|
||||
uint32_t code = nHeight * 2 + fCoinBase;
|
||||
::Serialize(s, VARINT(code));
|
||||
::Serialize(s, CTxOutCompressor(REF(out)));
|
||||
@ -73,7 +73,7 @@ public:
|
||||
::Unserialize(s, REF(CTxOutCompressor(out)));
|
||||
}
|
||||
|
||||
bool IsPruned() const {
|
||||
bool IsSpent() const {
|
||||
return out.IsNull();
|
||||
}
|
||||
|
||||
@ -147,11 +147,11 @@ class CCoinsView
|
||||
{
|
||||
public:
|
||||
//! 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.
|
||||
//! 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
|
||||
virtual uint256 GetBestBlock() const;
|
||||
@ -179,8 +179,8 @@ protected:
|
||||
|
||||
public:
|
||||
CCoinsViewBacked(CCoinsView *viewIn);
|
||||
bool GetCoins(const COutPoint &outpoint, Coin &coin) const override;
|
||||
bool HaveCoins(const COutPoint &outpoint) const override;
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
|
||||
bool HaveCoin(const COutPoint &outpoint) const override;
|
||||
uint256 GetBestBlock() const override;
|
||||
void SetBackend(CCoinsView &viewIn);
|
||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
|
||||
@ -207,22 +207,22 @@ public:
|
||||
CCoinsViewCache(CCoinsView *baseIn);
|
||||
|
||||
// Standard CCoinsView methods
|
||||
bool GetCoins(const COutPoint &outpoint, Coin &coin) const;
|
||||
bool HaveCoins(const COutPoint &outpoint) const;
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const;
|
||||
bool HaveCoin(const COutPoint &outpoint) const;
|
||||
uint256 GetBestBlock() const;
|
||||
void SetBestBlock(const uint256 &hashBlock);
|
||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
const Coin& AccessCoin(const COutPoint &output) const;
|
||||
@ -273,7 +273,7 @@ public:
|
||||
bool HaveInputs(const CTransaction& tx) const;
|
||||
|
||||
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.
|
||||
|
@ -214,7 +214,7 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
|
||||
{
|
||||
const COutPoint &prevout = tx.vin[i].prevout;
|
||||
const Coin& coin = inputs.AccessCoin(prevout);
|
||||
assert(!coin.IsPruned());
|
||||
assert(!coin.IsSpent());
|
||||
|
||||
// If prev is coinbase, check that it's matured
|
||||
if (coin.IsCoinBase()) {
|
||||
|
@ -146,9 +146,9 @@ class CCoinsViewErrorCatcher : public CCoinsViewBacked
|
||||
{
|
||||
public:
|
||||
CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
|
||||
bool GetCoins(const COutPoint &outpoint, Coin &coin) const override {
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override {
|
||||
try {
|
||||
return CCoinsViewBacked::GetCoins(outpoint, coin);
|
||||
return CCoinsViewBacked::GetCoin(outpoint, coin);
|
||||
} catch(const std::runtime_error& e) {
|
||||
uiInterface.ThreadSafeMessageBox(_("Error reading from database, shutting down."), "", CClientUIInterface::MSG_ERROR);
|
||||
LogPrintf("Error reading from database: %s\n", e.what());
|
||||
|
@ -914,8 +914,8 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
return recentRejects->contains(inv.hash) ||
|
||||
mempool.exists(inv.hash) ||
|
||||
mapOrphanTransactions.count(inv.hash) ||
|
||||
pcoinsTip->HaveCoinsInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1
|
||||
pcoinsTip->HaveCoinsInCache(COutPoint(inv.hash, 1));
|
||||
pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1
|
||||
pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1));
|
||||
}
|
||||
case MSG_BLOCK:
|
||||
case MSG_WITNESS_BLOCK:
|
||||
|
@ -294,7 +294,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
||||
COutPoint prevout = txin.prevout;
|
||||
|
||||
Coin prev;
|
||||
if(pcoinsTip->GetCoins(prevout, prev))
|
||||
if(pcoinsTip->GetCoin(prevout, prev))
|
||||
{
|
||||
{
|
||||
strHTML += "<li>";
|
||||
|
@ -514,7 +514,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
|
||||
for (size_t i = 0; i < vOutPoints.size(); i++) {
|
||||
bool hit = false;
|
||||
Coin coin;
|
||||
if (view.GetCoins(vOutPoints[i], coin) && !mempool.isSpent(vOutPoints[i])) {
|
||||
if (view.GetCoin(vOutPoints[i], coin) && !mempool.isSpent(vOutPoints[i])) {
|
||||
hit = true;
|
||||
outs.emplace_back(std::move(coin));
|
||||
}
|
||||
|
@ -985,11 +985,11 @@ UniValue gettxout(const JSONRPCRequest& request)
|
||||
if (fMempool) {
|
||||
LOCK(mempool.cs);
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
if (!pcoinsTip->GetCoins(out, coin)) {
|
||||
if (!pcoinsTip->GetCoin(out, coin)) {
|
||||
return NullUniValue;
|
||||
}
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
|
||||
pblockindex = mapBlockIndex[hashBlock];
|
||||
} else {
|
||||
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];
|
||||
}
|
||||
}
|
||||
@ -696,7 +696,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
|
||||
|
||||
{
|
||||
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");
|
||||
err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
|
||||
ScriptToAsmStr(scriptPubKey);
|
||||
@ -768,7 +768,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
|
||||
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
|
||||
CTxIn& txin = mergedTx.vin[i];
|
||||
const Coin& coin = view.AccessCoin(txin.prevout);
|
||||
if (coin.IsPruned()) {
|
||||
if (coin.IsSpent()) {
|
||||
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
|
||||
continue;
|
||||
}
|
||||
@ -848,7 +848,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
|
||||
bool fHaveChain = false;
|
||||
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
|
||||
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
|
||||
fHaveChain = !existingCoin.IsPruned();
|
||||
fHaveChain = !existingCoin.IsSpent();
|
||||
}
|
||||
bool fHaveMempool = mempool.exists(hashTx);
|
||||
if (!fHaveMempool && !fHaveChain) {
|
||||
|
@ -25,7 +25,7 @@ namespace
|
||||
//! equality test
|
||||
bool operator==(const Coin &a, const Coin &b) {
|
||||
// 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 &&
|
||||
a.nHeight == b.nHeight &&
|
||||
a.out == b.out;
|
||||
@ -37,24 +37,24 @@ class CCoinsViewTest : public CCoinsView
|
||||
std::map<COutPoint, Coin> map_;
|
||||
|
||||
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);
|
||||
if (it == map_.end()) {
|
||||
return false;
|
||||
}
|
||||
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.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HaveCoins(const COutPoint& outpoint) const
|
||||
bool HaveCoin(const COutPoint& outpoint) const
|
||||
{
|
||||
Coin coin;
|
||||
return GetCoins(outpoint, coin);
|
||||
return GetCoin(outpoint, coin);
|
||||
}
|
||||
|
||||
uint256 GetBestBlock() const { return hashBestBlock_; }
|
||||
@ -65,7 +65,7 @@ public:
|
||||
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
|
||||
// Same optimization used in CCoinsViewDB is to only write dirty entries.
|
||||
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.
|
||||
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));
|
||||
BOOST_CHECK(coin == entry);
|
||||
|
||||
if (insecure_rand() % 5 == 0 || coin.IsPruned()) {
|
||||
if (insecure_rand() % 5 == 0 || coin.IsSpent()) {
|
||||
Coin newcoin;
|
||||
newcoin.out.nValue = insecure_rand();
|
||||
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);
|
||||
BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable());
|
||||
added_an_unspendable_entry = true;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
removed_an_entry = true;
|
||||
coin.Clear();
|
||||
@ -177,20 +177,20 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
|
||||
COutPoint out(txids[insecure_rand() % txids.size()], 0);
|
||||
int cacheid = insecure_rand() % stack.size();
|
||||
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.
|
||||
if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
|
||||
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);
|
||||
BOOST_CHECK(have == !coin.IsPruned());
|
||||
BOOST_CHECK(have == !coin.IsSpent());
|
||||
BOOST_CHECK(coin == it->second);
|
||||
if (coin.IsPruned()) {
|
||||
if (coin.IsSpent()) {
|
||||
missed_an_entry = true;
|
||||
} else {
|
||||
BOOST_CHECK(stack.back()->HaveCoinsInCache(it->first));
|
||||
BOOST_CHECK(stack.back()->HaveCoinInCache(it->first));
|
||||
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.
|
||||
|
||||
// Track the txids we've used in various sets
|
||||
std::set<COutPoint> coinbaseids;
|
||||
std::set<COutPoint> disconnectedids;
|
||||
std::set<COutPoint> duplicateids;
|
||||
std::set<COutPoint> coinbase_coins;
|
||||
std::set<COutPoint> disconnected_coins;
|
||||
std::set<COutPoint> duplicate_coins;
|
||||
std::set<COutPoint> utxoset;
|
||||
|
||||
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].scriptPubKey.assign(insecure_rand() & 0x3F, 0); // Random sizes so we can test memory usage accounting
|
||||
unsigned int height = insecure_rand();
|
||||
Coin oldcoins;
|
||||
Coin old_coin;
|
||||
|
||||
// 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
|
||||
if (insecure_rand() % 10 == 0 && coinbaseids.size()) {
|
||||
auto utxod = FindRandomFrom(coinbaseids);
|
||||
if (insecure_rand() % 10 == 0 && coinbase_coins.size()) {
|
||||
auto utxod = FindRandomFrom(coinbase_coins);
|
||||
// Reuse the exact same coinbase
|
||||
tx = std::get<0>(utxod->second);
|
||||
// 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 {
|
||||
coinbaseids.insert(COutPoint(tx.GetHash(), 0));
|
||||
coinbase_coins.insert(COutPoint(tx.GetHash(), 0));
|
||||
}
|
||||
assert(CTransaction(tx).IsCoinBase());
|
||||
}
|
||||
@ -322,21 +322,21 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
|
||||
|
||||
COutPoint prevout;
|
||||
// 1/20 times reconnect a previously disconnected tx
|
||||
if (randiter % 20 == 2 && disconnectedids.size()) {
|
||||
auto utxod = FindRandomFrom(disconnectedids);
|
||||
if (randiter % 20 == 2 && disconnected_coins.size()) {
|
||||
auto utxod = FindRandomFrom(disconnected_coins);
|
||||
tx = std::get<0>(utxod->second);
|
||||
prevout = tx.vin[0].prevout;
|
||||
if (!CTransaction(tx).IsCoinBase() && !utxoset.count(prevout)) {
|
||||
disconnectedids.erase(utxod->first);
|
||||
disconnected_coins.erase(utxod->first);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
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
|
||||
@ -349,7 +349,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
|
||||
assert(!CTransaction(tx).IsCoinBase());
|
||||
}
|
||||
// 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
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -375,21 +375,21 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
|
||||
utxoset.insert(outpoint);
|
||||
|
||||
// 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()) {
|
||||
//1/20 times undo a previous transaction
|
||||
auto utxod = FindRandomFrom(utxoset);
|
||||
|
||||
CTransaction &tx = std::get<0>(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
|
||||
// Remove new outputs
|
||||
result[utxod->first].Clear();
|
||||
// If not coinbase restore prevout
|
||||
if (!tx.IsCoinBase()) {
|
||||
result[tx.vin[0].prevout] = origcoins;
|
||||
result[tx.vin[0].prevout] = orig_coin;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
// Store as a candidate for reconnection
|
||||
disconnectedids.insert(utxod->first);
|
||||
disconnected_coins.insert(utxod->first);
|
||||
|
||||
// Update the utxoset
|
||||
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.
|
||||
if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
|
||||
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);
|
||||
BOOST_CHECK(have == !coin.IsPruned());
|
||||
BOOST_CHECK(have == !coin.IsSpent());
|
||||
BOOST_CHECK(coin == it->second);
|
||||
}
|
||||
}
|
||||
@ -425,11 +425,11 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
|
||||
if (utxoset.size() > 1 && insecure_rand() % 30) {
|
||||
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first);
|
||||
}
|
||||
if (disconnectedids.size() > 1 && insecure_rand() % 30) {
|
||||
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(disconnectedids)->first);
|
||||
if (disconnected_coins.size() > 1 && insecure_rand() % 30) {
|
||||
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first);
|
||||
}
|
||||
if (duplicateids.size() > 1 && insecure_rand() % 30) {
|
||||
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(duplicateids)->first);
|
||||
if (duplicate_coins.size() > 1 && insecure_rand() % 30) {
|
||||
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(duplicate_coins)->first);
|
||||
}
|
||||
|
||||
if (insecure_rand() % 100 == 0) {
|
||||
@ -537,11 +537,11 @@ void SetCoinsValue(CAmount value, Coin& coin)
|
||||
{
|
||||
assert(value != ABSENT);
|
||||
coin.Clear();
|
||||
assert(coin.IsPruned());
|
||||
assert(coin.IsSpent());
|
||||
if (value != PRUNED) {
|
||||
coin.out.nValue = value;
|
||||
coin.nHeight = 1;
|
||||
assert(!coin.IsPruned());
|
||||
assert(!coin.IsSpent());
|
||||
}
|
||||
}
|
||||
|
||||
@ -567,7 +567,7 @@ void GetCoinsMapEntry(const CCoinsMap& map, CAmount& value, char& flags)
|
||||
value = ABSENT;
|
||||
flags = NO_ENTRY;
|
||||
} else {
|
||||
if (it->second.coin.IsPruned()) {
|
||||
if (it->second.coin.IsSpent()) {
|
||||
value = PRUNED;
|
||||
} else {
|
||||
value = it->second.coin.out.nValue;
|
||||
|
20
src/txdb.cpp
20
src/txdb.cpp
@ -27,10 +27,10 @@ static const char DB_LAST_BLOCK = 'l';
|
||||
|
||||
namespace {
|
||||
|
||||
struct CoinsEntry {
|
||||
struct CoinEntry {
|
||||
COutPoint* outpoint;
|
||||
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>
|
||||
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 {
|
||||
return db.Read(CoinsEntry(&outpoint), coin);
|
||||
bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
|
||||
return db.Read(CoinEntry(&outpoint), coin);
|
||||
}
|
||||
|
||||
bool CCoinsViewDB::HaveCoins(const COutPoint &outpoint) const {
|
||||
return db.Exists(CoinsEntry(&outpoint));
|
||||
bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
|
||||
return db.Exists(CoinEntry(&outpoint));
|
||||
}
|
||||
|
||||
uint256 CCoinsViewDB::GetBestBlock() const {
|
||||
@ -74,8 +74,8 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
|
||||
size_t changed = 0;
|
||||
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
|
||||
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
|
||||
CoinsEntry entry(&it->first);
|
||||
if (it->second.coin.IsPruned())
|
||||
CoinEntry entry(&it->first);
|
||||
if (it->second.coin.IsSpent())
|
||||
batch.Erase(entry);
|
||||
else
|
||||
batch.Write(entry, it->second.coin);
|
||||
@ -130,7 +130,7 @@ CCoinsViewCursor *CCoinsViewDB::Cursor() const
|
||||
i->pcursor->Seek(DB_COIN);
|
||||
// Cache key of first record
|
||||
if (i->pcursor->Valid()) {
|
||||
CoinsEntry entry(&i->keyTmp.second);
|
||||
CoinEntry entry(&i->keyTmp.second);
|
||||
i->pcursor->GetKey(entry);
|
||||
i->keyTmp.first = entry.key;
|
||||
} else {
|
||||
@ -167,7 +167,7 @@ bool CCoinsViewDBCursor::Valid() const
|
||||
void CCoinsViewDBCursor::Next()
|
||||
{
|
||||
pcursor->Next();
|
||||
CoinsEntry entry(&keyTmp.second);
|
||||
CoinEntry entry(&keyTmp.second);
|
||||
if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
|
||||
keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
|
||||
} else {
|
||||
|
@ -71,8 +71,8 @@ protected:
|
||||
public:
|
||||
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
|
||||
|
||||
bool GetCoins(const COutPoint &outpoint, Coin &coin) const override;
|
||||
bool HaveCoins(const COutPoint &outpoint) const override;
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
|
||||
bool HaveCoin(const COutPoint &outpoint) const override;
|
||||
uint256 GetBestBlock() const override;
|
||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
|
||||
CCoinsViewCursor *Cursor() const override;
|
||||
|
@ -525,8 +525,8 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
|
||||
if (it2 != mapTx.end())
|
||||
continue;
|
||||
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)) {
|
||||
if (nCheckFrequency != 0) assert(!coin.IsSpent());
|
||||
if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) {
|
||||
txToRemove.insert(it);
|
||||
break;
|
||||
}
|
||||
@ -654,7 +654,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
||||
parentSigOpCost += it2->GetSigOpCost();
|
||||
}
|
||||
} else {
|
||||
assert(pcoins->HaveCoins(txin.prevout));
|
||||
assert(pcoins->HaveCoin(txin.prevout));
|
||||
}
|
||||
// Check whether its inputs are marked in mapNextTx.
|
||||
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) { }
|
||||
|
||||
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
|
||||
// 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.
|
||||
@ -903,11 +903,11 @@ bool CCoinsViewMemPool::GetCoins(const COutPoint &outpoint, Coin &coin) const {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (base->GetCoins(outpoint, coin) && !coin.IsPruned());
|
||||
return (base->GetCoin(outpoint, coin) && !coin.IsSpent());
|
||||
}
|
||||
|
||||
bool CCoinsViewMemPool::HaveCoins(const COutPoint &outpoint) const {
|
||||
return mempool.exists(outpoint) || base->HaveCoins(outpoint);
|
||||
bool CCoinsViewMemPool::HaveCoin(const COutPoint &outpoint) const {
|
||||
return mempool.exists(outpoint) || base->HaveCoin(outpoint);
|
||||
}
|
||||
|
||||
size_t CTxMemPool::DynamicMemoryUsage() const {
|
||||
|
@ -679,8 +679,8 @@ protected:
|
||||
|
||||
public:
|
||||
CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn);
|
||||
bool GetCoins(const COutPoint &outpoint, Coin &coin) const;
|
||||
bool HaveCoins(const COutPoint &outpoint) const;
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const;
|
||||
bool HaveCoin(const COutPoint &outpoint) const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_TXMEMPOOL_H
|
||||
|
@ -269,7 +269,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
|
||||
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
|
||||
const CTxIn& txin = tx.vin[txinIndex];
|
||||
Coin coin;
|
||||
if (!viewMemPool.GetCoins(txin.prevout, coin)) {
|
||||
if (!viewMemPool.GetCoin(txin.prevout, coin)) {
|
||||
return error("%s: Missing input", __func__);
|
||||
}
|
||||
if (coin.nHeight == MEMPOOL_HEIGHT) {
|
||||
@ -344,7 +344,7 @@ static bool IsCurrentForFeeEstimation()
|
||||
|
||||
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, bool fLimitFree,
|
||||
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 uint256 hash = tx.GetHash();
|
||||
@ -439,10 +439,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||
// do we already have it?
|
||||
for (size_t out = 0; out < tx.vout.size(); out++) {
|
||||
COutPoint outpoint(hash, out);
|
||||
bool fHadTxInCache = pcoinsTip->HaveCoinsInCache(outpoint);
|
||||
if (view.HaveCoins(outpoint)) {
|
||||
if (!fHadTxInCache) {
|
||||
vHashTxnToUncache.push_back(outpoint);
|
||||
bool had_coin_in_cache = pcoinsTip->HaveCoinInCache(outpoint);
|
||||
if (view.HaveCoin(outpoint)) {
|
||||
if (!had_coin_in_cache) {
|
||||
coins_to_uncache.push_back(outpoint);
|
||||
}
|
||||
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?
|
||||
BOOST_FOREACH(const CTxIn txin, tx.vin) {
|
||||
if (!pcoinsTip->HaveCoinsInCache(txin.prevout)) {
|
||||
vHashTxnToUncache.push_back(txin.prevout);
|
||||
if (!pcoinsTip->HaveCoinInCache(txin.prevout)) {
|
||||
coins_to_uncache.push_back(txin.prevout);
|
||||
}
|
||||
if (!view.HaveCoins(txin.prevout)) {
|
||||
if (!view.HaveCoin(txin.prevout)) {
|
||||
if (pfMissingInputs) {
|
||||
*pfMissingInputs = true;
|
||||
}
|
||||
@ -763,10 +763,10 @@ bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const
|
||||
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
|
||||
bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
|
||||
{
|
||||
std::vector<COutPoint> vHashTxToUncache;
|
||||
bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
|
||||
std::vector<COutPoint> coins_to_uncache;
|
||||
bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, plTxnReplaced, fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache);
|
||||
if (!res) {
|
||||
BOOST_FOREACH(const COutPoint& hashTx, vHashTxToUncache)
|
||||
BOOST_FOREACH(const COutPoint& hashTx, coins_to_uncache)
|
||||
pcoinsTip->Uncache(hashTx);
|
||||
}
|
||||
// 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
|
||||
const Coin& coin = AccessByTxid(*pcoinsTip, hash);
|
||||
if (!coin.IsPruned()) pindexSlow = chainActive[coin.nHeight];
|
||||
if (!coin.IsSpent()) pindexSlow = chainActive[coin.nHeight];
|
||||
}
|
||||
|
||||
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++) {
|
||||
const COutPoint &prevout = tx.vin[i].prevout;
|
||||
const Coin& coin = inputs.AccessCoin(prevout);
|
||||
assert(!coin.IsPruned());
|
||||
assert(!coin.IsSpent());
|
||||
|
||||
// We very carefully only pass in things to CScriptCheck which
|
||||
// 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;
|
||||
|
||||
if (view.HaveCoins(out)) fClean = false; // overwriting transaction output
|
||||
if (view.HaveCoin(out)) fClean = false; // overwriting transaction output
|
||||
|
||||
if (undo.nHeight == 0) {
|
||||
// Missing undo metadata (height and coinbase). Older versions included this
|
||||
// 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.
|
||||
const Coin& alternate = AccessByTxid(view, out.hash);
|
||||
if (!alternate.IsPruned()) {
|
||||
if (!alternate.IsSpent()) {
|
||||
undo.nHeight = alternate.nHeight;
|
||||
undo.fCoinBase = alternate.fCoinBase;
|
||||
} else {
|
||||
@ -1510,7 +1510,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
|
||||
if (fEnforceBIP30) {
|
||||
for (const auto& tx : block.vtx) {
|
||||
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"),
|
||||
REJECT_INVALID, "bad-txns-BIP30");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user