chainntnfs/interface_test: add script dispatch test cases

This commit is contained in:
Wilmer Paulino
2018-12-06 21:14:37 -08:00
parent 83c7f204cd
commit 5ab30cf7ea

View File

@ -16,29 +16,18 @@ import (
"github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/chain"
_ "github.com/btcsuite/btcwallet/walletdb/bdb" // Required to auto-register the boltdb walletdb implementation.
"github.com/lightninglabs/neutrino" "github.com/lightninglabs/neutrino"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
// Required to auto-register the bitcoind backed ChainNotifier
// implementation.
"github.com/lightningnetwork/lnd/chainntnfs/bitcoindnotify" "github.com/lightningnetwork/lnd/chainntnfs/bitcoindnotify"
// Required to auto-register the btcd backed ChainNotifier
// implementation.
"github.com/lightningnetwork/lnd/chainntnfs/btcdnotify" "github.com/lightningnetwork/lnd/chainntnfs/btcdnotify"
// Required to auto-register the neutrino backed ChainNotifier
// implementation.
"github.com/lightningnetwork/lnd/chainntnfs/neutrinonotify" "github.com/lightningnetwork/lnd/chainntnfs/neutrinonotify"
"github.com/lightningnetwork/lnd/channeldb"
// Required to register the boltdb walletdb implementation.
"github.com/btcsuite/btcwallet/chain"
_ "github.com/btcsuite/btcwallet/walletdb/bdb"
) )
func testSingleConfirmationNotification(miner *rpctest.Harness, func testSingleConfirmationNotification(miner *rpctest.Harness,
notifier chainntnfs.TestChainNotifier, t *testing.T) { notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) {
// We'd like to test the case of being notified once a txid reaches // We'd like to test the case of being notified once a txid reaches
// a *single* confirmation. // a *single* confirmation.
@ -62,9 +51,16 @@ func testSingleConfirmationNotification(miner *rpctest.Harness,
// Now that we have a txid, register a confirmation notification with // Now that we have a txid, register a confirmation notification with
// the chainntfn source. // the chainntfn source.
numConfs := uint32(1) numConfs := uint32(1)
confIntent, err := notifier.RegisterConfirmationsNtfn( var confIntent *chainntnfs.ConfirmationEvent
txid, pkScript, numConfs, uint32(currentHeight), if scriptDispatch {
) confIntent, err = notifier.RegisterConfirmationsNtfn(
nil, pkScript, numConfs, uint32(currentHeight),
)
} else {
confIntent, err = notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register ntfn: %v", err) t.Fatalf("unable to register ntfn: %v", err)
} }
@ -106,7 +102,7 @@ func testSingleConfirmationNotification(miner *rpctest.Harness,
} }
func testMultiConfirmationNotification(miner *rpctest.Harness, func testMultiConfirmationNotification(miner *rpctest.Harness,
notifier chainntnfs.TestChainNotifier, t *testing.T) { notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) {
// We'd like to test the case of being notified once a txid reaches // We'd like to test the case of being notified once a txid reaches
// N confirmations, where N > 1. // N confirmations, where N > 1.
@ -127,9 +123,16 @@ func testMultiConfirmationNotification(miner *rpctest.Harness,
} }
numConfs := uint32(6) numConfs := uint32(6)
confIntent, err := notifier.RegisterConfirmationsNtfn( var confIntent *chainntnfs.ConfirmationEvent
txid, pkScript, numConfs, uint32(currentHeight), if scriptDispatch {
) confIntent, err = notifier.RegisterConfirmationsNtfn(
nil, pkScript, numConfs, uint32(currentHeight),
)
} else {
confIntent, err = notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register ntfn: %v", err) t.Fatalf("unable to register ntfn: %v", err)
} }
@ -152,7 +155,7 @@ func testMultiConfirmationNotification(miner *rpctest.Harness,
} }
func testBatchConfirmationNotification(miner *rpctest.Harness, func testBatchConfirmationNotification(miner *rpctest.Harness,
notifier chainntnfs.TestChainNotifier, t *testing.T) { notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) {
// We'd like to test a case of serving notifications to multiple // We'd like to test a case of serving notifications to multiple
// clients, each requesting to be notified once a txid receives // clients, each requesting to be notified once a txid receives
@ -174,9 +177,16 @@ func testBatchConfirmationNotification(miner *rpctest.Harness,
if err != nil { if err != nil {
t.Fatalf("unable to create test addr: %v", err) t.Fatalf("unable to create test addr: %v", err)
} }
confIntent, err := notifier.RegisterConfirmationsNtfn( var confIntent *chainntnfs.ConfirmationEvent
txid, pkScript, numConfs, uint32(currentHeight), if scriptDispatch {
) confIntent, err = notifier.RegisterConfirmationsNtfn(
nil, pkScript, numConfs, uint32(currentHeight),
)
} else {
confIntent, err = notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register ntfn: %v", err) t.Fatalf("unable to register ntfn: %v", err)
} }
@ -257,13 +267,13 @@ func checkNotificationFields(ntfn *chainntnfs.SpendDetail,
} }
func testSpendNotification(miner *rpctest.Harness, func testSpendNotification(miner *rpctest.Harness,
notifier chainntnfs.TestChainNotifier, t *testing.T) { notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) {
// We'd like to test the spend notifications for all ChainNotifier // We'd like to test the spend notifications for all ChainNotifier
// concrete implementations. // concrete implementations.
// //
// To do so, we first create a new output to our test target address. // To do so, we first create a new output to our test target address.
outpoint, pkScript := chainntnfs.CreateSpendableOutput(t, miner) outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner)
_, currentHeight, err := miner.Node.GetBestBlock() _, currentHeight, err := miner.Node.GetBestBlock()
if err != nil { if err != nil {
@ -277,9 +287,16 @@ func testSpendNotification(miner *rpctest.Harness,
const numClients = 5 const numClients = 5
spendClients := make([]*chainntnfs.SpendEvent, numClients) spendClients := make([]*chainntnfs.SpendEvent, numClients)
for i := 0; i < numClients; i++ { for i := 0; i < numClients; i++ {
spentIntent, err := notifier.RegisterSpendNtfn( var spentIntent *chainntnfs.SpendEvent
outpoint, pkScript, uint32(currentHeight), if scriptDispatch {
) spentIntent, err = notifier.RegisterSpendNtfn(
nil, output.PkScript, uint32(currentHeight),
)
} else {
spentIntent, err = notifier.RegisterSpendNtfn(
outpoint, output.PkScript, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register for spend ntfn: %v", err) t.Fatalf("unable to register for spend ntfn: %v", err)
} }
@ -288,7 +305,7 @@ func testSpendNotification(miner *rpctest.Harness,
} }
// Next, create a new transaction spending that output. // Next, create a new transaction spending that output.
spendingTx := chainntnfs.CreateSpendTx(t, outpoint, pkScript) spendingTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey)
// Broadcast our spending transaction. // Broadcast our spending transaction.
spenderSha, err := miner.Node.SendRawTransaction(spendingTx, true) spenderSha, err := miner.Node.SendRawTransaction(spendingTx, true)
@ -328,9 +345,16 @@ func testSpendNotification(miner *rpctest.Harness,
// Make sure registering a client after the tx is in the mempool still // Make sure registering a client after the tx is in the mempool still
// doesn't trigger a notification. // doesn't trigger a notification.
spentIntent, err := notifier.RegisterSpendNtfn( var spentIntent *chainntnfs.SpendEvent
outpoint, pkScript, uint32(currentHeight), if scriptDispatch {
) spentIntent, err = notifier.RegisterSpendNtfn(
nil, output.PkScript, uint32(currentHeight),
)
} else {
spentIntent, err = notifier.RegisterSpendNtfn(
outpoint, output.PkScript, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register for spend ntfn: %v", err) t.Fatalf("unable to register for spend ntfn: %v", err)
} }
@ -416,7 +440,7 @@ func testBlockEpochNotification(miner *rpctest.Harness,
} }
func testMultiClientConfirmationNotification(miner *rpctest.Harness, func testMultiClientConfirmationNotification(miner *rpctest.Harness,
notifier chainntnfs.TestChainNotifier, t *testing.T) { notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) {
// We'd like to test the case of a multiple clients registered to // We'd like to test the case of a multiple clients registered to
// receive a confirmation notification for the same transaction. // receive a confirmation notification for the same transaction.
@ -442,9 +466,16 @@ func testMultiClientConfirmationNotification(miner *rpctest.Harness,
// Register for a conf notification for the above generated txid with // Register for a conf notification for the above generated txid with
// numConfsClients distinct clients. // numConfsClients distinct clients.
for i := 0; i < numConfsClients; i++ { for i := 0; i < numConfsClients; i++ {
confClient, err := notifier.RegisterConfirmationsNtfn( var confClient *chainntnfs.ConfirmationEvent
txid, pkScript, numConfs, uint32(currentHeight), if scriptDispatch {
) confClient, err = notifier.RegisterConfirmationsNtfn(
nil, pkScript, numConfs, uint32(currentHeight),
)
} else {
confClient, err = notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register for confirmation: %v", err) t.Fatalf("unable to register for confirmation: %v", err)
} }
@ -479,7 +510,7 @@ func testMultiClientConfirmationNotification(miner *rpctest.Harness,
// transaction that has already been included in a block. In this case, the // transaction that has already been included in a block. In this case, the
// confirmation notification should be dispatched immediately. // confirmation notification should be dispatched immediately.
func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness, func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
notifier chainntnfs.TestChainNotifier, t *testing.T) { notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) {
// First, let's send some coins to "ourself", obtaining a txid. We're // First, let's send some coins to "ourself", obtaining a txid. We're
// spending from a coinbase output here, so we use the dedicated // spending from a coinbase output here, so we use the dedicated
@ -533,9 +564,16 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
// which is included in the last block. The height hint is the height before // which is included in the last block. The height hint is the height before
// the block is included. This notification should fire immediately since // the block is included. This notification should fire immediately since
// only 1 confirmation is required. // only 1 confirmation is required.
ntfn1, err := notifier.RegisterConfirmationsNtfn( var ntfn1 *chainntnfs.ConfirmationEvent
txid1, pkScript1, 1, uint32(currentHeight), if scriptDispatch {
) ntfn1, err = notifier.RegisterConfirmationsNtfn(
nil, pkScript1, 1, uint32(currentHeight),
)
} else {
ntfn1, err = notifier.RegisterConfirmationsNtfn(
txid1, pkScript1, 1, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register ntfn: %v", err) t.Fatalf("unable to register ntfn: %v", err)
} }
@ -572,9 +610,16 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
// Register a confirmation notification for tx2, requiring 3 confirmations. // Register a confirmation notification for tx2, requiring 3 confirmations.
// This transaction is only partially confirmed, so the notification should // This transaction is only partially confirmed, so the notification should
// not fire yet. // not fire yet.
ntfn2, err := notifier.RegisterConfirmationsNtfn( var ntfn2 *chainntnfs.ConfirmationEvent
txid2, pkScript2, 3, uint32(currentHeight), if scriptDispatch {
) ntfn2, err = notifier.RegisterConfirmationsNtfn(
nil, pkScript2, 3, uint32(currentHeight),
)
} else {
ntfn2, err = notifier.RegisterConfirmationsNtfn(
txid2, pkScript2, 3, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register ntfn: %v", err) t.Fatalf("unable to register ntfn: %v", err)
} }
@ -600,9 +645,16 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
// Finally register a confirmation notification for tx3, requiring 1 // Finally register a confirmation notification for tx3, requiring 1
// confirmation. Ensure that conf notifications do not refire on txs // confirmation. Ensure that conf notifications do not refire on txs
// 1 or 2. // 1 or 2.
ntfn3, err := notifier.RegisterConfirmationsNtfn( var ntfn3 *chainntnfs.ConfirmationEvent
txid3, pkScript3, 1, uint32(currentHeight-1), if scriptDispatch {
) ntfn3, err = notifier.RegisterConfirmationsNtfn(
nil, pkScript3, 1, uint32(currentHeight-1),
)
} else {
ntfn3, err = notifier.RegisterConfirmationsNtfn(
txid3, pkScript3, 1, uint32(currentHeight-1),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register ntfn: %v", err) t.Fatalf("unable to register ntfn: %v", err)
} }
@ -632,7 +684,7 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
// checking for a confirmation. This should not cause the notifier to stop // checking for a confirmation. This should not cause the notifier to stop
// working // working
func testLazyNtfnConsumer(miner *rpctest.Harness, func testLazyNtfnConsumer(miner *rpctest.Harness,
notifier chainntnfs.TestChainNotifier, t *testing.T) { notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) {
// Create a transaction to be notified about. We'll register for // Create a transaction to be notified about. We'll register for
// notifications on this transaction but won't be prompt in checking them // notifications on this transaction but won't be prompt in checking them
@ -657,9 +709,16 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
firstConfIntent, err := notifier.RegisterConfirmationsNtfn( var firstConfIntent *chainntnfs.ConfirmationEvent
txid, pkScript, numConfs, uint32(currentHeight), if scriptDispatch {
) firstConfIntent, err = notifier.RegisterConfirmationsNtfn(
nil, pkScript, numConfs, uint32(currentHeight),
)
} else {
firstConfIntent, err = notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register ntfn: %v", err) t.Fatalf("unable to register ntfn: %v", err)
} }
@ -686,10 +745,16 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
} }
numConfs = 1 numConfs = 1
var secondConfIntent *chainntnfs.ConfirmationEvent
secondConfIntent, err := notifier.RegisterConfirmationsNtfn( if scriptDispatch {
txid, pkScript, numConfs, uint32(currentHeight), secondConfIntent, err = notifier.RegisterConfirmationsNtfn(
) nil, pkScript, numConfs, uint32(currentHeight),
)
} else {
secondConfIntent, err = notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register ntfn: %v", err) t.Fatalf("unable to register ntfn: %v", err)
} }
@ -719,16 +784,21 @@ func testLazyNtfnConsumer(miner *rpctest.Harness,
// has already been included in a block. In this case, the spend notification // has already been included in a block. In this case, the spend notification
// should be dispatched immediately. // should be dispatched immediately.
func testSpendBeforeNtfnRegistration(miner *rpctest.Harness, func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
notifier chainntnfs.TestChainNotifier, t *testing.T) { notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) {
// We'd like to test the spend notifications for all ChainNotifier // We'd like to test the spend notifications for all ChainNotifier
// concrete implementations. // concrete implementations.
// //
// To do so, we first create a new output to our test target address. // To do so, we first create a new output to our test target address.
outpoint, pkScript := chainntnfs.CreateSpendableOutput(t, miner) outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner)
_, heightHint, err := miner.Node.GetBestBlock()
if err != nil {
t.Fatalf("unable to get current height: %v", err)
}
// We'll then spend this output and broadcast the spend transaction. // We'll then spend this output and broadcast the spend transaction.
spendingTx := chainntnfs.CreateSpendTx(t, outpoint, pkScript) spendingTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey)
spenderSha, err := miner.Node.SendRawTransaction(spendingTx, true) spenderSha, err := miner.Node.SendRawTransaction(spendingTx, true)
if err != nil { if err != nil {
t.Fatalf("unable to broadcast tx: %v", err) t.Fatalf("unable to broadcast tx: %v", err)
@ -748,8 +818,7 @@ func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
if _, err := miner.Node.Generate(1); err != nil { if _, err := miner.Node.Generate(1); err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
_, spendHeight, err := miner.Node.GetBestBlock()
_, currentHeight, err := miner.Node.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to get current height: %v", err) t.Fatalf("unable to get current height: %v", err)
} }
@ -763,9 +832,17 @@ func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
const numClients = 2 const numClients = 2
spendClients := make([]*chainntnfs.SpendEvent, numClients) spendClients := make([]*chainntnfs.SpendEvent, numClients)
for i := 0; i < numClients; i++ { for i := 0; i < numClients; i++ {
spentIntent, err := notifier.RegisterSpendNtfn( var spentIntent *chainntnfs.SpendEvent
outpoint, pkScript, uint32(currentHeight), if scriptDispatch {
) spentIntent, err = notifier.RegisterSpendNtfn(
nil, output.PkScript, uint32(heightHint),
)
} else {
spentIntent, err = notifier.RegisterSpendNtfn(
outpoint, output.PkScript,
uint32(heightHint),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register for spend ntfn: %v", t.Fatalf("unable to register for spend ntfn: %v",
err) err)
@ -779,8 +856,9 @@ func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
case ntfn := <-client.Spend: case ntfn := <-client.Spend:
// We've received the spend nftn. So now verify // We've received the spend nftn. So now verify
// all the fields have been set properly. // all the fields have been set properly.
checkNotificationFields(ntfn, outpoint, spenderSha, checkNotificationFields(
currentHeight, t) ntfn, outpoint, spenderSha, spendHeight, t,
)
case <-time.After(30 * time.Second): case <-time.After(30 * time.Second):
t.Fatalf("spend ntfn never received") t.Fatalf("spend ntfn never received")
} }
@ -824,14 +902,14 @@ func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
} }
func testCancelSpendNtfn(node *rpctest.Harness, func testCancelSpendNtfn(node *rpctest.Harness,
notifier chainntnfs.TestChainNotifier, t *testing.T) { notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) {
// We'd like to test that once a spend notification is registered, it // We'd like to test that once a spend notification is registered, it
// can be cancelled before the notification is dispatched. // can be cancelled before the notification is dispatched.
// First, we'll start by creating a new output that we can spend // First, we'll start by creating a new output that we can spend
// ourselves. // ourselves.
outpoint, pkScript := chainntnfs.CreateSpendableOutput(t, node) outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, node)
_, currentHeight, err := node.Node.GetBestBlock() _, currentHeight, err := node.Node.GetBestBlock()
if err != nil { if err != nil {
@ -844,9 +922,16 @@ func testCancelSpendNtfn(node *rpctest.Harness,
const numClients = 2 const numClients = 2
spendClients := make([]*chainntnfs.SpendEvent, numClients) spendClients := make([]*chainntnfs.SpendEvent, numClients)
for i := 0; i < numClients; i++ { for i := 0; i < numClients; i++ {
spentIntent, err := notifier.RegisterSpendNtfn( var spentIntent *chainntnfs.SpendEvent
outpoint, pkScript, uint32(currentHeight), if scriptDispatch {
) spentIntent, err = notifier.RegisterSpendNtfn(
nil, output.PkScript, uint32(currentHeight),
)
} else {
spentIntent, err = notifier.RegisterSpendNtfn(
outpoint, output.PkScript, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register for spend ntfn: %v", err) t.Fatalf("unable to register for spend ntfn: %v", err)
} }
@ -855,7 +940,7 @@ func testCancelSpendNtfn(node *rpctest.Harness,
} }
// Next, create a new transaction spending that output. // Next, create a new transaction spending that output.
spendingTx := chainntnfs.CreateSpendTx(t, outpoint, pkScript) spendingTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey)
// Before we broadcast the spending transaction, we'll cancel the // Before we broadcast the spending transaction, we'll cancel the
// notification of the first client. // notification of the first client.
@ -877,8 +962,8 @@ func testCancelSpendNtfn(node *rpctest.Harness,
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
// However, the spend notification for the first client should have // The spend notification for the first client should have been
// been dispatched. // dispatched.
select { select {
case ntfn := <-spendClients[0].Spend: case ntfn := <-spendClients[0].Spend:
// We've received the spend nftn. So now verify all the // We've received the spend nftn. So now verify all the
@ -902,7 +987,7 @@ func testCancelSpendNtfn(node *rpctest.Harness,
t.Fatalf("spend ntfn never received") t.Fatalf("spend ntfn never received")
} }
// However, The spend notification of the second client should NOT have // However, the spend notification of the second client should NOT have
// been dispatched. // been dispatched.
select { select {
case _, ok := <-spendClients[1].Spend: case _, ok := <-spendClients[1].Spend:
@ -914,8 +999,8 @@ func testCancelSpendNtfn(node *rpctest.Harness,
} }
} }
func testCancelEpochNtfn(node *rpctest.Harness, notifier chainntnfs.TestChainNotifier, func testCancelEpochNtfn(node *rpctest.Harness,
t *testing.T) { notifier chainntnfs.TestChainNotifier, t *testing.T) {
// We'd like to ensure that once a client cancels their block epoch // We'd like to ensure that once a client cancels their block epoch
// notifications, no further notifications are sent over the channel // notifications, no further notifications are sent over the channel
@ -964,8 +1049,8 @@ func testCancelEpochNtfn(node *rpctest.Harness, notifier chainntnfs.TestChainNot
} }
} }
func testReorgConf(miner *rpctest.Harness, notifier chainntnfs.TestChainNotifier, func testReorgConf(miner *rpctest.Harness,
t *testing.T) { notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) {
// Set up a new miner that we can use to cause a reorg. // Set up a new miner that we can use to cause a reorg.
miner2, err := rpctest.New(chainntnfs.NetParams, nil, []string{"--txindex"}) miner2, err := rpctest.New(chainntnfs.NetParams, nil, []string{"--txindex"})
@ -1026,9 +1111,16 @@ func testReorgConf(miner *rpctest.Harness, notifier chainntnfs.TestChainNotifier
// Now that we have a txid, register a confirmation notification with // Now that we have a txid, register a confirmation notification with
// the chainntfn source. // the chainntfn source.
numConfs := uint32(2) numConfs := uint32(2)
confIntent, err := notifier.RegisterConfirmationsNtfn( var confIntent *chainntnfs.ConfirmationEvent
txid, pkScript, numConfs, uint32(currentHeight), if scriptDispatch {
) confIntent, err = notifier.RegisterConfirmationsNtfn(
nil, pkScript, numConfs, uint32(currentHeight),
)
} else {
confIntent, err = notifier.RegisterConfirmationsNtfn(
txid, pkScript, numConfs, uint32(currentHeight),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register ntfn: %v", err) t.Fatalf("unable to register ntfn: %v", err)
} }
@ -1116,18 +1208,26 @@ func testReorgConf(miner *rpctest.Harness, notifier chainntnfs.TestChainNotifier
// correctly handle outpoints whose spending transaction has been reorged out of // correctly handle outpoints whose spending transaction has been reorged out of
// the chain. // the chain.
func testReorgSpend(miner *rpctest.Harness, func testReorgSpend(miner *rpctest.Harness,
notifier chainntnfs.TestChainNotifier, t *testing.T) { notifier chainntnfs.TestChainNotifier, scriptDispatch bool, t *testing.T) {
// We'll start by creating an output and registering a spend // We'll start by creating an output and registering a spend
// notification for it. // notification for it.
outpoint, pkScript := chainntnfs.CreateSpendableOutput(t, miner) outpoint, output, privKey := chainntnfs.CreateSpendableOutput(t, miner)
_, currentHeight, err := miner.Node.GetBestBlock() _, heightHint, err := miner.Node.GetBestBlock()
if err != nil { if err != nil {
t.Fatalf("unable to retrieve current height: %v", err) t.Fatalf("unable to retrieve current height: %v", err)
} }
spendIntent, err := notifier.RegisterSpendNtfn(
outpoint, pkScript, uint32(currentHeight), var spendIntent *chainntnfs.SpendEvent
) if scriptDispatch {
spendIntent, err = notifier.RegisterSpendNtfn(
nil, output.PkScript, uint32(heightHint),
)
} else {
spendIntent, err = notifier.RegisterSpendNtfn(
outpoint, output.PkScript, uint32(heightHint),
)
}
if err != nil { if err != nil {
t.Fatalf("unable to register for spend: %v", err) t.Fatalf("unable to register for spend: %v", err)
} }
@ -1174,7 +1274,7 @@ func testReorgSpend(miner *rpctest.Harness,
// Craft the spending transaction for the outpoint created above and // Craft the spending transaction for the outpoint created above and
// confirm it under the chain of the original miner. // confirm it under the chain of the original miner.
spendTx := chainntnfs.CreateSpendTx(t, outpoint, pkScript) spendTx := chainntnfs.CreateSpendTx(t, outpoint, output, privKey)
spendTxHash, err := miner.Node.SendRawTransaction(spendTx, true) spendTxHash, err := miner.Node.SendRawTransaction(spendTx, true)
if err != nil { if err != nil {
t.Fatalf("unable to broadcast spend tx: %v", err) t.Fatalf("unable to broadcast spend tx: %v", err)
@ -1186,14 +1286,17 @@ func testReorgSpend(miner *rpctest.Harness,
if _, err := miner.Node.Generate(numBlocks); err != nil { if _, err := miner.Node.Generate(numBlocks); err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to generate blocks: %v", err)
} }
_, spendHeight, err := miner.Node.GetBestBlock()
if err != nil {
t.Fatalf("unable to get spend height: %v", err)
}
// We should see a spend notification dispatched with the correct spend // We should see a spend notification dispatched with the correct spend
// details. // details.
select { select {
case spendDetails := <-spendIntent.Spend: case spendDetails := <-spendIntent.Spend:
checkNotificationFields( checkNotificationFields(
spendDetails, outpoint, spendTxHash, spendDetails, outpoint, spendTxHash, spendHeight, t,
currentHeight+numBlocks, t,
) )
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
t.Fatal("expected spend notification to be dispatched") t.Fatal("expected spend notification to be dispatched")
@ -1243,19 +1346,18 @@ func testReorgSpend(miner *rpctest.Harness,
if err := chainntnfs.WaitForMempoolTx(miner, spendTxHash); err != nil { if err := chainntnfs.WaitForMempoolTx(miner, spendTxHash); err != nil {
t.Fatalf("tx not relayed to miner: %v", err) t.Fatalf("tx not relayed to miner: %v", err)
} }
_, currentHeight, err = miner.Node.GetBestBlock()
if err != nil {
t.Fatalf("unable to retrieve current height: %v", err)
}
if _, err := miner.Node.Generate(numBlocks); err != nil { if _, err := miner.Node.Generate(numBlocks); err != nil {
t.Fatalf("unable to generate single block: %v", err) t.Fatalf("unable to generate single block: %v", err)
} }
_, spendHeight, err = miner.Node.GetBestBlock()
if err != nil {
t.Fatalf("unable to retrieve current height: %v", err)
}
select { select {
case spendDetails := <-spendIntent.Spend: case spendDetails := <-spendIntent.Spend:
checkNotificationFields( checkNotificationFields(
spendDetails, outpoint, spendTxHash, spendDetails, outpoint, spendTxHash, spendHeight, t,
currentHeight+numBlocks, t,
) )
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
t.Fatal("expected spend notification to be dispatched") t.Fatal("expected spend notification to be dispatched")
@ -1642,7 +1744,13 @@ func testCatchUpOnMissedBlocksWithReorg(miner1 *rpctest.Harness,
} }
} }
type testCase struct { type txNtfnTestCase struct {
name string
test func(node *rpctest.Harness, notifier chainntnfs.TestChainNotifier,
scriptDispatch bool, t *testing.T)
}
type blockNtfnTestCase struct {
name string name string
test func(node *rpctest.Harness, notifier chainntnfs.TestChainNotifier, test func(node *rpctest.Harness, notifier chainntnfs.TestChainNotifier,
t *testing.T) t *testing.T)
@ -1654,7 +1762,7 @@ type blockCatchupTestCase struct {
t *testing.T) t *testing.T)
} }
var ntfnTests = []testCase{ var txNtfnTests = []txNtfnTestCase{
{ {
name: "single conf ntfn", name: "single conf ntfn",
test: testSingleConfirmationNotification, test: testSingleConfirmationNotification,
@ -1672,41 +1780,44 @@ var ntfnTests = []testCase{
test: testMultiClientConfirmationNotification, test: testMultiClientConfirmationNotification,
}, },
{ {
name: "spend ntfn", name: "lazy ntfn consumer",
test: testSpendNotification, test: testLazyNtfnConsumer,
},
{
name: "block epoch",
test: testBlockEpochNotification,
}, },
{ {
name: "historical conf dispatch", name: "historical conf dispatch",
test: testTxConfirmedBeforeNtfnRegistration, test: testTxConfirmedBeforeNtfnRegistration,
}, },
{
name: "reorg conf",
test: testReorgConf,
},
{
name: "spend ntfn",
test: testSpendNotification,
},
{ {
name: "historical spend dispatch", name: "historical spend dispatch",
test: testSpendBeforeNtfnRegistration, test: testSpendBeforeNtfnRegistration,
}, },
{
name: "reorg spend",
test: testReorgSpend,
},
{ {
name: "cancel spend ntfn", name: "cancel spend ntfn",
test: testCancelSpendNtfn, test: testCancelSpendNtfn,
}, },
}
var blockNtfnTests = []blockNtfnTestCase{
{
name: "block epoch",
test: testBlockEpochNotification,
},
{ {
name: "cancel epoch ntfn", name: "cancel epoch ntfn",
test: testCancelEpochNtfn, test: testCancelEpochNtfn,
}, },
{
name: "lazy ntfn consumer",
test: testLazyNtfnConsumer,
},
{
name: "reorg conf",
test: testReorgConf,
},
{
name: "reorg spend",
test: testReorgSpend,
},
} }
var blockCatchupTests = []blockCatchupTestCase{ var blockCatchupTests = []blockCatchupTestCase{
@ -1746,7 +1857,8 @@ func TestInterfaces(t *testing.T) {
rpcConfig := miner.RPCConfig() rpcConfig := miner.RPCConfig()
p2pAddr := miner.P2PAddress() p2pAddr := miner.P2PAddress()
log.Printf("Running %v ChainNotifier interface tests", len(ntfnTests)) log.Printf("Running %v ChainNotifier interface tests",
2*len(txNtfnTests)+len(blockNtfnTests)+len(blockCatchupTests))
for _, notifierDriver := range chainntnfs.RegisteredNotifiers() { for _, notifierDriver := range chainntnfs.RegisteredNotifiers() {
// Initialize a height hint cache for each notifier. // Initialize a height hint cache for each notifier.
@ -1815,12 +1927,30 @@ func TestInterfaces(t *testing.T) {
notifierType, err) notifierType, err)
} }
for _, ntfnTest := range ntfnTests { for _, txNtfnTest := range txNtfnTests {
testName := fmt.Sprintf("%v: %v", notifierType, for _, scriptDispatch := range []bool{false, true} {
ntfnTest.name) testName := fmt.Sprintf("%v %v", notifierType,
txNtfnTest.name)
if scriptDispatch {
testName += " with script dispatch"
}
success := t.Run(testName, func(t *testing.T) {
txNtfnTest.test(
miner, notifier, scriptDispatch,
t,
)
})
if !success {
break
}
}
}
for _, blockNtfnTest := range blockNtfnTests {
testName := fmt.Sprintf("%v %v", notifierType,
blockNtfnTest.name)
success := t.Run(testName, func(t *testing.T) { success := t.Run(testName, func(t *testing.T) {
ntfnTest.test(miner, notifier, t) blockNtfnTest.test(miner, notifier, t)
}) })
if !success { if !success {
break break
@ -1838,7 +1968,7 @@ func TestInterfaces(t *testing.T) {
notifierType, err) notifierType, err)
} }
testName := fmt.Sprintf("%v: %v", notifierType, testName := fmt.Sprintf("%v %v", notifierType,
blockCatchupTest.name) blockCatchupTest.name)
success := t.Run(testName, func(t *testing.T) { success := t.Run(testName, func(t *testing.T) {