github.com/decred/dcrlnd@v0.7.6/chainntnfs/test/test_interface.go (about) 1 //go:build dev 2 // +build dev 3 4 package chainntnfstest 5 6 import ( 7 "bytes" 8 "context" 9 "fmt" 10 "io/ioutil" 11 "log" 12 "sync" 13 "testing" 14 "time" 15 16 "decred.org/dcrwallet/v4/wallet" 17 "github.com/decred/dcrd/chaincfg/chainhash" 18 "github.com/decred/dcrd/chaincfg/v3" 19 "github.com/decred/dcrd/dcrutil/v4" 20 rpctest "github.com/decred/dcrtest/dcrdtest" 21 "google.golang.org/grpc" 22 "matheusd.com/testctx" 23 24 "github.com/decred/dcrd/wire" 25 "github.com/decred/dcrlnd/chainntnfs" 26 "github.com/decred/dcrlnd/chainntnfs/dcrdnotify" 27 "github.com/decred/dcrlnd/chainntnfs/dcrwnotify" 28 "github.com/decred/dcrlnd/chainntnfs/remotedcrwnotify" 29 "github.com/decred/dcrlnd/channeldb" 30 "github.com/decred/dcrlnd/internal/testutils" 31 ) 32 33 var ctxb = context.Background() 34 var netParams = chaincfg.SimNetParams() 35 36 func testSingleConfirmationNotification(miner *rpctest.Harness, vw *rpctest.VotingWallet, 37 notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) { 38 39 // We'd like to test the case of being notified once a txid reaches a 40 // *single* confirmation. 41 // 42 // So first, let's send some coins to "ourself", obtaining a txid. 43 // We're spending from a coinbase output here, so we use the dedicated 44 // function. 45 txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner) 46 if err != nil { 47 t.Fatalf("unable to create test tx: %v", err) 48 } 49 if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil { 50 t.Fatalf("tx not relayed to miner: %v", err) 51 } 52 53 _, currentHeight, err := miner.Node.GetBestBlock(ctxb) 54 if err != nil { 55 t.Fatalf("unable to get current height: %v", err) 56 } 57 58 // Now that we have a txid, register a confirmation notification with 59 // the chainntfn source. 60 numConfs := uint32(1) 61 var confIntent *chainntnfs.ConfirmationEvent 62 if scriptDispatch { 63 confIntent, err = notifier.RegisterConfirmationsNtfn( 64 nil, pkScript, numConfs, uint32(currentHeight), 65 ) 66 } else { 67 confIntent, err = notifier.RegisterConfirmationsNtfn( 68 txid, pkScript, numConfs, uint32(currentHeight), 69 ) 70 } 71 if err != nil { 72 t.Fatalf("unable to register ntfn: %v", err) 73 } 74 75 // Now generate a single block, the transaction should be included which 76 // should trigger a notification event. 77 blockHash, err := vw.GenerateBlocks(ctxb, 1) 78 if err != nil { 79 t.Fatalf("unable to generate single block: %v", err) 80 } 81 82 select { 83 case confInfo := <-confIntent.Confirmed: 84 if !confInfo.BlockHash.IsEqual(blockHash[0]) { 85 t.Fatalf("mismatched block hashes: expected %v, got %v", 86 blockHash[0], confInfo.BlockHash) 87 } 88 89 // Finally, we'll verify that the tx index returned is the exact same 90 // as the tx index of the transaction within the block itself. 91 msgBlock, err := miner.Node.GetBlock(ctxb, blockHash[0]) 92 if err != nil { 93 t.Fatalf("unable to fetch block: %v", err) 94 } 95 96 block := dcrutil.NewBlock(msgBlock) 97 specifiedTxHash, err := block.TxHash(int(confInfo.TxIndex)) 98 if err != nil { 99 t.Fatalf("unable to index into block: %v", err) 100 } 101 102 if !specifiedTxHash.IsEqual(txid) { 103 t.Fatalf("mismatched tx indexes: expected %v, got %v", 104 txid, specifiedTxHash) 105 } 106 case <-time.After(20 * time.Second): 107 t.Fatalf("confirmation notification never received") 108 } 109 } 110 111 func testMultiConfirmationNotification(miner *rpctest.Harness, vw *rpctest.VotingWallet, 112 notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) { 113 114 // We'd like to test the case of being notified once a txid reaches N 115 // confirmations, where N > 1. 116 // 117 // Again, we'll begin by creating a fresh transaction, so we can obtain 118 // a fresh txid. 119 txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner) 120 if err != nil { 121 t.Fatalf("unable to create test addr: %v", err) 122 } 123 if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil { 124 t.Fatalf("tx not relayed to miner: %v", err) 125 } 126 127 _, currentHeight, err := miner.Node.GetBestBlock(ctxb) 128 if err != nil { 129 t.Fatalf("unable to get current height: %v", err) 130 } 131 132 numConfs := uint32(6) 133 var confIntent *chainntnfs.ConfirmationEvent 134 if scriptDispatch { 135 confIntent, err = notifier.RegisterConfirmationsNtfn( 136 nil, pkScript, numConfs, uint32(currentHeight), 137 ) 138 } else { 139 confIntent, err = notifier.RegisterConfirmationsNtfn( 140 txid, pkScript, numConfs, uint32(currentHeight), 141 ) 142 } 143 if err != nil { 144 t.Fatalf("unable to register ntfn: %v", err) 145 } 146 147 // Now generate a six blocks. The transaction should be included in the 148 // first block, which will be built upon by the other 5 blocks. 149 if _, err := vw.GenerateBlocks(ctxb, 6); err != nil { 150 t.Fatalf("unable to generate single block: %v", err) 151 } 152 153 // TODO(roasbeef): reduce all timeouts after neutrino sync tightended 154 // up 155 156 select { 157 case <-confIntent.Confirmed: 158 break 159 case <-time.After(20 * time.Second): 160 t.Fatalf("confirmation notification never received") 161 } 162 } 163 164 func testBatchConfirmationNotification(miner *rpctest.Harness, vw *rpctest.VotingWallet, 165 notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) { 166 167 // We'd like to test a case of serving notifications to multiple 168 // clients, each requesting to be notified once a txid receives various 169 // numbers of confirmations. 170 confSpread := [6]uint32{1, 2, 3, 6, 20, 22} 171 confIntents := make([]*chainntnfs.ConfirmationEvent, len(confSpread)) 172 173 _, currentHeight, err := miner.Node.GetBestBlock(ctxb) 174 if err != nil { 175 t.Fatalf("unable to get current height: %v", err) 176 } 177 178 // Create a new txid spending miner coins for each confirmation entry 179 // in confSpread, we collect each conf intent into a slice so we can 180 // verify they're each notified at the proper number of confirmations 181 // below. 182 for i, numConfs := range confSpread { 183 txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner) 184 if err != nil { 185 t.Fatalf("unable to create test addr: %v", err) 186 } 187 var confIntent *chainntnfs.ConfirmationEvent 188 if scriptDispatch { 189 confIntent, err = notifier.RegisterConfirmationsNtfn( 190 nil, pkScript, numConfs, uint32(currentHeight), 191 ) 192 } else { 193 confIntent, err = notifier.RegisterConfirmationsNtfn( 194 txid, pkScript, numConfs, uint32(currentHeight), 195 ) 196 } 197 if err != nil { 198 t.Fatalf("unable to register ntfn: %v", err) 199 } 200 confIntents[i] = confIntent 201 if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil { 202 t.Fatalf("tx not relayed to miner: %v", err) 203 } 204 205 } 206 207 initialConfHeight := uint32(currentHeight + 1) 208 209 // Now, for each confirmation intent, generate the delta number of blocks 210 // needed to trigger the confirmation notification. A goroutine is 211 // spawned in order to verify the proper notification is triggered. 212 for i, numConfs := range confSpread { 213 var blocksToGen uint32 214 215 // If this is the last instance, manually index to generate the 216 // proper block delta in order to avoid a panic. 217 if i == len(confSpread)-1 { 218 blocksToGen = confSpread[len(confSpread)-1] - confSpread[len(confSpread)-2] 219 } else { 220 blocksToGen = confSpread[i+1] - confSpread[i] 221 } 222 223 // Generate the number of blocks necessary to trigger this 224 // current confirmation notification. 225 if _, err := vw.GenerateBlocks(ctxb, blocksToGen); err != nil { 226 t.Fatalf("unable to generate single block: %v", err) 227 } 228 229 select { 230 case conf := <-confIntents[i].Confirmed: 231 // All of the notifications above were originally 232 // confirmed in the same block. The returned 233 // notification should list the initial confirmation 234 // height rather than the height they were _fully_ 235 // confirmed. 236 if conf.BlockHeight != initialConfHeight { 237 t.Fatalf("notification has incorrect initial "+ 238 "conf height: expected %v, got %v", 239 initialConfHeight, conf.BlockHeight) 240 } 241 continue 242 case <-time.After(20 * time.Second): 243 t.Fatalf("confirmation notification never received: %v", numConfs) 244 } 245 } 246 } 247 248 func checkNotificationFields(ntfn *chainntnfs.SpendDetail, 249 outpoint *wire.OutPoint, spenderHash *chainhash.Hash, 250 height int64, t *testing.T) { 251 252 t.Helper() 253 254 if *ntfn.SpentOutPoint != *outpoint { 255 t.Fatalf("ntfn includes wrong output, reports "+ 256 "%v instead of %v", 257 ntfn.SpentOutPoint, outpoint) 258 } 259 if !bytes.Equal(ntfn.SpenderTxHash[:], spenderHash[:]) { 260 t.Fatalf("ntfn includes wrong spender tx hash, "+ 261 "reports %v instead of %v", 262 ntfn.SpenderTxHash[:], spenderHash[:]) 263 } 264 if ntfn.SpenderInputIndex != 0 { 265 t.Fatalf("ntfn includes wrong spending input "+ 266 "index, reports %v, should be %v", 267 ntfn.SpenderInputIndex, 0) 268 } 269 if int64(ntfn.SpendingHeight) != height { 270 t.Fatalf("ntfn has wrong spending height: "+ 271 "expected %v, got %v", height, 272 ntfn.SpendingHeight) 273 } 274 } 275 276 func testSpendNotification(miner *rpctest.Harness, vw *rpctest.VotingWallet, 277 notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) { 278 279 // We'd like to test the spend notifications for all ChainNotifier 280 // concrete implementations. 281 // 282 // To do so, we first create a new output to our test target address. 283 outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner, vw) 284 285 _, currentHeight, err := miner.Node.GetBestBlock(ctxb) 286 if err != nil { 287 t.Fatalf("unable to get current height: %v", err) 288 } 289 290 // Now that we have an output index and the pkScript, register for a 291 // spentness notification for the newly created output with multiple 292 // clients in order to ensure the implementation can support 293 // multi-client spend notifications. 294 const numClients = 5 295 spendClients := make([]*chainntnfs.SpendEvent, numClients) 296 for i := 0; i < numClients; i++ { 297 var spentIntent *chainntnfs.SpendEvent 298 if scriptDispatch { 299 spentIntent, err = notifier.RegisterSpendNtfn( 300 nil, output.PkScript, uint32(currentHeight), 301 ) 302 } else { 303 spentIntent, err = notifier.RegisterSpendNtfn( 304 outpoint, output.PkScript, uint32(currentHeight), 305 ) 306 } 307 if err != nil { 308 t.Fatalf("unable to register for spend ntfn: %v", err) 309 } 310 311 spendClients[i] = spentIntent 312 } 313 314 // Next, create a new transaction spending that output. 315 spendingTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey) 316 317 // Broadcast our spending transaction. 318 spenderHash, err := miner.Node.SendRawTransaction(ctxb, spendingTx, true) 319 if err != nil { 320 t.Fatalf("unable to broadcast tx: %v", err) 321 } 322 323 if err := chainntnfs.WaitForMempoolTx(miner, spenderHash); err != nil { 324 t.Fatalf("tx not relayed to miner: %v", err) 325 } 326 327 // Make sure notifications are not yet sent. We launch a go routine for 328 // all the spend clients, such that we can wait for them all in 329 // parallel. 330 // 331 // Since dcrd is at times very slow at notifying about txs in the 332 // mempool, we use a quite large timeout of 10 seconds. 333 // TODO(halseth): change this when mempool spends are removed. 334 mempoolSpendTimeout := 10 * time.Second 335 mempoolSpends := make(chan *chainntnfs.SpendDetail, numClients) 336 for _, c := range spendClients { 337 go func(client *chainntnfs.SpendEvent) { 338 select { 339 case s := <-client.Spend: 340 mempoolSpends <- s 341 case <-time.After(mempoolSpendTimeout): 342 } 343 }(c) 344 } 345 346 select { 347 case <-mempoolSpends: 348 t.Fatalf("did not expect to get notification before " + 349 "block was mined") 350 case <-time.After(mempoolSpendTimeout): 351 } 352 353 // Make sure registering a client after the tx is in the mempool still 354 // doesn't trigger a notification. 355 var spentIntent *chainntnfs.SpendEvent 356 if scriptDispatch { 357 spentIntent, err = notifier.RegisterSpendNtfn( 358 nil, output.PkScript, uint32(currentHeight), 359 ) 360 } else { 361 spentIntent, err = notifier.RegisterSpendNtfn( 362 outpoint, output.PkScript, uint32(currentHeight), 363 ) 364 } 365 if err != nil { 366 t.Fatalf("unable to register for spend ntfn: %v", err) 367 } 368 369 select { 370 case <-spentIntent.Spend: 371 t.Fatalf("did not expect to get notification before " + 372 "block was mined") 373 case <-time.After(mempoolSpendTimeout): 374 } 375 spendClients = append(spendClients, spentIntent) 376 377 // Now we mine a single block, which should include our spend. The 378 // notification should also be sent off. 379 if _, err := vw.GenerateBlocks(ctxb, 1); err != nil { 380 t.Fatalf("unable to generate single block: %v", err) 381 } 382 383 _, currentHeight, err = miner.Node.GetBestBlock(ctxb) 384 if err != nil { 385 t.Fatalf("unable to get current height: %v", err) 386 } 387 388 for _, c := range spendClients { 389 select { 390 case ntfn := <-c.Spend: 391 // We've received the spend nftn. So now verify all the 392 // fields have been set properly. 393 checkNotificationFields(ntfn, outpoint, spenderHash, 394 currentHeight, t) 395 case <-time.After(30 * time.Second): 396 t.Fatalf("spend ntfn never received") 397 } 398 } 399 } 400 401 func testBlockEpochNotification(miner *rpctest.Harness, vw *rpctest.VotingWallet, 402 notifier chainntnfs.TestChainNotifier, t *testing.T) { 403 404 // We'd like to test the case of multiple registered clients receiving 405 // block epoch notifications. 406 const numBlocks = 10 407 const numNtfns = numBlocks + 1 408 const numClients = 5 409 var wg sync.WaitGroup 410 411 // Create numClients clients which will listen for block notifications. We 412 // expect each client to receive 11 notifications, one for the current 413 // tip of the chain, and one for each of the ten blocks we generate 414 // below. So we'll use a WaitGroup to synchronize the test. 415 clientErrors := make(chan error, numClients) 416 for i := 0; i < numClients; i++ { 417 epochClient, err := notifier.RegisterBlockEpochNtfn(nil) 418 if err != nil { 419 t.Fatalf("unable to register for epoch notification") 420 } 421 422 wg.Add(numNtfns) 423 go func() { 424 for i := 0; i < numNtfns; i++ { 425 // Ensure that each block epoch has a header, 426 // and that header matches the contained header 427 // hash. 428 blockEpoch := <-epochClient.Epochs 429 if blockEpoch.BlockHeader == nil { 430 fmt.Println(i) 431 clientErrors <- fmt.Errorf("block " + 432 "header is nil") 433 return 434 } 435 if blockEpoch.BlockHeader.BlockHash() != 436 *blockEpoch.Hash { 437 438 clientErrors <- fmt.Errorf("block " + 439 "header hash mismatch") 440 return 441 } 442 443 wg.Done() 444 } 445 }() 446 } 447 448 epochsSent := make(chan struct{}) 449 go func() { 450 wg.Wait() 451 close(epochsSent) 452 }() 453 454 // Now generate 10 blocks, the clients above should each receive 10 455 // notifications, thereby unblocking the goroutine above. 456 if _, err := vw.GenerateBlocks(ctxb, numBlocks); err != nil { 457 t.Fatalf("unable to generate blocks: %v", err) 458 } 459 460 select { 461 case err := <-clientErrors: 462 t.Fatalf("block epoch case failed: %v", err) 463 case <-epochsSent: 464 case <-time.After(30 * time.Second): 465 t.Fatalf("all notifications not sent") 466 } 467 } 468 469 func testMultiClientConfirmationNotification(miner *rpctest.Harness, vw *rpctest.VotingWallet, 470 notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) { 471 472 // We'd like to test the case of a multiple clients registered to 473 // receive a confirmation notification for the same transaction. 474 txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner) 475 if err != nil { 476 t.Fatalf("unable to create test tx: %v", err) 477 } 478 if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil { 479 t.Fatalf("tx not relayed to miner: %v", err) 480 } 481 482 var wg sync.WaitGroup 483 const ( 484 numConfsClients = 5 485 numConfs = 1 486 ) 487 488 _, currentHeight, err := miner.Node.GetBestBlock(ctxb) 489 if err != nil { 490 t.Fatalf("unable to get current height: %v", err) 491 } 492 493 // Register for a conf notification for the above generated txid with 494 // numConfsClients distinct clients. 495 for i := 0; i < numConfsClients; i++ { 496 var confClient *chainntnfs.ConfirmationEvent 497 if scriptDispatch { 498 confClient, err = notifier.RegisterConfirmationsNtfn( 499 nil, pkScript, numConfs, uint32(currentHeight), 500 ) 501 } else { 502 confClient, err = notifier.RegisterConfirmationsNtfn( 503 txid, pkScript, numConfs, uint32(currentHeight), 504 ) 505 } 506 if err != nil { 507 t.Fatalf("unable to register for confirmation: %v", err) 508 } 509 510 wg.Add(1) 511 go func() { 512 <-confClient.Confirmed 513 wg.Done() 514 }() 515 } 516 517 confsSent := make(chan struct{}) 518 go func() { 519 wg.Wait() 520 close(confsSent) 521 }() 522 523 // Finally, generate a single block which should trigger the unblocking 524 // of all numConfsClients blocked on the channel read above. 525 if _, err := vw.GenerateBlocks(ctxb, 1); err != nil { 526 t.Fatalf("unable to generate block: %v", err) 527 } 528 529 select { 530 case <-confsSent: 531 case <-time.After(30 * time.Second): 532 t.Fatalf("all confirmation notifications not sent") 533 } 534 } 535 536 // Tests the case in which a confirmation notification is requested for a 537 // transaction that has already been included in a block. In this case, the 538 // confirmation notification should be dispatched immediately. 539 func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness, vw *rpctest.VotingWallet, 540 notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) { 541 542 // First, let's send some coins to "ourself", obtaining a txid. We're 543 // spending from a coinbase output here, so we use the dedicated 544 // function. 545 txid3, pkScript3, err := chainntnfs.GetTestTxidAndScript(miner) 546 if err != nil { 547 t.Fatalf("unable to create test tx: %v", err) 548 } 549 if err := chainntnfs.WaitForMempoolTx(miner, txid3); err != nil { 550 t.Fatalf("tx not relayed to miner: %v", err) 551 } 552 553 // Generate another block containing tx 3, but we won't register conf 554 // notifications for this tx until much later. The notifier must check 555 // older blocks when the confirmation event is registered below to ensure 556 // that the TXID hasn't already been included in the chain, otherwise the 557 // notification will never be sent. 558 _, err = vw.GenerateBlocks(ctxb, 1) 559 if err != nil { 560 t.Fatalf("unable to generate block: %v", err) 561 } 562 563 txid1, pkScript1, err := chainntnfs.GetTestTxidAndScript(miner) 564 if err != nil { 565 t.Fatalf("unable to create test tx: %v", err) 566 } 567 if err := chainntnfs.WaitForMempoolTx(miner, txid1); err != nil { 568 t.Fatalf("tx not relayed to miner: %v", err) 569 } 570 571 txid2, pkScript2, err := chainntnfs.GetTestTxidAndScript(miner) 572 if err != nil { 573 t.Fatalf("unable to create test tx: %v", err) 574 } 575 if err := chainntnfs.WaitForMempoolTx(miner, txid2); err != nil { 576 t.Fatalf("tx not relayed to miner: %v", err) 577 } 578 579 _, currentHeight, err := miner.Node.GetBestBlock(ctxb) 580 if err != nil { 581 t.Fatalf("unable to get current height: %v", err) 582 } 583 584 // Now generate another block containing txs 1 & 2. 585 blockHash, err := vw.GenerateBlocks(ctxb, 1) 586 if err != nil { 587 t.Fatalf("unable to generate block: %v", err) 588 } 589 590 // Register a confirmation notification with the chainntfn source for tx2, 591 // which is included in the last block. The height hint is the height before 592 // the block is included. This notification should fire immediately since 593 // only 1 confirmation is required. 594 var ntfn1 *chainntnfs.ConfirmationEvent 595 if scriptDispatch { 596 ntfn1, err = notifier.RegisterConfirmationsNtfn( 597 nil, pkScript1, 1, uint32(currentHeight), 598 ) 599 } else { 600 ntfn1, err = notifier.RegisterConfirmationsNtfn( 601 txid1, pkScript1, 1, uint32(currentHeight), 602 ) 603 } 604 if err != nil { 605 t.Fatalf("unable to register ntfn: %v", err) 606 } 607 608 select { 609 case confInfo := <-ntfn1.Confirmed: 610 // Finally, we'll verify that the tx index returned is the exact same 611 // as the tx index of the transaction within the block itself. 612 msgBlock, err := miner.Node.GetBlock(ctxb, blockHash[0]) 613 if err != nil { 614 t.Fatalf("unable to fetch block: %v", err) 615 } 616 block := dcrutil.NewBlock(msgBlock) 617 specifiedTxHash, err := block.TxHash(int(confInfo.TxIndex)) 618 if err != nil { 619 t.Fatalf("unable to index into block: %v", err) 620 } 621 if !specifiedTxHash.IsEqual(txid1) { 622 t.Fatalf("mismatched tx indexes: expected %v, got %v", 623 txid1, specifiedTxHash) 624 } 625 626 // We'll also ensure that the block height has been set 627 // properly. 628 if confInfo.BlockHeight != uint32(currentHeight+1) { 629 t.Fatalf("incorrect block height: expected %v, got %v", 630 confInfo.BlockHeight, currentHeight) 631 } 632 break 633 case <-time.After(20 * time.Second): 634 t.Fatalf("confirmation notification never received") 635 } 636 637 // Register a confirmation notification for tx2, requiring 3 confirmations. 638 // This transaction is only partially confirmed, so the notification should 639 // not fire yet. 640 var ntfn2 *chainntnfs.ConfirmationEvent 641 if scriptDispatch { 642 ntfn2, err = notifier.RegisterConfirmationsNtfn( 643 nil, pkScript2, 3, uint32(currentHeight), 644 ) 645 } else { 646 ntfn2, err = notifier.RegisterConfirmationsNtfn( 647 txid2, pkScript2, 3, uint32(currentHeight), 648 ) 649 } 650 if err != nil { 651 t.Fatalf("unable to register ntfn: %v", err) 652 } 653 654 // Fully confirm tx3. 655 _, err = vw.GenerateBlocks(ctxb, 2) 656 if err != nil { 657 t.Fatalf("unable to generate block: %v", err) 658 } 659 660 select { 661 case <-ntfn2.Confirmed: 662 case <-time.After(10 * time.Second): 663 t.Fatalf("confirmation notification never received") 664 } 665 666 select { 667 case <-ntfn1.Confirmed: 668 t.Fatalf("received multiple confirmations for tx") 669 case <-time.After(1 * time.Second): 670 } 671 672 // Finally register a confirmation notification for tx3, requiring 1 673 // confirmation. Ensure that conf notifications do not refire on txs 674 // 1 or 2. 675 var ntfn3 *chainntnfs.ConfirmationEvent 676 if scriptDispatch { 677 ntfn3, err = notifier.RegisterConfirmationsNtfn( 678 nil, pkScript3, 1, uint32(currentHeight-1), 679 ) 680 } else { 681 ntfn3, err = notifier.RegisterConfirmationsNtfn( 682 txid3, pkScript3, 1, uint32(currentHeight-1), 683 ) 684 } 685 if err != nil { 686 t.Fatalf("unable to register ntfn: %v", err) 687 } 688 689 // We'll also register for a confirmation notification with the pkscript 690 // of a different transaction. This notification shouldn't fire since we 691 // match on both txid and pkscript. 692 var ntfn4 *chainntnfs.ConfirmationEvent 693 ntfn4, err = notifier.RegisterConfirmationsNtfn( 694 txid3, pkScript2, 1, uint32(currentHeight-1), 695 ) 696 if err != nil { 697 t.Fatalf("unable to register ntfn: %v", err) 698 } 699 700 select { 701 case <-ntfn3.Confirmed: 702 case <-time.After(10 * time.Second): 703 t.Fatalf("confirmation notification never received") 704 } 705 706 select { 707 case <-ntfn4.Confirmed: 708 t.Fatalf("confirmation notification received") 709 case <-time.After(5 * time.Second): 710 } 711 712 time.Sleep(1 * time.Second) 713 714 select { 715 case <-ntfn1.Confirmed: 716 t.Fatalf("received multiple confirmations for tx") 717 default: 718 } 719 720 select { 721 case <-ntfn2.Confirmed: 722 t.Fatalf("received multiple confirmations for tx") 723 default: 724 } 725 } 726 727 // Test the case of a notification consumer having forget or being delayed in 728 // checking for a confirmation. This should not cause the notifier to stop 729 // working 730 func testLazyNtfnConsumer(miner *rpctest.Harness, vw *rpctest.VotingWallet, 731 notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) { 732 733 // Create a transaction to be notified about. We'll register for 734 // notifications on this transaction but won't be prompt in checking them 735 txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner) 736 if err != nil { 737 t.Fatalf("unable to create test tx: %v", err) 738 } 739 if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil { 740 t.Fatalf("tx not relayed to miner: %v", err) 741 } 742 743 _, currentHeight, err := miner.Node.GetBestBlock(ctxb) 744 if err != nil { 745 t.Fatalf("unable to get current height: %v", err) 746 } 747 748 numConfs := uint32(3) 749 750 // Add a block right before registering, this makes race conditions 751 // between the historical dispatcher and the normal dispatcher more obvious 752 if _, err := vw.GenerateBlocks(ctxb, 1); err != nil { 753 t.Fatalf("unable to generate blocks: %v", err) 754 } 755 756 var firstConfIntent *chainntnfs.ConfirmationEvent 757 if scriptDispatch { 758 firstConfIntent, err = notifier.RegisterConfirmationsNtfn( 759 nil, pkScript, numConfs, uint32(currentHeight), 760 ) 761 } else { 762 firstConfIntent, err = notifier.RegisterConfirmationsNtfn( 763 txid, pkScript, numConfs, uint32(currentHeight), 764 ) 765 } 766 if err != nil { 767 t.Fatalf("unable to register ntfn: %v", err) 768 } 769 770 // Generate another 2 blocks, this should dispatch the confirm notification 771 if _, err := vw.GenerateBlocks(ctxb, 2); err != nil { 772 t.Fatalf("unable to generate blocks: %v", err) 773 } 774 775 // Now make another transaction, just because we haven't checked to see 776 // if the first transaction has confirmed doesn't mean that we shouldn't 777 // be able to see if this transaction confirms first 778 txid, pkScript, err = chainntnfs.GetTestTxidAndScript(miner) 779 if err != nil { 780 t.Fatalf("unable to create test tx: %v", err) 781 } 782 if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil { 783 t.Fatalf("tx not relayed to miner: %v", err) 784 } 785 786 _, currentHeight, err = miner.Node.GetBestBlock(ctxb) 787 if err != nil { 788 t.Fatalf("unable to get current height: %v", err) 789 } 790 791 numConfs = 1 792 var secondConfIntent *chainntnfs.ConfirmationEvent 793 if scriptDispatch { 794 secondConfIntent, err = notifier.RegisterConfirmationsNtfn( 795 nil, pkScript, numConfs, uint32(currentHeight), 796 ) 797 } else { 798 secondConfIntent, err = notifier.RegisterConfirmationsNtfn( 799 txid, pkScript, numConfs, uint32(currentHeight), 800 ) 801 } 802 if err != nil { 803 t.Fatalf("unable to register ntfn: %v", err) 804 } 805 806 if _, err := vw.GenerateBlocks(ctxb, 1); err != nil { 807 t.Fatalf("unable to generate blocks: %v", err) 808 } 809 810 select { 811 case <-secondConfIntent.Confirmed: 812 // Successfully receive the second notification 813 break 814 case <-time.After(30 * time.Second): 815 t.Fatalf("Second confirmation notification never received") 816 } 817 818 // Make sure the first tx confirmed successfully 819 select { 820 case <-firstConfIntent.Confirmed: 821 break 822 case <-time.After(30 * time.Second): 823 t.Fatalf("First confirmation notification never received") 824 } 825 } 826 827 // Tests the case in which a spend notification is requested for a spend that 828 // has already been included in a block. In this case, the spend notification 829 // should be dispatched immediately. 830 func testSpendBeforeNtfnRegistration(miner *rpctest.Harness, vw *rpctest.VotingWallet, 831 notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) { 832 833 // We'd like to test the spend notifications for all ChainNotifier 834 // concrete implementations. 835 // 836 // To do so, we first create a new output to our test target address. 837 outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner, vw) 838 839 _, heightHint, err := miner.Node.GetBestBlock(ctxb) 840 if err != nil { 841 t.Fatalf("unable to get current height: %v", err) 842 } 843 844 // We'll then spend this output and broadcast the spend transaction. 845 spendingTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey) 846 spenderHash, err := miner.Node.SendRawTransaction(ctxb, spendingTx, true) 847 if err != nil { 848 t.Fatalf("unable to broadcast tx: %v", err) 849 } 850 if err := chainntnfs.WaitForMempoolTx(miner, spenderHash); err != nil { 851 t.Fatalf("tx not relayed to miner: %v", err) 852 } 853 854 // We create an epoch client we can use to make sure the notifier is 855 // caught up to the mining node's chain. 856 epochClient, err := notifier.RegisterBlockEpochNtfn(nil) 857 if err != nil { 858 t.Fatalf("unable to register for block epoch: %v", err) 859 } 860 861 // Now we mine an additional block, which should include our spend. 862 if _, err := vw.GenerateBlocks(ctxb, 1); err != nil { 863 t.Fatalf("unable to generate single block: %v", err) 864 } 865 _, spendHeight, err := miner.Node.GetBestBlock(ctxb) 866 if err != nil { 867 t.Fatalf("unable to get current height: %v", err) 868 } 869 870 // When testing via scriptDispatch we ignore the outpoint. 871 if scriptDispatch { 872 outpoint = &chainntnfs.ZeroOutPoint 873 } 874 875 // checkSpends registers two clients to be notified of a spend that has 876 // already happened. The notifier should dispatch a spend notification 877 // immediately. 878 checkSpends := func() { 879 t.Helper() 880 881 const numClients = 2 882 spendClients := make([]*chainntnfs.SpendEvent, numClients) 883 for i := 0; i < numClients; i++ { 884 var spentIntent *chainntnfs.SpendEvent 885 if scriptDispatch { 886 spentIntent, err = notifier.RegisterSpendNtfn( 887 nil, output.PkScript, 888 uint32(heightHint), 889 ) 890 } else { 891 spentIntent, err = notifier.RegisterSpendNtfn( 892 outpoint, output.PkScript, 893 uint32(heightHint), 894 ) 895 } 896 if err != nil { 897 t.Fatalf("unable to register for spend ntfn: %v", 898 err) 899 } 900 901 spendClients[i] = spentIntent 902 } 903 904 for _, client := range spendClients { 905 select { 906 case ntfn := <-client.Spend: 907 // We've received the spend nftn. So now verify 908 // all the fields have been set properly. 909 checkNotificationFields( 910 ntfn, outpoint, spenderHash, spendHeight, t, 911 ) 912 case <-time.After(30 * time.Second): 913 t.Fatalf("spend ntfn never received") 914 } 915 } 916 } 917 918 // Wait for the notifier to have caught up to the mined block. 919 var lastBlockEpochHeight int64 920 for lastBlockEpochHeight != spendHeight { 921 select { 922 case be, ok := <-epochClient.Epochs: 923 lastBlockEpochHeight = int64(be.Height) 924 if !ok { 925 t.Fatalf("epoch channel was closed") 926 } 927 case <-time.After(15 * time.Second): 928 t.Fatalf("did not receive block epoch") 929 } 930 } 931 932 // Check that the spend clients gets immediately notified for the spend 933 // in the previous block. 934 checkSpends() 935 936 // Bury the spend even deeper, and do the same check. 937 const numBlocks = 10 938 if _, err := vw.GenerateBlocks(ctxb, numBlocks); err != nil { 939 t.Fatalf("unable to generate single block: %v", err) 940 } 941 942 // Wait for the notifier to have caught up with the new blocks. 943 for i := 0; i < numBlocks; i++ { 944 select { 945 case _, ok := <-epochClient.Epochs: 946 if !ok { 947 t.Fatalf("epoch channel was closed") 948 } 949 case <-time.After(15 * time.Second): 950 t.Fatalf("did not receive block epoch") 951 } 952 } 953 954 // The clients should still be notified immediately. 955 checkSpends() 956 } 957 958 func testCancelSpendNtfn(node *rpctest.Harness, vw *rpctest.VotingWallet, 959 notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) { 960 961 // We'd like to test that once a spend notification is registered, it 962 // can be canceled before the notification is dispatched. 963 964 // First, we'll start by creating a new output that we can spend 965 // ourselves. 966 outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, node, vw) 967 968 _, currentHeight, err := node.Node.GetBestBlock(ctxb) 969 if err != nil { 970 t.Fatalf("unable to get current height: %v", err) 971 } 972 973 // Create two clients that each registered to the spend notification. 974 // We'll cancel the notification for the first client and leave the 975 // notification for the second client enabled. 976 const numClients = 2 977 spendClients := make([]*chainntnfs.SpendEvent, numClients) 978 for i := 0; i < numClients; i++ { 979 var spentIntent *chainntnfs.SpendEvent 980 if scriptDispatch { 981 spentIntent, err = notifier.RegisterSpendNtfn( 982 nil, output.PkScript, uint32(currentHeight), 983 ) 984 } else { 985 spentIntent, err = notifier.RegisterSpendNtfn( 986 outpoint, output.PkScript, uint32(currentHeight), 987 ) 988 } 989 if err != nil { 990 t.Fatalf("unable to register for spend ntfn: %v", err) 991 } 992 993 spendClients[i] = spentIntent 994 } 995 996 // Next, create a new transaction spending that output. 997 spendingTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey) 998 999 // Before we broadcast the spending transaction, we'll cancel the 1000 // notification of the first client. 1001 spendClients[1].Cancel() 1002 1003 // Broadcast our spending transaction. 1004 spenderHash, err := node.Node.SendRawTransaction(ctxb, spendingTx, true) 1005 if err != nil { 1006 t.Fatalf("unable to broadcast tx: %v", err) 1007 } 1008 1009 if err := chainntnfs.WaitForMempoolTx(node, spenderHash); err != nil { 1010 t.Fatalf("tx not relayed to miner: %v", err) 1011 } 1012 1013 // Now we mine a single block, which should include our spend. The 1014 // notification should also be sent off. 1015 if _, err := vw.GenerateBlocks(ctxb, 1); err != nil { 1016 t.Fatalf("unable to generate single block: %v", err) 1017 } 1018 1019 // The spend notification for the first client should have been 1020 // dispatched. 1021 select { 1022 case ntfn := <-spendClients[0].Spend: 1023 // We've received the spend nftn. So now verify all the 1024 // fields have been set properly. 1025 if *ntfn.SpentOutPoint != *outpoint { 1026 t.Fatalf("ntfn includes wrong output, reports "+ 1027 "%v instead of %v", 1028 ntfn.SpentOutPoint, outpoint) 1029 } 1030 if !bytes.Equal(ntfn.SpenderTxHash[:], spenderHash[:]) { 1031 t.Fatalf("ntfn includes wrong spender tx hash, "+ 1032 "reports %v instead of %v", 1033 ntfn.SpenderTxHash[:], spenderHash[:]) 1034 } 1035 if ntfn.SpenderInputIndex != 0 { 1036 t.Fatalf("ntfn includes wrong spending input "+ 1037 "index, reports %v, should be %v", 1038 ntfn.SpenderInputIndex, 0) 1039 } 1040 case <-time.After(20 * time.Second): 1041 t.Fatalf("spend ntfn never received") 1042 } 1043 1044 // However, the spend notification of the second client should NOT have 1045 // been dispatched. 1046 select { 1047 case _, ok := <-spendClients[1].Spend: 1048 if ok { 1049 t.Fatalf("spend ntfn should have been canceled") 1050 } 1051 case <-time.After(20 * time.Second): 1052 t.Fatalf("spend ntfn never canceled") 1053 } 1054 } 1055 1056 func testCancelEpochNtfn(node *rpctest.Harness, vw *rpctest.VotingWallet, 1057 notifier chainntnfs.TestChainNotifier, t *testing.T) { 1058 1059 // We'd like to ensure that once a client cancels their block epoch 1060 // notifications, no further notifications are sent over the channel 1061 // if/when new blocks come in. 1062 const numClients = 2 1063 1064 epochClients := make([]*chainntnfs.BlockEpochEvent, numClients) 1065 for i := 0; i < numClients; i++ { 1066 epochClient, err := notifier.RegisterBlockEpochNtfn(nil) 1067 if err != nil { 1068 t.Fatalf("unable to register for epoch notification") 1069 } 1070 epochClients[i] = epochClient 1071 } 1072 1073 // Now before we mine any blocks, cancel the notification for the first 1074 // epoch client. 1075 epochClients[0].Cancel() 1076 1077 // Now mine a single block, this should trigger the logic to dispatch 1078 // epoch notifications. 1079 if _, err := vw.GenerateBlocks(ctxb, 1); err != nil { 1080 t.Fatalf("unable to generate blocks: %v", err) 1081 } 1082 1083 // The epoch notification for the first client shouldn't have been 1084 // dispatched. 1085 select { 1086 case _, ok := <-epochClients[0].Epochs: 1087 if ok { 1088 t.Fatalf("epoch notification should have been canceled") 1089 } 1090 case <-time.After(2 * time.Second): 1091 t.Fatalf("epoch notification not sent") 1092 } 1093 1094 // However, the epoch notification for the second client should have 1095 // been dispatched as normal. 1096 select { 1097 case _, ok := <-epochClients[1].Epochs: 1098 if !ok { 1099 t.Fatalf("epoch was canceled") 1100 } 1101 case <-time.After(20 * time.Second): 1102 t.Fatalf("epoch notification not sent") 1103 } 1104 } 1105 1106 func testReorgConf(miner *rpctest.Harness, vw *rpctest.VotingWallet, 1107 notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) { 1108 1109 // Set up a new miner that we can use to cause a reorg. 1110 extraArgs := []string{"--txindex", "--logdir=.miner2"} 1111 miner2, err := testutils.NewSetupRPCTest( 1112 testctx.New(t), 5, netParams, nil, extraArgs, false, 0, 1113 ) 1114 if err != nil { 1115 t.Fatalf("unable to create mining node: %v", err) 1116 } 1117 defer func() { 1118 time.Sleep(time.Millisecond * 50) 1119 miner2.TearDown() 1120 }() 1121 1122 // We start by connecting the new miner to our original miner, 1123 // such that it will sync to our original chain. 1124 if err := rpctest.ConnectNode(ctxb, miner, miner2); err != nil { 1125 t.Fatalf("unable to connect harnesses: %v", err) 1126 } 1127 nodeSlice := []*rpctest.Harness{miner, miner2} 1128 if err := rpctest.JoinNodes(ctxb, nodeSlice, rpctest.Blocks); err != nil { 1129 t.Fatalf("unable to join node on blocks: %v", err) 1130 } 1131 1132 // The two should be on the same blockheight. 1133 _, nodeHeight1, err := miner.Node.GetBestBlock(ctxb) 1134 if err != nil { 1135 t.Fatalf("unable to get current blockheight %v", err) 1136 } 1137 1138 _, nodeHeight2, err := miner2.Node.GetBestBlock(ctxb) 1139 if err != nil { 1140 t.Fatalf("unable to get current blockheight %v", err) 1141 } 1142 1143 if nodeHeight1 != nodeHeight2 { 1144 t.Fatalf("expected both miners to be on the same height: %v vs %v", 1145 nodeHeight1, nodeHeight2) 1146 } 1147 1148 // We disconnect the two nodes, such that we can start mining on them 1149 // individually without the other one learning about the new blocks. 1150 err = rpctest.RemoveNode(ctxb, miner, miner2) 1151 if err != nil { 1152 t.Fatalf("unable to remove node: %v", err) 1153 } 1154 1155 txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner) 1156 if err != nil { 1157 t.Fatalf("unable to create test tx: %v", err) 1158 } 1159 if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil { 1160 t.Fatalf("tx not relayed to miner: %v", err) 1161 } 1162 1163 _, currentHeight, err := miner.Node.GetBestBlock(ctxb) 1164 if err != nil { 1165 t.Fatalf("unable to get current height: %v", err) 1166 } 1167 1168 // Now that we have a txid, register a confirmation notification with 1169 // the chainntfn source. 1170 numConfs := uint32(2) 1171 var confIntent *chainntnfs.ConfirmationEvent 1172 if scriptDispatch { 1173 confIntent, err = notifier.RegisterConfirmationsNtfn( 1174 nil, pkScript, numConfs, uint32(currentHeight), 1175 ) 1176 } else { 1177 confIntent, err = notifier.RegisterConfirmationsNtfn( 1178 txid, pkScript, numConfs, uint32(currentHeight), 1179 ) 1180 } 1181 if err != nil { 1182 t.Fatalf("unable to register ntfn: %v", err) 1183 } 1184 1185 // Now generate a single block, the transaction should be included. 1186 _, err = vw.GenerateBlocks(ctxb, 1) 1187 if err != nil { 1188 t.Fatalf("unable to generate single block: %v", err) 1189 } 1190 1191 // Transaction only has one confirmation, and the notification is registered 1192 // with 2 confirmations, so we should not be notified yet. 1193 select { 1194 case <-confIntent.Confirmed: 1195 t.Fatal("tx was confirmed unexpectedly") 1196 case <-time.After(1 * time.Second): 1197 } 1198 1199 // Reorganize transaction out of the chain by generating a longer fork 1200 // from the other miner. The transaction is not included in this fork. 1201 if _, err := rpctest.AdjustedSimnetMiner(ctxb, miner2.Node, 2); err != nil { 1202 t.Fatalf("unable to generate longer fork: %v", err) 1203 } 1204 1205 // Reconnect nodes to reach consensus on the longest chain. miner2's chain 1206 // should win and become active on miner1. 1207 if err := rpctest.ConnectNode(ctxb, miner, miner2); err != nil { 1208 t.Fatalf("unable to connect harnesses: %v", err) 1209 } 1210 nodeSlice = []*rpctest.Harness{miner, miner2} 1211 if err := rpctest.JoinNodes(ctxb, nodeSlice, rpctest.Blocks); err != nil { 1212 t.Fatalf("unable to join node on blocks: %v", err) 1213 } 1214 1215 _, nodeHeight1, err = miner.Node.GetBestBlock(ctxb) 1216 if err != nil { 1217 t.Fatalf("unable to get current blockheight %v", err) 1218 } 1219 1220 _, nodeHeight2, err = miner2.Node.GetBestBlock(ctxb) 1221 if err != nil { 1222 t.Fatalf("unable to get current blockheight %v", err) 1223 } 1224 1225 if nodeHeight1 != nodeHeight2 { 1226 t.Fatalf("expected both miners to be on the same height: %v vs %v", 1227 nodeHeight1, nodeHeight2) 1228 } 1229 1230 // Even though there is one block above the height of the block that the 1231 // transaction was included in, it is not the active chain so the 1232 // notification should not be sent. 1233 select { 1234 case <-confIntent.Confirmed: 1235 t.Fatal("tx was confirmed unexpectedly") 1236 case <-time.After(1 * time.Second): 1237 } 1238 1239 // Now confirm the transaction on the longest chain and verify that we 1240 // receive the notification. 1241 tx, err := miner.Node.GetRawTransaction(ctxb, txid) 1242 if err != nil { 1243 t.Fatalf("unable to get raw tx: %v", err) 1244 } 1245 1246 txid, err = miner2.Node.SendRawTransaction(ctxb, tx.MsgTx(), false) 1247 if err != nil { 1248 t.Fatalf("unable to get send tx: %v", err) 1249 } 1250 if err := chainntnfs.WaitForMempoolTx(miner, txid); err != nil { 1251 t.Fatalf("tx not relayed to miner: %v", err) 1252 } 1253 1254 _, err = vw.GenerateBlocks(ctxb, 3) 1255 if err != nil { 1256 t.Fatalf("unable to generate single block: %v", err) 1257 } 1258 1259 select { 1260 case <-confIntent.Confirmed: 1261 case <-time.After(20 * time.Second): 1262 t.Fatalf("confirmation notification never received") 1263 } 1264 } 1265 1266 // testReorgSpend ensures that the different ChainNotifier implementations 1267 // correctly handle outpoints whose spending transaction has been reorged out of 1268 // the chain. 1269 func testReorgSpend(miner *rpctest.Harness, vw *rpctest.VotingWallet, 1270 notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) { 1271 1272 // We'll start by creating an output and registering a spend 1273 // notification for it. 1274 outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner, vw) 1275 _, heightHint, err := miner.Node.GetBestBlock(ctxb) 1276 if err != nil { 1277 t.Fatalf("unable to retrieve current height: %v", err) 1278 } 1279 1280 var spendIntent *chainntnfs.SpendEvent 1281 if scriptDispatch { 1282 spendIntent, err = notifier.RegisterSpendNtfn( 1283 nil, output.PkScript, uint32(heightHint), 1284 ) 1285 } else { 1286 spendIntent, err = notifier.RegisterSpendNtfn( 1287 outpoint, output.PkScript, uint32(heightHint), 1288 ) 1289 } 1290 if err != nil { 1291 t.Fatalf("unable to register for spend: %v", err) 1292 } 1293 1294 // Set up a new miner that we can use to cause a reorg. 1295 miner2, err := testutils.NewSetupRPCTest( 1296 testctx.New(t), 5, netParams, nil, []string{"--txindex"}, false, 0, 1297 ) 1298 if err != nil { 1299 t.Fatalf("unable to create mining node: %v", err) 1300 } 1301 defer func() { 1302 time.Sleep(time.Millisecond * 50) 1303 miner2.TearDown() 1304 }() 1305 1306 // We start by connecting the new miner to our original miner, in order 1307 // to have a consistent view of the chain from both miners. They should 1308 // be on the same block height. 1309 if err := rpctest.ConnectNode(ctxb, miner, miner2); err != nil { 1310 t.Fatalf("unable to connect miners: %v", err) 1311 } 1312 nodeSlice := []*rpctest.Harness{miner, miner2} 1313 if err := rpctest.JoinNodes(ctxb, nodeSlice, rpctest.Blocks); err != nil { 1314 t.Fatalf("unable to sync miners: %v", err) 1315 } 1316 _, minerHeight1, err := miner.Node.GetBestBlock(ctxb) 1317 if err != nil { 1318 t.Fatalf("unable to get miner1's current height: %v", err) 1319 } 1320 _, minerHeight2, err := miner2.Node.GetBestBlock(ctxb) 1321 if err != nil { 1322 t.Fatalf("unable to get miner2's current height: %v", err) 1323 } 1324 if minerHeight1 != minerHeight2 { 1325 t.Fatalf("expected both miners to be on the same height: "+ 1326 "%v vs %v", minerHeight1, minerHeight2) 1327 } 1328 1329 // We disconnect the two nodes, such that we can start mining on them 1330 // individually without the other one learning about the new blocks. 1331 err = rpctest.RemoveNode(ctxb, miner, miner2) 1332 if err != nil { 1333 t.Fatalf("unable to disconnect miners: %v", err) 1334 } 1335 1336 // Craft the spending transaction for the outpoint created above and 1337 // confirm it under the chain of the original miner. 1338 spendTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey) 1339 spendTxHash, err := miner.Node.SendRawTransaction(ctxb, spendTx, true) 1340 if err != nil { 1341 t.Fatalf("unable to broadcast spend tx: %v", err) 1342 } 1343 if err := chainntnfs.WaitForMempoolTx(miner, spendTxHash); err != nil { 1344 t.Fatalf("spend tx not relayed to miner: %v", err) 1345 } 1346 const numBlocks = 1 1347 if _, err := vw.GenerateBlocks(ctxb, numBlocks); err != nil { 1348 t.Fatalf("unable to generate blocks: %v", err) 1349 } 1350 _, spendHeight, err := miner.Node.GetBestBlock(ctxb) 1351 if err != nil { 1352 t.Fatalf("unable to get spend height: %v", err) 1353 } 1354 1355 // We should see a spend notification dispatched with the correct spend 1356 // details. 1357 select { 1358 case spendDetails := <-spendIntent.Spend: 1359 checkNotificationFields( 1360 spendDetails, outpoint, spendTxHash, spendHeight, t, 1361 ) 1362 case <-time.After(5 * time.Second): 1363 t.Fatal("expected spend notification to be dispatched") 1364 } 1365 1366 // Now, with the other miner, we'll generate one more block than the 1367 // other miner and connect them to cause a reorg. 1368 if _, err := rpctest.AdjustedSimnetMiner(ctxb, miner2.Node, numBlocks+1); err != nil { 1369 t.Fatalf("unable to generate blocks: %v", err) 1370 } 1371 if err := rpctest.ConnectNode(ctxb, miner, miner2); err != nil { 1372 t.Fatalf("unable to connect miners: %v", err) 1373 } 1374 nodeSlice = []*rpctest.Harness{miner2, miner} 1375 if err := rpctest.JoinNodes(ctxb, nodeSlice, rpctest.Blocks); err != nil { 1376 t.Fatalf("unable to sync miners: %v", err) 1377 } 1378 _, minerHeight1, err = miner.Node.GetBestBlock(ctxb) 1379 if err != nil { 1380 t.Fatalf("unable to get miner1's current height: %v", err) 1381 } 1382 _, minerHeight2, err = miner2.Node.GetBestBlock(ctxb) 1383 if err != nil { 1384 t.Fatalf("unable to get miner2's current height: %v", err) 1385 } 1386 if minerHeight1 != minerHeight2 { 1387 t.Fatalf("expected both miners to be on the same height: "+ 1388 "%v vs %v", minerHeight1, minerHeight2) 1389 } 1390 1391 // We should receive a reorg notification. 1392 select { 1393 case _, ok := <-spendIntent.Reorg: 1394 if !ok { 1395 t.Fatal("unexpected reorg channel closed") 1396 } 1397 case <-time.After(5 * time.Second): 1398 t.Fatal("expected to receive reorg notification") 1399 } 1400 1401 // Now that both miners are on the same chain, we'll confirm the 1402 // spending transaction of the outpoint and receive a notification for 1403 // it. 1404 if _, err = miner2.Node.SendRawTransaction(ctxb, spendTx, true); err != nil { 1405 t.Fatalf("unable to broadcast spend tx: %v", err) 1406 } 1407 if err := chainntnfs.WaitForMempoolTx(miner, spendTxHash); err != nil { 1408 t.Fatalf("tx not relayed to miner: %v", err) 1409 } 1410 if _, err := vw.GenerateBlocks(ctxb, numBlocks); err != nil { 1411 t.Fatalf("unable to generate single block: %v", err) 1412 } 1413 _, spendHeight, err = miner.Node.GetBestBlock(ctxb) 1414 if err != nil { 1415 t.Fatalf("unable to retrieve current height: %v", err) 1416 } 1417 1418 select { 1419 case spendDetails := <-spendIntent.Spend: 1420 checkNotificationFields( 1421 spendDetails, outpoint, spendTxHash, spendHeight, t, 1422 ) 1423 case <-time.After(5 * time.Second): 1424 t.Fatal("expected spend notification to be dispatched") 1425 } 1426 } 1427 1428 // testCatchUpClientOnMissedBlocks tests the case of multiple registered client 1429 // receiving historical block epoch notifications due to their best known block 1430 // being out of date. 1431 func testCatchUpClientOnMissedBlocks(miner *rpctest.Harness, vw *rpctest.VotingWallet, 1432 notifier chainntnfs.TestChainNotifier, t *testing.T) { 1433 1434 const numBlocks = 10 1435 const numClients = 5 1436 var wg sync.WaitGroup 1437 1438 outdatedHash, outdatedHeight, err := miner.Node.GetBestBlock(ctxb) 1439 if err != nil { 1440 t.Fatalf("unable to retrieve current height: %v", err) 1441 } 1442 1443 // This function is used by UnsafeStart to ensure all notifications 1444 // are fully drained before clients register for notifications. 1445 generateBlocks := func() error { 1446 _, err = vw.GenerateBlocks(ctxb, numBlocks) 1447 return err 1448 } 1449 1450 // We want to ensure that when a client registers for block notifications, 1451 // the notifier's best block is at the tip of the chain. If it isn't, the 1452 // client may not receive all historical notifications. 1453 bestHeight := outdatedHeight + numBlocks 1454 err = notifier.UnsafeStart(bestHeight, nil, bestHeight, generateBlocks) 1455 if err != nil { 1456 t.Fatalf("unable to unsafe start the notifier: %v", err) 1457 } 1458 defer notifier.Stop() 1459 1460 // Create numClients clients whose best known block is 10 blocks behind 1461 // the tip of the chain. We expect each client to receive numBlocks 1462 // notifications, 1 for each block they're behind. 1463 clients := make([]*chainntnfs.BlockEpochEvent, 0, numClients) 1464 outdatedBlock := &chainntnfs.BlockEpoch{ 1465 Height: int32(outdatedHeight), Hash: outdatedHash, 1466 } 1467 for i := 0; i < numClients; i++ { 1468 epochClient, err := notifier.RegisterBlockEpochNtfn(outdatedBlock) 1469 if err != nil { 1470 t.Fatalf("unable to register for epoch notification: %v", err) 1471 } 1472 clients = append(clients, epochClient) 1473 } 1474 for expectedHeight := outdatedHeight + 1; expectedHeight <= 1475 bestHeight; expectedHeight++ { 1476 1477 for _, epochClient := range clients { 1478 select { 1479 case block := <-epochClient.Epochs: 1480 if block.Height != int32(expectedHeight) { 1481 t.Fatalf("received block of height: %d, "+ 1482 "expected: %d", block.Height, 1483 expectedHeight) 1484 } 1485 case <-time.After(20 * time.Second): 1486 t.Fatalf("did not receive historical notification "+ 1487 "for height %d", expectedHeight) 1488 } 1489 1490 } 1491 } 1492 1493 // Finally, ensure that an extra block notification wasn't received. 1494 anyExtras := make(chan struct{}, len(clients)) 1495 for _, epochClient := range clients { 1496 wg.Add(1) 1497 go func(epochClient *chainntnfs.BlockEpochEvent) { 1498 defer wg.Done() 1499 select { 1500 case <-epochClient.Epochs: 1501 anyExtras <- struct{}{} 1502 case <-time.After(5 * time.Second): 1503 } 1504 }(epochClient) 1505 } 1506 1507 wg.Wait() 1508 close(anyExtras) 1509 1510 var extraCount int 1511 for range anyExtras { 1512 extraCount++ 1513 } 1514 1515 if extraCount > 0 { 1516 t.Fatalf("received %d unexpected block notification", extraCount) 1517 } 1518 } 1519 1520 // testCatchUpOnMissedBlocks the case of multiple registered clients receiving 1521 // historical block epoch notifications due to the notifier's best known block 1522 // being out of date. 1523 func testCatchUpOnMissedBlocks(miner *rpctest.Harness, vw *rpctest.VotingWallet, 1524 notifier chainntnfs.TestChainNotifier, t *testing.T) { 1525 1526 const numBlocks = 10 1527 const numClients = 5 1528 var wg sync.WaitGroup 1529 1530 _, bestHeight, err := miner.Node.GetBestBlock(ctxb) 1531 if err != nil { 1532 t.Fatalf("unable to get current blockheight %v", err) 1533 } 1534 1535 // This function is used by UnsafeStart to ensure all notifications 1536 // are fully drained before clients register for notifications. 1537 generateBlocks := func() error { 1538 _, err = vw.GenerateBlocks(ctxb, numBlocks) 1539 return err 1540 } 1541 1542 // Next, start the notifier with outdated best block information. 1543 err = notifier.UnsafeStart( 1544 bestHeight, nil, bestHeight+numBlocks, generateBlocks, 1545 ) 1546 if err != nil { 1547 t.Fatalf("unable to unsafe start the notifier: %v", err) 1548 } 1549 defer notifier.Stop() 1550 1551 // Create numClients clients who will listen for block notifications. 1552 clients := make([]*chainntnfs.BlockEpochEvent, 0, numClients) 1553 for i := 0; i < numClients; i++ { 1554 epochClient, err := notifier.RegisterBlockEpochNtfn(nil) 1555 if err != nil { 1556 t.Fatalf("unable to register for epoch notification: %v", err) 1557 } 1558 1559 // Drain the notification dispatched upon registration as we're 1560 // not interested in it. 1561 select { 1562 case <-epochClient.Epochs: 1563 case <-time.After(5 * time.Second): 1564 t.Fatal("expected to receive epoch for current block " + 1565 "upon registration") 1566 } 1567 1568 clients = append(clients, epochClient) 1569 } 1570 1571 // Generate a single block to trigger the backlog of historical 1572 // notifications for the previously mined blocks. 1573 if _, err := vw.GenerateBlocks(ctxb, 1); err != nil { 1574 t.Fatalf("unable to generate blocks: %v", err) 1575 } 1576 1577 // We expect each client to receive numBlocks + 1 notifications, 1 for 1578 // each block that the notifier has missed out on. 1579 for expectedHeight := bestHeight + 1; expectedHeight <= 1580 bestHeight+numBlocks+1; expectedHeight++ { 1581 1582 for _, epochClient := range clients { 1583 select { 1584 case block := <-epochClient.Epochs: 1585 if int64(block.Height) != expectedHeight { 1586 t.Fatalf("received block of height: %d, "+ 1587 "expected: %d", block.Height, 1588 expectedHeight) 1589 } 1590 case <-time.After(20 * time.Second): 1591 t.Fatalf("did not receive historical notification "+ 1592 "for height %d", expectedHeight) 1593 } 1594 } 1595 } 1596 1597 // Finally, ensure that an extra block notification wasn't received. 1598 anyExtras := make(chan struct{}, len(clients)) 1599 for _, epochClient := range clients { 1600 wg.Add(1) 1601 go func(epochClient *chainntnfs.BlockEpochEvent) { 1602 defer wg.Done() 1603 select { 1604 case <-epochClient.Epochs: 1605 anyExtras <- struct{}{} 1606 case <-time.After(5 * time.Second): 1607 } 1608 }(epochClient) 1609 } 1610 1611 wg.Wait() 1612 close(anyExtras) 1613 1614 var extraCount int 1615 for range anyExtras { 1616 extraCount++ 1617 } 1618 1619 if extraCount > 0 { 1620 t.Fatalf("received %d unexpected block notification", extraCount) 1621 } 1622 } 1623 1624 // testCatchUpOnMissedBlocks tests that a client will still receive all valid 1625 // block notifications in the case where a notifier's best block has been reorged 1626 // out of the chain. 1627 func testCatchUpOnMissedBlocksWithReorg(miner1 *rpctest.Harness, vw *rpctest.VotingWallet, 1628 notifier chainntnfs.TestChainNotifier, t *testing.T) { 1629 1630 const numBlocks = 10 1631 const numClients = 5 1632 var wg sync.WaitGroup 1633 1634 // Set up a new miner that we can use to cause a reorg. 1635 miner2, err := testutils.NewSetupRPCTest( 1636 testctx.New(t), 5, netParams, nil, []string{"--txindex"}, false, 0, 1637 ) 1638 if err != nil { 1639 t.Fatalf("unable to create mining node: %v", err) 1640 } 1641 defer func() { 1642 time.Sleep(time.Millisecond * 50) 1643 miner2.TearDown() 1644 }() 1645 1646 // We start by connecting the new miner to our original miner, 1647 // such that it will sync to our original chain. 1648 if err := rpctest.ConnectNode(ctxb, miner1, miner2); err != nil { 1649 t.Fatalf("unable to connect harnesses: %v", err) 1650 } 1651 nodeSlice := []*rpctest.Harness{miner1, miner2} 1652 if err := rpctest.JoinNodes(ctxb, nodeSlice, rpctest.Blocks); err != nil { 1653 t.Fatalf("unable to join node on blocks: %v", err) 1654 } 1655 1656 // The two should be on the same blockheight. 1657 _, nodeHeight1, err := miner1.Node.GetBestBlock(ctxb) 1658 if err != nil { 1659 t.Fatalf("unable to get current blockheight %v", err) 1660 } 1661 1662 _, nodeHeight2, err := miner2.Node.GetBestBlock(ctxb) 1663 if err != nil { 1664 t.Fatalf("unable to get current blockheight %v", err) 1665 } 1666 1667 if nodeHeight1 != nodeHeight2 { 1668 t.Fatalf("expected both miners to be on the same height: %v vs %v", 1669 nodeHeight1, nodeHeight2) 1670 } 1671 1672 // We disconnect the two nodes, such that we can start mining on them 1673 // individually without the other one learning about the new blocks. 1674 err = rpctest.RemoveNode(ctxb, miner1, miner2) 1675 if err != nil { 1676 t.Fatalf("unable to remove node: %v", err) 1677 } 1678 1679 // Now mine on each chain separately 1680 blocks, err := vw.GenerateBlocks(ctxb, numBlocks) 1681 if err != nil { 1682 t.Fatalf("unable to generate single block: %v", err) 1683 } 1684 1685 // We generate an extra block on miner 2's chain to ensure it is the 1686 // longer chain. 1687 _, err = rpctest.AdjustedSimnetMiner(ctxb, miner2.Node, numBlocks+1) 1688 if err != nil { 1689 t.Fatalf("unable to generate single block: %v", err) 1690 } 1691 1692 // Sync the two chains to ensure they will sync to miner2's chain. 1693 if err := rpctest.ConnectNode(ctxb, miner1, miner2); err != nil { 1694 t.Fatalf("unable to connect harnesses: %v", err) 1695 } 1696 nodeSlice = []*rpctest.Harness{miner1, miner2} 1697 if err := rpctest.JoinNodes(ctxb, nodeSlice, rpctest.Blocks); err != nil { 1698 t.Fatalf("unable to join node on blocks: %v", err) 1699 } 1700 1701 // The two should be on the same block hash. 1702 timeout := time.After(10 * time.Second) 1703 for { 1704 nodeHash1, _, err := miner1.Node.GetBestBlock(ctxb) 1705 if err != nil { 1706 t.Fatalf("unable to get current block hash: %v", err) 1707 } 1708 1709 nodeHash2, _, err := miner2.Node.GetBestBlock(ctxb) 1710 if err != nil { 1711 t.Fatalf("unable to get current block hash: %v", err) 1712 } 1713 1714 if *nodeHash1 == *nodeHash2 { 1715 break 1716 } 1717 select { 1718 case <-timeout: 1719 t.Fatalf("Unable to sync two chains") 1720 case <-time.After(50 * time.Millisecond): 1721 continue 1722 } 1723 } 1724 1725 // Next, start the notifier with outdated best block information. 1726 // We set the notifier's best block to be the last block mined on the 1727 // shorter chain, to test that the notifier correctly rewinds to 1728 // the common ancestor between the two chains. 1729 syncHeight := nodeHeight1 + numBlocks + 1 1730 err = notifier.UnsafeStart( 1731 nodeHeight1+numBlocks, blocks[numBlocks-1], syncHeight, nil, 1732 ) 1733 if err != nil { 1734 t.Fatalf("Unable to unsafe start the notifier: %v", err) 1735 } 1736 defer notifier.Stop() 1737 1738 // Create numClients clients who will listen for block notifications. 1739 clients := make([]*chainntnfs.BlockEpochEvent, 0, numClients) 1740 for i := 0; i < numClients; i++ { 1741 epochClient, err := notifier.RegisterBlockEpochNtfn(nil) 1742 if err != nil { 1743 t.Fatalf("unable to register for epoch notification: %v", err) 1744 } 1745 1746 // Drain the notification dispatched upon registration as we're 1747 // not interested in it. 1748 select { 1749 case <-epochClient.Epochs: 1750 case <-time.After(5 * time.Second): 1751 t.Fatal("expected to receive epoch for current block " + 1752 "upon registration") 1753 } 1754 1755 clients = append(clients, epochClient) 1756 } 1757 1758 // Generate a single block, which should trigger the notifier to rewind 1759 // to the common ancestor and dispatch notifications from there. 1760 _, err = rpctest.AdjustedSimnetMiner(ctxb, miner2.Node, 1) 1761 if err != nil { 1762 t.Fatalf("unable to generate single block: %v", err) 1763 } 1764 1765 // If the chain backend to the notifier stores information about reorged 1766 // blocks, the notifier is able to rewind the chain to the common 1767 // ancestor between the chain tip and its outdated best known block. 1768 // In this case, the client is expected to receive numBlocks + 2 1769 // notifications, 1 for each block the notifier has missed out on from 1770 // the longer chain. 1771 // 1772 // If the chain backend does not store information about reorged blocks, 1773 // the notifier has no way of knowing where to rewind to and therefore 1774 // the client is only expected to receive notifications for blocks 1775 // whose height is greater than the notifier's best known height: 2 1776 // notifications, in this case. 1777 var startingHeight int64 1778 switch notifier.(type) { 1779 default: 1780 startingHeight = nodeHeight1 + 1 1781 } 1782 1783 for expectedHeight := startingHeight; expectedHeight <= 1784 nodeHeight1+numBlocks+2; expectedHeight++ { 1785 1786 for _, epochClient := range clients { 1787 select { 1788 case block := <-epochClient.Epochs: 1789 if int64(block.Height) != expectedHeight { 1790 t.Fatalf("received block of height: %d, "+ 1791 "expected: %d", block.Height, 1792 expectedHeight) 1793 } 1794 case <-time.After(20 * time.Second): 1795 t.Fatalf("did not receive historical notification "+ 1796 "for height %d", expectedHeight) 1797 } 1798 } 1799 } 1800 1801 // Finally, ensure that an extra block notification wasn't received. 1802 anyExtras := make(chan struct{}, len(clients)) 1803 for _, epochClient := range clients { 1804 wg.Add(1) 1805 go func(epochClient *chainntnfs.BlockEpochEvent) { 1806 defer wg.Done() 1807 select { 1808 case <-epochClient.Epochs: 1809 anyExtras <- struct{}{} 1810 case <-time.After(5 * time.Second): 1811 } 1812 }(epochClient) 1813 } 1814 1815 wg.Wait() 1816 close(anyExtras) 1817 1818 var extraCount int 1819 for range anyExtras { 1820 extraCount++ 1821 } 1822 1823 if extraCount > 0 { 1824 t.Fatalf("received %d unexpected block notification", extraCount) 1825 } 1826 } 1827 1828 type txNtfnTestCase struct { 1829 name string 1830 test func(node *rpctest.Harness, vw *rpctest.VotingWallet, notifier chainntnfs.TestChainNotifier, 1831 scriptDispatch bool, t *testing.T) 1832 } 1833 1834 type blockNtfnTestCase struct { 1835 name string 1836 test func(node *rpctest.Harness, vw *rpctest.VotingWallet, notifier chainntnfs.TestChainNotifier, 1837 t *testing.T) 1838 } 1839 1840 type blockCatchupTestCase struct { 1841 name string 1842 test func(node *rpctest.Harness, vw *rpctest.VotingWallet, notifier chainntnfs.TestChainNotifier, 1843 t *testing.T) 1844 } 1845 1846 var txNtfnTests = []txNtfnTestCase{ 1847 // These tests needs come before the others to prevent the reorg 1848 // messing with stake voting. 1849 { 1850 name: "reorg conf", 1851 test: testReorgConf, 1852 }, 1853 { 1854 name: "reorg spend", 1855 test: testReorgSpend, 1856 }, 1857 { 1858 name: "single conf ntfn", 1859 test: testSingleConfirmationNotification, 1860 }, 1861 { 1862 name: "multi conf ntfn", 1863 test: testMultiConfirmationNotification, 1864 }, 1865 { 1866 name: "batch conf ntfn", 1867 test: testBatchConfirmationNotification, 1868 }, 1869 { 1870 name: "multi client conf", 1871 test: testMultiClientConfirmationNotification, 1872 }, 1873 { 1874 name: "lazy ntfn consumer", 1875 test: testLazyNtfnConsumer, 1876 }, 1877 { 1878 name: "historical conf dispatch", 1879 test: testTxConfirmedBeforeNtfnRegistration, 1880 }, 1881 { 1882 name: "spend ntfn", 1883 test: testSpendNotification, 1884 }, 1885 { 1886 name: "historical spend dispatch", 1887 test: testSpendBeforeNtfnRegistration, 1888 }, 1889 { 1890 name: "cancel spend ntfn", 1891 test: testCancelSpendNtfn, 1892 }, 1893 } 1894 1895 var blockNtfnTests = []blockNtfnTestCase{ 1896 { 1897 name: "block epoch", 1898 test: testBlockEpochNotification, 1899 }, 1900 { 1901 name: "cancel epoch ntfn", 1902 test: testCancelEpochNtfn, 1903 }, 1904 } 1905 1906 var blockCatchupTests = []blockCatchupTestCase{ 1907 // This test needs to come first to prevent it messing with stake 1908 // transactions for the others. 1909 { 1910 name: "test catch up on missed blocks w/ reorged best block", 1911 test: testCatchUpOnMissedBlocksWithReorg, 1912 }, 1913 { 1914 name: "catch up client on historical block epoch ntfns", 1915 test: testCatchUpClientOnMissedBlocks, 1916 }, 1917 { 1918 name: "test catch up on missed blocks", 1919 test: testCatchUpOnMissedBlocks, 1920 }, 1921 } 1922 1923 // TestInterfaces tests all registered interfaces with a unified set of tests 1924 // which exercise each of the required methods found within the ChainNotifier 1925 // interface. 1926 // 1927 // NOTE: In the future, when additional implementations of the ChainNotifier 1928 // interface have been implemented, in order to ensure the new concrete 1929 // implementation is automatically tested, two steps must be undertaken. First, 1930 // one needs add a "non-captured" (_) import from the new sub-package. This 1931 // import should trigger an init() method within the package which registers 1932 // the interface. Second, an additional case in the switch within the main loop 1933 // below needs to be added which properly initializes the interface. 1934 // 1935 // syncerType may be "dcrd" or "spv", depending on what the backing wallet 1936 // should be syncing to. This is only applicable to the dcrw and remotedcrw 1937 // notifier types. 1938 func TestInterfaces(t *testing.T, notifierType, syncerType string) { 1939 t.Parallel() 1940 1941 if chainntnfs.NotifierByName(notifierType) == nil { 1942 t.Fatalf("Notifier %s does not exist", notifierType) 1943 } 1944 1945 // newMiner initializes a new rpctest harness for testing and returns 1946 // that. 1947 newMiner := func(t *testing.T, notifierType string) (*rpctest.Harness, *rpctest.VotingWallet, func()) { 1948 // Initialize the harness around a dcrd node which will serve as our 1949 // dedicated miner to generate blocks, cause re-orgs, etc. We'll set up 1950 // this node with a chain length of 125, so we have plenty of DCR to 1951 // play around with. 1952 minerLogDir := fmt.Sprintf(".miner-logs-%s-%s", notifierType, syncerType) 1953 minerArgs := []string{"--debuglevel=debug", "--logdir=" + minerLogDir} 1954 1955 miner, err := testutils.NewSetupRPCTest( 1956 testctx.New(t), 5, netParams, nil, minerArgs, false, 0, 1957 ) 1958 if err != nil { 1959 t.Fatalf("unable to create backend node: %v", err) 1960 } 1961 1962 // Generate the premine block the usual way. 1963 _, err = miner.Node.Generate(ctxb, 1) 1964 if err != nil { 1965 t.Fatalf("unable to generate premine: %v", err) 1966 } 1967 1968 // Generate enough blocks so that the network harness can have 1969 // funds to send to the voting wallet, Alice and Bob. 1970 _, err = rpctest.AdjustedSimnetMiner(ctxb, miner.Node, 64) 1971 if err != nil { 1972 t.Fatalf("unable to init chain: %v", err) 1973 } 1974 1975 vw, err := rpctest.NewVotingWallet(ctxb, miner) 1976 if err != nil { 1977 t.Fatalf("unable to create voting wallet: %v", err) 1978 } 1979 1980 // Use a custom miner on the voting wallet that ensures simnet blocks 1981 // are generated as fast as possible without triggering PoW difficulty 1982 // increases. 1983 vw.SetMiner(func(ctx context.Context, nb uint32) ([]*chainhash.Hash, error) { 1984 return rpctest.AdjustedSimnetMiner(ctxb, miner.Node, nb) 1985 }) 1986 1987 vwCtx, vwCancel := context.WithCancel(ctxb) 1988 err = vw.Start(vwCtx) 1989 if err != nil { 1990 t.Fatalf("unable to start voting wallet: %v", err) 1991 } 1992 1993 tearDown := func() { 1994 vwCancel() 1995 miner.TearDown() 1996 } 1997 1998 return miner, vw, tearDown 1999 } 2000 2001 newNotifier := func(t *testing.T, notifierType string, startNotifier bool, miner *rpctest.Harness) (chainntnfs.TestChainNotifier, func()) { 2002 // Initialize a height hint cache for each notifier. 2003 tempDir, err := ioutil.TempDir("", "channeldb") 2004 if err != nil { 2005 t.Fatalf("unable to create temp dir: %v", err) 2006 } 2007 db, err := channeldb.Open(tempDir) 2008 if err != nil { 2009 t.Fatalf("unable to create db: %v", err) 2010 } 2011 testCfg := chainntnfs.CacheConfig{ 2012 QueryDisable: false, 2013 } 2014 hintCache, err := chainntnfs.NewHeightHintCache( 2015 testCfg, db.Backend, 2016 ) 2017 if err != nil { 2018 t.Fatalf("unable to create height hint cache: %v", err) 2019 } 2020 2021 var notifier chainntnfs.TestChainNotifier 2022 var tearDownNotifier func() 2023 switch notifierType { 2024 case "dcrd": 2025 backend := miner.RPCConfig() 2026 notifier, err = dcrdnotify.New( 2027 &backend, netParams, hintCache, 2028 hintCache, nil, 2029 ) 2030 if err != nil { 2031 t.Fatalf("error initializing dcrd notifier: %v", err) 2032 } 2033 2034 case "dcrw": 2035 var w *wallet.Wallet 2036 var teardown func() 2037 switch syncerType { 2038 case "dcrd": 2039 backend := miner.RPCConfig() 2040 w, teardown = testutils.NewRPCSyncingTestWallet(t, &backend) 2041 case "spv": 2042 w, teardown = testutils.NewSPVSyncingTestWallet(t, miner.P2PAddress()) 2043 default: 2044 t.Fatalf("unknown syncer type %s", syncerType) 2045 } 2046 2047 notifier, err = dcrwnotify.New( 2048 w, netParams, hintCache, hintCache, nil, 2049 ) 2050 if err != nil { 2051 t.Fatalf("error initializing dcrw notifier: %v", err) 2052 } 2053 tearDownNotifier = teardown 2054 2055 case "remotedcrw": 2056 var c *grpc.ClientConn 2057 var teardown func() 2058 switch syncerType { 2059 case "dcrd": 2060 backend := miner.RPCConfig() 2061 c, teardown = testutils.NewRPCSyncingTestRemoteDcrwallet(t, &backend) 2062 case "spv": 2063 c, teardown = testutils.NewSPVSyncingTestRemoteDcrwallet(t, miner.P2PAddress()) 2064 default: 2065 t.Fatalf("unknown syncer type %s", syncerType) 2066 } 2067 notifier, err = remotedcrwnotify.New( 2068 c, netParams, hintCache, hintCache, nil, 2069 ) 2070 if err != nil { 2071 t.Fatalf("error initializing dcrw notifier: %v", err) 2072 } 2073 tearDownNotifier = teardown 2074 2075 default: 2076 t.Fatalf("unknown notifier type: %v", notifierType) 2077 } 2078 2079 if startNotifier { 2080 if err := notifier.Start(); err != nil { 2081 t.Fatalf("unable to start notifier %v: %v", 2082 notifierType, err) 2083 } 2084 } 2085 2086 cleanUp := func() { 2087 if startNotifier { 2088 notifier.Stop() 2089 } 2090 if tearDownNotifier != nil { 2091 tearDownNotifier() 2092 } 2093 } 2094 2095 return notifier, cleanUp 2096 } 2097 2098 log.Printf("Running %v ChainNotifier interface tests", len(txNtfnTests)) 2099 2100 miner, vw, tearDownMiner := newMiner(t, notifierType) 2101 defer tearDownMiner() 2102 2103 notifier, tearDownNotifier := newNotifier( 2104 t, notifierType, true, miner, 2105 ) 2106 defer tearDownNotifier() 2107 2108 for _, txNtfnTest := range txNtfnTests { 2109 for _, scriptDispatch := range []bool{false, true} { 2110 testName := txNtfnTest.name 2111 if scriptDispatch { 2112 testName += " with script dispatch" 2113 } 2114 success := t.Run(testName, func(t *testing.T) { 2115 txNtfnTest.test( 2116 miner, vw, notifier, 2117 scriptDispatch, t, 2118 ) 2119 }) 2120 if !success { 2121 return 2122 } 2123 } 2124 } 2125 2126 for _, blockNtfnTest := range blockNtfnTests { 2127 testName := blockNtfnTest.name 2128 success := t.Run(testName, func(t *testing.T) { 2129 blockNtfnTest.test(miner, vw, notifier, t) 2130 }) 2131 if !success { 2132 return 2133 } 2134 } 2135 2136 // The first test for the next set of tests causes a 2137 // reorg, so recreate a new miner. 2138 miner, vw, tearDownMiner = newMiner(t, notifierType) 2139 defer tearDownMiner() 2140 2141 // Run catchup tests separately since they require restarting 2142 // the notifier every time. 2143 for _, blockCatchupTest := range blockCatchupTests { 2144 testName := blockCatchupTest.name 2145 2146 success := t.Run(testName, func(t *testing.T) { 2147 notifier, tearDownNotifier := newNotifier( 2148 t, notifierType, false, miner, 2149 ) 2150 defer tearDownNotifier() 2151 blockCatchupTest.test(miner, vw, notifier, t) 2152 }) 2153 if !success { 2154 return 2155 } 2156 } 2157 }