chainntnfs/btcd: commit spend hints before notifying

This commit is contained in:
Conner Fromknecht 2018-08-24 19:45:25 -07:00
parent fb7b12a7db
commit e498a837a3
No known key found for this signature in database
GPG Key ID: E7D737B67FA592C7

@ -715,16 +715,16 @@ func (b *BtcdNotifier) handleBlockConnected(epoch chainntnfs.BlockEpoch) error {
chainntnfs.Log.Infof("New block: height=%v, sha=%v", epoch.Height,
epoch.Hash)
// We want to set the best block before dispatching notifications
// so if any subscribers make queries based on their received
// block epoch, our state is fully updated in time.
b.bestBlock = epoch
// Next we'll notify any subscribed clients of the block.
b.notifyBlockEpochs(int32(newBlock.height), &newBlock.hash)
// Define a helper struct for coalescing the spend notifications we will
// dispatch after trying to commit the spend hints.
type spendNtfnBatch struct {
details *chainntnfs.SpendDetail
clients map[uint64]*spendNotification
}
// Scan over the list of relevant transactions and possibly dispatch
// notifications for spends.
spendBatches := make(map[wire.OutPoint]spendNtfnBatch)
for _, tx := range newBlock.txns {
mtx := tx.MsgTx()
txSha := mtx.TxHash()
@ -740,6 +740,7 @@ func (b *BtcdNotifier) handleBlockConnected(epoch chainntnfs.BlockEpoch) error {
if !ok {
continue
}
delete(b.spendNotifications, prevOut)
spendDetails := &chainntnfs.SpendDetail{
SpentOutPoint: &prevOut,
@ -749,21 +750,10 @@ func (b *BtcdNotifier) handleBlockConnected(epoch chainntnfs.BlockEpoch) error {
SpendingHeight: int32(newBlock.height),
}
for _, ntfn := range clients {
chainntnfs.Log.Infof("Dispatching spend "+
"notification for outpoint=%v",
ntfn.targetOutpoint)
ntfn.spendChan <- spendDetails
// Close spendChan to ensure that any calls to
// Cancel will not block. This is safe to do
// since the channel is buffered, and the
// message can still be read by the receiver.
close(ntfn.spendChan)
spendBatches[prevOut] = spendNtfnBatch{
details: spendDetails,
clients: clients,
}
delete(b.spendNotifications, prevOut)
}
}
@ -780,13 +770,39 @@ func (b *BtcdNotifier) handleBlockConnected(epoch chainntnfs.BlockEpoch) error {
uint32(epoch.Height), ops...,
)
if err != nil {
// The error is not fatal, so we should not return an
// error to the caller.
// The error is not fatal since we are connecting a
// block, and advancing the spend hint is an optimistic
// optimization.
chainntnfs.Log.Errorf("Unable to update spend hint to "+
"%d for %v: %v", epoch.Height, ops, err)
}
}
// We want to set the best block before dispatching notifications
// so if any subscribers make queries based on their received
// block epoch, our state is fully updated in time.
b.bestBlock = epoch
// Next we'll notify any subscribed clients of the block.
b.notifyBlockEpochs(int32(newBlock.height), &newBlock.hash)
// Finally, send off the spend details to the notification subscribers.
for _, batch := range spendBatches {
for _, ntfn := range batch.clients {
chainntnfs.Log.Infof("Dispatching spend "+
"notification for outpoint=%v",
ntfn.targetOutpoint)
ntfn.spendChan <- batch.details
// Close spendChan to ensure that any calls to
// Cancel will not block. This is safe to do
// since the channel is buffered, and the
// message can still be read by the receiver.
close(ntfn.spendChan)
}
}
return nil
}