engine_test.go raw
1 package txscript
2
3 import (
4 "testing"
5
6 "github.com/p9c/p9/pkg/chainhash"
7 "github.com/p9c/p9/pkg/wire"
8 )
9
10 // TestBadPC sets the pc to a deliberately bad result then confirms that Step() and Disasm fail correctly.
11 func TestBadPC(t *testing.T) {
12 t.Parallel()
13 tests := []struct {
14 script, off int
15 }{
16 {script: 2, off: 0},
17 {script: 0, off: 2},
18 }
19 // tx with almost empty scripts.
20 tx := &wire.MsgTx{
21 Version: 1,
22 TxIn: []*wire.TxIn{
23 {
24 PreviousOutPoint: wire.OutPoint{
25 Hash: chainhash.Hash(
26 [32]byte{
27 0xc9, 0x97, 0xa5, 0xe5,
28 0x6e, 0x10, 0x41, 0x02,
29 0xfa, 0x20, 0x9c, 0x6a,
30 0x85, 0x2d, 0xd9, 0x06,
31 0x60, 0xa2, 0x0b, 0x2d,
32 0x9c, 0x35, 0x24, 0x23,
33 0xed, 0xce, 0x25, 0x85,
34 0x7f, 0xcd, 0x37, 0x04,
35 },
36 ),
37 Index: 0,
38 },
39 SignatureScript: mustParseShortForm("NOP"),
40 Sequence: 4294967295,
41 },
42 },
43 TxOut: []*wire.TxOut{
44 {
45 Value: 1000000000,
46 PkScript: nil,
47 },
48 },
49 LockTime: 0,
50 }
51 pkScript := mustParseShortForm("NOP")
52 for _, test := range tests {
53 vm, e := NewEngine(pkScript, tx, 0, 0, nil, nil, -1)
54 if e != nil {
55 t.Errorf("Failed to create script: %v", e)
56 }
57 // set to after all scripts
58 vm.scriptIdx.Store(int64(test.script))
59 vm.scriptOff.Store(int64(test.off))
60 _, e = vm.Step()
61 if e == nil {
62 t.Errorf("Step with invalid pc (%v) succeeds!", test)
63 continue
64 }
65 _, e = vm.DisasmPC()
66 if e == nil {
67 t.Errorf(
68 "DisasmPC with invalid pc (%v) succeeds!",
69 test,
70 )
71 }
72 }
73 }
74
75 // TestCheckErrorCondition tests the execute early test in CheckErrorCondition() since most code paths are tested
76 // elsewhere.
77 func TestCheckErrorCondition(t *testing.T) {
78 t.Parallel()
79 // tx with almost empty scripts.
80 tx := &wire.MsgTx{
81 Version: 1,
82 TxIn: []*wire.TxIn{
83 {
84 PreviousOutPoint: wire.OutPoint{
85 Hash: chainhash.Hash(
86 [32]byte{
87 0xc9, 0x97, 0xa5, 0xe5,
88 0x6e, 0x10, 0x41, 0x02,
89 0xfa, 0x20, 0x9c, 0x6a,
90 0x85, 0x2d, 0xd9, 0x06,
91 0x60, 0xa2, 0x0b, 0x2d,
92 0x9c, 0x35, 0x24, 0x23,
93 0xed, 0xce, 0x25, 0x85,
94 0x7f, 0xcd, 0x37, 0x04,
95 },
96 ),
97 Index: 0,
98 },
99 SignatureScript: nil,
100 Sequence: 4294967295,
101 },
102 },
103 TxOut: []*wire.TxOut{
104 {
105 Value: 1000000000,
106 PkScript: nil,
107 },
108 },
109 LockTime: 0,
110 }
111 pkScript := mustParseShortForm(
112 "NOP NOP NOP NOP NOP NOP NOP NOP NOP" +
113 " NOP TRUE",
114 )
115 vm, e := NewEngine(pkScript, tx, 0, 0, nil, nil, 0)
116 if e != nil {
117 t.Errorf("failed to create script: %v", e)
118 }
119 for i := 0; i < len(pkScript)-1; i++ {
120 var done bool
121 done, e = vm.Step()
122 if e != nil {
123 t.Fatalf("failed to step %dth time: %v", i, e)
124 }
125 if done {
126 t.Fatalf("finshed early on %dth time", i)
127 }
128 e = vm.CheckErrorCondition(false)
129 if !IsErrorCode(e, ErrScriptUnfinished) {
130 t.Fatalf(
131 "got unexepected error %v on %dth iteration",
132 e, i,
133 )
134 }
135 }
136 done, e := vm.Step()
137 if e != nil {
138 t.Fatalf("final step failed %v", e)
139 }
140 if !done {
141 t.Fatalf("final step isn't done!")
142 }
143 e = vm.CheckErrorCondition(false)
144 if e != nil {
145 t.Errorf("unexpected error %v on final check", e)
146 }
147 }
148
149 // TestInvalidFlagCombinations ensures the script engine returns the expected error when disallowed flag combinations
150 // are specified.
151 func TestInvalidFlagCombinations(t *testing.T) {
152 t.Parallel()
153 tests := []ScriptFlags{
154 ScriptVerifyCleanStack,
155 }
156 // tx with almost empty scripts.
157 tx := &wire.MsgTx{
158 Version: 1,
159 TxIn: []*wire.TxIn{
160 {
161 PreviousOutPoint: wire.OutPoint{
162 Hash: chainhash.Hash(
163 [32]byte{
164 0xc9, 0x97, 0xa5, 0xe5,
165 0x6e, 0x10, 0x41, 0x02,
166 0xfa, 0x20, 0x9c, 0x6a,
167 0x85, 0x2d, 0xd9, 0x06,
168 0x60, 0xa2, 0x0b, 0x2d,
169 0x9c, 0x35, 0x24, 0x23,
170 0xed, 0xce, 0x25, 0x85,
171 0x7f, 0xcd, 0x37, 0x04,
172 },
173 ),
174 Index: 0,
175 },
176 SignatureScript: []uint8{OP_NOP},
177 Sequence: 4294967295,
178 },
179 },
180 TxOut: []*wire.TxOut{
181 {
182 Value: 1000000000,
183 PkScript: nil,
184 },
185 },
186 LockTime: 0,
187 }
188 pkScript := []byte{OP_NOP}
189 for i, test := range tests {
190 _, e := NewEngine(pkScript, tx, 0, test, nil, nil, -1)
191 if !IsErrorCode(e, ErrInvalidFlags) {
192 t.Fatalf(
193 "TestInvalidFlagCombinations #%d unexpected "+
194 "error: %v", i, e,
195 )
196 }
197 }
198 }
199
200 // TestCheckPubKeyEncoding ensures the internal checkPubKeyEncoding function works as expected.
201 func TestCheckPubKeyEncoding(t *testing.T) {
202 t.Parallel()
203 tests := []struct {
204 name string
205 key []byte
206 isValid bool
207 }{
208 {
209 name: "uncompressed ok",
210 key: hexToBytes(
211 "0411db93e1dcdb8a016b49840f8c53bc1eb68" +
212 "a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf" +
213 "9744464f82e160bfa9b8b64f9d4c03f999b8643f656b" +
214 "412a3",
215 ),
216 isValid: true,
217 },
218 {
219 name: "compressed ok",
220 key: hexToBytes(
221 "02ce0b14fb842b1ba549fdd675c98075f12e9" +
222 "c510f8ef52bd021a9a1f4809d3b4d",
223 ),
224 isValid: true,
225 },
226 {
227 name: "compressed ok",
228 key: hexToBytes(
229 "032689c7c2dab13309fb143e0e8fe39634252" +
230 "1887e976690b6b47f5b2a4b7d448e",
231 ),
232 isValid: true,
233 },
234 {
235 name: "hybrid",
236 key: hexToBytes(
237 "0679be667ef9dcbbac55a06295ce870b07029" +
238 "bfcdb2dce28d959f2815b16f81798483ada7726a3c46" +
239 "55da4fbfc0e1108a8fd17b448a68554199c47d08ffb1" +
240 "0d4b8",
241 ),
242 isValid: false,
243 },
244 {
245 name: "empty",
246 key: nil,
247 isValid: false,
248 },
249 }
250 vm := Engine{flags: ScriptVerifyStrictEncoding}
251 for _, test := range tests {
252 e := vm.checkPubKeyEncoding(test.key)
253 if e != nil && test.isValid {
254 t.Errorf(
255 "checkSignatureEncoding test '%s' failed "+
256 "when it should have succeeded: %v", test.name,
257 e,
258 )
259 } else if e == nil && !test.isValid {
260 t.Errorf(
261 "checkSignatureEncooding test '%s' succeeded "+
262 "when it should have failed", test.name,
263 )
264 }
265 }
266 }
267
268 // TestCheckSignatureEncoding ensures the internal checkSignatureEncoding function works as expected.
269 func TestCheckSignatureEncoding(t *testing.T) {
270 t.Parallel()
271 tests := []struct {
272 name string
273 sig []byte
274 isValid bool
275 }{
276 {
277 name: "valid signature",
278 sig: hexToBytes(
279 "304402204e45e16932b8af514961a1d3a1a25" +
280 "fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
281 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
282 "82221a8768d1d09",
283 ),
284 isValid: true,
285 },
286 {
287 name: "empty.",
288 sig: nil,
289 isValid: false,
290 },
291 {
292 name: "bad magic",
293 sig: hexToBytes(
294 "314402204e45e16932b8af514961a1d3a1a25" +
295 "fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
296 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
297 "82221a8768d1d09",
298 ),
299 isValid: false,
300 },
301 {
302 name: "bad 1st int marker magic",
303 sig: hexToBytes(
304 "304403204e45e16932b8af514961a1d3a1a25" +
305 "fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
306 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
307 "82221a8768d1d09",
308 ),
309 isValid: false,
310 },
311 {
312 name: "bad 2nd int marker",
313 sig: hexToBytes(
314 "304402204e45e16932b8af514961a1d3a1a25" +
315 "fdf3f4f7732e9d624c6c61548ab5fb8cd41032018152" +
316 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
317 "82221a8768d1d09",
318 ),
319 isValid: false,
320 },
321 {
322 name: "short len",
323 sig: hexToBytes(
324 "304302204e45e16932b8af514961a1d3a1a25" +
325 "fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
326 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
327 "82221a8768d1d09",
328 ),
329 isValid: false,
330 },
331 {
332 name: "long len",
333 sig: hexToBytes(
334 "304502204e45e16932b8af514961a1d3a1a25" +
335 "fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
336 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
337 "82221a8768d1d09",
338 ),
339 isValid: false,
340 },
341 {
342 name: "long X",
343 sig: hexToBytes(
344 "304402424e45e16932b8af514961a1d3a1a25" +
345 "fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
346 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
347 "82221a8768d1d09",
348 ),
349 isValid: false,
350 },
351 {
352 name: "long Y",
353 sig: hexToBytes(
354 "304402204e45e16932b8af514961a1d3a1a25" +
355 "fdf3f4f7732e9d624c6c61548ab5fb8cd41022118152" +
356 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
357 "82221a8768d1d09",
358 ),
359 isValid: false,
360 },
361 {
362 name: "short Y",
363 sig: hexToBytes(
364 "304402204e45e16932b8af514961a1d3a1a25" +
365 "fdf3f4f7732e9d624c6c61548ab5fb8cd41021918152" +
366 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
367 "82221a8768d1d09",
368 ),
369 isValid: false,
370 },
371 {
372 name: "trailing crap",
373 sig: hexToBytes(
374 "304402204e45e16932b8af514961a1d3a1a25" +
375 "fdf3f4f7732e9d624c6c61548ab5fb8cd41022018152" +
376 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
377 "82221a8768d1d0901",
378 ),
379 isValid: false,
380 },
381 {
382 name: "X == N ",
383 sig: hexToBytes(
384 "30440220fffffffffffffffffffffffffffff" +
385 "ffebaaedce6af48a03bbfd25e8cd0364141022018152" +
386 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
387 "82221a8768d1d09",
388 ),
389 isValid: false,
390 },
391 {
392 name: "X == N ",
393 sig: hexToBytes(
394 "30440220fffffffffffffffffffffffffffff" +
395 "ffebaaedce6af48a03bbfd25e8cd0364142022018152" +
396 "2ec8eca07de4860a4acdd12909d831cc56cbbac46220" +
397 "82221a8768d1d09",
398 ),
399 isValid: false,
400 },
401 {
402 name: "Y == N",
403 sig: hexToBytes(
404 "304402204e45e16932b8af514961a1d3a1a25" +
405 "fdf3f4f7732e9d624c6c61548ab5fb8cd410220fffff" +
406 "ffffffffffffffffffffffffffebaaedce6af48a03bb" +
407 "fd25e8cd0364141",
408 ),
409 isValid: false,
410 },
411 {
412 name: "Y > N",
413 sig: hexToBytes(
414 "304402204e45e16932b8af514961a1d3a1a25" +
415 "fdf3f4f7732e9d624c6c61548ab5fb8cd410220fffff" +
416 "ffffffffffffffffffffffffffebaaedce6af48a03bb" +
417 "fd25e8cd0364142",
418 ),
419 isValid: false,
420 },
421 {
422 name: "0 len X",
423 sig: hexToBytes(
424 "302402000220181522ec8eca07de4860a4acd" +
425 "d12909d831cc56cbbac4622082221a8768d1d09",
426 ),
427 isValid: false,
428 },
429 {
430 name: "0 len Y",
431 sig: hexToBytes(
432 "302402204e45e16932b8af514961a1d3a1a25" +
433 "fdf3f4f7732e9d624c6c61548ab5fb8cd410200",
434 ),
435 isValid: false,
436 },
437 {
438 name: "extra R padding",
439 sig: hexToBytes(
440 "30450221004e45e16932b8af514961a1d3a1a" +
441 "25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181" +
442 "522ec8eca07de4860a4acdd12909d831cc56cbbac462" +
443 "2082221a8768d1d09",
444 ),
445 isValid: false,
446 },
447 {
448 name: "extra S padding",
449 sig: hexToBytes(
450 "304502204e45e16932b8af514961a1d3a1a25" +
451 "fdf3f4f7732e9d624c6c61548ab5fb8cd41022100181" +
452 "522ec8eca07de4860a4acdd12909d831cc56cbbac462" +
453 "2082221a8768d1d09",
454 ),
455 isValid: false,
456 },
457 }
458 vm := Engine{flags: ScriptVerifyStrictEncoding}
459 for _, test := range tests {
460 e := vm.checkSignatureEncoding(test.sig)
461 if e != nil && test.isValid {
462 t.Errorf(
463 "checkSignatureEncoding test '%s' failed "+
464 "when it should have succeeded: %v", test.name,
465 e,
466 )
467 } else if e == nil && !test.isValid {
468 t.Errorf(
469 "checkSignatureEncooding test '%s' succeeded "+
470 "when it should have failed", test.name,
471 )
472 }
473 }
474 }
475