diff --git a/chainntnfs/interface_test.go b/chainntnfs/interface_test.go index f59582fe1..dc8599265 100644 --- a/chainntnfs/interface_test.go +++ b/chainntnfs/interface_test.go @@ -509,36 +509,54 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness, // spending from a coinbase output here, so we use the dedicated // function. - txid, err := getTestTxId(miner) + txid3, err := getTestTxId(miner) if err != nil { t.Fatalf("unable to create test tx: %v", err) } - // Now generate one block. The notifier must check older blocks when - // the confirmation event is registered below to ensure that the TXID - // hasn't already been included in the chain, otherwise the + // Generate another block containing tx 3, but we won't register conf + // notifications for this tx until much later. The notifier must check + // older blocks when the confirmation event is registered below to ensure + // that the TXID hasn't already been included in the chain, otherwise the // notification will never be sent. - blockHash, err := miner.Node.Generate(1) + _, err = miner.Node.Generate(1) if err != nil { t.Fatalf("unable to generate block: %v", err) } + txid1, err := getTestTxId(miner) + if err != nil { + t.Fatalf("unable to create test tx: %v", err) + } + + txid2, err := getTestTxId(miner) + if err != nil { + t.Fatalf("unable to create test tx: %v", err) + } + _, currentHeight, err := miner.Node.GetBestBlock() if err != nil { t.Fatalf("unable to get current height: %v", err) } - // Now that we have a txid, register a confirmation notification with - // the chainntfn source. - numConfs := uint32(1) - confIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs, + // Now generate another block containing txs 1 & 2. + blockHash, err := miner.Node.Generate(1) + if err != nil { + t.Fatalf("unable to generate block: %v", err) + } + + // Register a confirmation notification with the chainntfn source for tx2, + // which is included in the last block. The height hint is the height before + // the block is included. This notification should fire immediately since + // only 1 confirmation is required. + ntfn1, err := notifier.RegisterConfirmationsNtfn(txid1, 1, uint32(currentHeight)) if err != nil { t.Fatalf("unable to register ntfn: %v", err) } select { - case confInfo := <-confIntent.Confirmed: + case confInfo := <-ntfn1.Confirmed: // Finally, we'll verify that the tx index returned is the exact same // as the tx index of the transaction within the block itself. msgBlock, err := miner.Node.GetBlock(blockHash[0]) @@ -550,14 +568,14 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness, if err != nil { t.Fatalf("unable to index into block: %v", err) } - if !specifiedTxHash.IsEqual(txid) { + if !specifiedTxHash.IsEqual(txid1) { t.Fatalf("mismatched tx indexes: expected %v, got %v", - txid, specifiedTxHash) + txid1, specifiedTxHash) } // We'll also ensure that the block height has been set // properly. - if confInfo.BlockHeight != uint32(currentHeight) { + if confInfo.BlockHeight != uint32(currentHeight+1) { t.Fatalf("incorrect block height: expected %v, got %v", confInfo.BlockHeight, currentHeight) } @@ -566,76 +584,61 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness, t.Fatalf("confirmation notification never received") } - // Next, we want to test fully dispatching the notification for a - // transaction that has been *partially* confirmed. So we'll create - // another test txid. - txid, err = getTestTxId(miner) - if err != nil { - t.Fatalf("unable to create test tx: %v", err) - } - - _, currentHeight, err = miner.Node.GetBestBlock() - if err != nil { - t.Fatalf("unable to get current height: %v", err) - } - - // We'll request 6 confirmations for the above generated txid, but we - // will generate the confirmations in chunks. - numConfs = 6 - - time.Sleep(time.Second * 2) - - // First, generate 2 confirmations. - if _, err := miner.Node.Generate(2); err != nil { - t.Fatalf("unable to generate blocks: %v", err) - } - - time.Sleep(time.Second * 2) - - // Next, register for the notification *after* the transition has - // already been partially confirmed. - confIntent, err = notifier.RegisterConfirmationsNtfn(txid, numConfs, + // Register a confirmation notification for tx2, requiring 3 confirmations. + // This transaction is only partially confirmed, so the notification should + // not fire yet. + ntfn2, err := notifier.RegisterConfirmationsNtfn(txid2, 3, uint32(currentHeight)) if err != nil { t.Fatalf("unable to register ntfn: %v", err) } - // We shouldn't receive a notification at this point, as the - // transaction hasn't yet been fully confirmed. - select { - case <-confIntent.Confirmed: - t.Fatalf("received confirmation notification but shouldn't " + - "have") - default: - // Expected case - } - - // With the notification registered, generate another 3 blocks, this - // shouldn't yet dispatch the notification. - if _, err := miner.Node.Generate(3); err != nil { - t.Fatalf("unable to generate blocks: %v", err) + // Fully confirm tx3. + _, err = miner.Node.Generate(2) + if err != nil { + t.Fatalf("unable to generate block: %v", err) } select { - case <-confIntent.Confirmed: - t.Fatalf("received confirmation notification but shouldn't " + - "have") - default: - // Expected case - } - - // Finally, we'll mine the final block which should dispatch the - // notification. - if _, err := miner.Node.Generate(1); err != nil { - t.Fatalf("unable to generate blocks: %v", err) - } - - select { - case <-confIntent.Confirmed: - break - case <-time.After(30 * time.Second): + case <-ntfn2.Confirmed: + case <-time.After(10 * time.Second): t.Fatalf("confirmation notification never received") } + + select { + case <-ntfn1.Confirmed: + t.Fatalf("received multiple confirmations for tx") + case <-time.After(1 * time.Second): + } + + // Finally register a confirmation notification for tx3, requiring 1 + // confirmation. Ensure that conf notifications do not refire on txs + // 1 or 2. + ntfn3, err := notifier.RegisterConfirmationsNtfn(txid3, 1, + uint32(currentHeight-1)) + if err != nil { + t.Fatalf("unable to register ntfn: %v", err) + } + + select { + case <-ntfn3.Confirmed: + case <-time.After(10 * time.Second): + t.Fatalf("confirmation notification never received") + } + + time.Sleep(1 * time.Second) + + select { + case <-ntfn1.Confirmed: + t.Fatalf("received multiple confirmations for tx") + default: + } + + select { + case <-ntfn2.Confirmed: + t.Fatalf("received multiple confirmations for tx") + default: + } } // Test the case of a notification consumer having forget or being delayed in