Published: 2018-12-18


1 BIP地址


BIP: 112
Layer: Consensus (soft fork)
Author: BtcDrak <>
        Mark Friedenbach <>
        Eric Lombrozo <>
Comments-Summary: No comments yet.
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"成为可能。

3 部署

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

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

4 相关实现


// 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
        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",
                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 |
        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


Author: Nisen