13 func TestStackOps(t *testing.T) {
14 type testStruct struct {
16 startVM *virtualMachine
18 wantVM *virtualMachine
21 cases := []testStruct{{
23 startVM: &virtualMachine{
25 dataStack: [][]byte{{1}},
27 wantVM: &virtualMachine{
29 dataStack: [][]byte{},
30 altStack: [][]byte{{1}},
34 startVM: &virtualMachine{
36 altStack: [][]byte{{1}},
38 wantVM: &virtualMachine{
41 dataStack: [][]byte{{1}},
45 startVM: &virtualMachine{
49 wantErr: ErrAltStackUnderflow,
52 startVM: &virtualMachine{
54 dataStack: [][]byte{{1}, {1}},
56 wantVM: &virtualMachine{
58 dataStack: [][]byte{},
62 startVM: &virtualMachine{
64 dataStack: [][]byte{{2}, {1}},
66 wantVM: &virtualMachine{
68 dataStack: [][]byte{{2}, {1}, {2}, {1}},
72 startVM: &virtualMachine{
74 dataStack: [][]byte{{3}, {2}, {1}},
76 wantVM: &virtualMachine{
78 dataStack: [][]byte{{3}, {2}, {1}, {3}, {2}, {1}},
82 startVM: &virtualMachine{
84 dataStack: [][]byte{{4}, {3}, {2}, {1}},
86 wantVM: &virtualMachine{
88 dataStack: [][]byte{{4}, {3}, {2}, {1}, {4}, {3}},
92 startVM: &virtualMachine{
94 dataStack: [][]byte{{4}, {3}, {2}, {1}},
96 wantErr: ErrRunLimitExceeded,
99 startVM: &virtualMachine{
101 dataStack: [][]byte{{6}, {5}, {4}, {3}, {2}, {1}},
103 wantVM: &virtualMachine{
105 dataStack: [][]byte{{4}, {3}, {2}, {1}, {6}, {5}},
109 startVM: &virtualMachine{
111 dataStack: [][]byte{{4}, {3}, {2}, {1}},
113 wantVM: &virtualMachine{
115 dataStack: [][]byte{{2}, {1}, {4}, {3}},
119 startVM: &virtualMachine{
121 dataStack: [][]byte{{1}},
123 wantVM: &virtualMachine{
125 dataStack: [][]byte{{1}, {1}},
129 startVM: &virtualMachine{
131 dataStack: [][]byte{{}},
133 wantVM: &virtualMachine{
135 dataStack: [][]byte{{}},
139 startVM: &virtualMachine{
141 dataStack: [][]byte{{1}},
143 wantErr: ErrRunLimitExceeded,
146 startVM: &virtualMachine{
148 dataStack: [][]byte{{1}},
150 wantVM: &virtualMachine{
152 dataStack: [][]byte{{1}, {1}},
156 startVM: &virtualMachine{
158 dataStack: [][]byte{{1}},
160 wantErr: ErrRunLimitExceeded,
163 startVM: &virtualMachine{
165 dataStack: [][]byte{{1}},
167 wantVM: &virtualMachine{
169 dataStack: [][]byte{},
173 startVM: &virtualMachine{
175 dataStack: [][]byte{{1}},
177 wantVM: &virtualMachine{
179 dataStack: [][]byte{{1}, {1}},
183 startVM: &virtualMachine{
185 dataStack: [][]byte{{1}},
187 wantErr: ErrRunLimitExceeded,
190 startVM: &virtualMachine{
192 dataStack: [][]byte{{2}, {1}},
194 wantVM: &virtualMachine{
196 dataStack: [][]byte{{1}},
200 startVM: &virtualMachine{
202 dataStack: [][]byte{{2}, {1}},
204 wantVM: &virtualMachine{
206 dataStack: [][]byte{{2}, {1}, {2}},
210 startVM: &virtualMachine{
212 dataStack: [][]byte{{2}, {1}},
214 wantErr: ErrRunLimitExceeded,
217 startVM: &virtualMachine{
219 dataStack: [][]byte{{3}, {2}, {1}, {2}},
221 wantVM: &virtualMachine{
223 dataStack: [][]byte{{3}, {2}, {1}, {3}},
227 startVM: &virtualMachine{
229 dataStack: [][]byte{{0xff, 0xff}, {2}, {1}, {2}},
231 wantErr: ErrRunLimitExceeded,
234 startVM: &virtualMachine{
236 dataStack: [][]byte{{3}, {2}, {1}, {2}},
238 wantVM: &virtualMachine{
240 dataStack: [][]byte{{2}, {1}, {3}},
244 startVM: &virtualMachine{
246 dataStack: [][]byte{{3}, {2}, {1}},
248 wantVM: &virtualMachine{
250 dataStack: [][]byte{{2}, {1}, {3}},
254 startVM: &virtualMachine{
256 dataStack: [][]byte{{2}, {1}},
258 wantVM: &virtualMachine{
260 dataStack: [][]byte{{1}, {2}},
264 startVM: &virtualMachine{
266 dataStack: [][]byte{{2}, {1}},
268 wantVM: &virtualMachine{
270 dataStack: [][]byte{{1}, {2}, {1}},
274 startVM: &virtualMachine{
276 dataStack: [][]byte{{2}, {1}},
278 wantErr: ErrRunLimitExceeded,
281 OP_DEPTH, OP_FROMALTSTACK, OP_TOALTSTACK, OP_2DROP, OP_2DUP, OP_3DUP,
282 OP_2OVER, OP_2ROT, OP_2SWAP, OP_IFDUP, OP_DROP, OP_DUP, OP_NIP,
283 OP_OVER, OP_PICK, OP_ROLL, OP_ROT, OP_SWAP, OP_TUCK,
285 for _, op := range stackops {
286 cases = append(cases, testStruct{
288 startVM: &virtualMachine{runLimit: 0},
289 wantErr: ErrRunLimitExceeded,
293 for i, c := range cases {
294 err := ops[c.op].fn(c.startVM)
296 if err != c.wantErr {
297 t.Errorf("case %d, op %s: got err = %v want %v", i, ops[c.op].name, err, c.wantErr)
300 if c.wantErr != nil {
304 if !testutil.DeepEqual(c.startVM, c.wantVM) {
305 t.Errorf("case %d, op %s: unexpected vm result\n\tgot: %+v\n\twant: %+v\n", i, ops[c.op].name, c.startVM, c.wantVM)
310 func TestStackUnderflow(t *testing.T) {
312 narg int // number of stack items required
313 op func(*virtualMachine) error
325 {3, opCheckPredicate},
332 {3, opCheckMultiSig}, // special, see also TestCryptoOps
356 {2, opNumEqualVerify},
360 {2, opLessThanOrEqual},
361 {2, opGreaterThanOrEqual},
387 {2, opPick}, // TODO(kr): special; check data-dependent # of pops
388 {2, opRoll}, // TODO(kr): special; check data-dependent # of pops
394 for _, test := range cases {
395 t.Run(funcName(test.op), func(t *testing.T) {
397 for i := 0; i < test.narg; i++ {
398 t.Run(fmt.Sprintf("%d args", i), func(t *testing.T) {
400 vm := &virtualMachine{
402 dataStack: make([][]byte, i),
405 if err != ErrDataStackUnderflow {
406 t.Errorf("err = %v, want ErrStackUnderflow", err)
416 func funcName(f interface{}) string {
417 v := reflect.ValueOf(f)
418 if v.Kind() != reflect.Func {
421 s := runtime.FuncForPC(v.Pointer()).Name()
422 return s[strings.LastIndex(s, ".")+1:]