2

BIP112(CHECKSEQUENCEVERIFY)

 2 years ago
source link: https://imnisen.github.io/bip0112.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

BIP112(CHECKSEQUENCEVERIFY)

1 BIP地址

BIP112

BIP: 112
Layer: Consensus (soft fork)
Title: CHECKSEQUENCEVERIFY
Author: BtcDrak <[email protected]>
        Mark Friedenbach <[email protected]>
        Eric Lombrozo <[email protected]>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0112
Status: Final
Type: Standards Track
Created: 2015-08-10
License: PD

2 原因和目的

BIP112 定义了新的比特币脚本操作符 CHECKSEQUENCEVERIFY ,和BIP68(nSequence)组合使用,提供将transaction的output锁定到一定期限后(时间期限或者block个数期限)才可以被花费使用的能力。

BIP68(nSequence)重新定义TxIn的sequence字段为relative lock time, 使得"non-final" transaction直到一定期限后才能被包含进一个block。 通过这一限制,新的操作符 CHECKSEQUENCEVERIFY 使得脚本拥有控制生成的transaction的outputs冻结一段时间才能被花费的能力。

CHECKSEQUENCEVERIFY 赋予了脚本能够访问TxIn的sequence字段的能力。这也使得像许多像"三方委托"(escrow)、"支付通道"(patment channels)、"bidirectional pegs"成为可能。

采用bip9的bit 0部署,必须和BIP68,BIP113使用相同的部署机制。

mainnet上,开始时间是"midnight 1st May 2016 UTC (Epoch timestamp 1462060800)", 超时时间是"midnight 1st May 2017 UTC (Epoch timestamp 1493596800)."

4 相关实现

CHECKSEQUENCEVERIFY 的验证逻辑:

// opcodeCheckSequenceVerify compares the top item on the data stack to the
// LockTime field of the transaction containing the script signature
// validating if the transaction outputs are spendable yet.  If flag
// ScriptVerifyCheckSequenceVerify is not set, the code continues as if OP_NOP3
// were executed.
func opcodeCheckSequenceVerify(op *parsedOpcode, vm *Engine) error {
        // If the ScriptVerifyCheckSequenceVerify script flag is not set, treat
        // opcode as OP_NOP3 instead.
        if !vm.hasFlag(ScriptVerifyCheckSequenceVerify) {
                if vm.hasFlag(ScriptDiscourageUpgradableNops) {
                        return scriptError(ErrDiscourageUpgradableNOPs,
                                "OP_NOP3 reserved for soft-fork upgrades")
                }
                return nil
        }

        // The current transaction sequence is a uint32 resulting in a maximum
        // sequence of 2^32-1.  However, scriptNums are signed and therefore a
        // standard 4-byte scriptNum would only support up to a maximum of
        // 2^31-1.  Thus, a 5-byte scriptNum is used here since it will support
        // up to 2^39-1 which allows sequences beyond the current sequence
        // limit.
        //
        // PeekByteArray is used here instead of PeekInt because we do not want
        // to be limited to a 4-byte integer for reasons specified above.
        so, err := vm.dstack.PeekByteArray(0)
        if err != nil {
                return err
        }
        stackSequence, err := makeScriptNum(so, vm.dstack.verifyMinimalData, 5)
        if err != nil {
                return err
        }

        // In the rare event that the argument needs to be < 0 due to some
        // arithmetic being done first, you can always use
        // 0 OP_MAX OP_CHECKSEQUENCEVERIFY.
        if stackSequence < 0 {
                str := fmt.Sprintf("negative sequence: %d", stackSequence)
                return scriptError(ErrNegativeLockTime, str)
        }

        sequence := int64(stackSequence)

        // To provide for future soft-fork extensibility, if the
        // operand has the disabled lock-time flag set,
        // CHECKSEQUENCEVERIFY behaves as a NOP.
        if sequence&int64(wire.SequenceLockTimeDisabled) != 0 {
                return nil
        }

        // Transaction version numbers not high enough to trigger CSV rules must
        // fail.
        if vm.tx.Version < 2 {
                str := fmt.Sprintf("invalid transaction version: %d",
                        vm.tx.Version)
                return scriptError(ErrUnsatisfiedLockTime, str)
        }

        // Sequence numbers with their most significant bit set are not
        // consensus constrained. Testing that the transaction's sequence
        // number does not have this bit set prevents using this property
        // to get around a CHECKSEQUENCEVERIFY check.
        txSequence := int64(vm.tx.TxIn[vm.txIdx].Sequence)
        if txSequence&int64(wire.SequenceLockTimeDisabled) != 0 {
                str := fmt.Sprintf("transaction sequence has sequence "+
                        "locktime disabled bit set: 0x%x", txSequence)
                return scriptError(ErrUnsatisfiedLockTime, str)
        }

        // Mask off non-consensus bits before doing comparisons.
        lockTimeMask := int64(wire.SequenceLockTimeIsSeconds |
                wire.SequenceLockTimeMask)
        return verifyLockTime(txSequence&lockTimeMask,
                wire.SequenceLockTimeIsSeconds, sequence&lockTimeMask)
}


// verifyLockTime is a helper function used to validate locktimes.
func verifyLockTime(txLockTime, threshold, lockTime int64) error {
        // The lockTimes in both the script and transaction must be of the same
        // type.
        if !((txLockTime < threshold && lockTime < threshold) ||
                (txLockTime >= threshold && lockTime >= threshold)) {
                str := fmt.Sprintf("mismatched locktime types -- tx locktime "+
                        "%d, stack locktime %d", txLockTime, lockTime)
                return scriptError(ErrUnsatisfiedLockTime, str)
        }

        if lockTime > txLockTime {
                str := fmt.Sprintf("locktime requirement not satisfied -- "+
                        "locktime is greater than the transaction locktime: "+
                        "%d > %d", lockTime, txLockTime)
                return scriptError(ErrUnsatisfiedLockTime, str)
        }

        return nil
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK