1// Copyright (c) 2013-2017 The btcsuite developers
2// Use of this source code is governed by an ISC
3// license that can be found in the LICENSE file.
4
5package blockchain
6
7import (
8	"math"
9	"reflect"
10	"testing"
11	"time"
12
13	"github.com/btcsuite/btcd/chaincfg"
14	"github.com/btcsuite/btcd/chaincfg/chainhash"
15	"github.com/btcsuite/btcd/wire"
16	"github.com/btcsuite/btcutil"
17)
18
19// TestSequenceLocksActive tests the SequenceLockActive function to ensure it
20// works as expected in all possible combinations/scenarios.
21func TestSequenceLocksActive(t *testing.T) {
22	seqLock := func(h int32, s int64) *SequenceLock {
23		return &SequenceLock{
24			Seconds:     s,
25			BlockHeight: h,
26		}
27	}
28
29	tests := []struct {
30		seqLock     *SequenceLock
31		blockHeight int32
32		mtp         time.Time
33
34		want bool
35	}{
36		// Block based sequence lock with equal block height.
37		{seqLock: seqLock(1000, -1), blockHeight: 1001, mtp: time.Unix(9, 0), want: true},
38
39		// Time based sequence lock with mtp past the absolute time.
40		{seqLock: seqLock(-1, 30), blockHeight: 2, mtp: time.Unix(31, 0), want: true},
41
42		// Block based sequence lock with current height below seq lock block height.
43		{seqLock: seqLock(1000, -1), blockHeight: 90, mtp: time.Unix(9, 0), want: false},
44
45		// Time based sequence lock with current time before lock time.
46		{seqLock: seqLock(-1, 30), blockHeight: 2, mtp: time.Unix(29, 0), want: false},
47
48		// Block based sequence lock at the same height, so shouldn't yet be active.
49		{seqLock: seqLock(1000, -1), blockHeight: 1000, mtp: time.Unix(9, 0), want: false},
50
51		// Time based sequence lock with current time equal to lock time, so shouldn't yet be active.
52		{seqLock: seqLock(-1, 30), blockHeight: 2, mtp: time.Unix(30, 0), want: false},
53	}
54
55	t.Logf("Running %d sequence locks tests", len(tests))
56	for i, test := range tests {
57		got := SequenceLockActive(test.seqLock,
58			test.blockHeight, test.mtp)
59		if got != test.want {
60			t.Fatalf("SequenceLockActive #%d got %v want %v", i,
61				got, test.want)
62		}
63	}
64}
65
66// TestCheckConnectBlockTemplate tests the CheckConnectBlockTemplate function to
67// ensure it fails.
68func TestCheckConnectBlockTemplate(t *testing.T) {
69	// Create a new database and chain instance to run tests against.
70	chain, teardownFunc, err := chainSetup("checkconnectblocktemplate",
71		&chaincfg.MainNetParams)
72	if err != nil {
73		t.Errorf("Failed to setup chain instance: %v", err)
74		return
75	}
76	defer teardownFunc()
77
78	// Since we're not dealing with the real block chain, set the coinbase
79	// maturity to 1.
80	chain.TstSetCoinbaseMaturity(1)
81
82	// Load up blocks such that there is a side chain.
83	// (genesis block) -> 1 -> 2 -> 3 -> 4
84	//                          \-> 3a
85	testFiles := []string{
86		"blk_0_to_4.dat.bz2",
87		"blk_3A.dat.bz2",
88	}
89
90	var blocks []*btcutil.Block
91	for _, file := range testFiles {
92		blockTmp, err := loadBlocks(file)
93		if err != nil {
94			t.Fatalf("Error loading file: %v\n", err)
95		}
96		blocks = append(blocks, blockTmp...)
97	}
98
99	for i := 1; i <= 3; i++ {
100		isMainChain, _, err := chain.ProcessBlock(blocks[i], BFNone)
101		if err != nil {
102			t.Fatalf("CheckConnectBlockTemplate: Received unexpected error "+
103				"processing block %d: %v", i, err)
104		}
105		if !isMainChain {
106			t.Fatalf("CheckConnectBlockTemplate: Expected block %d to connect "+
107				"to main chain", i)
108		}
109	}
110
111	// Block 3 should fail to connect since it's already inserted.
112	err = chain.CheckConnectBlockTemplate(blocks[3])
113	if err == nil {
114		t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
115			"on block 3")
116	}
117
118	// Block 4 should connect successfully to tip of chain.
119	err = chain.CheckConnectBlockTemplate(blocks[4])
120	if err != nil {
121		t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+
122			"block 4: %v", err)
123	}
124
125	// Block 3a should fail to connect since does not build on chain tip.
126	err = chain.CheckConnectBlockTemplate(blocks[5])
127	if err == nil {
128		t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
129			"on block 3a")
130	}
131
132	// Block 4 should connect even if proof of work is invalid.
133	invalidPowBlock := *blocks[4].MsgBlock()
134	invalidPowBlock.Header.Nonce++
135	err = chain.CheckConnectBlockTemplate(btcutil.NewBlock(&invalidPowBlock))
136	if err != nil {
137		t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+
138			"block 4 with bad nonce: %v", err)
139	}
140
141	// Invalid block building on chain tip should fail to connect.
142	invalidBlock := *blocks[4].MsgBlock()
143	invalidBlock.Header.Bits--
144	err = chain.CheckConnectBlockTemplate(btcutil.NewBlock(&invalidBlock))
145	if err == nil {
146		t.Fatal("CheckConnectBlockTemplate: Did not received expected error " +
147			"on block 4 with invalid difficulty bits")
148	}
149}
150
151// TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works
152// as expected.
153func TestCheckBlockSanity(t *testing.T) {
154	powLimit := chaincfg.MainNetParams.PowLimit
155	block := btcutil.NewBlock(&Block100000)
156	timeSource := NewMedianTime()
157	err := CheckBlockSanity(block, powLimit, timeSource)
158	if err != nil {
159		t.Errorf("CheckBlockSanity: %v", err)
160	}
161
162	// Ensure a block that has a timestamp with a precision higher than one
163	// second fails.
164	timestamp := block.MsgBlock().Header.Timestamp
165	block.MsgBlock().Header.Timestamp = timestamp.Add(time.Nanosecond)
166	err = CheckBlockSanity(block, powLimit, timeSource)
167	if err == nil {
168		t.Errorf("CheckBlockSanity: error is nil when it shouldn't be")
169	}
170}
171
172// TestCheckSerializedHeight tests the checkSerializedHeight function with
173// various serialized heights and also does negative tests to ensure errors
174// and handled properly.
175func TestCheckSerializedHeight(t *testing.T) {
176	// Create an empty coinbase template to be used in the tests below.
177	coinbaseOutpoint := wire.NewOutPoint(&chainhash.Hash{}, math.MaxUint32)
178	coinbaseTx := wire.NewMsgTx(1)
179	coinbaseTx.AddTxIn(wire.NewTxIn(coinbaseOutpoint, nil, nil))
180
181	// Expected rule errors.
182	missingHeightError := RuleError{
183		ErrorCode: ErrMissingCoinbaseHeight,
184	}
185	badHeightError := RuleError{
186		ErrorCode: ErrBadCoinbaseHeight,
187	}
188
189	tests := []struct {
190		sigScript  []byte // Serialized data
191		wantHeight int32  // Expected height
192		err        error  // Expected error type
193	}{
194		// No serialized height length.
195		{[]byte{}, 0, missingHeightError},
196		// Serialized height length with no height bytes.
197		{[]byte{0x02}, 0, missingHeightError},
198		// Serialized height length with too few height bytes.
199		{[]byte{0x02, 0x4a}, 0, missingHeightError},
200		// Serialized height that needs 2 bytes to encode.
201		{[]byte{0x02, 0x4a, 0x52}, 21066, nil},
202		// Serialized height that needs 2 bytes to encode, but backwards
203		// endianness.
204		{[]byte{0x02, 0x4a, 0x52}, 19026, badHeightError},
205		// Serialized height that needs 3 bytes to encode.
206		{[]byte{0x03, 0x40, 0x0d, 0x03}, 200000, nil},
207		// Serialized height that needs 3 bytes to encode, but backwards
208		// endianness.
209		{[]byte{0x03, 0x40, 0x0d, 0x03}, 1074594560, badHeightError},
210	}
211
212	t.Logf("Running %d tests", len(tests))
213	for i, test := range tests {
214		msgTx := coinbaseTx.Copy()
215		msgTx.TxIn[0].SignatureScript = test.sigScript
216		tx := btcutil.NewTx(msgTx)
217
218		err := checkSerializedHeight(tx, test.wantHeight)
219		if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
220			t.Errorf("checkSerializedHeight #%d wrong error type "+
221				"got: %v <%T>, want: %T", i, err, err, test.err)
222			continue
223		}
224
225		if rerr, ok := err.(RuleError); ok {
226			trerr := test.err.(RuleError)
227			if rerr.ErrorCode != trerr.ErrorCode {
228				t.Errorf("checkSerializedHeight #%d wrong "+
229					"error code got: %v, want: %v", i,
230					rerr.ErrorCode, trerr.ErrorCode)
231				continue
232			}
233		}
234	}
235}
236
237// Block100000 defines block 100,000 of the block chain.  It is used to
238// test Block operations.
239var Block100000 = wire.MsgBlock{
240	Header: wire.BlockHeader{
241		Version: 1,
242		PrevBlock: chainhash.Hash([32]byte{ // Make go vet happy.
243			0x50, 0x12, 0x01, 0x19, 0x17, 0x2a, 0x61, 0x04,
244			0x21, 0xa6, 0xc3, 0x01, 0x1d, 0xd3, 0x30, 0xd9,
245			0xdf, 0x07, 0xb6, 0x36, 0x16, 0xc2, 0xcc, 0x1f,
246			0x1c, 0xd0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
247		}), // 000000000002d01c1fccc21636b607dfd930d31d01c3a62104612a1719011250
248		MerkleRoot: chainhash.Hash([32]byte{ // Make go vet happy.
249			0x66, 0x57, 0xa9, 0x25, 0x2a, 0xac, 0xd5, 0xc0,
250			0xb2, 0x94, 0x09, 0x96, 0xec, 0xff, 0x95, 0x22,
251			0x28, 0xc3, 0x06, 0x7c, 0xc3, 0x8d, 0x48, 0x85,
252			0xef, 0xb5, 0xa4, 0xac, 0x42, 0x47, 0xe9, 0xf3,
253		}), // f3e94742aca4b5ef85488dc37c06c3282295ffec960994b2c0d5ac2a25a95766
254		Timestamp: time.Unix(1293623863, 0), // 2010-12-29 11:57:43 +0000 UTC
255		Bits:      0x1b04864c,               // 453281356
256		Nonce:     0x10572b0f,               // 274148111
257	},
258	Transactions: []*wire.MsgTx{
259		{
260			Version: 1,
261			TxIn: []*wire.TxIn{
262				{
263					PreviousOutPoint: wire.OutPoint{
264						Hash:  chainhash.Hash{},
265						Index: 0xffffffff,
266					},
267					SignatureScript: []byte{
268						0x04, 0x4c, 0x86, 0x04, 0x1b, 0x02, 0x06, 0x02,
269					},
270					Sequence: 0xffffffff,
271				},
272			},
273			TxOut: []*wire.TxOut{
274				{
275					Value: 0x12a05f200, // 5000000000
276					PkScript: []byte{
277						0x41, // OP_DATA_65
278						0x04, 0x1b, 0x0e, 0x8c, 0x25, 0x67, 0xc1, 0x25,
279						0x36, 0xaa, 0x13, 0x35, 0x7b, 0x79, 0xa0, 0x73,
280						0xdc, 0x44, 0x44, 0xac, 0xb8, 0x3c, 0x4e, 0xc7,
281						0xa0, 0xe2, 0xf9, 0x9d, 0xd7, 0x45, 0x75, 0x16,
282						0xc5, 0x81, 0x72, 0x42, 0xda, 0x79, 0x69, 0x24,
283						0xca, 0x4e, 0x99, 0x94, 0x7d, 0x08, 0x7f, 0xed,
284						0xf9, 0xce, 0x46, 0x7c, 0xb9, 0xf7, 0xc6, 0x28,
285						0x70, 0x78, 0xf8, 0x01, 0xdf, 0x27, 0x6f, 0xdf,
286						0x84, // 65-byte signature
287						0xac, // OP_CHECKSIG
288					},
289				},
290			},
291			LockTime: 0,
292		},
293		{
294			Version: 1,
295			TxIn: []*wire.TxIn{
296				{
297					PreviousOutPoint: wire.OutPoint{
298						Hash: chainhash.Hash([32]byte{ // Make go vet happy.
299							0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60,
300							0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac,
301							0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07,
302							0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87,
303						}), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03
304						Index: 0,
305					},
306					SignatureScript: []byte{
307						0x49, // OP_DATA_73
308						0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3,
309						0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6,
310						0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94,
311						0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58,
312						0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00,
313						0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62,
314						0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c,
315						0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60,
316						0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48,
317						0x01, // 73-byte signature
318						0x41, // OP_DATA_65
319						0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d,
320						0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38,
321						0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25,
322						0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e,
323						0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8,
324						0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd,
325						0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b,
326						0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3,
327						0xd3, // 65-byte pubkey
328					},
329					Sequence: 0xffffffff,
330				},
331			},
332			TxOut: []*wire.TxOut{
333				{
334					Value: 0x2123e300, // 556000000
335					PkScript: []byte{
336						0x76, // OP_DUP
337						0xa9, // OP_HASH160
338						0x14, // OP_DATA_20
339						0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60,
340						0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e,
341						0xf7, 0xf5, 0x8b, 0x32,
342						0x88, // OP_EQUALVERIFY
343						0xac, // OP_CHECKSIG
344					},
345				},
346				{
347					Value: 0x108e20f00, // 4444000000
348					PkScript: []byte{
349						0x76, // OP_DUP
350						0xa9, // OP_HASH160
351						0x14, // OP_DATA_20
352						0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f,
353						0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b,
354						0x52, 0xde, 0x3d, 0x7c,
355						0x88, // OP_EQUALVERIFY
356						0xac, // OP_CHECKSIG
357					},
358				},
359			},
360			LockTime: 0,
361		},
362		{
363			Version: 1,
364			TxIn: []*wire.TxIn{
365				{
366					PreviousOutPoint: wire.OutPoint{
367						Hash: chainhash.Hash([32]byte{ // Make go vet happy.
368							0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d,
369							0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27,
370							0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65,
371							0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf,
372						}), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3
373						Index: 1,
374					},
375					SignatureScript: []byte{
376						0x47, // OP_DATA_71
377						0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf,
378						0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5,
379						0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34,
380						0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31,
381						0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee,
382						0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f,
383						0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c,
384						0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e,
385						0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01,
386						0x41, // OP_DATA_65
387						0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78,
388						0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5,
389						0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39,
390						0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21,
391						0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee,
392						0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3,
393						0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95,
394						0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85,
395						0x0f, // 65-byte pubkey
396					},
397					Sequence: 0xffffffff,
398				},
399			},
400			TxOut: []*wire.TxOut{
401				{
402					Value: 0xf4240, // 1000000
403					PkScript: []byte{
404						0x76, // OP_DUP
405						0xa9, // OP_HASH160
406						0x14, // OP_DATA_20
407						0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04,
408						0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d,
409						0xad, 0xbe, 0x7e, 0x10,
410						0x88, // OP_EQUALVERIFY
411						0xac, // OP_CHECKSIG
412					},
413				},
414				{
415					Value: 0x11d260c0, // 299000000
416					PkScript: []byte{
417						0x76, // OP_DUP
418						0xa9, // OP_HASH160
419						0x14, // OP_DATA_20
420						0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1,
421						0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab,
422						0xb3, 0x40, 0x9c, 0xd9,
423						0x88, // OP_EQUALVERIFY
424						0xac, // OP_CHECKSIG
425					},
426				},
427			},
428			LockTime: 0,
429		},
430		{
431			Version: 1,
432			TxIn: []*wire.TxIn{
433				{
434					PreviousOutPoint: wire.OutPoint{
435						Hash: chainhash.Hash([32]byte{ // Make go vet happy.
436							0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73,
437							0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac,
438							0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90,
439							0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4,
440						}), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b
441						Index: 0,
442					},
443					SignatureScript: []byte{
444						0x49, // OP_DATA_73
445						0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2,
446						0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c,
447						0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd,
448						0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f,
449						0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00,
450						0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14,
451						0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb,
452						0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c,
453						0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3,
454						0x01, // 73-byte signature
455						0x41, // OP_DATA_65
456						0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97,
457						0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18,
458						0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17,
459						0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94,
460						0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65,
461						0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f,
462						0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce,
463						0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f,
464						0xbb, // 65-byte pubkey
465					},
466					Sequence: 0xffffffff,
467				},
468			},
469			TxOut: []*wire.TxOut{
470				{
471					Value: 0xf4240, // 1000000
472					PkScript: []byte{
473						0x76, // OP_DUP
474						0xa9, // OP_HASH160
475						0x14, // OP_DATA_20
476						0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7,
477						0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b,
478						0xf2, 0xeb, 0x9e, 0xe0,
479						0x88, // OP_EQUALVERIFY
480						0xac, // OP_CHECKSIG
481					},
482				},
483			},
484			LockTime: 0,
485		},
486	},
487}
488