-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathstate.go
135 lines (117 loc) · 3.54 KB
/
state.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package interpreter
import "github.com/libsv/go-bt/v2/bscript/interpreter/scriptflag"
// State a snapshot of a threads state during execution.
type State struct {
DataStack [][]byte
AltStack [][]byte
ElseStack [][]byte
CondStack []int
SavedFirstStack [][]byte
Scripts []ParsedScript
ScriptIdx int
OpcodeIdx int
LastCodeSeparatorIdx int
NumOps int
Flags scriptflag.Flag
IsFinished bool
Genesis struct {
AfterGenesis bool
EarlyReturn bool
}
}
// Opcode the current interpreter.ParsedOpcode from the
// threads program counter.
func (s *State) Opcode() ParsedOpcode {
return s.Scripts[s.ScriptIdx][s.OpcodeIdx]
}
// RemainingScript the remaining script to be executed.
func (s *State) RemainingScript() ParsedScript {
return s.Scripts[s.ScriptIdx][s.OpcodeIdx:]
}
// StateHandler interfaces getting and applying state.
type StateHandler interface {
State() *State
SetState(state *State)
}
type nopStateHandler struct{}
func (n *nopStateHandler) State() *State {
return &State{}
}
func (n *nopStateHandler) SetState(state *State) {}
func (t *thread) State() *State {
scriptIdx := t.scriptIdx
offsetIdx := t.scriptOff
if scriptIdx >= len(t.scripts) {
scriptIdx = len(t.scripts) - 1
offsetIdx = len(t.scripts[scriptIdx]) - 1
}
if offsetIdx >= len(t.scripts[scriptIdx]) {
offsetIdx = len(t.scripts[scriptIdx]) - 1
}
ts := State{
DataStack: make([][]byte, int(t.dstack.Depth())),
AltStack: make([][]byte, int(t.astack.Depth())),
ElseStack: make([][]byte, int(t.elseStack.Depth())),
CondStack: make([]int, len(t.condStack)),
SavedFirstStack: make([][]byte, len(t.savedFirstStack)),
Scripts: make([]ParsedScript, len(t.scripts)),
ScriptIdx: scriptIdx,
OpcodeIdx: offsetIdx,
LastCodeSeparatorIdx: t.lastCodeSep,
NumOps: t.numOps,
Flags: t.flags,
IsFinished: t.scriptIdx > scriptIdx,
Genesis: struct {
AfterGenesis bool
EarlyReturn bool
}{
AfterGenesis: t.afterGenesis,
EarlyReturn: t.earlyReturnAfterGenesis,
},
}
for i, dd := range t.dstack.stk {
ts.DataStack[i] = make([]byte, len(dd))
copy(ts.DataStack[i], dd)
}
for i, aa := range t.astack.stk {
ts.AltStack[i] = make([]byte, len(aa))
copy(ts.AltStack[i], aa)
}
if stk, ok := t.elseStack.(*stack); ok {
for i, ee := range stk.stk {
ts.ElseStack[i] = make([]byte, len(ee))
copy(ts.ElseStack[i], ee)
}
}
for i, ss := range t.savedFirstStack {
ts.SavedFirstStack[i] = make([]byte, len(ss))
copy(ts.SavedFirstStack[i], ss)
}
copy(ts.CondStack, t.condStack)
for i, script := range t.scripts {
ts.Scripts[i] = make(ParsedScript, len(script))
copy(ts.Scripts[i], script)
}
return &ts
}
func (t *thread) SetState(state *State) {
setStack(&t.dstack, state.DataStack)
setStack(&t.astack, state.AltStack)
t.elseStack = &nopBoolStack{}
if state.Genesis.AfterGenesis {
es := &stack{debug: &nopDebugger{}, sh: &nopStateHandler{}}
setStack(es, state.ElseStack)
t.elseStack = es
}
t.condStack = make([]int, len(state.CondStack))
copy(t.condStack, state.CondStack)
t.savedFirstStack = state.SavedFirstStack
t.scripts = state.Scripts
t.scriptIdx = state.ScriptIdx
t.scriptOff = state.OpcodeIdx
t.lastCodeSep = state.LastCodeSeparatorIdx
t.numOps = state.NumOps
t.flags = state.Flags
t.afterGenesis = state.Genesis.AfterGenesis
t.earlyReturnAfterGenesis = state.Genesis.EarlyReturn
}