44
55#include " coins.h"
66
7+ #include " consensus/consensus.h"
78#include " memusage.h"
89#include " random.h"
910
@@ -70,7 +71,7 @@ size_t CCoinsViewCache::DynamicMemoryUsage() const {
7071 return memusage::DynamicUsage (cacheCoins) + cachedCoinsUsage;
7172}
7273
73- CCoinsMap::const_iterator CCoinsViewCache::FetchCoins (const uint256 &txid) const {
74+ CCoinsMap::iterator CCoinsViewCache::FetchCoins (const uint256 &txid) const {
7475 CCoinsMap::iterator it = cacheCoins.find (txid);
7576 if (it != cacheCoins.end ())
7677 return it;
@@ -153,6 +154,58 @@ CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, bool coinbas
153154 return CCoinsModifier (*this , ret.first , 0 );
154155}
155156
157+ void CCoinsViewCache::AddCoin (const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) {
158+ assert (!coin.IsPruned ());
159+ if (coin.out .scriptPubKey .IsUnspendable ()) return ;
160+ CCoinsMap::iterator it;
161+ bool inserted;
162+ std::tie (it, inserted) = cacheCoins.emplace (std::piecewise_construct, std::forward_as_tuple (outpoint.hash ), std::tuple<>());
163+ bool fresh = false ;
164+ if (!inserted) {
165+ cachedCoinsUsage -= it->second .coins .DynamicMemoryUsage ();
166+ }
167+ if (!possible_overwrite) {
168+ if (it->second .coins .IsAvailable (outpoint.n )) {
169+ throw std::logic_error (" Adding new coin that replaces non-pruned entry" );
170+ }
171+ fresh = it->second .coins .IsPruned () && !(it->second .flags & CCoinsCacheEntry::DIRTY);
172+ }
173+ if (it->second .coins .vout .size () <= outpoint.n ) {
174+ it->second .coins .vout .resize (outpoint.n + 1 );
175+ }
176+ it->second .coins .vout [outpoint.n ] = std::move (coin.out );
177+ it->second .coins .nHeight = coin.nHeight ;
178+ it->second .coins .fCoinBase = coin.fCoinBase ;
179+ it->second .flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0 );
180+ cachedCoinsUsage += it->second .coins .DynamicMemoryUsage ();
181+ }
182+
183+ void AddCoins (CCoinsViewCache& cache, const CTransaction &tx, int nHeight) {
184+ bool fCoinbase = tx.IsCoinBase ();
185+ const uint256& txid = tx.GetHash ();
186+ for (size_t i = 0 ; i < tx.vout .size (); ++i) {
187+ // Pass fCoinbase as the possible_overwrite flag to AddCoin, in order to correctly
188+ // deal with the pre-BIP30 occurrances of duplicate coinbase transactions.
189+ cache.AddCoin (COutPoint (txid, i), Coin (tx.vout [i], nHeight, fCoinbase ), fCoinbase );
190+ }
191+ }
192+
193+ void CCoinsViewCache::SpendCoin (const COutPoint &outpoint, Coin* moveout) {
194+ CCoinsMap::iterator it = FetchCoins (outpoint.hash );
195+ if (it == cacheCoins.end ()) return ;
196+ cachedCoinsUsage -= it->second .coins .DynamicMemoryUsage ();
197+ if (moveout && it->second .coins .IsAvailable (outpoint.n )) {
198+ *moveout = Coin (it->second .coins .vout [outpoint.n ], it->second .coins .nHeight , it->second .coins .fCoinBase );
199+ }
200+ it->second .coins .Spend (outpoint.n ); // Ignore return value: SpendCoin has no effect if no UTXO found.
201+ if (it->second .coins .IsPruned () && it->second .flags & CCoinsCacheEntry::FRESH) {
202+ cacheCoins.erase (it);
203+ } else {
204+ cachedCoinsUsage += it->second .coins .DynamicMemoryUsage ();
205+ it->second .flags |= CCoinsCacheEntry::DIRTY;
206+ }
207+ }
208+
156209const CCoins* CCoinsViewCache::AccessCoins (const uint256 &txid) const {
157210 CCoinsMap::const_iterator it = FetchCoins (txid);
158211 if (it == cacheCoins.end ()) {
@@ -162,6 +215,18 @@ const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
162215 }
163216}
164217
218+ static const Coin coinEmpty;
219+
220+ const Coin CCoinsViewCache::AccessCoin (const COutPoint &outpoint) const {
221+ CCoinsMap::const_iterator it = FetchCoins (outpoint.hash );
222+ if (it == cacheCoins.end () || !it->second .coins .IsAvailable (outpoint.n )) {
223+ return coinEmpty;
224+ } else {
225+ return Coin (it->second .coins .vout [outpoint.n ], it->second .coins .nHeight , it->second .coins .fCoinBase );
226+ }
227+ }
228+
229+
165230bool CCoinsViewCache::HaveCoins (const uint256 &txid) const {
166231 CCoinsMap::const_iterator it = FetchCoins (txid);
167232 // We're using vtx.empty() instead of IsPruned here for performance reasons,
@@ -171,6 +236,11 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
171236 return (it != cacheCoins.end () && !it->second .coins .vout .empty ());
172237}
173238
239+ bool CCoinsViewCache::HaveCoins (const COutPoint &outpoint) const {
240+ CCoinsMap::const_iterator it = FetchCoins (outpoint.hash );
241+ return (it != cacheCoins.end () && it->second .coins .IsAvailable (outpoint.n ));
242+ }
243+
174244bool CCoinsViewCache::HaveCoinsInCache (const uint256 &txid) const {
175245 CCoinsMap::const_iterator it = cacheCoins.find (txid);
176246 return it != cacheCoins.end ();
@@ -318,3 +388,16 @@ CCoinsModifier::~CCoinsModifier()
318388CCoinsViewCursor::~CCoinsViewCursor ()
319389{
320390}
391+
392+ static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE / ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); // TODO: merge with similar definition in undo.h.
393+
394+ const Coin AccessByTxid (const CCoinsViewCache& view, const uint256& txid)
395+ {
396+ COutPoint iter (txid, 0 );
397+ while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
398+ const Coin& alternate = view.AccessCoin (iter);
399+ if (!alternate.IsPruned ()) return alternate;
400+ ++iter.n ;
401+ }
402+ return coinEmpty;
403+ }
0 commit comments