Skip to content

Commit

Permalink
txscript/engine: add execution StepCallback
Browse files Browse the repository at this point in the history
We add a new StepCallback as optional function closure on the Engine
that will be called every time a step has been performed during script
execution.

This is only meant to be used in debugging.
  • Loading branch information
halseth committed Jun 26, 2023
1 parent 7fd5c1e commit 363479f
Showing 1 changed file with 68 additions and 0 deletions.
68 changes: 68 additions & 0 deletions txscript/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,33 @@ type Engine struct {
witnessProgram []byte
inputAmount int64
taprootCtx *taprootExecutionCtx

// StepCallback is an optional function that will be called every time
// a step has been performed during script execution.
//
// NOTE: This is only meant to be used in debugging, and SHOULD NOT BE
// USED during regular operation.
StepCallback func(*StepInfo) error
}

// StepInfo houses the current VM state information that is passed back to the
// StepCallback during script execution.
type StepInfo struct {
// ScriptIndex is the index of the script currently being executed by
// the Engine.
ScriptIndex int

// OpcodeIndex is the index of the next opcode that will be executed.
// In case the execution has completed, the opcode index will be
// incrementet beyond the number of the current script's opcodes. This
// indicates no new script is being executed, and execution is done.
OpcodeIndex int

// Stack is the Engine's current content on the stack:
Stack [][]byte

// AltStack is the Engine's current content on the alt stack.
AltStack [][]byte
}

// hasFlag returns whether the script engine instance has the passed flag set.
Expand Down Expand Up @@ -1033,6 +1060,22 @@ func (vm *Engine) Execute() (err error) {
return nil
}

// If the StepCallback is set, we start by making a call back with the
// initial engine state.
var stepInfo *StepInfo
if vm.StepCallback != nil {
stepInfo = &StepInfo{
ScriptIndex: vm.scriptIdx,
OpcodeIndex: vm.opcodeIdx,
Stack: vm.dstack.stk,
AltStack: vm.astack.stk,
}
err := vm.StepCallback(stepInfo)
if err != nil {
return err
}
}

done := false
for !done {
log.Tracef("%v", newLogClosure(func() string {
Expand Down Expand Up @@ -1060,6 +1103,31 @@ func (vm *Engine) Execute() (err error) {

return dstr + astr
}))

if vm.StepCallback != nil {
scriptIdx := vm.scriptIdx
opcodeIdx := vm.opcodeIdx

// In case the execution has completed, we keep the
// current script index while increasing the opcode
// index. This is to indicate that no new script is
// being executed.
if done {
scriptIdx = stepInfo.ScriptIndex
opcodeIdx = stepInfo.OpcodeIndex + 1
}

stepInfo = &StepInfo{
ScriptIndex: scriptIdx,
OpcodeIndex: opcodeIdx,
Stack: vm.dstack.stk,
AltStack: vm.astack.stk,
}
err := vm.StepCallback(stepInfo)
if err != nil {
return err
}
}
}

return vm.CheckErrorCondition(true)
Expand Down

0 comments on commit 363479f

Please sign in to comment.