From 2e433b0eb3e8ef291f6251b09e24182fccb10c0f Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 27 Apr 2015 12:51:06 -0500 Subject: [PATCH] txscript: Move opcode execution logic to engine This commit moves the opcode execution logic from the opcode type to the engine type because execution of an opcode modifies the engine state (primarily the main and alternate data stacks) as opposed to the state of the opcode. Making the engine the receiver more clearly indicates this fact. --- txscript/engine.go | 47 ++++++++++++++++++++++++++++++++++++++++++++-- txscript/opcode.go | 43 ------------------------------------------ 2 files changed, 45 insertions(+), 45 deletions(-) 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)