@@ -185,11 +185,89 @@ bool CheckFinalTxAtTip(const CBlockIndex& active_chain_tip, const CTransaction&
185185 return IsFinalTx (tx, nBlockHeight, nBlockTime);
186186}
187187
188+ namespace {
189+ /* *
190+ * A helper which calculates heights of inputs of a given transaction.
191+ *
192+ * @param[in] tip The current chain tip. If an input belongs to a mempool
193+ * transaction, we assume it will be confirmed in the next block.
194+ * @param[in] coins Any CCoinsView that provides access to the relevant coins.
195+ * @param[in] tx The transaction being evaluated.
196+ *
197+ * @returns A vector of input heights or nullopt, in case of an error.
198+ */
199+ std::optional<std::vector<int >> CalculatePrevHeights (
200+ const CBlockIndex& tip,
201+ const CCoinsView& coins,
202+ const CTransaction& tx)
203+ {
204+ std::vector<int > prev_heights;
205+ prev_heights.resize (tx.vin .size ());
206+ for (size_t i = 0 ; i < tx.vin .size (); ++i) {
207+ const CTxIn& txin = tx.vin [i];
208+ Coin coin;
209+ if (!coins.GetCoin (txin.prevout , coin)) {
210+ LogPrintf (" ERROR: %s: Missing input %d in transaction \' %s\'\n " , __func__, i, tx.GetHash ().GetHex ());
211+ return std::nullopt ;
212+ }
213+ if (coin.nHeight == MEMPOOL_HEIGHT) {
214+ // Assume all mempool transaction confirm in the next block.
215+ prev_heights[i] = tip.nHeight + 1 ;
216+ } else {
217+ prev_heights[i] = coin.nHeight ;
218+ }
219+ }
220+ return prev_heights;
221+ }
222+ } // namespace
223+
224+ std::optional<LockPoints> CalculateLockPointsAtTip (
225+ CBlockIndex* tip,
226+ const CCoinsView& coins_view,
227+ const CTransaction& tx)
228+ {
229+ assert (tip);
230+
231+ auto prev_heights{CalculatePrevHeights (*tip, coins_view, tx)};
232+ if (!prev_heights.has_value ()) return std::nullopt ;
233+
234+ CBlockIndex next_tip;
235+ next_tip.pprev = tip;
236+ // When SequenceLocks() is called within ConnectBlock(), the height
237+ // of the block *being* evaluated is what is used.
238+ // Thus if we want to know if a transaction can be part of the
239+ // *next* block, we need to use one more than active_chainstate.m_chain.Height()
240+ next_tip.nHeight = tip->nHeight + 1 ;
241+ const auto [min_height, min_time] = CalculateSequenceLocks (tx, STANDARD_LOCKTIME_VERIFY_FLAGS, prev_heights.value (), next_tip);
242+
243+ // Also store the hash of the block with the highest height of
244+ // all the blocks which have sequence locked prevouts.
245+ // This hash needs to still be on the chain
246+ // for these LockPoint calculations to be valid
247+ // Note: It is impossible to correctly calculate a maxInputBlock
248+ // if any of the sequence locked inputs depend on unconfirmed txs,
249+ // except in the special case where the relative lock time/height
250+ // is 0, which is equivalent to no sequence lock. Since we assume
251+ // input height of tip+1 for mempool txs and test the resulting
252+ // min_height and min_time from CalculateSequenceLocks against tip+1.
253+ int max_input_height{0 };
254+ for (const int height : prev_heights.value ()) {
255+ // Can ignore mempool inputs since we'll fail if they had non-zero locks
256+ if (height != next_tip.nHeight ) {
257+ max_input_height = std::max (max_input_height, height);
258+ }
259+ }
260+
261+ // tip->GetAncestor(max_input_height) should never return a nullptr
262+ // because max_input_height is always less than the tip height.
263+ // It would, however, be a bad bug to continue execution, since a
264+ // LockPoints object with the maxInputBlock member set to nullptr
265+ // signifies no relative lock time.
266+ return LockPoints{min_height, min_time, Assert (tip->GetAncestor (max_input_height))};
267+ }
268+
188269bool CheckSequenceLocksAtTip (CBlockIndex* tip,
189- const CCoinsView& coins_view,
190- const CTransaction& tx,
191- LockPoints* lp,
192- bool useExistingLockPoints)
270+ const LockPoints& lock_points)
193271{
194272 assert (tip != nullptr );
195273
@@ -203,61 +281,7 @@ bool CheckSequenceLocksAtTip(CBlockIndex* tip,
203281 // *next* block, we need to use one more than active_chainstate.m_chain.Height()
204282 index.nHeight = tip->nHeight + 1 ;
205283
206- std::pair<int , int64_t > lockPair;
207- if (useExistingLockPoints) {
208- assert (lp);
209- lockPair.first = lp->height ;
210- lockPair.second = lp->time ;
211- }
212- else {
213- std::vector<int > prevheights;
214- prevheights.resize (tx.vin .size ());
215- for (size_t txinIndex = 0 ; txinIndex < tx.vin .size (); txinIndex++) {
216- const CTxIn& txin = tx.vin [txinIndex];
217- Coin coin;
218- if (!coins_view.GetCoin (txin.prevout , coin)) {
219- return error (" %s: Missing input" , __func__);
220- }
221- if (coin.nHeight == MEMPOOL_HEIGHT) {
222- // Assume all mempool transaction confirm in the next block
223- prevheights[txinIndex] = tip->nHeight + 1 ;
224- } else {
225- prevheights[txinIndex] = coin.nHeight ;
226- }
227- }
228- lockPair = CalculateSequenceLocks (tx, STANDARD_LOCKTIME_VERIFY_FLAGS, prevheights, index);
229- if (lp) {
230- lp->height = lockPair.first ;
231- lp->time = lockPair.second ;
232- // Also store the hash of the block with the highest height of
233- // all the blocks which have sequence locked prevouts.
234- // This hash needs to still be on the chain
235- // for these LockPoint calculations to be valid
236- // Note: It is impossible to correctly calculate a maxInputBlock
237- // if any of the sequence locked inputs depend on unconfirmed txs,
238- // except in the special case where the relative lock time/height
239- // is 0, which is equivalent to no sequence lock. Since we assume
240- // input height of tip+1 for mempool txs and test the resulting
241- // lockPair from CalculateSequenceLocks against tip+1. We know
242- // EvaluateSequenceLocks will fail if there was a non-zero sequence
243- // lock on a mempool input, so we can use the return value of
244- // CheckSequenceLocksAtTip to indicate the LockPoints validity
245- int maxInputHeight = 0 ;
246- for (const int height : prevheights) {
247- // Can ignore mempool inputs since we'll fail if they had non-zero locks
248- if (height != tip->nHeight +1 ) {
249- maxInputHeight = std::max (maxInputHeight, height);
250- }
251- }
252- // tip->GetAncestor(maxInputHeight) should never return a nullptr
253- // because maxInputHeight is always less than the tip height.
254- // It would, however, be a bad bug to continue execution, since a
255- // LockPoints object with the maxInputBlock member set to nullptr
256- // signifies no relative lock time.
257- lp->maxInputBlock = Assert (tip->GetAncestor (maxInputHeight));
258- }
259- }
260- return EvaluateSequenceLocks (index, lockPair);
284+ return EvaluateSequenceLocks (index, {lock_points.height , lock_points.time });
261285}
262286
263287bool GetUTXOCoin (CChainState& active_chainstate, const COutPoint& outpoint, Coin& coin)
@@ -405,20 +429,23 @@ void CChainState::MaybeUpdateMempoolForReorg(
405429
406430 // The transaction must be final.
407431 if (!CheckFinalTxAtTip (*Assert (m_chain.Tip ()), tx)) return true ;
408- LockPoints lp = it->GetLockPoints ();
409- const bool validLP{TestLockPointValidity (m_chain, lp)};
410- CCoinsViewMemPool view_mempool (&CoinsTip (), *m_mempool);
432+
433+ const LockPoints& lp = it->GetLockPoints ();
411434 // CheckSequenceLocksAtTip checks if the transaction will be final in the next block to be
412- // created on top of the new chain. We use useExistingLockPoints=false so that, instead of
413- // using the information in lp (which might now refer to a block that no longer exists in
414- // the chain), it will update lp to contain LockPoints relevant to the new chain.
415- if (!CheckSequenceLocksAtTip (m_chain.Tip (), view_mempool, tx, &lp, validLP)) {
416- // If CheckSequenceLocksAtTip fails, remove the tx and don't depend on the LockPoints.
417- return true ;
418- } else if (!validLP) {
419- // If CheckSequenceLocksAtTip succeeded, it also updated the LockPoints.
420- // Now update the mempool entry lockpoints as well.
421- m_mempool->mapTx .modify (it, [&lp](CTxMemPoolEntry& e) { e.UpdateLockPoints (lp); });
435+ // created on top of the new chain.
436+ if (TestLockPointValidity (m_chain, lp)) {
437+ if (!CheckSequenceLocksAtTip (m_chain.Tip (), lp)) {
438+ return true ;
439+ }
440+ } else {
441+ const CCoinsViewMemPool view_mempool{&CoinsTip (), *m_mempool};
442+ const std::optional<LockPoints> new_lock_points{CalculateLockPointsAtTip (m_chain.Tip (), view_mempool, tx)};
443+ if (new_lock_points.has_value () && CheckSequenceLocksAtTip (m_chain.Tip (), *new_lock_points)) {
444+ // Now update the mempool entry lockpoints as well.
445+ m_mempool->mapTx .modify (it, [&new_lock_points](CTxMemPoolEntry& e) { e.UpdateLockPoints (*new_lock_points); });
446+ } else {
447+ return true ;
448+ }
422449 }
423450
424451 // If the transaction spends any coinbase outputs, it must be mature.
@@ -781,7 +808,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
781808 }
782809 }
783810 }
784- LockPoints lp;
785811 m_view.SetBackend (m_viewmempool);
786812
787813 const CCoinsViewCache& coins_cache = m_active_chainstate.CoinsTip ();
@@ -823,7 +849,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
823849 // be mined yet.
824850 // Pass in m_view which has all of the relevant inputs cached. Note that, since m_view's
825851 // backend was removed, it no longer pulls coins from the mempool.
826- if (!CheckSequenceLocksAtTip (m_active_chainstate.m_chain .Tip (), m_view, tx, &lp)) {
852+ const std::optional<LockPoints> lock_points{CalculateLockPointsAtTip (m_active_chainstate.m_chain .Tip (), m_view, tx)};
853+ if (!lock_points.has_value () || !CheckSequenceLocksAtTip (m_active_chainstate.m_chain .Tip (), *lock_points)) {
827854 return state.Invalid (TxValidationResult::TX_PREMATURE_SPEND, " non-BIP68-final" );
828855 }
829856
@@ -854,7 +881,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
854881 }
855882
856883 entry.reset (new CTxMemPoolEntry (ptx, ws.m_base_fees , nAcceptTime, m_active_chainstate.m_chain .Height (),
857- fSpendsCoinbase , nSigOps, lp ));
884+ fSpendsCoinbase , nSigOps, lock_points. value () ));
858885 ws.m_vsize = entry->GetTxSize ();
859886
860887 if (nSigOps > MAX_STANDARD_TX_SIGOPS)
@@ -1930,11 +1957,21 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
19301957 return DISCONNECT_FAILED;
19311958 }
19321959
1960+ // Ignore blocks that contain transactions which are 'overwritten' by later transactions,
1961+ // unless those are already completely spent.
1962+ // See https://github.com/bitcoin/bitcoin/issues/22596 for additional information.
1963+ // Note: the blocks specified here are different than the ones used in ConnectBlock because DisconnectBlock
1964+ // unwinds the blocks in reverse. As a result, the inconsistency is not discovered until the earlier
1965+ // blocks with the duplicate coinbase transactions are disconnected.
1966+ bool fEnforceBIP30 = !((pindex->nHeight ==91722 && pindex->GetBlockHash () == uint256S (" 0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e" )) ||
1967+ (pindex->nHeight ==91812 && pindex->GetBlockHash () == uint256S (" 0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f" )));
1968+
19331969 // undo transactions in reverse order
19341970 for (int i = block.vtx .size () - 1 ; i >= 0 ; i--) {
19351971 const CTransaction &tx = *(block.vtx [i]);
19361972 uint256 hash = tx.GetHash ();
19371973 bool is_coinbase = tx.IsCoinBase ();
1974+ bool is_bip30_exception = (is_coinbase && !fEnforceBIP30 );
19381975
19391976 if (fAddressIndex ) {
19401977 for (unsigned int k = tx.vout .size (); k-- > 0 ;) {
@@ -1963,7 +2000,9 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
19632000 Coin coin;
19642001 bool is_spent = view.SpendCoin (out, &coin);
19652002 if (!is_spent || tx.vout [o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase ) {
1966- fClean = false ; // transaction output mismatch
2003+ if (!is_bip30_exception) {
2004+ fClean = false ; // transaction output mismatch
2005+ }
19672006 }
19682007 }
19692008 }
0 commit comments