chainntnfs: add heightHint to RegisterSpendNtfn+ RegisterConfirmationsNtfn
This commit modifies two of the main methods in the ChainNotifier interface to be more light client friendly. In order to do so, we now tack on an extra parameter to the methods: heightHint. This value represents the earliest known height that the chain should be scanned when attempting to do a dispatch from historical data. All tests have also been updated to use these new parameters properly when excising the expected behavior of each interface implementation.
This commit is contained in:
parent
45bbeb8f84
commit
2f0639f1af
@ -618,7 +618,8 @@ type spendCancel struct {
|
||||
// outpoint has been spent by a transaction on-chain. Once a spend of the target
|
||||
// outpoint has been detected, the details of the spending event will be sent
|
||||
// across the 'Spend' channel.
|
||||
func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint) (*chainntnfs.SpendEvent, error) {
|
||||
func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
|
||||
_ uint32) (*chainntnfs.SpendEvent, error) {
|
||||
|
||||
if err := b.chainConn.NotifySpent([]*wire.OutPoint{outpoint}); err != nil {
|
||||
return nil, err
|
||||
@ -694,7 +695,7 @@ type confirmationsNotification struct {
|
||||
// which will be triggered once the txid reaches numConfs number of
|
||||
// confirmations.
|
||||
func (b *BtcdNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
|
||||
numConfs uint32) (*chainntnfs.ConfirmationEvent, error) {
|
||||
numConfs, _ uint32) (*chainntnfs.ConfirmationEvent, error) {
|
||||
|
||||
ntfn := &confirmationsNotification{
|
||||
txid: txid,
|
||||
|
@ -23,23 +23,32 @@ type ChainNotifier interface {
|
||||
// txid reaches numConfs confirmations. The returned ConfirmationEvent
|
||||
// should properly notify the client once the specified number of
|
||||
// confirmations has been reached for the txid, as well as if the
|
||||
// original tx gets re-org'd out of the mainchain.
|
||||
// original tx gets re-org'd out of the mainchain. The heightHint
|
||||
// parameter is provided as a convenience to light clients. The
|
||||
// heightHint denotes the earlies height in the blockchain in which the
|
||||
// target txid _could_ have been included in the chain. This can be
|
||||
// used to bound the search space when checking to see if a
|
||||
// notification can immediately be dispatched due to historical data.
|
||||
//
|
||||
// NOTE: Dispatching notifications to multiple clients subscribed to
|
||||
// the same (txid, numConfs) tuple MUST be supported.
|
||||
RegisterConfirmationsNtfn(txid *chainhash.Hash, numConfs uint32) (*ConfirmationEvent, error)
|
||||
RegisterConfirmationsNtfn(txid *chainhash.Hash, numConfs,
|
||||
heightHint uint32) (*ConfirmationEvent, error)
|
||||
|
||||
// RegisterSpendNtfn registers an intent to be notified once the target
|
||||
// outpoint is succesfully spent within a confirmed transaction. The
|
||||
// returned SpendEvent will receive a send on the 'Spend' transaction
|
||||
// once a transaction spending the input is detected on the blockchain.
|
||||
// The heightHint parameter is provided as a convenience to light
|
||||
// clients. The heightHint denotes the earlies height in the blockchain
|
||||
// in which the target output could've been created.
|
||||
//
|
||||
// NOTE: This notifications should be triggered once the transaction is
|
||||
// *seen* on the network, not when it has received a single confirmation.
|
||||
//
|
||||
// NOTE: Dispatching notifications to multiple clients subscribed to a
|
||||
// spend of the same outpoint MUST be supported.
|
||||
RegisterSpendNtfn(outpoint *wire.OutPoint) (*SpendEvent, error)
|
||||
RegisterSpendNtfn(outpoint *wire.OutPoint, heightHint uint32) (*SpendEvent, error)
|
||||
|
||||
// RegisterBlockEpochNtfn registers an intent to be notified of each
|
||||
// new block connected to the tip of the main chain. The returned
|
||||
|
@ -66,10 +66,16 @@ func testSingleConfirmationNotification(miner *rpctest.Harness,
|
||||
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 notiication with
|
||||
// the chainntfn source.
|
||||
numConfs := uint32(1)
|
||||
confIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs)
|
||||
confIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs,
|
||||
uint32(currentHeight))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to register ntfn: %v", err)
|
||||
}
|
||||
@ -107,8 +113,14 @@ func testMultiConfirmationNotification(miner *rpctest.Harness,
|
||||
t.Fatalf("unable to create test addr: %v", err)
|
||||
}
|
||||
|
||||
_, currentHeight, err := miner.Node.GetBestBlock()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get current height: %v", err)
|
||||
}
|
||||
|
||||
numConfs := uint32(6)
|
||||
confIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs)
|
||||
confIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs,
|
||||
uint32(currentHeight))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to register ntfn: %v", err)
|
||||
}
|
||||
@ -143,6 +155,11 @@ func testBatchConfirmationNotification(miner *rpctest.Harness,
|
||||
confSpread := [6]uint32{1, 2, 3, 6, 20, 22}
|
||||
confIntents := make([]*chainntnfs.ConfirmationEvent, len(confSpread))
|
||||
|
||||
_, currentHeight, err := miner.Node.GetBestBlock()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get current height: %v", err)
|
||||
}
|
||||
|
||||
// Create a new txid spending miner coins for each confirmation entry
|
||||
// in confSpread, we collect each conf intent into a slice so we can
|
||||
// verify they're each notified at the proper number of confirmations
|
||||
@ -152,7 +169,8 @@ func testBatchConfirmationNotification(miner *rpctest.Harness,
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test addr: %v", err)
|
||||
}
|
||||
confIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs)
|
||||
confIntent, err := notifier.RegisterConfirmationsNtfn(txid,
|
||||
numConfs, uint32(currentHeight))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to register ntfn: %v", err)
|
||||
}
|
||||
@ -263,6 +281,11 @@ func testSpendNotification(miner *rpctest.Harness,
|
||||
// To do so, we first create a new output to our test target address.
|
||||
outpoint, pkScript := createSpendableOutput(miner, t)
|
||||
|
||||
_, currentHeight, err := miner.Node.GetBestBlock()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get current height: %v", err)
|
||||
}
|
||||
|
||||
// Now that we have a output index and the pkScript, register for a
|
||||
// spentness notification for the newly created output with multiple
|
||||
// clients in order to ensure the implementation can support
|
||||
@ -270,7 +293,8 @@ func testSpendNotification(miner *rpctest.Harness,
|
||||
const numClients = 5
|
||||
spendClients := make([]*chainntnfs.SpendEvent, numClients)
|
||||
for i := 0; i < numClients; i++ {
|
||||
spentIntent, err := notifier.RegisterSpendNtfn(outpoint)
|
||||
spentIntent, err := notifier.RegisterSpendNtfn(outpoint,
|
||||
uint32(currentHeight))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to register for spend ntfn: %v", err)
|
||||
}
|
||||
@ -408,10 +432,16 @@ func testMultiClientConfirmationNotification(miner *rpctest.Harness,
|
||||
numConfs = 1
|
||||
)
|
||||
|
||||
_, currentHeight, err := miner.Node.GetBestBlock()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get current height: %v", err)
|
||||
}
|
||||
|
||||
// Register for a conf notification for the above generated txid with
|
||||
// numConfsClients distinct clients.
|
||||
for i := 0; i < numConfsClients; i++ {
|
||||
confClient, err := notifier.RegisterConfirmationsNtfn(txid, numConfs)
|
||||
confClient, err := notifier.RegisterConfirmationsNtfn(txid,
|
||||
numConfs, uint32(currentHeight))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to register for confirmation: %v", err)
|
||||
}
|
||||
@ -467,10 +497,16 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
|
||||
t.Fatalf("unable to generate two blocks: %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)
|
||||
confIntent, err := notifier.RegisterConfirmationsNtfn(txid, numConfs,
|
||||
uint32(currentHeight))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to register ntfn: %v", err)
|
||||
}
|
||||
@ -495,6 +531,11 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
|
||||
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
|
||||
@ -506,7 +547,8 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness,
|
||||
|
||||
// Next, register for the notification *after* the transition has
|
||||
// already been partially confirmed.
|
||||
confIntent, err = notifier.RegisterConfirmationsNtfn(txid, numConfs)
|
||||
confIntent, err = notifier.RegisterConfirmationsNtfn(txid, numConfs,
|
||||
uint32(currentHeight))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to register ntfn: %v", err)
|
||||
}
|
||||
@ -605,10 +647,16 @@ func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
|
||||
t.Fatalf("unable to generate single block: %v", err)
|
||||
}
|
||||
|
||||
_, currentHeight, err := miner.Node.GetBestBlock()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get current height: %v", err)
|
||||
}
|
||||
|
||||
// Now, we register to be notified of a spend that has already
|
||||
// happened. The notifier should dispatch a spend notification
|
||||
// immediately.
|
||||
spentIntent, err := notifier.RegisterSpendNtfn(outpoint)
|
||||
spentIntent, err := notifier.RegisterSpendNtfn(outpoint,
|
||||
uint32(currentHeight))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to register for spend ntfn: %v", err)
|
||||
}
|
||||
@ -622,7 +670,7 @@ func testSpendBeforeNtfnRegistration(miner *rpctest.Harness,
|
||||
case ntfn := <-spentNtfn:
|
||||
// We've received the spend nftn. So now verify all the fields
|
||||
// have been set properly.
|
||||
if ntfn.SpentOutPoint != outpoint {
|
||||
if *ntfn.SpentOutPoint != *outpoint {
|
||||
t.Fatalf("ntfn includes wrong output, reports %v instead of %v",
|
||||
ntfn.SpentOutPoint, outpoint)
|
||||
}
|
||||
@ -649,13 +697,19 @@ func testCancelSpendNtfn(node *rpctest.Harness,
|
||||
// ourselves.
|
||||
outpoint, pkScript := createSpendableOutput(node, t)
|
||||
|
||||
_, currentHeight, err := node.Node.GetBestBlock()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get current height: %v", err)
|
||||
}
|
||||
|
||||
// Create two clients that each registered to the spend notification.
|
||||
// We'll cancel the notification for the first client and leave the
|
||||
// notification for the second client enabled.
|
||||
const numClients = 2
|
||||
spendClients := make([]*chainntnfs.SpendEvent, numClients)
|
||||
for i := 0; i < numClients; i++ {
|
||||
spentIntent, err := notifier.RegisterSpendNtfn(outpoint)
|
||||
spentIntent, err := notifier.RegisterSpendNtfn(outpoint,
|
||||
uint32(currentHeight))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to register for spend ntfn: %v", err)
|
||||
}
|
||||
@ -688,7 +742,7 @@ func testCancelSpendNtfn(node *rpctest.Harness,
|
||||
case ntfn := <-spendClients[0].Spend:
|
||||
// We've received the spend nftn. So now verify all the
|
||||
// fields have been set properly.
|
||||
if ntfn.SpentOutPoint != outpoint {
|
||||
if *ntfn.SpentOutPoint != *outpoint {
|
||||
t.Fatalf("ntfn includes wrong output, reports "+
|
||||
"%v instead of %v",
|
||||
ntfn.SpentOutPoint, outpoint)
|
||||
|
Loading…
Reference in New Issue
Block a user