@@ -498,8 +498,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
498498 // during reorgs to ensure COINBASE_MATURITY is still met.
499499 bool fSpendsCoinbase = false ;
500500 BOOST_FOREACH (const CTxIn &txin, tx.vin ) {
501- const CCoins *coins = view.AccessCoins (txin.prevout . hash );
502- if (coins-> IsCoinBase ()) {
501+ const Coin &coin = view.AccessCoin (txin.prevout );
502+ if (coin. IsCoinBase ()) {
503503 fSpendsCoinbase = true ;
504504 break ;
505505 }
@@ -818,15 +818,8 @@ bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus
818818 }
819819
820820 if (fAllowSlow ) { // use coin database to locate block that contains transaction, and scan it
821- int nHeight = -1 ;
822- {
823- const CCoinsViewCache& view = *pcoinsTip;
824- const CCoins* coins = view.AccessCoins (hash);
825- if (coins)
826- nHeight = coins->nHeight ;
827- }
828- if (nHeight > 0 )
829- pindexSlow = chainActive[nHeight];
821+ const Coin& coin = AccessByTxid (*pcoinsTip, hash);
822+ if (!coin.IsPruned ()) pindexSlow = chainActive[coin.nHeight ];
830823 }
831824
832825 if (pindexSlow) {
@@ -1074,19 +1067,12 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
10741067 if (!tx.IsCoinBase ()) {
10751068 txundo.vprevout .reserve (tx.vin .size ());
10761069 BOOST_FOREACH (const CTxIn &txin, tx.vin ) {
1077- CCoinsModifier coins = inputs.ModifyCoins (txin.prevout .hash );
1078- unsigned nPos = txin.prevout .n ;
1079-
1080- if (nPos >= coins->vout .size () || coins->vout [nPos].IsNull ())
1081- assert (false );
1082- // mark an outpoint spent, and construct undo information
1083- txundo.vprevout .emplace_back (coins->vout [nPos], coins->nHeight , coins->fCoinBase );
1084- bool ret = coins->Spend (nPos);
1085- assert (ret);
1070+ txundo.vprevout .emplace_back ();
1071+ inputs.SpendCoin (txin.prevout , &txundo.vprevout .back ());
10861072 }
10871073 }
10881074 // add outputs
1089- inputs. ModifyNewCoins (tx. GetHash (), tx. IsCoinBase ())-> FromTx ( tx, nHeight);
1075+ AddCoins (inputs, tx, nHeight);
10901076}
10911077
10921078void UpdateCoins (const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
@@ -1260,24 +1246,21 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
12601246{
12611247 bool fClean = true ;
12621248
1263- CCoinsModifier coins = view.ModifyCoins (out.hash );
1264- if (undo.nHeight != 0 ) {
1265- if (!coins->IsPruned ()) {
1266- if (coins->fCoinBase != undo.fCoinBase || (uint32_t )coins->nHeight != undo.nHeight ) fClean = false ; // metadata mismatch
1249+ if (view.HaveCoins (out)) fClean = false ; // overwriting transaction output
1250+
1251+ if (undo.nHeight == 0 ) {
1252+ // Missing undo metadata (height and coinbase). Older versions included this
1253+ // information only in undo records for the last spend of a transactions'
1254+ // outputs. This implies that it must be present for some other output of the same tx.
1255+ const Coin& alternate = AccessByTxid (view, out.hash );
1256+ if (!alternate.IsPruned ()) {
1257+ undo.nHeight = alternate.nHeight ;
1258+ undo.fCoinBase = alternate.fCoinBase ;
1259+ } else {
1260+ return DISCONNECT_FAILED; // adding output for transaction without known metadata
12671261 }
1268- // restore height/coinbase tx metadata from undo data
1269- coins->fCoinBase = undo.fCoinBase ;
1270- coins->nHeight = undo.nHeight ;
1271- } else {
1272- // Undo data does not contain height/coinbase. This should never happen
1273- // for newly created undo entries. Previously, this data was only saved
1274- // for the last spend of a transaction's outputs, so check IsPruned().
1275- if (coins->IsPruned ()) fClean = false ; // adding output to missing transaction
12761262 }
1277- if (coins->IsAvailable (out.n )) fClean = false ; // overwriting existing output
1278- if (coins->vout .size () < out.n +1 )
1279- coins->vout .resize (out.n +1 );
1280- coins->vout [out.n ] = std::move (undo.out );
1263+ view.AddCoin (out, std::move (undo), undo.fCoinBase );
12811264
12821265 return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
12831266}
@@ -1313,15 +1296,15 @@ static DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex*
13131296
13141297 // Check that all outputs are available and match the outputs in the block itself
13151298 // exactly.
1316- {
1317- CCoinsModifier outs = view. ModifyCoins (hash);
1318- outs-> ClearUnspendable ( );
1319-
1320- CCoins outsBlock (tx, pindex-> nHeight );
1321- if (*outs != outsBlock) fClean = false ; // transaction mismatch
1322-
1323- // remove outputs
1324- outs-> Clear ();
1299+ for ( size_t o = 0 ; o < tx. vout . size (); o++) {
1300+ if (!tx. vout [o]. scriptPubKey . IsUnspendable ()) {
1301+ COutPoint out (hash, o );
1302+ Coin coin;
1303+ view. SpendCoin (out, &coin );
1304+ if (tx. vout [o] != coin. out ) {
1305+ fClean = false ; // transaction output mismatch
1306+ }
1307+ }
13251308 }
13261309
13271310 // restore inputs
@@ -1518,10 +1501,12 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
15181501
15191502 if (fEnforceBIP30 ) {
15201503 for (const auto & tx : block.vtx ) {
1521- const CCoins* coins = view.AccessCoins (tx->GetHash ());
1522- if (coins && !coins->IsPruned ())
1523- return state.DoS (100 , error (" ConnectBlock(): tried to overwrite transaction" ),
1524- REJECT_INVALID, " bad-txns-BIP30" );
1504+ for (size_t o = 0 ; o < tx->vout .size (); o++) {
1505+ if (view.HaveCoins (COutPoint (tx->GetHash (), o))) {
1506+ return state.DoS (100 , error (" ConnectBlock(): tried to overwrite transaction" ),
1507+ REJECT_INVALID, " bad-txns-BIP30" );
1508+ }
1509+ }
15251510 }
15261511 }
15271512
@@ -1588,7 +1573,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
15881573 // be in ConnectBlock because they require the UTXO set
15891574 prevheights.resize (tx.vin .size ());
15901575 for (size_t j = 0 ; j < tx.vin .size (); j++) {
1591- prevheights[j] = view.AccessCoins (tx.vin [j].prevout . hash )-> nHeight ;
1576+ prevheights[j] = view.AccessCoin (tx.vin [j].prevout ). nHeight ;
15921577 }
15931578
15941579 if (!SequenceLocks (tx, nLockTimeFlags, &prevheights, *pindex)) {
0 commit comments