txscript: Make op callbacks take opcode and data.

This converts the callback function defined on the internal opcode
struct to accept the opcode and data slice instead of a parsed opcode as
the final step towards removing the parsed opcode struct and associated
supporting code altogether.

It also updates all of the callbacks and tests accordingly and finally
removes the now unused parsedOpcode struct.

The final results for the raw script analysis and tokenizer
optimizations are as follows:

benchmark                                       old ns/op     new ns/op     delta
BenchmarkIsPayToScriptHash-8                    62393         0.51          -100.00%
BenchmarkIsPubKeyHashScript-8                   62228         0.56          -100.00%
BenchmarkGetSigOpCount-8                        61051         658           -98.92%
BenchmarkExtractPkScriptAddrsLarge-8            60713         17.2          -99.97%
BenchmarkExtractPkScriptAddrs-8                 289           17.9          -93.81%
BenchmarkIsWitnessPubKeyHash-8                  61688         0.42          -100.00%
BenchmarkIsUnspendable-8                        656           520           -20.73%
BenchmarkExtractAtomicSwapDataPushesLarge-8     61332         44.0          -99.93%
BenchmarkExtractAtomicSwapDataPushes-8          990           260           -73.74%
BenchmarkDisasmString-8                         102902        39754         -61.37%
BenchmarkGetPreciseSigOpCount-8                 130223        715           -99.45%
BenchmarkScriptParsing-8                        63464         681           -98.93%
BenchmarkIsMultisigScriptLarge-8                64166         5.83          -99.99%
BenchmarkIsMultisigScript-8                     630           58.5          -90.71%
BenchmarkPushedData-8                           64837         1779          -97.26%
BenchmarkCalcSigHash-8                          3627895       3605459       -0.62%
BenchmarkIsPubKeyScript-8                       62323         2.83          -100.00%
BenchmarkIsPushOnlyScript-8                     62412         569           -99.09%
BenchmarkIsWitnessScriptHash-8                  61243         0.56          -100.00%
BenchmarkGetScriptClass-8                       61515         16.4          -99.97%
BenchmarkIsNullDataScript-8                     62495         2.53          -100.00%
BenchmarkIsMultisigSigScriptLarge-8             69328         2.52          -100.00%
BenchmarkIsMultisigSigScript-8                  2375          141           -94.06%
BenchmarkGetWitnessSigOpCountP2WKH-8            504           72.0          -85.71%
BenchmarkGetWitnessSigOpCountNested-8           1158          136           -88.26%
BenchmarkIsWitnessPubKeyHash-8                  68927         0.53          -100.00%
BenchmarkIsWitnessScriptHash-8                  62774         0.63          -100.00%

benchmark                                       old allocs     new allocs     delta
BenchmarkIsPayToScriptHash-8                    1              0              -100.00%
BenchmarkIsPubKeyHashScript-8                   1              0              -100.00%
BenchmarkGetSigOpCount-8                        1              0              -100.00%
BenchmarkExtractPkScriptAddrsLarge-8            1              0              -100.00%
BenchmarkExtractPkScriptAddrs-8                 1              0              -100.00%
BenchmarkIsWitnessPubKeyHash-8                  1              0              -100.00%
BenchmarkIsUnspendable-8                        1              0              -100.00%
BenchmarkExtractAtomicSwapDataPushesLarge-8     1              0              -100.00%
BenchmarkExtractAtomicSwapDataPushes-8          2              1              -50.00%
BenchmarkDisasmString-8                         46             51             +10.87%
BenchmarkGetPreciseSigOpCount-8                 3              0              -100.00%
BenchmarkScriptParsing-8                        1              0              -100.00%
BenchmarkIsMultisigScriptLarge-8                1              0              -100.00%
BenchmarkIsMultisigScript-8                     1              0              -100.00%
BenchmarkPushedData-8                           7              6              -14.29%
BenchmarkCalcSigHash-8                          1335           712            -46.67%
BenchmarkIsPubKeyScript-8                       1              0              -100.00%
BenchmarkIsPushOnlyScript-8                     1              0              -100.00%
BenchmarkIsWitnessScriptHash-8                  1              0              -100.00%
BenchmarkGetScriptClass-8                       1              0              -100.00%
BenchmarkIsNullDataScript-8                     1              0              -100.00%
BenchmarkIsMultisigSigScriptLarge-8             5              0              -100.00%
BenchmarkIsMultisigSigScript-8                  3              0              -100.00%
BenchmarkGetWitnessSigOpCountP2WKH-8            2              0              -100.00%
BenchmarkGetWitnessSigOpCountNested-8           4              0              -100.00%
BenchmarkIsWitnessPubKeyHash-8                  1              0              -100.00%
BenchmarkIsWitnessScriptHash-8                  1              0              -100.00%

benchmark                                       old bytes     new bytes     delta
BenchmarkIsPayToScriptHash-8                    311299        0             -100.00%
BenchmarkIsPubKeyHashScript-8                   311299        0             -100.00%
BenchmarkGetSigOpCount-8                        311299        0             -100.00%
BenchmarkExtractPkScriptAddrsLarge-8            311299        0             -100.00%
BenchmarkExtractPkScriptAddrs-8                 768           0             -100.00%
BenchmarkIsWitnessPubKeyHash-8                  311299        0             -100.00%
BenchmarkIsUnspendable-8                        1             0             -100.00%
BenchmarkExtractAtomicSwapDataPushesLarge-8     311299        0             -100.00%
BenchmarkExtractAtomicSwapDataPushes-8          3168          96            -96.97%
BenchmarkDisasmString-8                         389324        130552        -66.47%
BenchmarkGetPreciseSigOpCount-8                 623367        0             -100.00%
BenchmarkScriptParsing-8                        311299        0             -100.00%
BenchmarkIsMultisigScriptLarge-8                311299        0             -100.00%
BenchmarkIsMultisigScript-8                     2304          0             -100.00%
BenchmarkPushedData-8                           312816        1520          -99.51%
BenchmarkCalcSigHash-8                          1373812       1290507       -6.06%
BenchmarkIsPubKeyScript-8                       311299        0             -100.00%
BenchmarkIsPushOnlyScript-8                     311299        0             -100.00%
BenchmarkIsWitnessScriptHash-8                  311299        0             -100.00%
BenchmarkGetScriptClass-8                       311299        0             -100.00%
BenchmarkIsNullDataScript-8                     311299        0             -100.00%
BenchmarkIsMultisigSigScriptLarge-8             330035        0             -100.00%
BenchmarkIsMultisigSigScript-8                  9472          0             -100.00%
BenchmarkGetWitnessSigOpCountP2WKH-8            1408          0             -100.00%
BenchmarkGetWitnessSigOpCountNested-8           3200          0             -100.00%
BenchmarkIsWitnessPubKeyHash-8                  311299        0             -100.00%
BenchmarkIsWitnessScriptHash-8                  311299        0             -100.00%
This commit is contained in:
Dave Collins 2019-03-13 01:13:08 -05:00 committed by Olaoluwa Osuntokun
parent ef3d06e62b
commit b95ba0ac95
No known key found for this signature in database
GPG key ID: 3BBD59E99B280306
3 changed files with 90 additions and 100 deletions

View file

@ -385,8 +385,7 @@ func (vm *Engine) executeOpcode(op *opcode, data []byte) error {
} }
} }
pop := parsedOpcode{opcode: op, data: data} return op.opfunc(op, data, vm)
return op.opfunc(&pop, vm)
} }
// checkValidPC returns an error if the current script position is not valid for // checkValidPC returns an error if the current script position is not valid for

View file

@ -28,7 +28,7 @@ type opcode struct {
value byte value byte
name string name string
length int length int
opfunc func(*parsedOpcode, *Engine) error opfunc func(*opcode, []byte, *Engine) error
} }
// These constants are the values of the official opcodes used on the btc wiki, // These constants are the values of the official opcodes used on the btc wiki,
@ -611,13 +611,6 @@ var opcodeOnelineRepls = map[string]string{
"OP_16": "16", "OP_16": "16",
} }
// parsedOpcode represents an opcode that has been parsed and includes any
// potential data associated with it.
type parsedOpcode struct {
opcode *opcode
data []byte
}
// disasmOpcode writes a human-readable disassembly of the provided opcode and // disasmOpcode writes a human-readable disassembly of the provided opcode and
// data into the provided buffer. The compact flag indicates the disassembly // data into the provided buffer. The compact flag indicates the disassembly
// should print a more compact representation of data-carrying and small integer // should print a more compact representation of data-carrying and small integer
@ -676,45 +669,42 @@ func disasmOpcode(buf *strings.Builder, op *opcode, data []byte, compact bool) {
// opcodes before executing in an initial parse step, the consensus rules // opcodes before executing in an initial parse step, the consensus rules
// dictate the script doesn't fail until the program counter passes over a // dictate the script doesn't fail until the program counter passes over a
// disabled opcode (even when they appear in a branch that is not executed). // disabled opcode (even when they appear in a branch that is not executed).
func opcodeDisabled(op *parsedOpcode, vm *Engine) error { func opcodeDisabled(op *opcode, data []byte, vm *Engine) error {
str := fmt.Sprintf("attempt to execute disabled opcode %s", str := fmt.Sprintf("attempt to execute disabled opcode %s", op.name)
op.opcode.name)
return scriptError(ErrDisabledOpcode, str) return scriptError(ErrDisabledOpcode, str)
} }
// opcodeReserved is a common handler for all reserved opcodes. It returns an // opcodeReserved is a common handler for all reserved opcodes. It returns an
// appropriate error indicating the opcode is reserved. // appropriate error indicating the opcode is reserved.
func opcodeReserved(op *parsedOpcode, vm *Engine) error { func opcodeReserved(op *opcode, data []byte, vm *Engine) error {
str := fmt.Sprintf("attempt to execute reserved opcode %s", str := fmt.Sprintf("attempt to execute reserved opcode %s", op.name)
op.opcode.name)
return scriptError(ErrReservedOpcode, str) return scriptError(ErrReservedOpcode, str)
} }
// opcodeInvalid is a common handler for all invalid opcodes. It returns an // opcodeInvalid is a common handler for all invalid opcodes. It returns an
// appropriate error indicating the opcode is invalid. // appropriate error indicating the opcode is invalid.
func opcodeInvalid(op *parsedOpcode, vm *Engine) error { func opcodeInvalid(op *opcode, data []byte, vm *Engine) error {
str := fmt.Sprintf("attempt to execute invalid opcode %s", str := fmt.Sprintf("attempt to execute invalid opcode %s", op.name)
op.opcode.name)
return scriptError(ErrReservedOpcode, str) return scriptError(ErrReservedOpcode, str)
} }
// opcodeFalse pushes an empty array to the data stack to represent false. Note // opcodeFalse pushes an empty array to the data stack to represent false. Note
// that 0, when encoded as a number according to the numeric encoding consensus // that 0, when encoded as a number according to the numeric encoding consensus
// rules, is an empty array. // rules, is an empty array.
func opcodeFalse(op *parsedOpcode, vm *Engine) error { func opcodeFalse(op *opcode, data []byte, vm *Engine) error {
vm.dstack.PushByteArray(nil) vm.dstack.PushByteArray(nil)
return nil return nil
} }
// opcodePushData is a common handler for the vast majority of opcodes that push // opcodePushData is a common handler for the vast majority of opcodes that push
// raw data (bytes) to the data stack. // raw data (bytes) to the data stack.
func opcodePushData(op *parsedOpcode, vm *Engine) error { func opcodePushData(op *opcode, data []byte, vm *Engine) error {
vm.dstack.PushByteArray(op.data) vm.dstack.PushByteArray(data)
return nil return nil
} }
// opcode1Negate pushes -1, encoded as a number, to the data stack. // opcode1Negate pushes -1, encoded as a number, to the data stack.
func opcode1Negate(op *parsedOpcode, vm *Engine) error { func opcode1Negate(op *opcode, data []byte, vm *Engine) error {
vm.dstack.PushInt(scriptNum(-1)) vm.dstack.PushInt(scriptNum(-1))
return nil return nil
} }
@ -722,23 +712,24 @@ func opcode1Negate(op *parsedOpcode, vm *Engine) error {
// opcodeN is a common handler for the small integer data push opcodes. It // opcodeN is a common handler for the small integer data push opcodes. It
// pushes the numeric value the opcode represents (which will be from 1 to 16) // pushes the numeric value the opcode represents (which will be from 1 to 16)
// onto the data stack. // onto the data stack.
func opcodeN(op *parsedOpcode, vm *Engine) error { func opcodeN(op *opcode, data []byte, vm *Engine) error {
// The opcodes are all defined consecutively, so the numeric value is // The opcodes are all defined consecutively, so the numeric value is
// the difference. // the difference.
vm.dstack.PushInt(scriptNum((op.opcode.value - (OP_1 - 1)))) vm.dstack.PushInt(scriptNum((op.value - (OP_1 - 1))))
return nil return nil
} }
// opcodeNop is a common handler for the NOP family of opcodes. As the name // opcodeNop is a common handler for the NOP family of opcodes. As the name
// implies it generally does nothing, however, it will return an error when // implies it generally does nothing, however, it will return an error when
// 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 *opcode, data []byte, vm *Engine) error {
switch op.opcode.value { switch op.value {
case OP_NOP1, 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) {
str := fmt.Sprintf("OP_NOP%d reserved for soft-fork "+ str := fmt.Sprintf("%v reserved for soft-fork "+
"upgrades", op.opcode.value-(OP_NOP1-1)) "upgrades", op.name)
return scriptError(ErrDiscourageUpgradableNOPs, str) return scriptError(ErrDiscourageUpgradableNOPs, str)
} }
} }
@ -801,7 +792,7 @@ func popIfBool(vm *Engine) (bool, error) {
// //
// Data stack transformation: [... bool] -> [...] // Data stack transformation: [... bool] -> [...]
// Conditional stack transformation: [...] -> [... OpCondValue] // Conditional stack transformation: [...] -> [... OpCondValue]
func opcodeIf(op *parsedOpcode, vm *Engine) error { func opcodeIf(op *opcode, data []byte, vm *Engine) error {
condVal := OpCondFalse condVal := OpCondFalse
if vm.isBranchExecuting() { if vm.isBranchExecuting() {
ok, err := popIfBool(vm) ok, err := popIfBool(vm)
@ -835,7 +826,7 @@ func opcodeIf(op *parsedOpcode, vm *Engine) error {
// //
// Data stack transformation: [... bool] -> [...] // Data stack transformation: [... bool] -> [...]
// Conditional stack transformation: [...] -> [... OpCondValue] // Conditional stack transformation: [...] -> [... OpCondValue]
func opcodeNotIf(op *parsedOpcode, vm *Engine) error { func opcodeNotIf(op *opcode, data []byte, vm *Engine) error {
condVal := OpCondFalse condVal := OpCondFalse
if vm.isBranchExecuting() { if vm.isBranchExecuting() {
ok, err := popIfBool(vm) ok, err := popIfBool(vm)
@ -858,10 +849,10 @@ func opcodeNotIf(op *parsedOpcode, vm *Engine) error {
// An error is returned if there has not already been a matching OP_IF. // An error is returned if there has not already been a matching OP_IF.
// //
// Conditional stack transformation: [... OpCondValue] -> [... !OpCondValue] // Conditional stack transformation: [... OpCondValue] -> [... !OpCondValue]
func opcodeElse(op *parsedOpcode, vm *Engine) error { func opcodeElse(op *opcode, data []byte, vm *Engine) error {
if len(vm.condStack) == 0 { if len(vm.condStack) == 0 {
str := fmt.Sprintf("encountered opcode %s with no matching "+ str := fmt.Sprintf("encountered opcode %s with no matching "+
"opcode to begin conditional execution", op.opcode.name) "opcode to begin conditional execution", op.name)
return scriptError(ErrUnbalancedConditional, str) return scriptError(ErrUnbalancedConditional, str)
} }
@ -884,10 +875,10 @@ func opcodeElse(op *parsedOpcode, vm *Engine) error {
// An error is returned if there has not already been a matching OP_IF. // An error is returned if there has not already been a matching OP_IF.
// //
// Conditional stack transformation: [... OpCondValue] -> [...] // Conditional stack transformation: [... OpCondValue] -> [...]
func opcodeEndif(op *parsedOpcode, vm *Engine) error { func opcodeEndif(op *opcode, data []byte, vm *Engine) error {
if len(vm.condStack) == 0 { if len(vm.condStack) == 0 {
str := fmt.Sprintf("encountered opcode %s with no matching "+ str := fmt.Sprintf("encountered opcode %s with no matching "+
"opcode to begin conditional execution", op.opcode.name) "opcode to begin conditional execution", op.name)
return scriptError(ErrUnbalancedConditional, str) return scriptError(ErrUnbalancedConditional, str)
} }
@ -900,14 +891,14 @@ func opcodeEndif(op *parsedOpcode, vm *Engine) error {
// item on the stack or when that item evaluates to false. In the latter case // item on the stack or when that item evaluates to false. In the latter case
// where the verification fails specifically due to the top item evaluating // where the verification fails specifically due to the top item evaluating
// to false, the returned error will use the passed error code. // to false, the returned error will use the passed error code.
func abstractVerify(op *parsedOpcode, vm *Engine, c ErrorCode) error { func abstractVerify(op *opcode, vm *Engine, c ErrorCode) error {
verified, err := vm.dstack.PopBool() verified, err := vm.dstack.PopBool()
if err != nil { if err != nil {
return err return err
} }
if !verified { if !verified {
str := fmt.Sprintf("%s failed", op.opcode.name) str := fmt.Sprintf("%s failed", op.name)
return scriptError(c, str) return scriptError(c, str)
} }
return nil return nil
@ -915,13 +906,13 @@ func abstractVerify(op *parsedOpcode, vm *Engine, c ErrorCode) error {
// opcodeVerify examines the top item on the data stack as a boolean value and // opcodeVerify examines the top item on the data stack as a boolean value and
// verifies it evaluates to true. An error is returned if it does not. // verifies it evaluates to true. An error is returned if it does not.
func opcodeVerify(op *parsedOpcode, vm *Engine) error { func opcodeVerify(op *opcode, data []byte, vm *Engine) error {
return abstractVerify(op, vm, ErrVerify) return abstractVerify(op, vm, ErrVerify)
} }
// opcodeReturn returns an appropriate error since it is always an error to // opcodeReturn returns an appropriate error since it is always an error to
// return early from a script. // return early from a script.
func opcodeReturn(op *parsedOpcode, vm *Engine) error { func opcodeReturn(op *opcode, data []byte, vm *Engine) error {
return scriptError(ErrEarlyReturn, "script returned early") return scriptError(ErrEarlyReturn, "script returned early")
} }
@ -951,7 +942,7 @@ func verifyLockTime(txLockTime, threshold, lockTime int64) error {
// validating if the transaction outputs are spendable yet. If flag // validating if the transaction outputs are spendable yet. If flag
// ScriptVerifyCheckLockTimeVerify is not set, the code continues as if OP_NOP2 // ScriptVerifyCheckLockTimeVerify is not set, the code continues as if OP_NOP2
// were executed. // were executed.
func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error { func opcodeCheckLockTimeVerify(op *opcode, data []byte, vm *Engine) error {
// If the ScriptVerifyCheckLockTimeVerify script flag is not set, treat // If the ScriptVerifyCheckLockTimeVerify script flag is not set, treat
// opcode as OP_NOP2 instead. // opcode as OP_NOP2 instead.
if !vm.hasFlag(ScriptVerifyCheckLockTimeVerify) { if !vm.hasFlag(ScriptVerifyCheckLockTimeVerify) {
@ -1025,7 +1016,7 @@ func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error {
// validating if the transaction outputs are spendable yet. If flag // validating if the transaction outputs are spendable yet. If flag
// ScriptVerifyCheckSequenceVerify is not set, the code continues as if OP_NOP3 // ScriptVerifyCheckSequenceVerify is not set, the code continues as if OP_NOP3
// were executed. // were executed.
func opcodeCheckSequenceVerify(op *parsedOpcode, vm *Engine) error { func opcodeCheckSequenceVerify(op *opcode, data []byte, vm *Engine) error {
// If the ScriptVerifyCheckSequenceVerify script flag is not set, treat // If the ScriptVerifyCheckSequenceVerify script flag is not set, treat
// opcode as OP_NOP3 instead. // opcode as OP_NOP3 instead.
if !vm.hasFlag(ScriptVerifyCheckSequenceVerify) { if !vm.hasFlag(ScriptVerifyCheckSequenceVerify) {
@ -1102,7 +1093,7 @@ func opcodeCheckSequenceVerify(op *parsedOpcode, vm *Engine) error {
// //
// Main data stack transformation: [... x1 x2 x3] -> [... x1 x2] // Main data stack transformation: [... x1 x2 x3] -> [... x1 x2]
// Alt data stack transformation: [... y1 y2 y3] -> [... y1 y2 y3 x3] // Alt data stack transformation: [... y1 y2 y3] -> [... y1 y2 y3 x3]
func opcodeToAltStack(op *parsedOpcode, vm *Engine) error { func opcodeToAltStack(op *opcode, data []byte, vm *Engine) error {
so, err := vm.dstack.PopByteArray() so, err := vm.dstack.PopByteArray()
if err != nil { if err != nil {
return err return err
@ -1117,7 +1108,7 @@ func opcodeToAltStack(op *parsedOpcode, vm *Engine) error {
// //
// Main data stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 y3] // Main data stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 y3]
// Alt data stack transformation: [... y1 y2 y3] -> [... y1 y2] // Alt data stack transformation: [... y1 y2 y3] -> [... y1 y2]
func opcodeFromAltStack(op *parsedOpcode, vm *Engine) error { func opcodeFromAltStack(op *opcode, data []byte, vm *Engine) error {
so, err := vm.astack.PopByteArray() so, err := vm.astack.PopByteArray()
if err != nil { if err != nil {
return err return err
@ -1130,35 +1121,35 @@ func opcodeFromAltStack(op *parsedOpcode, vm *Engine) error {
// opcode2Drop removes the top 2 items from the data stack. // opcode2Drop removes the top 2 items from the data stack.
// //
// Stack transformation: [... x1 x2 x3] -> [... x1] // Stack transformation: [... x1 x2 x3] -> [... x1]
func opcode2Drop(op *parsedOpcode, vm *Engine) error { func opcode2Drop(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.DropN(2) return vm.dstack.DropN(2)
} }
// opcode2Dup duplicates the top 2 items on the data stack. // opcode2Dup duplicates the top 2 items on the data stack.
// //
// Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x2 x3] // Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x2 x3]
func opcode2Dup(op *parsedOpcode, vm *Engine) error { func opcode2Dup(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.DupN(2) return vm.dstack.DupN(2)
} }
// opcode3Dup duplicates the top 3 items on the data stack. // opcode3Dup duplicates the top 3 items on the data stack.
// //
// Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x1 x2 x3] // Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x1 x2 x3]
func opcode3Dup(op *parsedOpcode, vm *Engine) error { func opcode3Dup(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.DupN(3) return vm.dstack.DupN(3)
} }
// opcode2Over duplicates the 2 items before the top 2 items on the data stack. // opcode2Over duplicates the 2 items before the top 2 items on the data stack.
// //
// Stack transformation: [... x1 x2 x3 x4] -> [... x1 x2 x3 x4 x1 x2] // Stack transformation: [... x1 x2 x3 x4] -> [... x1 x2 x3 x4 x1 x2]
func opcode2Over(op *parsedOpcode, vm *Engine) error { func opcode2Over(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.OverN(2) return vm.dstack.OverN(2)
} }
// opcode2Rot rotates the top 6 items on the data stack to the left twice. // opcode2Rot rotates the top 6 items on the data stack to the left twice.
// //
// Stack transformation: [... x1 x2 x3 x4 x5 x6] -> [... x3 x4 x5 x6 x1 x2] // Stack transformation: [... x1 x2 x3 x4 x5 x6] -> [... x3 x4 x5 x6 x1 x2]
func opcode2Rot(op *parsedOpcode, vm *Engine) error { func opcode2Rot(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.RotN(2) return vm.dstack.RotN(2)
} }
@ -1166,7 +1157,7 @@ func opcode2Rot(op *parsedOpcode, vm *Engine) error {
// before them. // before them.
// //
// Stack transformation: [... x1 x2 x3 x4] -> [... x3 x4 x1 x2] // Stack transformation: [... x1 x2 x3 x4] -> [... x3 x4 x1 x2]
func opcode2Swap(op *parsedOpcode, vm *Engine) error { func opcode2Swap(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.SwapN(2) return vm.dstack.SwapN(2)
} }
@ -1174,7 +1165,7 @@ func opcode2Swap(op *parsedOpcode, vm *Engine) error {
// //
// Stack transformation (x1==0): [... x1] -> [... x1] // Stack transformation (x1==0): [... x1] -> [... x1]
// Stack transformation (x1!=0): [... x1] -> [... x1 x1] // Stack transformation (x1!=0): [... x1] -> [... x1 x1]
func opcodeIfDup(op *parsedOpcode, vm *Engine) error { func opcodeIfDup(op *opcode, data []byte, vm *Engine) error {
so, err := vm.dstack.PeekByteArray(0) so, err := vm.dstack.PeekByteArray(0)
if err != nil { if err != nil {
return err return err
@ -1194,7 +1185,7 @@ func opcodeIfDup(op *parsedOpcode, vm *Engine) error {
// Stack transformation: [...] -> [... <num of items on the stack>] // Stack transformation: [...] -> [... <num of items on the stack>]
// Example with 2 items: [x1 x2] -> [x1 x2 2] // Example with 2 items: [x1 x2] -> [x1 x2 2]
// Example with 3 items: [x1 x2 x3] -> [x1 x2 x3 3] // Example with 3 items: [x1 x2 x3] -> [x1 x2 x3 3]
func opcodeDepth(op *parsedOpcode, vm *Engine) error { func opcodeDepth(op *opcode, data []byte, vm *Engine) error {
vm.dstack.PushInt(scriptNum(vm.dstack.Depth())) vm.dstack.PushInt(scriptNum(vm.dstack.Depth()))
return nil return nil
} }
@ -1202,28 +1193,28 @@ func opcodeDepth(op *parsedOpcode, vm *Engine) error {
// opcodeDrop removes the top item from the data stack. // opcodeDrop removes the top item from the data stack.
// //
// Stack transformation: [... x1 x2 x3] -> [... x1 x2] // Stack transformation: [... x1 x2 x3] -> [... x1 x2]
func opcodeDrop(op *parsedOpcode, vm *Engine) error { func opcodeDrop(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.DropN(1) return vm.dstack.DropN(1)
} }
// opcodeDup duplicates the top item on the data stack. // opcodeDup duplicates the top item on the data stack.
// //
// Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x3] // Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x3]
func opcodeDup(op *parsedOpcode, vm *Engine) error { func opcodeDup(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.DupN(1) return vm.dstack.DupN(1)
} }
// opcodeNip removes the item before the top item on the data stack. // opcodeNip removes the item before the top item on the data stack.
// //
// Stack transformation: [... x1 x2 x3] -> [... x1 x3] // Stack transformation: [... x1 x2 x3] -> [... x1 x3]
func opcodeNip(op *parsedOpcode, vm *Engine) error { func opcodeNip(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.NipN(1) return vm.dstack.NipN(1)
} }
// opcodeOver duplicates the item before the top item on the data stack. // opcodeOver duplicates the item before the top item on the data stack.
// //
// Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x2] // Stack transformation: [... x1 x2 x3] -> [... x1 x2 x3 x2]
func opcodeOver(op *parsedOpcode, vm *Engine) error { func opcodeOver(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.OverN(1) return vm.dstack.OverN(1)
} }
@ -1233,7 +1224,7 @@ func opcodeOver(op *parsedOpcode, vm *Engine) error {
// Stack transformation: [xn ... x2 x1 x0 n] -> [xn ... x2 x1 x0 xn] // Stack transformation: [xn ... x2 x1 x0 n] -> [xn ... x2 x1 x0 xn]
// Example with n=1: [x2 x1 x0 1] -> [x2 x1 x0 x1] // Example with n=1: [x2 x1 x0 1] -> [x2 x1 x0 x1]
// Example with n=2: [x2 x1 x0 2] -> [x2 x1 x0 x2] // Example with n=2: [x2 x1 x0 2] -> [x2 x1 x0 x2]
func opcodePick(op *parsedOpcode, vm *Engine) error { func opcodePick(op *opcode, data []byte, vm *Engine) error {
val, err := vm.dstack.PopInt() val, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1248,7 +1239,7 @@ func opcodePick(op *parsedOpcode, vm *Engine) error {
// Stack transformation: [xn ... x2 x1 x0 n] -> [... x2 x1 x0 xn] // Stack transformation: [xn ... x2 x1 x0 n] -> [... x2 x1 x0 xn]
// Example with n=1: [x2 x1 x0 1] -> [x2 x0 x1] // Example with n=1: [x2 x1 x0 1] -> [x2 x0 x1]
// Example with n=2: [x2 x1 x0 2] -> [x1 x0 x2] // Example with n=2: [x2 x1 x0 2] -> [x1 x0 x2]
func opcodeRoll(op *parsedOpcode, vm *Engine) error { func opcodeRoll(op *opcode, data []byte, vm *Engine) error {
val, err := vm.dstack.PopInt() val, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1260,14 +1251,14 @@ func opcodeRoll(op *parsedOpcode, vm *Engine) error {
// opcodeRot rotates the top 3 items on the data stack to the left. // opcodeRot rotates the top 3 items on the data stack to the left.
// //
// Stack transformation: [... x1 x2 x3] -> [... x2 x3 x1] // Stack transformation: [... x1 x2 x3] -> [... x2 x3 x1]
func opcodeRot(op *parsedOpcode, vm *Engine) error { func opcodeRot(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.RotN(1) return vm.dstack.RotN(1)
} }
// opcodeSwap swaps the top two items on the stack. // opcodeSwap swaps the top two items on the stack.
// //
// Stack transformation: [... x1 x2] -> [... x2 x1] // Stack transformation: [... x1 x2] -> [... x2 x1]
func opcodeSwap(op *parsedOpcode, vm *Engine) error { func opcodeSwap(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.SwapN(1) return vm.dstack.SwapN(1)
} }
@ -1275,7 +1266,7 @@ func opcodeSwap(op *parsedOpcode, vm *Engine) error {
// second-to-top item. // second-to-top item.
// //
// Stack transformation: [... x1 x2] -> [... x2 x1 x2] // Stack transformation: [... x1 x2] -> [... x2 x1 x2]
func opcodeTuck(op *parsedOpcode, vm *Engine) error { func opcodeTuck(op *opcode, data []byte, vm *Engine) error {
return vm.dstack.Tuck() return vm.dstack.Tuck()
} }
@ -1283,7 +1274,7 @@ func opcodeTuck(op *parsedOpcode, vm *Engine) error {
// stack. // stack.
// //
// Stack transformation: [... x1] -> [... x1 len(x1)] // Stack transformation: [... x1] -> [... x1 len(x1)]
func opcodeSize(op *parsedOpcode, vm *Engine) error { func opcodeSize(op *opcode, data []byte, vm *Engine) error {
so, err := vm.dstack.PeekByteArray(0) so, err := vm.dstack.PeekByteArray(0)
if err != nil { if err != nil {
return err return err
@ -1297,7 +1288,7 @@ func opcodeSize(op *parsedOpcode, vm *Engine) error {
// bytes, and pushes the result, encoded as a boolean, back to the stack. // bytes, and pushes the result, encoded as a boolean, back to the stack.
// //
// Stack transformation: [... x1 x2] -> [... bool] // Stack transformation: [... x1 x2] -> [... bool]
func opcodeEqual(op *parsedOpcode, vm *Engine) error { func opcodeEqual(op *opcode, data []byte, vm *Engine) error {
a, err := vm.dstack.PopByteArray() a, err := vm.dstack.PopByteArray()
if err != nil { if err != nil {
return err return err
@ -1318,8 +1309,8 @@ func opcodeEqual(op *parsedOpcode, vm *Engine) error {
// evaluates to true. An error is returned if it does not. // evaluates to true. An error is returned if it does not.
// //
// Stack transformation: [... x1 x2] -> [... bool] -> [...] // Stack transformation: [... x1 x2] -> [... bool] -> [...]
func opcodeEqualVerify(op *parsedOpcode, vm *Engine) error { func opcodeEqualVerify(op *opcode, data []byte, vm *Engine) error {
err := opcodeEqual(op, vm) err := opcodeEqual(op, data, vm)
if err == nil { if err == nil {
err = abstractVerify(op, vm, ErrEqualVerify) err = abstractVerify(op, vm, ErrEqualVerify)
} }
@ -1330,7 +1321,7 @@ func opcodeEqualVerify(op *parsedOpcode, vm *Engine) error {
// it with its incremented value (plus 1). // it with its incremented value (plus 1).
// //
// Stack transformation: [... x1 x2] -> [... x1 x2+1] // Stack transformation: [... x1 x2] -> [... x1 x2+1]
func opcode1Add(op *parsedOpcode, vm *Engine) error { func opcode1Add(op *opcode, data []byte, vm *Engine) error {
m, err := vm.dstack.PopInt() m, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1344,7 +1335,7 @@ func opcode1Add(op *parsedOpcode, vm *Engine) error {
// it with its decremented value (minus 1). // it with its decremented value (minus 1).
// //
// Stack transformation: [... x1 x2] -> [... x1 x2-1] // Stack transformation: [... x1 x2] -> [... x1 x2-1]
func opcode1Sub(op *parsedOpcode, vm *Engine) error { func opcode1Sub(op *opcode, data []byte, vm *Engine) error {
m, err := vm.dstack.PopInt() m, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1358,7 +1349,7 @@ func opcode1Sub(op *parsedOpcode, vm *Engine) error {
// it with its negation. // it with its negation.
// //
// Stack transformation: [... x1 x2] -> [... x1 -x2] // Stack transformation: [... x1 x2] -> [... x1 -x2]
func opcodeNegate(op *parsedOpcode, vm *Engine) error { func opcodeNegate(op *opcode, data []byte, vm *Engine) error {
m, err := vm.dstack.PopInt() m, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1372,7 +1363,7 @@ func opcodeNegate(op *parsedOpcode, vm *Engine) error {
// it with its absolute value. // it with its absolute value.
// //
// Stack transformation: [... x1 x2] -> [... x1 abs(x2)] // Stack transformation: [... x1 x2] -> [... x1 abs(x2)]
func opcodeAbs(op *parsedOpcode, vm *Engine) error { func opcodeAbs(op *opcode, data []byte, vm *Engine) error {
m, err := vm.dstack.PopInt() m, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1397,7 +1388,7 @@ func opcodeAbs(op *parsedOpcode, vm *Engine) error {
// Stack transformation (x2==0): [... x1 0] -> [... x1 1] // Stack transformation (x2==0): [... x1 0] -> [... x1 1]
// Stack transformation (x2!=0): [... x1 1] -> [... x1 0] // Stack transformation (x2!=0): [... x1 1] -> [... x1 0]
// Stack transformation (x2!=0): [... x1 17] -> [... x1 0] // Stack transformation (x2!=0): [... x1 17] -> [... x1 0]
func opcodeNot(op *parsedOpcode, vm *Engine) error { func opcodeNot(op *opcode, data []byte, vm *Engine) error {
m, err := vm.dstack.PopInt() m, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1417,7 +1408,7 @@ func opcodeNot(op *parsedOpcode, vm *Engine) error {
// Stack transformation (x2==0): [... x1 0] -> [... x1 0] // Stack transformation (x2==0): [... x1 0] -> [... x1 0]
// Stack transformation (x2!=0): [... x1 1] -> [... x1 1] // Stack transformation (x2!=0): [... x1 1] -> [... x1 1]
// Stack transformation (x2!=0): [... x1 17] -> [... x1 1] // Stack transformation (x2!=0): [... x1 17] -> [... x1 1]
func opcode0NotEqual(op *parsedOpcode, vm *Engine) error { func opcode0NotEqual(op *opcode, data []byte, vm *Engine) error {
m, err := vm.dstack.PopInt() m, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1434,7 +1425,7 @@ func opcode0NotEqual(op *parsedOpcode, vm *Engine) error {
// them with their sum. // them with their sum.
// //
// Stack transformation: [... x1 x2] -> [... x1+x2] // Stack transformation: [... x1 x2] -> [... x1+x2]
func opcodeAdd(op *parsedOpcode, vm *Engine) error { func opcodeAdd(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1454,7 +1445,7 @@ func opcodeAdd(op *parsedOpcode, vm *Engine) error {
// entry. // entry.
// //
// Stack transformation: [... x1 x2] -> [... x1-x2] // Stack transformation: [... x1 x2] -> [... x1-x2]
func opcodeSub(op *parsedOpcode, vm *Engine) error { func opcodeSub(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1476,7 +1467,7 @@ func opcodeSub(op *parsedOpcode, vm *Engine) error {
// Stack transformation (x1!=0, x2==0): [... 5 0] -> [... 0] // Stack transformation (x1!=0, x2==0): [... 5 0] -> [... 0]
// Stack transformation (x1==0, x2!=0): [... 0 7] -> [... 0] // Stack transformation (x1==0, x2!=0): [... 0 7] -> [... 0]
// Stack transformation (x1!=0, x2!=0): [... 4 8] -> [... 1] // Stack transformation (x1!=0, x2!=0): [... 4 8] -> [... 1]
func opcodeBoolAnd(op *parsedOpcode, vm *Engine) error { func opcodeBoolAnd(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1503,7 +1494,7 @@ func opcodeBoolAnd(op *parsedOpcode, vm *Engine) error {
// Stack transformation (x1!=0, x2==0): [... 5 0] -> [... 1] // Stack transformation (x1!=0, x2==0): [... 5 0] -> [... 1]
// Stack transformation (x1==0, x2!=0): [... 0 7] -> [... 1] // Stack transformation (x1==0, x2!=0): [... 0 7] -> [... 1]
// Stack transformation (x1!=0, x2!=0): [... 4 8] -> [... 1] // Stack transformation (x1!=0, x2!=0): [... 4 8] -> [... 1]
func opcodeBoolOr(op *parsedOpcode, vm *Engine) error { func opcodeBoolOr(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1528,7 +1519,7 @@ func opcodeBoolOr(op *parsedOpcode, vm *Engine) error {
// //
// Stack transformation (x1==x2): [... 5 5] -> [... 1] // Stack transformation (x1==x2): [... 5 5] -> [... 1]
// Stack transformation (x1!=x2): [... 5 7] -> [... 0] // Stack transformation (x1!=x2): [... 5 7] -> [... 0]
func opcodeNumEqual(op *parsedOpcode, vm *Engine) error { func opcodeNumEqual(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1556,8 +1547,8 @@ func opcodeNumEqual(op *parsedOpcode, vm *Engine) error {
// to true. An error is returned if it does not. // to true. An error is returned if it does not.
// //
// Stack transformation: [... x1 x2] -> [... bool] -> [...] // Stack transformation: [... x1 x2] -> [... bool] -> [...]
func opcodeNumEqualVerify(op *parsedOpcode, vm *Engine) error { func opcodeNumEqualVerify(op *opcode, data []byte, vm *Engine) error {
err := opcodeNumEqual(op, vm) err := opcodeNumEqual(op, data, vm)
if err == nil { if err == nil {
err = abstractVerify(op, vm, ErrNumEqualVerify) err = abstractVerify(op, vm, ErrNumEqualVerify)
} }
@ -1569,7 +1560,7 @@ func opcodeNumEqualVerify(op *parsedOpcode, vm *Engine) error {
// //
// Stack transformation (x1==x2): [... 5 5] -> [... 0] // Stack transformation (x1==x2): [... 5 5] -> [... 0]
// Stack transformation (x1!=x2): [... 5 7] -> [... 1] // Stack transformation (x1!=x2): [... 5 7] -> [... 1]
func opcodeNumNotEqual(op *parsedOpcode, vm *Engine) error { func opcodeNumNotEqual(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1594,7 +1585,7 @@ func opcodeNumNotEqual(op *parsedOpcode, vm *Engine) error {
// otherwise a 0. // otherwise a 0.
// //
// Stack transformation: [... x1 x2] -> [... bool] // Stack transformation: [... x1 x2] -> [... bool]
func opcodeLessThan(op *parsedOpcode, vm *Engine) error { func opcodeLessThan(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1619,7 +1610,7 @@ func opcodeLessThan(op *parsedOpcode, vm *Engine) error {
// with a 1, otherwise a 0. // with a 1, otherwise a 0.
// //
// Stack transformation: [... x1 x2] -> [... bool] // Stack transformation: [... x1 x2] -> [... bool]
func opcodeGreaterThan(op *parsedOpcode, vm *Engine) error { func opcodeGreaterThan(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1643,7 +1634,7 @@ func opcodeGreaterThan(op *parsedOpcode, vm *Engine) error {
// replaced with a 1, otherwise a 0. // replaced with a 1, otherwise a 0.
// //
// Stack transformation: [... x1 x2] -> [... bool] // Stack transformation: [... x1 x2] -> [... bool]
func opcodeLessThanOrEqual(op *parsedOpcode, vm *Engine) error { func opcodeLessThanOrEqual(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1667,7 +1658,7 @@ func opcodeLessThanOrEqual(op *parsedOpcode, vm *Engine) error {
// item, they are replaced with a 1, otherwise a 0. // item, they are replaced with a 1, otherwise a 0.
// //
// Stack transformation: [... x1 x2] -> [... bool] // Stack transformation: [... x1 x2] -> [... bool]
func opcodeGreaterThanOrEqual(op *parsedOpcode, vm *Engine) error { func opcodeGreaterThanOrEqual(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1691,7 +1682,7 @@ func opcodeGreaterThanOrEqual(op *parsedOpcode, vm *Engine) error {
// them with the minimum of the two. // them with the minimum of the two.
// //
// Stack transformation: [... x1 x2] -> [... min(x1, x2)] // Stack transformation: [... x1 x2] -> [... min(x1, x2)]
func opcodeMin(op *parsedOpcode, vm *Engine) error { func opcodeMin(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1715,7 +1706,7 @@ func opcodeMin(op *parsedOpcode, vm *Engine) error {
// them with the maximum of the two. // them with the maximum of the two.
// //
// Stack transformation: [... x1 x2] -> [... max(x1, x2)] // Stack transformation: [... x1 x2] -> [... max(x1, x2)]
func opcodeMax(op *parsedOpcode, vm *Engine) error { func opcodeMax(op *opcode, data []byte, vm *Engine) error {
v0, err := vm.dstack.PopInt() v0, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1743,7 +1734,7 @@ func opcodeMax(op *parsedOpcode, vm *Engine) error {
// the third-to-top item is the value to test. // the third-to-top item is the value to test.
// //
// Stack transformation: [... x1 min max] -> [... bool] // Stack transformation: [... x1 min max] -> [... bool]
func opcodeWithin(op *parsedOpcode, vm *Engine) error { func opcodeWithin(op *opcode, data []byte, vm *Engine) error {
maxVal, err := vm.dstack.PopInt() maxVal, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -1777,7 +1768,7 @@ func calcHash(buf []byte, hasher hash.Hash) []byte {
// replaces it with ripemd160(data). // replaces it with ripemd160(data).
// //
// Stack transformation: [... x1] -> [... ripemd160(x1)] // Stack transformation: [... x1] -> [... ripemd160(x1)]
func opcodeRipemd160(op *parsedOpcode, vm *Engine) error { func opcodeRipemd160(op *opcode, data []byte, vm *Engine) error {
buf, err := vm.dstack.PopByteArray() buf, err := vm.dstack.PopByteArray()
if err != nil { if err != nil {
return err return err
@ -1791,7 +1782,7 @@ func opcodeRipemd160(op *parsedOpcode, vm *Engine) error {
// with sha1(data). // with sha1(data).
// //
// Stack transformation: [... x1] -> [... sha1(x1)] // Stack transformation: [... x1] -> [... sha1(x1)]
func opcodeSha1(op *parsedOpcode, vm *Engine) error { func opcodeSha1(op *opcode, data []byte, vm *Engine) error {
buf, err := vm.dstack.PopByteArray() buf, err := vm.dstack.PopByteArray()
if err != nil { if err != nil {
return err return err
@ -1806,7 +1797,7 @@ func opcodeSha1(op *parsedOpcode, vm *Engine) error {
// it with sha256(data). // it with sha256(data).
// //
// Stack transformation: [... x1] -> [... sha256(x1)] // Stack transformation: [... x1] -> [... sha256(x1)]
func opcodeSha256(op *parsedOpcode, vm *Engine) error { func opcodeSha256(op *opcode, data []byte, vm *Engine) error {
buf, err := vm.dstack.PopByteArray() buf, err := vm.dstack.PopByteArray()
if err != nil { if err != nil {
return err return err
@ -1821,7 +1812,7 @@ func opcodeSha256(op *parsedOpcode, vm *Engine) error {
// it with ripemd160(sha256(data)). // it with ripemd160(sha256(data)).
// //
// Stack transformation: [... x1] -> [... ripemd160(sha256(x1))] // Stack transformation: [... x1] -> [... ripemd160(sha256(x1))]
func opcodeHash160(op *parsedOpcode, vm *Engine) error { func opcodeHash160(op *opcode, data []byte, vm *Engine) error {
buf, err := vm.dstack.PopByteArray() buf, err := vm.dstack.PopByteArray()
if err != nil { if err != nil {
return err return err
@ -1836,7 +1827,7 @@ func opcodeHash160(op *parsedOpcode, vm *Engine) error {
// it with sha256(sha256(data)). // it with sha256(sha256(data)).
// //
// Stack transformation: [... x1] -> [... sha256(sha256(x1))] // Stack transformation: [... x1] -> [... sha256(sha256(x1))]
func opcodeHash256(op *parsedOpcode, vm *Engine) error { func opcodeHash256(op *opcode, data []byte, vm *Engine) error {
buf, err := vm.dstack.PopByteArray() buf, err := vm.dstack.PopByteArray()
if err != nil { if err != nil {
return err return err
@ -1850,7 +1841,7 @@ func opcodeHash256(op *parsedOpcode, vm *Engine) error {
// seen OP_CODESEPARATOR which is used during signature checking. // seen OP_CODESEPARATOR which is used during signature checking.
// //
// This opcode does not change the contents of the data stack. // This opcode does not change the contents of the data stack.
func opcodeCodeSeparator(op *parsedOpcode, vm *Engine) error { func opcodeCodeSeparator(op *opcode, data []byte, vm *Engine) error {
vm.lastCodeSep = int(vm.tokenizer.ByteIndex()) vm.lastCodeSep = int(vm.tokenizer.ByteIndex())
return nil return nil
} }
@ -1869,7 +1860,7 @@ func opcodeCodeSeparator(op *parsedOpcode, vm *Engine) error {
// cryptographic methods against the provided public key. // cryptographic methods against the provided public key.
// //
// Stack transformation: [... signature pubkey] -> [... bool] // Stack transformation: [... signature pubkey] -> [... bool]
func opcodeCheckSig(op *parsedOpcode, vm *Engine) error { func opcodeCheckSig(op *opcode, data []byte, vm *Engine) error {
pkBytes, err := vm.dstack.PopByteArray() pkBytes, err := vm.dstack.PopByteArray()
if err != nil { if err != nil {
return err return err
@ -1984,9 +1975,9 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error {
// The opcodeCheckSig function is invoked followed by opcodeVerify. See the // The opcodeCheckSig function is invoked followed by opcodeVerify. See the
// documentation for each of those opcodes for more details. // documentation for each of those opcodes for more details.
// //
// Stack transformation: signature pubkey] -> [... bool] -> [...] // Stack transformation: [... signature pubkey] -> [... bool] -> [...]
func opcodeCheckSigVerify(op *parsedOpcode, vm *Engine) error { func opcodeCheckSigVerify(op *opcode, data []byte, vm *Engine) error {
err := opcodeCheckSig(op, vm) err := opcodeCheckSig(op, data, vm)
if err == nil { if err == nil {
err = abstractVerify(op, vm, ErrCheckSigVerify) err = abstractVerify(op, vm, ErrCheckSigVerify)
} }
@ -2021,7 +2012,7 @@ type parsedSigInfo struct {
// //
// Stack transformation: // Stack transformation:
// [... dummy [sig ...] numsigs [pubkey ...] numpubkeys] -> [... bool] // [... dummy [sig ...] numsigs [pubkey ...] numpubkeys] -> [... bool]
func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { func opcodeCheckMultiSig(op *opcode, data []byte, vm *Engine) error {
numKeys, err := vm.dstack.PopInt() numKeys, err := vm.dstack.PopInt()
if err != nil { if err != nil {
return err return err
@ -2247,8 +2238,8 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error {
// //
// Stack transformation: // Stack transformation:
// [... dummy [sig ...] numsigs [pubkey ...] numpubkeys] -> [... bool] -> [...] // [... dummy [sig ...] numsigs [pubkey ...] numpubkeys] -> [... bool] -> [...]
func opcodeCheckMultiSigVerify(op *parsedOpcode, vm *Engine) error { func opcodeCheckMultiSigVerify(op *opcode, data []byte, vm *Engine) error {
err := opcodeCheckMultiSig(op, vm) err := opcodeCheckMultiSig(op, data, vm)
if err == nil { if err == nil {
err = abstractVerify(op, vm, ErrCheckMultiSigVerify) err = abstractVerify(op, vm, ErrCheckMultiSigVerify)
} }

View file

@ -23,8 +23,8 @@ func TestOpcodeDisabled(t *testing.T) {
OP_LSHIFT, OP_RSHIFT, OP_LSHIFT, OP_RSHIFT,
} }
for _, opcodeVal := range tests { for _, opcodeVal := range tests {
pop := parsedOpcode{opcode: &opcodeArray[opcodeVal], data: nil} op := &opcodeArray[opcodeVal]
err := opcodeDisabled(&pop, nil) err := opcodeDisabled(op, nil, nil)
if !IsErrorCode(err, ErrDisabledOpcode) { if !IsErrorCode(err, ErrDisabledOpcode) {
t.Errorf("opcodeDisabled: unexpected error - got %v, "+ t.Errorf("opcodeDisabled: unexpected error - got %v, "+
"want %v", err, ErrDisabledOpcode) "want %v", err, ErrDisabledOpcode)