// Copyright (c) 2013-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package blockdag import ( "math" "path/filepath" "testing" "time" "github.com/kaspanet/kaspad/dagconfig" "github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/util/daghash" "github.com/kaspanet/kaspad/util/subnetworkid" "github.com/kaspanet/kaspad/wire" ) // TestSequenceLocksActive tests the SequenceLockActive function to ensure it // works as expected in all possible combinations/scenarios. func TestSequenceLocksActive(t *testing.T) { seqLock := func(h int64, s int64) *SequenceLock { return &SequenceLock{ Seconds: s, BlockBlueScore: h, } } tests := []struct { seqLock *SequenceLock blockBlueScore uint64 mtp time.Time want bool }{ // Block based sequence lock with equal block blue score. {seqLock: seqLock(1000, -1), blockBlueScore: 1001, mtp: time.Unix(9, 0), want: true}, // Time based sequence lock with mtp past the absolute time. {seqLock: seqLock(-1, 30), blockBlueScore: 2, mtp: time.Unix(31, 0), want: true}, // Block based sequence lock with current blue score below seq lock block blue score. {seqLock: seqLock(1000, -1), blockBlueScore: 90, mtp: time.Unix(9, 0), want: false}, // Time based sequence lock with current time before lock time. {seqLock: seqLock(-1, 30), blockBlueScore: 2, mtp: time.Unix(29, 0), want: false}, // Block based sequence lock at the same blue score, so shouldn't yet be active. {seqLock: seqLock(1000, -1), blockBlueScore: 1000, mtp: time.Unix(9, 0), want: false}, // Time based sequence lock with current time equal to lock time, so shouldn't yet be active. {seqLock: seqLock(-1, 30), blockBlueScore: 2, mtp: time.Unix(30, 0), want: false}, } t.Logf("Running %d sequence locks tests", len(tests)) for i, test := range tests { got := SequenceLockActive(test.seqLock, test.blockBlueScore, test.mtp) if got != test.want { t.Fatalf("SequenceLockActive #%d got %v want %v", i, got, test.want) } } } // TestCheckConnectBlockTemplate tests the CheckConnectBlockTemplate function to // ensure it fails. func TestCheckConnectBlockTemplate(t *testing.T) { // Create a new database and DAG instance to run tests against. dag, teardownFunc, err := DAGSetup("checkconnectblocktemplate", Config{ DAGParams: &dagconfig.SimnetParams, }) if err != nil { t.Errorf("Failed to setup dag instance: %v", err) return } defer teardownFunc() // Since we're not dealing with the real block DAG, set the coinbase // maturity to 0. dag.TestSetCoinbaseMaturity(0) // Load up blocks such that there is a side chain. // (genesis block) -> 1 -> 2 -> 3 -> 4 // \-> 3a testFiles := []string{ "blk_0_to_4.dat", "blk_3B.dat", } var blocks []*util.Block for _, file := range testFiles { blockTmp, err := LoadBlocks(filepath.Join("testdata/", file)) if err != nil { t.Fatalf("Error loading file: %v\n", err) } blocks = append(blocks, blockTmp...) } for i := 1; i <= 3; i++ { _, isDelayed, err := dag.ProcessBlock(blocks[i], BFNone) if err != nil { t.Fatalf("CheckConnectBlockTemplate: Received unexpected error "+ "processing block %d: %v", i, err) } if isDelayed { t.Fatalf("CheckConnectBlockTemplate: block %d is too far in the future", i) } } // Block 3 should fail to connect since it's already inserted. err = dag.CheckConnectBlockTemplateNoLock(blocks[3]) if err == nil { t.Fatal("CheckConnectBlockTemplate: Did not received expected error " + "on block 3") } // Block 4 should connect successfully to tip of chain. err = dag.CheckConnectBlockTemplateNoLock(blocks[4]) if err != nil { t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+ "block 4: %v", err) } blockNode3 := dag.index.LookupNode(blocks[3].Hash()) if blockNode3.children.containsHash(blocks[4].Hash()) { t.Errorf("Block 4 wasn't successfully detached as a child from block3") } // Block 3a should connect even though it does not build on dag tips. err = dag.CheckConnectBlockTemplateNoLock(blocks[5]) if err != nil { t.Fatal("CheckConnectBlockTemplate: Recieved unexpected error on " + "block 3a that connects below the tips") } // Block 4 should connect even if proof of work is invalid. invalidPowMsgBlock := *blocks[4].MsgBlock() invalidPowMsgBlock.Header.Nonce++ invalidPowBlock := util.NewBlock(&invalidPowMsgBlock) err = dag.CheckConnectBlockTemplateNoLock(invalidPowBlock) if err != nil { t.Fatalf("CheckConnectBlockTemplate: Received unexpected error on "+ "block 4 with bad nonce: %v", err) } // Invalid block building on chain tip should fail to connect. invalidBlock := *blocks[4].MsgBlock() invalidBlock.Header.Bits-- err = dag.CheckConnectBlockTemplateNoLock(util.NewBlock(&invalidBlock)) if err == nil { t.Fatal("CheckConnectBlockTemplate: Did not received expected error " + "on block 4 with invalid difficulty bits") } } // TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works // as expected. func TestCheckBlockSanity(t *testing.T) { // Create a new database and dag instance to run tests against. dag, teardownFunc, err := DAGSetup("TestCheckBlockSanity", Config{ DAGParams: &dagconfig.SimnetParams, }) if err != nil { t.Errorf("Failed to setup dag instance: %v", err) return } defer teardownFunc() block := util.NewBlock(&Block100000) if len(block.Transactions()) < 3 { t.Fatalf("Too few transactions in block, expect at least 3, got %v", len(block.Transactions())) } delay, err := dag.checkBlockSanity(block, BFNone) if err != nil { t.Errorf("CheckBlockSanity: %v", err) } if delay != 0 { t.Errorf("CheckBlockSanity: unexpected return %s delay", delay) } // Test with block with wrong transactions sorting order blockWithWrongTxOrder := util.NewBlock(&BlockWithWrongTxOrder) delay, err = dag.checkBlockSanity(blockWithWrongTxOrder, BFNone) if err == nil { t.Errorf("CheckBlockSanity: transactions disorder is not detected") } ruleErr, ok := err.(RuleError) if !ok { t.Errorf("CheckBlockSanity: wrong error returned, expect RuleError, got %T", err) } else if ruleErr.ErrorCode != ErrTransactionsNotSorted { t.Errorf("CheckBlockSanity: wrong error returned, expect ErrTransactionsNotSorted, got %v, err %s", ruleErr.ErrorCode, err) } if delay != 0 { t.Errorf("CheckBlockSanity: unexpected return %s delay", delay) } // Ensure a block that has a timestamp with a precision higher than one // second fails. timestamp := block.MsgBlock().Header.Timestamp block.MsgBlock().Header.Timestamp = timestamp.Add(time.Nanosecond) delay, err = dag.checkBlockSanity(block, BFNone) if err == nil { t.Errorf("CheckBlockSanity: error is nil when it shouldn't be") } if delay != 0 { t.Errorf("CheckBlockSanity: unexpected return %s delay", delay) } var invalidParentsOrderBlock = wire.MsgBlock{ Header: wire.BlockHeader{ Version: 0x10000000, ParentHashes: []*daghash.Hash{ { 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, }, { 0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95, 0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3, 0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b, 0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00, }, }, HashMerkleRoot: &daghash.Hash{ 0x2f, 0x4c, 0xc3, 0x0b, 0x0a, 0x84, 0xbb, 0x95, 0x56, 0x9d, 0x77, 0xa2, 0xee, 0x3e, 0xb1, 0xac, 0x48, 0x3e, 0x8b, 0xe1, 0xcf, 0xdc, 0x20, 0xba, 0xae, 0xec, 0x0a, 0x2f, 0xe4, 0x85, 0x31, 0x30, }, AcceptedIDMerkleRoot: &daghash.Hash{ 0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95, 0x5b, 0x7e, 0xaf, 0x84, 0x7e, 0x1b, 0x6b, 0x06, 0x4e, 0x06, 0xba, 0x64, 0xd7, 0x61, 0xda, 0x25, 0x1a, 0x0e, 0x21, 0xd4, 0x64, 0x49, 0x02, 0xa2, }, UTXOCommitment: &daghash.Hash{ 0x80, 0xf7, 0x00, 0xe3, 0x16, 0x3d, 0x04, 0x95, 0x5b, 0x7e, 0xaf, 0x84, 0x7e, 0x1b, 0x6b, 0x06, 0x4e, 0x06, 0xba, 0x64, 0xd7, 0x61, 0xda, 0x25, 0x1a, 0x0e, 0x21, 0xd4, 0x64, 0x49, 0x02, 0xa2, }, Timestamp: time.Unix(0x5cd18053, 0), Bits: 0x207fffff, Nonce: 0x1, }, Transactions: []*wire.MsgTx{ { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID{}, Index: 0xffffffff, }, SignatureScript: []byte{ 0x02, 0x10, 0x27, 0x08, 0xac, 0x29, 0x2f, 0x2f, 0xcf, 0x70, 0xb0, 0x7e, 0x0b, 0x2f, 0x50, 0x32, 0x53, 0x48, 0x2f, 0x62, 0x74, 0x63, 0x64, 0x2f, }, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0x12a05f200, // 5000000000 ScriptPubKey: []byte{ 0x51, }, }, }, LockTime: 0, SubnetworkID: *subnetworkid.SubnetworkIDNative, }, { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID([32]byte{ 0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60, 0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac, 0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07, 0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87, }), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03 Index: 0, }, SignatureScript: []byte{ 0x49, // OP_DATA_73 0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3, 0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6, 0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94, 0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58, 0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00, 0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62, 0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c, 0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60, 0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48, 0x01, // 73-byte signature 0x41, // OP_DATA_65 0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d, 0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38, 0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25, 0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e, 0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8, 0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd, 0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b, 0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3, 0xd3, // 65-byte pubkey }, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0x2123e300, // 556000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60, 0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e, 0xf7, 0xf5, 0x8b, 0x32, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, { Value: 0x108e20f00, // 4444000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f, 0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b, 0x52, 0xde, 0x3d, 0x7c, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, }, LockTime: 0, SubnetworkID: *subnetworkid.SubnetworkIDNative, }, { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID([32]byte{ 0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d, 0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27, 0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65, 0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf, }), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3 Index: 1, }, SignatureScript: []byte{ 0x47, // OP_DATA_71 0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf, 0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5, 0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34, 0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31, 0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee, 0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f, 0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c, 0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e, 0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01, 0x41, // OP_DATA_65 0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78, 0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5, 0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39, 0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21, 0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee, 0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3, 0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95, 0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85, 0x0f, // 65-byte pubkey }, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0xf4240, // 1000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04, 0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d, 0xad, 0xbe, 0x7e, 0x10, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, { Value: 0x11d260c0, // 299000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1, 0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab, 0xb3, 0x40, 0x9c, 0xd9, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, }, LockTime: 0, SubnetworkID: *subnetworkid.SubnetworkIDNative, }, { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID([32]byte{ 0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73, 0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac, 0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90, 0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4, }), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b Index: 0, }, SignatureScript: []byte{ 0x49, // OP_DATA_73 0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2, 0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c, 0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd, 0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f, 0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00, 0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14, 0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb, 0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c, 0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3, 0x01, // 73-byte signature 0x41, // OP_DATA_65 0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97, 0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18, 0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17, 0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94, 0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65, 0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f, 0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce, 0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f, 0xbb, // 65-byte pubkey }, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0xf4240, // 1000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7, 0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b, 0xf2, 0xeb, 0x9e, 0xe0, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, }, LockTime: 0, SubnetworkID: *subnetworkid.SubnetworkIDNative, }, }, } utilInvalidBlock := util.NewBlock(&invalidParentsOrderBlock) delay, err = dag.checkBlockSanity(utilInvalidBlock, BFNone) if err == nil { t.Errorf("CheckBlockSanity: error is nil when it shouldn't be") } rError := err.(RuleError) if rError.ErrorCode != ErrWrongParentsOrder { t.Errorf("CheckBlockSanity: Expected error was ErrWrongParentsOrder but got %v", err) } if delay != 0 { t.Errorf("CheckBlockSanity: unexpected return %s delay", delay) } blockInTheFuture := Block100000 expectedDelay := 10 * time.Second now := time.Unix(time.Now().Unix(), 0) blockInTheFuture.Header.Timestamp = now.Add(time.Duration(dag.TimestampDeviationTolerance)*time.Second + expectedDelay) delay, err = dag.checkBlockSanity(util.NewBlock(&blockInTheFuture), BFNoPoWCheck) if err != nil { t.Errorf("CheckBlockSanity: %v", err) } if delay != expectedDelay { t.Errorf("CheckBlockSanity: expected %s delay but got %s", expectedDelay, delay) } } func TestPastMedianTime(t *testing.T) { dag := newTestDAG(&dagconfig.MainnetParams) tip := dag.genesis blockVersion := int32(0x10000000) blockTime := tip.Header().Timestamp for i := 0; i < 100; i++ { blockTime = blockTime.Add(time.Second) tip = newTestNode(dag, setFromSlice(tip), blockVersion, 0, blockTime) } // Checks that a block is valid if it has timestamp equals to past median time node := newTestNode(dag, setFromSlice(tip), blockVersion, dag.powMaxBits, tip.PastMedianTime(dag)) header := node.Header() err := dag.checkBlockHeaderContext(header, node.parents.bluest(), false) if err != nil { t.Errorf("TestPastMedianTime: unexpected error from checkBlockHeaderContext: %v"+ "(a block with timestamp equals to past median time should be valid)", err) } // Checks that a block is valid if its timestamp is after past median time node = newTestNode(dag, setFromSlice(tip), blockVersion, dag.powMaxBits, tip.PastMedianTime(dag).Add(time.Second)) header = node.Header() err = dag.checkBlockHeaderContext(header, node.parents.bluest(), false) if err != nil { t.Errorf("TestPastMedianTime: unexpected error from checkBlockHeaderContext: %v"+ "(a block with timestamp bigger than past median time should be valid)", err) } // Checks that a block is invalid if its timestamp is before past median time node = newTestNode(dag, setFromSlice(tip), blockVersion, 0, tip.PastMedianTime(dag).Add(-time.Second)) header = node.Header() err = dag.checkBlockHeaderContext(header, node.parents.bluest(), false) if err == nil { t.Errorf("TestPastMedianTime: unexpected success: block should be invalid if its timestamp is before past median time") } } func TestValidateParents(t *testing.T) { dag := newTestDAG(&dagconfig.SimnetParams) genesisNode := dag.genesis blockVersion := int32(0x10000000) blockTime := genesisNode.Header().Timestamp generateNode := func(parents ...*blockNode) *blockNode { // The timestamp of each block is changed to prevent a situation where two blocks share the same hash blockTime = blockTime.Add(time.Second) return newTestNode(dag, setFromSlice(parents...), blockVersion, 0, blockTime) } a := generateNode(genesisNode) b := generateNode(a) c := generateNode(genesisNode) fakeBlockHeader := &wire.BlockHeader{ HashMerkleRoot: &daghash.ZeroHash, AcceptedIDMerkleRoot: &daghash.ZeroHash, UTXOCommitment: &daghash.ZeroHash, } // Check direct parents relation err := validateParents(fakeBlockHeader, setFromSlice(a, b)) if err == nil { t.Errorf("validateParents: `a` is a parent of `b`, so an error is expected") } // Check indirect parents relation err = validateParents(fakeBlockHeader, setFromSlice(genesisNode, b)) if err == nil { t.Errorf("validateParents: `genesis` and `b` are indirectly related, so an error is expected") } // Check parents with no relation err = validateParents(fakeBlockHeader, setFromSlice(b, c)) if err != nil { t.Errorf("validateParents: unexpected error: %v", err) } } func TestCheckTransactionSanity(t *testing.T) { tests := []struct { name string numInputs uint32 numOutputs uint32 outputValue uint64 nodeSubnetworkID subnetworkid.SubnetworkID txSubnetworkData *txSubnetworkData extraModificationsFunc func(*wire.MsgTx) expectedErr error }{ {"good one", 1, 1, 1, *subnetworkid.SubnetworkIDNative, nil, nil, nil}, {"no inputs", 0, 1, 1, *subnetworkid.SubnetworkIDNative, nil, nil, ruleError(ErrNoTxInputs, "")}, {"no outputs", 1, 0, 1, *subnetworkid.SubnetworkIDNative, nil, nil, nil}, {"too massive", 1, 1000000, 1, *subnetworkid.SubnetworkIDNative, nil, nil, ruleError(ErrTxMassTooHigh, "")}, {"too much sompi in one output", 1, 1, util.MaxSompi + 1, *subnetworkid.SubnetworkIDNative, nil, nil, ruleError(ErrBadTxOutValue, "")}, {"too much sompi in total outputs", 1, 2, util.MaxSompi - 1, *subnetworkid.SubnetworkIDNative, nil, nil, ruleError(ErrBadTxOutValue, "")}, {"duplicate inputs", 2, 1, 1, *subnetworkid.SubnetworkIDNative, nil, func(tx *wire.MsgTx) { tx.TxIn[1].PreviousOutpoint.Index = 0 }, ruleError(ErrDuplicateTxInputs, "")}, {"1 input coinbase", 1, 1, 1, *subnetworkid.SubnetworkIDNative, &txSubnetworkData{subnetworkid.SubnetworkIDCoinbase, 0, nil}, nil, nil}, {"no inputs coinbase", 0, 1, 1, *subnetworkid.SubnetworkIDNative, &txSubnetworkData{subnetworkid.SubnetworkIDCoinbase, 0, nil}, nil, nil}, {"too long payload coinbase", 1, 1, 1, *subnetworkid.SubnetworkIDNative, &txSubnetworkData{subnetworkid.SubnetworkIDCoinbase, 0, make([]byte, MaxCoinbasePayloadLen+1)}, nil, ruleError(ErrBadCoinbasePayloadLen, "")}, {"non-zero gas in Kaspa", 1, 1, 0, *subnetworkid.SubnetworkIDNative, &txSubnetworkData{subnetworkid.SubnetworkIDNative, 1, []byte{}}, nil, ruleError(ErrInvalidGas, "")}, {"non-zero gas in subnetwork registry", 1, 1, 0, *subnetworkid.SubnetworkIDNative, &txSubnetworkData{subnetworkid.SubnetworkIDNative, 1, []byte{}}, nil, ruleError(ErrInvalidGas, "")}, {"non-zero payload in Kaspa", 1, 1, 0, *subnetworkid.SubnetworkIDNative, &txSubnetworkData{subnetworkid.SubnetworkIDNative, 0, []byte{1}}, nil, ruleError(ErrInvalidPayload, "")}, {"payload in subnetwork registry isn't 8 bytes", 1, 1, 0, *subnetworkid.SubnetworkIDNative, &txSubnetworkData{subnetworkid.SubnetworkIDNative, 0, []byte{1, 2, 3, 4, 5, 6, 7}}, nil, ruleError(ErrInvalidPayload, "")}, {"payload in other subnetwork isn't 0 bytes", 1, 1, 0, subnetworkid.SubnetworkID{123}, &txSubnetworkData{&subnetworkid.SubnetworkID{234}, 0, []byte{1}}, nil, ruleError(ErrInvalidPayload, "")}, {"invalid payload hash", 1, 1, 0, subnetworkid.SubnetworkID{123}, &txSubnetworkData{&subnetworkid.SubnetworkID{123}, 0, []byte{1}}, func(tx *wire.MsgTx) { tx.PayloadHash = &daghash.Hash{} }, ruleError(ErrInvalidPayloadHash, "")}, {"invalid payload hash in native subnetwork", 1, 1, 0, *subnetworkid.SubnetworkIDNative, nil, func(tx *wire.MsgTx) { tx.PayloadHash = daghash.DoubleHashP(tx.Payload) }, ruleError(ErrInvalidPayloadHash, "")}, } for _, test := range tests { tx := createTxForTest(test.numInputs, test.numOutputs, test.outputValue, test.txSubnetworkData) if test.extraModificationsFunc != nil { test.extraModificationsFunc(tx) } err := CheckTransactionSanity(util.NewTx(tx), &test.nodeSubnetworkID) if e := checkRuleError(err, test.expectedErr); e != nil { t.Errorf("TestCheckTransactionSanity: '%s': %v", test.name, e) continue } } } // Block100000 defines block 100,000 of the block DAG. It is used to // test Block operations. var Block100000 = wire.MsgBlock{ Header: wire.BlockHeader{ Version: 0x10000000, ParentHashes: []*daghash.Hash{ { 0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95, 0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3, 0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b, 0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00, }, { 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, }, }, HashMerkleRoot: &daghash.Hash{ 0x32, 0x30, 0x46, 0x39, 0x5e, 0x27, 0x6d, 0x5a, 0xc9, 0x64, 0x16, 0x29, 0x5b, 0xa4, 0x5a, 0xf3, 0xc0, 0xfc, 0x1a, 0xa9, 0xcb, 0x2a, 0xd2, 0x9f, 0xbe, 0x07, 0x0c, 0x47, 0xc9, 0x84, 0x39, 0x15, }, AcceptedIDMerkleRoot: &daghash.Hash{ 0x8a, 0xb7, 0xd6, 0x73, 0x1b, 0xe6, 0xc5, 0xd3, 0x5d, 0x4e, 0x2c, 0xc9, 0x57, 0x88, 0x30, 0x65, 0x81, 0xb8, 0xa0, 0x68, 0x77, 0xc4, 0x02, 0x1e, 0x3c, 0xb1, 0x16, 0x8f, 0x5f, 0x6b, 0x45, 0x87, }, UTXOCommitment: &daghash.ZeroHash, Timestamp: time.Unix(0x5cdac4b1, 0), Bits: 0x207fffff, Nonce: 0x00000001, }, Transactions: []*wire.MsgTx{ { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID{ 0x9b, 0x22, 0x59, 0x44, 0x66, 0xf0, 0xbe, 0x50, 0x7c, 0x1c, 0x8a, 0xf6, 0x06, 0x27, 0xe6, 0x33, 0x38, 0x7e, 0xd1, 0xd5, 0x8c, 0x42, 0x59, 0x1a, 0x31, 0xac, 0x9a, 0xa6, 0x2e, 0xd5, 0x2b, 0x0f, }, Index: 0xffffffff, }, SignatureScript: nil, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0x12a05f200, // 5000000000 ScriptPubKey: []byte{ 0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49, 0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7, 0x7e, 0xba, 0x30, 0xcd, 0x5a, 0x4b, 0x87, }, }, }, LockTime: 0, SubnetworkID: *subnetworkid.SubnetworkIDCoinbase, Payload: []byte{0x00}, PayloadHash: &daghash.Hash{ 0x14, 0x06, 0xe0, 0x58, 0x81, 0xe2, 0x99, 0x36, 0x77, 0x66, 0xd3, 0x13, 0xe2, 0x6c, 0x05, 0x56, 0x4e, 0xc9, 0x1b, 0xf7, 0x21, 0xd3, 0x17, 0x26, 0xbd, 0x6e, 0x46, 0xe6, 0x06, 0x89, 0x53, 0x9a, }, }, { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID{ 0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95, 0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3, 0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b, 0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00, }, Index: 0xffffffff, }, Sequence: math.MaxUint64, }, { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID{ 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, }, Index: 0xffffffff, }, Sequence: math.MaxUint64, }, }, SubnetworkID: *subnetworkid.SubnetworkIDNative, }, { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID([32]byte{ 0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60, 0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac, 0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07, 0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87, }), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03 Index: 0, }, SignatureScript: []byte{ 0x49, // OP_DATA_73 0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3, 0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6, 0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94, 0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58, 0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00, 0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62, 0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c, 0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60, 0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48, 0x01, // 73-byte signature 0x41, // OP_DATA_65 0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d, 0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38, 0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25, 0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e, 0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8, 0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd, 0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b, 0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3, 0xd3, // 65-byte pubkey }, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0x2123e300, // 556000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60, 0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e, 0xf7, 0xf5, 0x8b, 0x32, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, { Value: 0x108e20f00, // 4444000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f, 0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b, 0x52, 0xde, 0x3d, 0x7c, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, }, LockTime: 0, SubnetworkID: *subnetworkid.SubnetworkIDNative, }, { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID([32]byte{ 0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d, 0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27, 0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65, 0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf, }), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3 Index: 1, }, SignatureScript: []byte{ 0x47, // OP_DATA_71 0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf, 0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5, 0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34, 0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31, 0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee, 0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f, 0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c, 0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e, 0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01, 0x41, // OP_DATA_65 0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78, 0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5, 0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39, 0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21, 0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee, 0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3, 0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95, 0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85, 0x0f, // 65-byte pubkey }, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0xf4240, // 1000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04, 0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d, 0xad, 0xbe, 0x7e, 0x10, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, { Value: 0x11d260c0, // 299000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1, 0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab, 0xb3, 0x40, 0x9c, 0xd9, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, }, LockTime: 0, SubnetworkID: *subnetworkid.SubnetworkIDNative, }, { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID([32]byte{ 0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73, 0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac, 0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90, 0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4, }), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b Index: 0, }, SignatureScript: []byte{ 0x49, // OP_DATA_73 0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2, 0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c, 0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd, 0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f, 0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00, 0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14, 0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb, 0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c, 0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3, 0x01, // 73-byte signature 0x41, // OP_DATA_65 0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97, 0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18, 0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17, 0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94, 0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65, 0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f, 0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce, 0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f, 0xbb, // 65-byte pubkey }, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0xf4240, // 1000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7, 0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b, 0xf2, 0xeb, 0x9e, 0xe0, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, }, LockTime: 0, SubnetworkID: *subnetworkid.SubnetworkIDNative, }, }, } // BlockWithWrongTxOrder defines invalid block 100,000 of the block DAG. var BlockWithWrongTxOrder = wire.MsgBlock{ Header: wire.BlockHeader{ Version: 1, ParentHashes: []*daghash.Hash{ { 0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95, 0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3, 0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b, 0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00, }, { 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, }, }, HashMerkleRoot: &daghash.Hash{ 0xac, 0xa4, 0x21, 0xe1, 0xa6, 0xc3, 0xbe, 0x5d, 0x52, 0x66, 0xf3, 0x0b, 0x21, 0x87, 0xbc, 0xf3, 0xf3, 0x2d, 0xd1, 0x05, 0x64, 0xb5, 0x16, 0x76, 0xe4, 0x66, 0x7d, 0x51, 0x53, 0x18, 0x6d, 0xb1, }, AcceptedIDMerkleRoot: &daghash.Hash{ 0xa0, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3, 0xcd, 0xc7, 0xc9, 0xaf, 0xfb, 0xd2, 0x1b, 0x85, 0x0b, 0x79, 0xf5, 0x29, 0x6d, 0x1c, 0xaa, 0x90, 0x2f, 0x01, 0xd4, 0x83, 0x9b, 0x2a, 0x04, 0x5e, }, UTXOCommitment: &daghash.Hash{ 0x00, 0x69, 0x2d, 0x16, 0xb5, 0xd7, 0xe4, 0xf3, 0xcd, 0xc7, 0xc9, 0xaf, 0xfb, 0xd2, 0x1b, 0x85, 0x0b, 0x79, 0xf5, 0x29, 0x6d, 0x1c, 0xaa, 0x90, 0x2f, 0x01, 0xd4, 0x83, 0x9b, 0x2a, 0x04, 0x5e, }, Timestamp: time.Unix(0x5cd16eaa, 0), Bits: 0x207fffff, Nonce: 0x0, }, Transactions: []*wire.MsgTx{ { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID{ 0x9b, 0x22, 0x59, 0x44, 0x66, 0xf0, 0xbe, 0x50, 0x7c, 0x1c, 0x8a, 0xf6, 0x06, 0x27, 0xe6, 0x33, 0x38, 0x7e, 0xd1, 0xd5, 0x8c, 0x42, 0x59, 0x1a, 0x31, 0xac, 0x9a, 0xa6, 0x2e, 0xd5, 0x2b, 0x0f, }, Index: 0xffffffff, }, SignatureScript: nil, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0x12a05f200, // 5000000000 ScriptPubKey: []byte{ 0xa9, 0x14, 0xda, 0x17, 0x45, 0xe9, 0xb5, 0x49, 0xbd, 0x0b, 0xfa, 0x1a, 0x56, 0x99, 0x71, 0xc7, 0x7e, 0xba, 0x30, 0xcd, 0x5a, 0x4b, 0x87, }, }, }, LockTime: 0, SubnetworkID: *subnetworkid.SubnetworkIDCoinbase, Payload: []byte{0x00}, PayloadHash: &daghash.Hash{ 0x14, 0x06, 0xe0, 0x58, 0x81, 0xe2, 0x99, 0x36, 0x77, 0x66, 0xd3, 0x13, 0xe2, 0x6c, 0x05, 0x56, 0x4e, 0xc9, 0x1b, 0xf7, 0x21, 0xd3, 0x17, 0x26, 0xbd, 0x6e, 0x46, 0xe6, 0x06, 0x89, 0x53, 0x9a, }, }, { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID{ 0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95, 0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3, 0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b, 0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00, }, Index: 0xffffffff, }, Sequence: math.MaxUint64, }, { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID{ 0x4b, 0xb0, 0x75, 0x35, 0xdf, 0xd5, 0x8e, 0x0b, 0x3c, 0xd6, 0x4f, 0xd7, 0x15, 0x52, 0x80, 0x87, 0x2a, 0x04, 0x71, 0xbc, 0xf8, 0x30, 0x95, 0x52, 0x6a, 0xce, 0x0e, 0x38, 0xc6, 0x00, 0x00, 0x00, }, Index: 0xffffffff, }, Sequence: math.MaxUint64, }, }, SubnetworkID: *subnetworkid.SubnetworkIDNative, }, { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID([32]byte{ 0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60, 0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac, 0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07, 0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87, }), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03 Index: 0, }, SignatureScript: []byte{ 0x49, // OP_DATA_73 0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3, 0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6, 0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94, 0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58, 0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00, 0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62, 0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c, 0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60, 0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48, 0x01, // 73-byte signature 0x41, // OP_DATA_65 0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d, 0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38, 0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25, 0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e, 0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8, 0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd, 0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b, 0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3, 0xd3, // 65-byte pubkey }, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0x2123e300, // 556000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60, 0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e, 0xf7, 0xf5, 0x8b, 0x32, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, { Value: 0x108e20f00, // 4444000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f, 0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b, 0x52, 0xde, 0x3d, 0x7c, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, }, LockTime: 0, SubnetworkID: subnetworkid.SubnetworkID{11}, Payload: []byte{}, PayloadHash: daghash.DoubleHashP([]byte{}), }, { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID([32]byte{ 0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d, 0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27, 0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65, 0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf, }), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3 Index: 1, }, SignatureScript: []byte{ 0x47, // OP_DATA_71 0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf, 0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5, 0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34, 0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31, 0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee, 0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f, 0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c, 0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e, 0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01, 0x41, // OP_DATA_65 0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78, 0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5, 0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39, 0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21, 0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee, 0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3, 0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95, 0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85, 0x0f, // 65-byte pubkey }, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0xf4240, // 1000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04, 0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d, 0xad, 0xbe, 0x7e, 0x10, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, { Value: 0x11d260c0, // 299000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1, 0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab, 0xb3, 0x40, 0x9c, 0xd9, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, }, LockTime: 0, SubnetworkID: *subnetworkid.SubnetworkIDNative, }, { Version: 1, TxIn: []*wire.TxIn{ { PreviousOutpoint: wire.Outpoint{ TxID: daghash.TxID([32]byte{ 0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73, 0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac, 0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90, 0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4, }), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b Index: 0, }, SignatureScript: []byte{ 0x49, // OP_DATA_73 0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2, 0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c, 0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd, 0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f, 0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00, 0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14, 0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb, 0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c, 0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3, 0x01, // 73-byte signature 0x41, // OP_DATA_65 0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97, 0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18, 0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17, 0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94, 0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65, 0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f, 0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce, 0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f, 0xbb, // 65-byte pubkey }, Sequence: math.MaxUint64, }, }, TxOut: []*wire.TxOut{ { Value: 0xf4240, // 1000000 ScriptPubKey: []byte{ 0x76, // OP_DUP 0xa9, // OP_HASH160 0x14, // OP_DATA_20 0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7, 0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b, 0xf2, 0xeb, 0x9e, 0xe0, 0x88, // OP_EQUALVERIFY 0xac, // OP_CHECKSIG }, }, }, LockTime: 0, SubnetworkID: *subnetworkid.SubnetworkIDNative, }, }, }