txscript: Implement CheckSequenceVerify (BIP0112)

This commit is contained in:
David Hill 2015-10-23 17:05:24 -04:00
parent fdfa07b0be
commit a6bf1d9850
9 changed files with 293 additions and 37 deletions

View file

@ -1,4 +1,4 @@
// Copyright (c) 2015 The btcsuite developers // Copyright (c) 2015-2016 The btcsuite developers
// Use of this source code is governed by an ISC // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -8,7 +8,6 @@ const (
// LockTimeThreshold is the number below which a lock time is // LockTimeThreshold is the number below which a lock time is
// interpreted to be a block number. Since an average of one block // interpreted to be a block number. Since an average of one block
// is generated per 10 minutes, this allows blocks for about 9,512 // is generated per 10 minutes, this allows blocks for about 9,512
// years. However, if the field is interpreted as a timestamp, given // years.
// the lock time is a uint32, the max is sometime around 2106. LockTimeThreshold = 5e8 // Tue Nov 5 00:53:20 1985 UTC
LockTimeThreshold uint32 = 5e8 // Tue Nov 5 00:53:20 1985 UTC
) )

View file

@ -191,5 +191,59 @@
[[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]], [[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]],
"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH,DERSIG"], "010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH,DERSIG"],
["CHECKSEQUENCEVERIFY tests"],
["By-height locks, with argument just beyond txin.nSequence"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["By-time locks, with argument just beyond txin.nSequence (but within numerical boundries)"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument missing"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument negative with by-blockheight txin.nSequence=0"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument negative with by-blocktime txin.nSequence=CTxIn::SEQUENCE_UNITS_THRESHOD"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument/tx height/time mismatch, both versions"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Failure due to failing CHECKSEQUENCEVERIFY in scriptSig"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Failure due to failing CHECKSEQUENCEVERIFY in redeemScript"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]],
"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Failure due to insufficient tx.nVersion (<2)"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Make diffs cleaner by leaving a comment here without comma at the end"] ["Make diffs cleaner by leaving a comment here without comma at the end"]
] ]

View file

@ -233,5 +233,89 @@
[[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]], [[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]],
"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH"], "010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH"],
["CHECKSEQUENCEVERIFY tests"],
["By-height locks, with argument == 0 and == txin.nSequence"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["By-time locks, with argument == 0 and == txin.nSequence"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Upper sequence with upper sequence is fine"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument 2^31 with various nSequence"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument 2^32-1 with various nSequence"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Argument 3<<31 with various nSequence"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["5 byte non-minimally-encoded operandss are valid"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["The argument can be calculated rather than created directly by a PUSHDATA"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194303 1ADD NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 1SUB NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["An ADD producing a 5-byte result that sets CTxIn::SEQUENCE_LOCKTIME_DISABLED_FLAG"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 65536 NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 4259840 ADD NOP3 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Valid CHECKSEQUENCEVERIFY in scriptSig"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Valid CHECKSEQUENCEVERIFY in redeemScript"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]],
"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
["Make diffs cleaner by leaving a comment here without comma at the end"] ["Make diffs cleaner by leaving a comment here without comma at the end"]
] ]

View file

@ -1,4 +1,4 @@
// Copyright (c) 2013-2015 The btcsuite developers // Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -38,6 +38,11 @@ const (
// This is BIP0065. // This is BIP0065.
ScriptVerifyCheckLockTimeVerify ScriptVerifyCheckLockTimeVerify
// ScriptVerifyCheckSequenceVerify defines whether to allow execution
// pathways of a script to be restricted based on the age of the output
// being spent. This is BIP0112.
ScriptVerifyCheckSequenceVerify
// ScriptVerifyCleanStack defines that the stack must contain only // ScriptVerifyCleanStack defines that the stack must contain only
// one stack element after evaluation and that the element must be // one stack element after evaluation and that the element must be
// true if interpreted as a boolean. This is rule 6 of BIP0062. // true if interpreted as a boolean. This is rule 6 of BIP0062.

View file

@ -216,6 +216,7 @@ const (
OP_NOP2 = 0xb1 // 177 OP_NOP2 = 0xb1 // 177
OP_CHECKLOCKTIMEVERIFY = 0xb1 // 177 - AKA OP_NOP2 OP_CHECKLOCKTIMEVERIFY = 0xb1 // 177 - AKA OP_NOP2
OP_NOP3 = 0xb2 // 178 OP_NOP3 = 0xb2 // 178
OP_CHECKSEQUENCEVERIFY = 0xb2 // 178 - AKA OP_NOP3
OP_NOP4 = 0xb3 // 179 OP_NOP4 = 0xb3 // 179
OP_NOP5 = 0xb4 // 180 OP_NOP5 = 0xb4 // 180
OP_NOP6 = 0xb5 // 181 OP_NOP6 = 0xb5 // 181
@ -417,6 +418,7 @@ var opcodeArray = [256]opcode{
OP_VERIFY: {OP_VERIFY, "OP_VERIFY", 1, opcodeVerify}, OP_VERIFY: {OP_VERIFY, "OP_VERIFY", 1, opcodeVerify},
OP_RETURN: {OP_RETURN, "OP_RETURN", 1, opcodeReturn}, OP_RETURN: {OP_RETURN, "OP_RETURN", 1, opcodeReturn},
OP_CHECKLOCKTIMEVERIFY: {OP_CHECKLOCKTIMEVERIFY, "OP_CHECKLOCKTIMEVERIFY", 1, opcodeCheckLockTimeVerify}, OP_CHECKLOCKTIMEVERIFY: {OP_CHECKLOCKTIMEVERIFY, "OP_CHECKLOCKTIMEVERIFY", 1, opcodeCheckLockTimeVerify},
OP_CHECKSEQUENCEVERIFY: {OP_CHECKSEQUENCEVERIFY, "OP_CHECKSEQUENCEVERIFY", 1, opcodeCheckSequenceVerify},
// Stack opcodes. // Stack opcodes.
OP_TOALTSTACK: {OP_TOALTSTACK, "OP_TOALTSTACK", 1, opcodeToAltStack}, OP_TOALTSTACK: {OP_TOALTSTACK, "OP_TOALTSTACK", 1, opcodeToAltStack},
@ -499,7 +501,6 @@ var opcodeArray = [256]opcode{
// Reserved opcodes. // Reserved opcodes.
OP_NOP1: {OP_NOP1, "OP_NOP1", 1, opcodeNop}, OP_NOP1: {OP_NOP1, "OP_NOP1", 1, opcodeNop},
OP_NOP3: {OP_NOP3, "OP_NOP3", 1, opcodeNop},
OP_NOP4: {OP_NOP4, "OP_NOP4", 1, opcodeNop}, OP_NOP4: {OP_NOP4, "OP_NOP4", 1, opcodeNop},
OP_NOP5: {OP_NOP5, "OP_NOP5", 1, opcodeNop}, OP_NOP5: {OP_NOP5, "OP_NOP5", 1, opcodeNop},
OP_NOP6: {OP_NOP6, "OP_NOP6", 1, opcodeNop}, OP_NOP6: {OP_NOP6, "OP_NOP6", 1, opcodeNop},
@ -876,7 +877,7 @@ func opcodeN(op *parsedOpcode, vm *Engine) error {
// the flag to discourage use of NOPs is set for select opcodes. // the flag to discourage use of NOPs is set for select opcodes.
func opcodeNop(op *parsedOpcode, vm *Engine) error { func opcodeNop(op *parsedOpcode, vm *Engine) error {
switch op.opcode.value { switch op.opcode.value {
case OP_NOP1, OP_NOP3, OP_NOP4, OP_NOP5, case OP_NOP1, OP_NOP4, OP_NOP5,
OP_NOP6, OP_NOP7, OP_NOP8, OP_NOP9, OP_NOP10: OP_NOP6, OP_NOP7, OP_NOP8, OP_NOP9, OP_NOP10:
if vm.hasFlag(ScriptDiscourageUpgradableNops) { if vm.hasFlag(ScriptDiscourageUpgradableNops) {
return fmt.Errorf("OP_NOP%d reserved for soft-fork "+ return fmt.Errorf("OP_NOP%d reserved for soft-fork "+
@ -1009,6 +1010,25 @@ func opcodeReturn(op *parsedOpcode, vm *Engine) error {
return ErrStackEarlyReturn return ErrStackEarlyReturn
} }
// 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)) {
return fmt.Errorf("mismatched locktime types -- tx locktime %d, stack "+
"locktime %d", txLockTime, lockTime)
}
if lockTime > txLockTime {
str := "locktime requirement not satisfied -- locktime is " +
"greater than the transaction locktime: %d > %d"
return fmt.Errorf(str, lockTime, txLockTime)
}
return nil
}
// opcodeCheckLockTimeVerify compares the top item on the data stack to the // opcodeCheckLockTimeVerify compares the top item on the data stack to the
// LockTime field of the transaction containing the script signature // LockTime field of the transaction containing the script signature
// validating if the transaction outputs are spendable yet. If flag // validating if the transaction outputs are spendable yet. If flag
@ -1043,8 +1063,9 @@ func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error {
return err return err
} }
// In the rare event that the argument may be < 0 due to some arithmetic // In the rare event that the argument needs to be < 0 due to some
// being done first, you can always use 0 OP_MAX OP_CHECKLOCKTIMEVERIFY. // arithmetic being done first, you can always use
// 0 OP_MAX OP_CHECKLOCKTIMEVERIFY.
if lockTime < 0 { if lockTime < 0 {
return fmt.Errorf("negative locktime: %d", lockTime) return fmt.Errorf("negative locktime: %d", lockTime)
} }
@ -1053,19 +1074,10 @@ func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error {
// which the transaction is finalized or a timestamp depending on if the // which the transaction is finalized or a timestamp depending on if the
// value is before the txscript.LockTimeThreshold. When it is under the // value is before the txscript.LockTimeThreshold. When it is under the
// threshold it is a block height. // threshold it is a block height.
// err = verifyLockTime(int64(vm.tx.LockTime), LockTimeThreshold,
// The lockTimes in both the script and transaction must be of the same int64(lockTime))
// type. if err != nil {
if !((vm.tx.LockTime < LockTimeThreshold && int64(lockTime) < int64(LockTimeThreshold)) || return err
(vm.tx.LockTime >= LockTimeThreshold && int64(lockTime) >= int64(LockTimeThreshold))) {
return fmt.Errorf("mismatched locktime types -- tx locktime %d, stack "+
"locktime %d", vm.tx.LockTime, lockTime)
}
if int64(lockTime) > int64(vm.tx.LockTime) {
str := "locktime requirement not satisfied -- locktime is " +
"greater than the transaction locktime: %d > %d"
return fmt.Errorf(str, lockTime, vm.tx.LockTime)
} }
// The lock time feature can also be disabled, thereby bypassing // The lock time feature can also be disabled, thereby bypassing
@ -1089,6 +1101,84 @@ func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error {
return nil return nil
} }
// 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 errors.New("OP_NOP3 reserved for soft-fork " +
"upgrades")
}
return nil
}
if vm.tx.Version < 2 {
return fmt.Errorf("invalid transaction version: %d",
vm.tx.Version)
}
// 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 {
return fmt.Errorf("negative sequence: %d", stackSequence)
}
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
}
// 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 {
return fmt.Errorf("transaction sequence has sequence "+
"locktime disabled bit set: 0x%x", txSequence)
}
// Mask off non-consensus bits before doing comparisons.
lockTimeMask := int64(wire.SequenceLockTimeIsSeconds |
wire.SequenceLockTimeMask)
err = verifyLockTime(txSequence&lockTimeMask,
wire.SequenceLockTimeIsSeconds,
sequence&lockTimeMask)
if err != nil {
return err
}
return nil
}
// opcodeToAltStack removes the top item from the main data stack and pushes it // opcodeToAltStack removes the top item from the main data stack and pushes it
// onto the alternate data stack. // onto the alternate data stack.
// //
@ -2201,4 +2291,5 @@ func init() {
OpcodeByName["OP_FALSE"] = OP_FALSE OpcodeByName["OP_FALSE"] = OP_FALSE
OpcodeByName["OP_TRUE"] = OP_TRUE OpcodeByName["OP_TRUE"] = OP_TRUE
OpcodeByName["OP_NOP2"] = OP_CHECKLOCKTIMEVERIFY OpcodeByName["OP_NOP2"] = OP_CHECKLOCKTIMEVERIFY
OpcodeByName["OP_NOP3"] = OP_CHECKSEQUENCEVERIFY
} }

View file

@ -1,4 +1,4 @@
// Copyright (c) 2013-2015 The btcsuite developers // Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -109,10 +109,14 @@ func TestOpcodeDisasm(t *testing.T) {
// OP_NOP1 through OP_NOP10. // OP_NOP1 through OP_NOP10.
case opcodeVal >= 0xb0 && opcodeVal <= 0xb9: case opcodeVal >= 0xb0 && opcodeVal <= 0xb9:
// OP_NOP2 is an alias of OP_CHECKLOCKTIMEVERIFY switch opcodeVal {
if opcodeVal == 0xb1 { case 0xb1:
// OP_NOP2 is an alias of OP_CHECKLOCKTIMEVERIFY
expectedStr = "OP_CHECKLOCKTIMEVERIFY" expectedStr = "OP_CHECKLOCKTIMEVERIFY"
} else { case 0xb2:
// OP_NOP3 is an alias of OP_CHECKSEQUENCEVERIFY
expectedStr = "OP_CHECKSEQUENCEVERIFY"
default:
val := byte(opcodeVal - (0xb0 - 1)) val := byte(opcodeVal - (0xb0 - 1))
expectedStr = "OP_NOP" + strconv.Itoa(int(val)) expectedStr = "OP_NOP" + strconv.Itoa(int(val))
} }
@ -171,10 +175,14 @@ func TestOpcodeDisasm(t *testing.T) {
// OP_NOP1 through OP_NOP10. // OP_NOP1 through OP_NOP10.
case opcodeVal >= 0xb0 && opcodeVal <= 0xb9: case opcodeVal >= 0xb0 && opcodeVal <= 0xb9:
// OP_NOP2 is an alias of OP_CHECKLOCKTIMEVERIFY switch opcodeVal {
if opcodeVal == 0xb1 { case 0xb1:
// OP_NOP2 is an alias of OP_CHECKLOCKTIMEVERIFY
expectedStr = "OP_CHECKLOCKTIMEVERIFY" expectedStr = "OP_CHECKLOCKTIMEVERIFY"
} else { case 0xb2:
// OP_NOP3 is an alias of OP_CHECKSEQUENCEVERIFY
expectedStr = "OP_CHECKSEQUENCEVERIFY"
default:
val := byte(opcodeVal - (0xb0 - 1)) val := byte(opcodeVal - (0xb0 - 1))
expectedStr = "OP_NOP" + strconv.Itoa(int(val)) expectedStr = "OP_NOP" + strconv.Itoa(int(val))
} }

View file

@ -128,6 +128,8 @@ func parseScriptFlags(flagStr string) (ScriptFlags, error) {
// Nothing. // Nothing.
case "CHECKLOCKTIMEVERIFY": case "CHECKLOCKTIMEVERIFY":
flags |= ScriptVerifyCheckLockTimeVerify flags |= ScriptVerifyCheckLockTimeVerify
case "CHECKSEQUENCEVERIFY":
flags |= ScriptVerifyCheckSequenceVerify
case "CLEANSTACK": case "CLEANSTACK":
flags |= ScriptVerifyCleanStack flags |= ScriptVerifyCleanStack
case "DERSIG": case "DERSIG":

View file

@ -1,4 +1,4 @@
// Copyright (c) 2013-2015 The btcsuite developers // Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -32,6 +32,7 @@ const (
ScriptDiscourageUpgradableNops | ScriptDiscourageUpgradableNops |
ScriptVerifyCleanStack | ScriptVerifyCleanStack |
ScriptVerifyCheckLockTimeVerify | ScriptVerifyCheckLockTimeVerify |
ScriptVerifyCheckSequenceVerify |
ScriptVerifyLowS ScriptVerifyLowS
) )

View file

@ -24,14 +24,26 @@ const (
// MaxPrevOutIndex is the maximum index the index field of a previous // MaxPrevOutIndex is the maximum index the index field of a previous
// outpoint can be. // outpoint can be.
MaxPrevOutIndex uint32 = 0xffffffff MaxPrevOutIndex uint32 = 0xffffffff
)
const ( // SequenceLockTimeDisabled is a flag that if set on a transaction
// defaultTxInOutAlloc is the default size used for the backing array // input's sequence number, the sequence number will not be interpreted
// for transaction inputs and outputs. The array will dynamically grow // as a relative locktime.
// as needed, but this figure is intended to provide enough space for SequenceLockTimeDisabled = 1 << 31
// the number of inputs and outputs in a typical transaction without
// needing to grow the backing array multiple times. // SequenceLockTimeIsSeconds is a flag that if set on a transaction
// input's sequence number, the relative locktime has units of 512
// seconds.
SequenceLockTimeIsSeconds = 1 << 22
// SequenceLockTimeMask is a mask that extracts the relative locktime
// when masked against the transaction input sequence number.
SequenceLockTimeMask = 0x0000ffff
// defaultTxInOutAlloc is the default size used for the backing array for
// transaction inputs and outputs. The array will dynamically grow as needed,
// but this figure is intended to provide enough space for the number of
// inputs and outputs in a typical transaction without needing to grow the
// backing array multiple times.
defaultTxInOutAlloc = 15 defaultTxInOutAlloc = 15
// minTxInPayload is the minimum payload size for a transaction input. // minTxInPayload is the minimum payload size for a transaction input.