Script

為什麼 OP_CHECKLOCKTIMEVERIFY 被最大序列號禁用?

  • June 14, 2021

在我的程式碼中,OP_CHECKLOCKTIMEVERIFY我注意到如果 txin 序列號被最大化,那麼腳本將無法驗證。我想知道這是什麼意思?為什麼有人會向網路送出無法驗證的交易?

這是程式碼的相關部分:

// Finally the nLockTime feature can be disabled and thus
// CHECKLOCKTIMEVERIFY bypassed if every txin has been
// finalized by setting nSequence to maxint. The
// transaction would be allowed into the blockchain, making
// the opcode ineffective.
//
// Testing if this vin is not final is sufficient to
// prevent this condition. Alternatively we could test all
// inputs, but testing just this input minimizes the data
// required to prove correct CHECKLOCKTIMEVERIFY execution.
if (txTo->vin[nIn].IsFinal())
   return false;

我也對程式碼中的註釋感到困惑。他們說每個序列號都必須被最大化才能使腳本無法驗證,但在我看來這不是真的 - 看起來只需要最大化一個序列號然後整個事務(所有txins) 將失敗。我認為這意味著交易不會因此包含在區塊鏈中?但這與程式碼註釋背道而馳。!如果有一個on if 條件,那將是有意義的。

的目的與OP_CHECKLOCKTIMEVERIFY目的相反tx.nLockTimetx.nLockTime防止具有未來日期的交易進入區塊鏈,同時OP_CHECKLOCKTIMEVERIFY使某人能夠凍結資金,以便它們只能給定的時間戳或塊高度之後使用。

tx.nLockTime

tx.nLockTime由函式IsFinalTx() 驗證src/main.cpp

bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
{
   if (tx.nLockTime == 0)
       return true;
   if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
       return true;
   BOOST_FOREACH(const CTxIn& txin, tx.vin)
       if (!txin.IsFinal())
           return false;
   return true;
}

哪裡:txin.IsFinal()_src/primitives/transaction.h

bool IsFinal() const
{
   return (nSequence == std::numeric_limits<uint32_t>::max());
}

如果 tx 鎖定時間低於門檻值,則將其視為塊高度,如果高於門檻值,則將其視為時間戳。無論哪種方式,事務鎖定時間值都必須小於相關約束。如果它更大,那麼礦工必須等待才能將交易包含在一個塊中。

繞過此事務鎖定時間約束的唯一方法是通過將所有 txin 序列號設置為 maxint 來完全禁用事務鎖定時間。完成此操作後,即使尚未達到鎖定時間,礦工也會立即包含交易。

交易鎖定時間的想法是在交易被鎖定之前(即在區塊高度或時間戳趕上 tx 鎖定時間之前),有人可以對交易進行修改。每次他們進行更改時,他們都必須增加序列號,以讓礦工知道哪個修改接踵而至。

一個案例可能是數字遺囑。如果您想在您去世時專門將錢轉給其他人,那麼您可以創建一個鎖定時間為一年的交易,然後將其提供給幾個朋友。如果您去世,他們可以在一年在網路上廣播此交易,並相應地發送資金。在一年的這個時間段之前廣播交易不會使他們能夠收到資金,因為礦工將忽略該交易,直到該時間段生效(並且顯然朋友無法更改該交易的功能,因為它是由您的私鑰簽名的你從不透露)。

如果您沒有死,那麼您可以通過在網路上廣播不同的交易,將資金花到您自己選擇的不同地址。然後,您的朋友將無法使用您給他們的原始交易,因為這將是雙花,礦工不允許。對於您廣播以取消遺囑的交易,您將更改鎖定時間以使其更快,並增加序列號。或者,您可以將鎖定時間設置為 0 或將序列號設置為 maxint 以立即使用。

OP_CHECKLOCKTIMEVERIFY

OP_CHECKLOCKTIMEVERIFY有非常不同的用途。它在以下功能EvalScript() src/script/interpreter.cpp得到驗證:

           case OP_CHECKLOCKTIMEVERIFY:
           {
               if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
                   // not enabled; treat as a NOP2
                   if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
                       return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
                   }
                   break;
               }

               if (stack.size() < 1)
                   return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);

               // Note that elsewhere numeric opcodes are limited to
               // operands in the range -2**31+1 to 2**31-1, however it is
               // legal for opcodes to produce results exceeding that
               // range. This limitation is implemented by CScriptNum's
               // default 4-byte limit.
               //
               // If we kept to that limit we'd have a year 2038 problem,
               // even though the nLockTime field in transactions
               // themselves is uint32 which only becomes meaningless
               // after the year 2106.
               //
               // Thus as a special case we tell CScriptNum to accept up
               // to 5-byte bignums, which are good until 2**39-1, well
               // beyond the 2**32-1 limit of the nLockTime field itself.
               const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5);

               // In the rare event that the argument may be < 0 due to
               // some arithmetic being done first, you can always use
               // 0 MAX CHECKLOCKTIMEVERIFY.
               if (nLockTime < 0)
                   return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);

               // Actually compare the specified lock time with the transaction.
               if (!checker.CheckLockTime(nLockTime))
                   return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);

               break;
           }

它依賴於CheckLockTime() 同一文件中的功能:

bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
{
   // There are two kinds of nLockTime: lock-by-blockheight
   // and lock-by-blocktime, distinguished by whether
   // nLockTime < LOCKTIME_THRESHOLD.
   //
   // We want to compare apples to apples, so fail the script
   // unless the type of nLockTime being tested is the same as
   // the nLockTime in the transaction.
   if (!(
       (txTo->nLockTime <  LOCKTIME_THRESHOLD && nLockTime <  LOCKTIME_THRESHOLD) ||
       (txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
   ))
       return false;

   // Now that we know we're comparing apples-to-apples, the
   // comparison is a simple numeric one.
   if (nLockTime > (int64_t)txTo->nLockTime)
       return false;

   // Finally the nLockTime feature can be disabled and thus
   // CHECKLOCKTIMEVERIFY bypassed if every txin has been
   // finalized by setting nSequence to maxint. The
   // transaction would be allowed into the blockchain, making
   // the opcode ineffective.
   //
   // Testing if this vin is not final is sufficient to
   // prevent this condition. Alternatively we could test all
   // inputs, but testing just this input minimizes the data
   // required to prove correct CHECKLOCKTIMEVERIFY execution.
   if (txTo->vin[nIn].IsFinal())
       return false;

   return true;
}

這裡將事務鎖定時間與堆棧上的值進行比較。要成功驗證,兩者必須在門檻值的同一側(即兩者都必須解釋為塊高度,或都解釋為時間戳),並且腳本僅在堆棧值低於 tx 鎖定時間時進行驗證。或者換一種說法,腳本只會驗證事務鎖定時間是否已超過堆棧值。

鑑於IsFinalTx()目前阻止具有鎖定時間的交易被包含在區塊鏈中,OP_CHECKLOCKTIMEVERIFY凍結區塊鏈中的資金,以便它們只能在未來的指定時間之後使用。

請注意,用於比較的堆棧值在放在 scriptPubKey 中時最有用。用於與堆棧值比較的鎖定時間是簽名交易的鎖定時間。這迫使花費者等待區塊或時間戳才能花費資金。

如前所述,IsFinalTx() 確實允許探勘鎖定時間高於目前塊高度或時間戳的交易——前提是序列號被最大化,從而禁用 tx 鎖定時間。送出具有最大序列號的此類交易將是接收方在發送方在 txout 腳本中指定的時間之前花費資金的一種偷偷摸摸的方式。因此,為了防止OP_CHECKLOCKTIMEVERIFY繞過條件,當序列號禁用 tx 鎖定時間時,腳本驗證必須失敗。

引用自:https://bitcoin.stackexchange.com/questions/40706