From 1ed68dc60527fab374057039803a5f8f9a7648f3 Mon Sep 17 00:00:00 2001
From: Mark Friedenbach <mark@friedenbach.org>
Date: Mon, 5 Oct 2015 15:37:23 -0700
Subject: Update code to match current pull request.

---
 bip-0068.mediawiki | 73 +++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 53 insertions(+), 20 deletions(-)

(limited to 'bip-0068.mediawiki')

diff --git a/bip-0068.mediawiki b/bip-0068.mediawiki
index 28df807..89cb27a 100644
--- a/bip-0068.mediawiki
+++ b/bip-0068.mediawiki
@@ -52,7 +52,7 @@ This is proposed to be accomplished by replacing IsFinalTx() and CheckFinalTx(),
     {
         CCoins coins;
     
-        bool fEnforceBIP68 = tx.nVersion >= 2
+        bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2
                           && flags & LOCKTIME_VERIFY_SEQUENCE;
     
         // Will be set to the equivalent height- and time-based nLockTime
@@ -72,8 +72,9 @@ This is proposed to be accomplished by replacing IsFinalTx() and CheckFinalTx(),
                 fFinalized = false;
     
             // Do not enforce sequence numbers as a relative lock time
-            // unless we have been instructed to.
-            if (!fEnforceBIP68)
+            // unless we have been instructed to, and a view has been
+            // provided.
+            if (!(fEnforceBIP68 && pCoinsView))
                 continue;
     
             // Sequence numbers equal to or above the locktime threshold
@@ -82,31 +83,62 @@ This is proposed to be accomplished by replacing IsFinalTx() and CheckFinalTx(),
             if (txin.nSequence >= CTxIn::SEQUENCE_LOCKTIME_THRESHOLD)
                 continue;
     
-            // Skip this input if it is not in the UTXO set. Aside from
-            // the coinbase input, this should only ever happen in non-
-            // consensus code.
-            if (!pCoinsView->GetCoins(txin.prevout.hash, coins))
-                continue;
-    
-            if (txin.nSequence < CTxIn::SEQUENCE_UNITS_THRESHOLD)
+            // Fetch the UTXO corresponding to this input.
+            if (!pCoinsView->GetCoins(txin.prevout.hash, coins)) {
+                // It is fully expected that coinbases inputs are not
+                // found in the UTXO set. Proceed to the next intput...
+                if (txin.prevout.IsNull())
+                    continue;
+                // If a non-coinbase input cannot be found, we cannot
+                // be certain about whether lock-time constraints have
+                // been satisfied. Note that it should only ever be
+                // possible for this to happen with wallet transactions
+                // that have unknown inputs.
+                else
+                    return std::numeric_limits<int64_t>::max();
+            }
+    
+            // coins.nHeight is MEMPOOL_HEIGHT (an absurdly high value)
+            // if the parent transaction was from the mempool. We can't
+            // know what height it will have once confirmed, but we
+            // assume it makes it in the same block.
+            int nCoinHeight = std::min(coins.nHeight, nBlockHeight);
+    
+            if (txin.nSequence < CTxIn::SEQUENCE_UNITS_THRESHOLD) {
                 // We subtract 1 from relative lock-times because a lock-
                 // time of 0 has the semantics of "same block," so a lock-
                 // time of 1 should mean "next block," but nLockTime has
                 // the semantics of "last invalid block height."
-                nMinHeight = std::max(nMinHeight,
-                      coins.nHeight
-                    + (int)(txin.nSequence >> CTxIn::SEQUENCE_BLOCKS_OFFSET)
-                    - 1);
-            else
+                nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(
+                    txin.nSequence >> CTxIn::SEQUENCE_BLOCKS_OFFSET) - 1);
+            } else {
+                // In two locations that follow we make reference to
+                // chainActive.Tip(). To prevent a race condition, we
+                // store a reference to the current tip.
+                //
+                // Note that it is not guaranteed that indexBestBlock will
+                // be consistent with the passed in view. The proper thing
+                // to do is to have the view return time information about
+                // UTXOs.
+                const CBlockIndex& indexBestBlock = *chainActive.Tip();
+    
+                // The only time the negative branch of this conditional
+                // is executed is when the prior output was taken from the
+                // mempool, in which case we assume it makes it into the
+                // same block (see above).
+                int64_t nCoinTime = (nCoinHeight <= (indexBestBlock.nHeight+1))
+                                  ? indexBestBlock.GetAncestor(nCoinHeight-1)->GetMedianTimePast()
+                                  : nBlockTime;
+
                 // Time-based relative lock-times are measured from the
                 // smallest allowed timestamp of the block containing the
                 // txout being spent, which is the median time past of the
                 // block prior. We subtract one for the same reason as
                 // above.
-                nMinTime = std::max(nMinTime,
-                      pindexBestHeader->GetAncestor(coins.nHeight-1)->GetMedianTimePast()
-                    + (int64_t)((txin.nSequence ^ CTxIn::SEQUENCE_UNITS_THRESHOLD) >> CTxIn::SEQUENCE_SECONDS_OFFSET)
-                    - 1);
+                nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((
+                    txin.nSequence - CTxIn::SEQUENCE_UNITS_THRESHOLD)
+                    >> CTxIn::SEQUENCE_SECONDS_OFFSET) - 1);
+            }
         }
     
         // If all sequence numbers are CTxIn::SEQUENCE_FINAL, the
@@ -137,7 +169,8 @@ This is proposed to be accomplished by replacing IsFinalTx() and CheckFinalTx(),
         flags = std::max(flags, 0);
     
         // pcoinsTip contains the UTXO set for chainActive.Tip()
-        const CCoinsView *pCoinsView = pcoinsTip;
+        CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
+        const CCoinsView *pCoinsView = &viewMemPool;
     
         // CheckLockTime() uses chainActive.Height()+1 to evaluate
         // nLockTime because when LockTime() is called within
-- 
cgit v1.2.3

