txscript: Implement CheckLockTimeVerify (BIP0065)
See https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki for more information. This commit mimics Bitcoin Core commit bc60b2b4b401f0adff5b8b9678903ff8feb5867b and includes additional tests from Bitcoin Core commit cb54d17355864fa08826d6511a0d7692b21ef2c9
This commit is contained in:
parent
0f57a41ed8
commit
4c3ad4987b
7 changed files with 234 additions and 18 deletions
|
@ -114,6 +114,78 @@
|
||||||
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
|
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
|
||||||
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510100ffffffff010000000000000000016a00000000", "P2SH"],
|
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510100ffffffff010000000000000000016a00000000", "P2SH"],
|
||||||
|
|
||||||
|
["CHECKLOCKTIMEVERIFY tests"],
|
||||||
|
|
||||||
|
["By-height locks, with argument just beyond tx nLockTime"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP2 1"]],
|
||||||
|
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 NOP2 1"]],
|
||||||
|
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Argument missing"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP2 1"]],
|
||||||
|
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
|
||||||
|
"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Argument negative with by-blockheight nLockTime=0"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
|
||||||
|
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Argument negative with by-blocktime nLockTime=500,000,000"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
|
||||||
|
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
|
||||||
|
"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Input locked"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
|
||||||
|
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]],
|
||||||
|
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1ffffffff0100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"] ,
|
||||||
|
["0000000000000000000000000000000000000000000000000000000000000200", 1, "1"]],
|
||||||
|
"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Argument/tx height/time mismatch, both versions"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
|
||||||
|
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]],
|
||||||
|
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
|
||||||
|
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
|
||||||
|
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Argument 2^32 with nLockTime=2^32-1"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 NOP2 1"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Same, but with nLockTime=2^31-1"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP2 1"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP2 1"]],
|
||||||
|
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Failure due to failing CHECKLOCKTIMEVERIFY in scriptSig"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
|
||||||
|
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Failure due to failing CHECKLOCKTIMEVERIFY in redeemScript"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
["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"]
|
||||||
]
|
]
|
||||||
|
|
|
@ -187,5 +187,47 @@
|
||||||
"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"],
|
"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"],
|
||||||
|
|
||||||
|
|
||||||
|
["CHECKLOCKTIMEVERIFY tests"],
|
||||||
|
|
||||||
|
["By-height locks, with argument == 0 and == tx nLockTime"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
|
||||||
|
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
|
||||||
|
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Any non-maxint nSequence is fine"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
|
||||||
|
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["The argument can be calculated rather than created directly by a PUSHDATA"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD NOP2 1"]],
|
||||||
|
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Perhaps even by an ADD producing a 5-byte result that is out of bounds for other opcodes"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD NOP2 1"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["5 byte non-minimally-encoded arguments are valid"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP2 1"]],
|
||||||
|
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Valid CHECKLOCKTIMEVERIFY in scriptSig"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
|
||||||
|
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
|
["Valid CHECKLOCKTIMEVERIFY in redeemScript"],
|
||||||
|
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
|
||||||
|
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
|
||||||
|
|
||||||
["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"]
|
||||||
]
|
]
|
||||||
|
|
|
@ -33,6 +33,11 @@ const (
|
||||||
// executed.
|
// executed.
|
||||||
ScriptDiscourageUpgradableNops
|
ScriptDiscourageUpgradableNops
|
||||||
|
|
||||||
|
// ScriptVerifyCheckLockTimeVerify defines whether to verify that
|
||||||
|
// a transaction output is spendable based on the locktime.
|
||||||
|
// This is BIP0065.
|
||||||
|
ScriptVerifyCheckLockTimeVerify
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
|
|
||||||
|
@ -212,6 +213,7 @@ const (
|
||||||
OP_CHECKMULTISIGVERIFY = 0xaf // 175
|
OP_CHECKMULTISIGVERIFY = 0xaf // 175
|
||||||
OP_NOP1 = 0xb0 // 176
|
OP_NOP1 = 0xb0 // 176
|
||||||
OP_NOP2 = 0xb1 // 177
|
OP_NOP2 = 0xb1 // 177
|
||||||
|
OP_CHECKLOCKTIMEVERIFY = 0xb1 // 177 - AKA OP_NOP2
|
||||||
OP_NOP3 = 0xb2 // 178
|
OP_NOP3 = 0xb2 // 178
|
||||||
OP_NOP4 = 0xb3 // 179
|
OP_NOP4 = 0xb3 // 179
|
||||||
OP_NOP5 = 0xb4 // 180
|
OP_NOP5 = 0xb4 // 180
|
||||||
|
@ -413,6 +415,7 @@ var opcodeArray = [256]opcode{
|
||||||
OP_ENDIF: {OP_ENDIF, "OP_ENDIF", 1, opcodeEndif},
|
OP_ENDIF: {OP_ENDIF, "OP_ENDIF", 1, opcodeEndif},
|
||||||
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},
|
||||||
|
|
||||||
// Stack opcodes.
|
// Stack opcodes.
|
||||||
OP_TOALTSTACK: {OP_TOALTSTACK, "OP_TOALTSTACK", 1, opcodeToAltStack},
|
OP_TOALTSTACK: {OP_TOALTSTACK, "OP_TOALTSTACK", 1, opcodeToAltStack},
|
||||||
|
@ -495,7 +498,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_NOP2: {OP_NOP2, "OP_NOP2", 1, opcodeNop},
|
|
||||||
OP_NOP3: {OP_NOP3, "OP_NOP3", 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},
|
||||||
|
@ -873,7 +875,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_NOP2, OP_NOP3, OP_NOP4, OP_NOP5,
|
case OP_NOP1, OP_NOP3, 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 "+
|
||||||
|
@ -1006,6 +1008,86 @@ func opcodeReturn(op *parsedOpcode, vm *Engine) error {
|
||||||
return ErrStackEarlyReturn
|
return ErrStackEarlyReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// opcodeCheckLockTimeVerify 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
|
||||||
|
// ScriptVerifyCheckLockTimeVerify is not set, the code continues as if OP_NOP2
|
||||||
|
// were executed.
|
||||||
|
func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error {
|
||||||
|
// If the ScriptVerifyCheckLockTimeVerify script flag is not set, treat
|
||||||
|
// opcode as OP_NOP2 instead.
|
||||||
|
if !vm.hasFlag(ScriptVerifyCheckLockTimeVerify) {
|
||||||
|
if vm.hasFlag(ScriptDiscourageUpgradableNops) {
|
||||||
|
return errors.New("OP_NOP2 reserved for soft-fork " +
|
||||||
|
"upgrades")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The current transaction locktime is a uint32 resulting in a maximum
|
||||||
|
// locktime of 2^32-1 (the year 2106). However, scriptNums are signed
|
||||||
|
// and therefore a standard 4-byte scriptNum would only support up to a
|
||||||
|
// maximum of 2^31-1 (the year 2038). Thus, a 5-byte scriptNum is used
|
||||||
|
// here since it will support up to 2^39-1 which allows dates beyond the
|
||||||
|
// current locktime 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
|
||||||
|
}
|
||||||
|
lockTime, err := makeScriptNum(so, vm.dstack.verifyMinimalData, 5)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the rare event that the argument may be < 0 due to some arithmetic
|
||||||
|
// being done first, you can always use 0 OP_MAX OP_CHECKLOCKTIMEVERIFY.
|
||||||
|
if lockTime < 0 {
|
||||||
|
return fmt.Errorf("negative locktime: %d", lockTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The lock time field of a transaction is either a block height at
|
||||||
|
// which the transaction is finalized or a timestamp depending on if the
|
||||||
|
// value is before the txscript.LockTimeThreshold. When it is under the
|
||||||
|
// threshold it is a block height.
|
||||||
|
//
|
||||||
|
// The lockTimes in both the script and transaction must be of the same
|
||||||
|
// type.
|
||||||
|
if !((vm.tx.LockTime < LockTimeThreshold && int64(lockTime) < int64(LockTimeThreshold)) ||
|
||||||
|
(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
|
||||||
|
// OP_CHECKLOCKTIMEVERIFY, if every transaction input has been finalized by
|
||||||
|
// setting its sequence to the maximum value (wire.MaxTxInSequenceNum). This
|
||||||
|
// condition would result in the transaction being allowed into the blockchain
|
||||||
|
// making the opcode ineffective.
|
||||||
|
//
|
||||||
|
// This condition is prevented by enforcing that the input being used by
|
||||||
|
// the opcode is unlocked (its sequence number is less than the max
|
||||||
|
// value). This is sufficient to prove correctness without having to
|
||||||
|
// check every input.
|
||||||
|
//
|
||||||
|
// NOTE: This implies that even if the transaction is not finalized due to
|
||||||
|
// another input being unlocked, the opcode execution will still fail when the
|
||||||
|
// input being used by the opcode is locked.
|
||||||
|
if vm.tx.TxIn[vm.txIdx].Sequence == wire.MaxTxInSequenceNum {
|
||||||
|
return errors.New("transaction input is finalized")
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
//
|
//
|
||||||
|
@ -2109,11 +2191,13 @@ var OpcodeByName = make(map[string]byte)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Initialize the opcode name to value map using the contents of the
|
// Initialize the opcode name to value map using the contents of the
|
||||||
// opcode array. Also add entries for "OP_FALSE" and "OP_TRUE" since
|
// opcode array. Also add entries for "OP_FALSE", "OP_TRUE", and
|
||||||
// they are aliases for "OP_0" and "OP_1", respectively.
|
// "OP_NOP2" since they are aliases for "OP_0", "OP_1",
|
||||||
|
// and "OP_CHECKLOCKTIMEVERIFY" respectively.
|
||||||
for _, op := range opcodeArray {
|
for _, op := range opcodeArray {
|
||||||
OpcodeByName[op.name] = op.value
|
OpcodeByName[op.name] = op.value
|
||||||
}
|
}
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,8 +109,13 @@ 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
|
||||||
|
if opcodeVal == 0xb1 {
|
||||||
|
expectedStr = "OP_CHECKLOCKTIMEVERIFY"
|
||||||
|
} else {
|
||||||
val := byte(opcodeVal - (0xb0 - 1))
|
val := byte(opcodeVal - (0xb0 - 1))
|
||||||
expectedStr = "OP_NOP" + strconv.Itoa(int(val))
|
expectedStr = "OP_NOP" + strconv.Itoa(int(val))
|
||||||
|
}
|
||||||
|
|
||||||
// OP_UNKNOWN#.
|
// OP_UNKNOWN#.
|
||||||
case opcodeVal >= 0xba && opcodeVal <= 0xf8 || opcodeVal == 0xfc:
|
case opcodeVal >= 0xba && opcodeVal <= 0xf8 || opcodeVal == 0xfc:
|
||||||
|
@ -166,8 +171,13 @@ 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
|
||||||
|
if opcodeVal == 0xb1 {
|
||||||
|
expectedStr = "OP_CHECKLOCKTIMEVERIFY"
|
||||||
|
} else {
|
||||||
val := byte(opcodeVal - (0xb0 - 1))
|
val := byte(opcodeVal - (0xb0 - 1))
|
||||||
expectedStr = "OP_NOP" + strconv.Itoa(int(val))
|
expectedStr = "OP_NOP" + strconv.Itoa(int(val))
|
||||||
|
}
|
||||||
|
|
||||||
// OP_UNKNOWN#.
|
// OP_UNKNOWN#.
|
||||||
case opcodeVal >= 0xba && opcodeVal <= 0xf8 || opcodeVal == 0xfc:
|
case opcodeVal >= 0xba && opcodeVal <= 0xf8 || opcodeVal == 0xfc:
|
||||||
|
|
|
@ -124,6 +124,8 @@ func parseScriptFlags(flagStr string) (ScriptFlags, error) {
|
||||||
switch flag {
|
switch flag {
|
||||||
case "":
|
case "":
|
||||||
// Nothing.
|
// Nothing.
|
||||||
|
case "CHECKLOCKTIMEVERIFY":
|
||||||
|
flags |= ScriptVerifyCheckLockTimeVerify
|
||||||
case "CLEANSTACK":
|
case "CLEANSTACK":
|
||||||
flags |= ScriptVerifyCleanStack
|
flags |= ScriptVerifyCleanStack
|
||||||
case "DERSIG":
|
case "DERSIG":
|
||||||
|
|
|
@ -31,6 +31,7 @@ const (
|
||||||
ScriptStrictMultiSig |
|
ScriptStrictMultiSig |
|
||||||
ScriptDiscourageUpgradableNops |
|
ScriptDiscourageUpgradableNops |
|
||||||
ScriptVerifyCleanStack |
|
ScriptVerifyCleanStack |
|
||||||
|
ScriptVerifyCheckLockTimeVerify |
|
||||||
ScriptVerifyLowS
|
ScriptVerifyLowS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue