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.
This commit is contained in:
Dave Collins 2015-04-27 12:51:06 -05:00
parent c701477eaf
commit 2e433b0eb3
2 changed files with 45 additions and 45 deletions

View file

@ -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
}

View file

@ -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)