diff --git a/txscript/engine.go b/txscript/engine.go index 5fa26f5e..e030b28e 100644 --- a/txscript/engine.go +++ b/txscript/engine.go @@ -111,6 +111,49 @@ func (vm *Engine) isBranchExecuting() bool { return vm.condStack[len(vm.condStack)-1] == OpCondTrue } +// executeOpcode peforms execution on the passed opcode. It takes into account +// whether or not it is hidden by conditionals, but some rules still must be +// tested in this case. +func (vm *Engine) executeOpcode(pop *parsedOpcode) error { + // Disabled opcodes are ``fail on program counter''. + if pop.disabled() { + return ErrStackOpDisabled + } + + // Always-illegal opcodes are ``fail on program counter''. + if pop.alwaysIllegal() { + return ErrStackReservedOpcode + } + + // Note that this includes OP_RESERVED which counts as a push operation. + if pop.opcode.value > OP_16 { + vm.numOps++ + if vm.numOps > MaxOpsPerScript { + return ErrStackTooManyOperations + } + + } else if len(pop.data) > MaxScriptElementSize { + return ErrStackElementTooBig + } + + // If we are not a conditional opcode and we aren't executing, then + // we are done now. + if !vm.isBranchExecuting() && !pop.conditional() { + return nil + } + + // Ensure all executed data push opcodes use the minimal encoding when + // the minimal data verification is set. + if vm.dstack.verifyMinimalData && vm.isBranchExecuting() && + pop.opcode.value >= 0 && pop.opcode.value <= OP_PUSHDATA4 { + if err := pop.checkMinimalDataPush(); err != nil { + return err + } + } + + return pop.opcode.opfunc(pop, vm) +} + // Execute will execute all script in the script engine and return either nil // for successful validation or an error if one occurred. func (vm *Engine) Execute() (err error) { @@ -191,9 +234,9 @@ func (vm *Engine) Step() (done bool, err error) { if err != nil { return true, err } - opcode := vm.scripts[vm.scriptIdx][vm.scriptOff] + opcode := &vm.scripts[vm.scriptIdx][vm.scriptOff] - err = opcode.exec(vm) + err = vm.executeOpcode(opcode) if err != nil { return true, err } diff --git a/txscript/opcode.go b/txscript/opcode.go index 6e826e35..203a48d2 100644 --- a/txscript/opcode.go +++ b/txscript/opcode.go @@ -718,49 +718,6 @@ func (pop *parsedOpcode) checkMinimalDataPush() error { return nil } -// exec peforms execution on the opcode. It takes into account whether or not -// it is hidden by conditionals, but some rules still must be tested in this -// case. -func (pop *parsedOpcode) exec(vm *Engine) error { - // Disabled opcodes are ``fail on program counter''. - if pop.disabled() { - return ErrStackOpDisabled - } - - // Always-illegal opcodes are ``fail on program counter''. - if pop.alwaysIllegal() { - return ErrStackReservedOpcode - } - - // Note that this includes OP_RESERVED which counts as a push operation. - if pop.opcode.value > OP_16 { - vm.numOps++ - if vm.numOps > MaxOpsPerScript { - return ErrStackTooManyOperations - } - - } else if len(pop.data) > MaxScriptElementSize { - return ErrStackElementTooBig - } - - // If we are not a conditional opcode and we aren't executing, then - // we are done now. - if !vm.isBranchExecuting() && !pop.conditional() { - return nil - } - - // Ensure all executed data push opcodes use the minimal encoding when - // the minimal data verification is set. - if vm.dstack.verifyMinimalData && vm.isBranchExecuting() && - pop.opcode.value >= 0 && pop.opcode.value <= OP_PUSHDATA4 { - if err := pop.checkMinimalDataPush(); err != nil { - return err - } - } - - return pop.opcode.opfunc(pop, vm) -} - func (pop *parsedOpcode) print(oneline bool) string { // The reference implementation one-line disassembly replaces opcodes // which represent values (e.g. OP_0 through OP_16 and OP_1NEGATE)