chainntnfs/neutrinonotify: track best block hash

This commit is contained in:
Wilmer Paulino 2018-12-10 18:29:25 -08:00
parent 060f2f7774
commit 568f8271a0
No known key found for this signature in database
GPG Key ID: 6DF57B9F9514972F
2 changed files with 34 additions and 43 deletions

@ -44,8 +44,8 @@ type NeutrinoNotifier struct {
started int32 // To be used atomically.
stopped int32 // To be used atomically.
heightMtx sync.RWMutex
bestHeight uint32
bestBlockMtx sync.RWMutex
bestBlock chainntnfs.BlockEpoch
p2pNode *neutrino.ChainService
chainView *neutrino.Rescan
@ -126,10 +126,12 @@ func (n *NeutrinoNotifier) Start() error {
if err != nil {
return err
}
n.bestHeight = uint32(startingPoint.Height)
n.bestBlock.Hash = &startingPoint.Hash
n.bestBlock.Height = startingPoint.Height
n.txNotifier = chainntnfs.NewTxNotifier(
n.bestHeight, chainntnfs.ReorgSafetyLimit, n.confirmHintCache,
n.spendHintCache,
uint32(n.bestBlock.Height), chainntnfs.ReorgSafetyLimit,
n.confirmHintCache, n.spendHintCache,
)
// Next, we'll create our set of rescan options. Currently it's
@ -334,9 +336,9 @@ out:
chainntnfs.Log.Infof("New block epoch subscription")
n.blockEpochClients[msg.epochID] = msg
if msg.bestBlock != nil {
n.heightMtx.Lock()
bestHeight := int32(n.bestHeight)
n.heightMtx.Unlock()
n.bestBlockMtx.Lock()
bestHeight := n.bestBlock.Height
n.bestBlockMtx.Unlock()
missedBlocks, err :=
chainntnfs.GetClientMissedBlocks(
n.chainConn, msg.bestBlock,
@ -365,7 +367,7 @@ out:
case item := <-n.chainUpdates.ChanOut():
update := item.(*filteredBlock)
if update.connect {
n.heightMtx.Lock()
n.bestBlockMtx.Lock()
// Since neutrino has no way of knowing what
// height to rewind to in the case of a reorged
// best known height, there is no point in
@ -374,27 +376,24 @@ out:
// the other notifiers do when they receive
// a new connected block. Therefore, we just
// compare the heights.
if update.height != n.bestHeight+1 {
if update.height != uint32(n.bestBlock.Height+1) {
// Handle the case where the notifier
// missed some blocks from its chain
// backend
chainntnfs.Log.Infof("Missed blocks, " +
"attempting to catch up")
bestBlock := chainntnfs.BlockEpoch{
Height: int32(n.bestHeight),
Hash: nil,
}
_, missedBlocks, err :=
chainntnfs.HandleMissedBlocks(
n.chainConn,
n.txNotifier,
bestBlock,
n.bestBlock,
int32(update.height),
false,
)
if err != nil {
chainntnfs.Log.Error(err)
n.heightMtx.Unlock()
n.bestBlockMtx.Unlock()
continue
}
@ -403,13 +402,13 @@ out:
n.getFilteredBlock(block)
if err != nil {
chainntnfs.Log.Error(err)
n.heightMtx.Unlock()
n.bestBlockMtx.Unlock()
continue out
}
err = n.handleBlockConnected(filteredBlock)
if err != nil {
chainntnfs.Log.Error(err)
n.heightMtx.Unlock()
n.bestBlockMtx.Unlock()
continue out
}
}
@ -420,42 +419,30 @@ out:
if err != nil {
chainntnfs.Log.Error(err)
}
n.heightMtx.Unlock()
n.bestBlockMtx.Unlock()
continue
}
n.heightMtx.Lock()
if update.height != uint32(n.bestHeight) {
n.bestBlockMtx.Lock()
if update.height != uint32(n.bestBlock.Height) {
chainntnfs.Log.Infof("Missed disconnected " +
"blocks, attempting to catch up")
}
hash, err := n.p2pNode.GetBlockHash(int64(n.bestHeight))
if err != nil {
chainntnfs.Log.Errorf("Unable to fetch block hash "+
"for height %d: %v", n.bestHeight, err)
n.heightMtx.Unlock()
continue
}
notifierBestBlock := chainntnfs.BlockEpoch{
Height: int32(n.bestHeight),
Hash: hash,
}
newBestBlock, err := chainntnfs.RewindChain(
n.chainConn, n.txNotifier, notifierBestBlock,
n.chainConn, n.txNotifier, n.bestBlock,
int32(update.height-1),
)
if err != nil {
chainntnfs.Log.Errorf("Unable to rewind chain "+
"from height %d to height %d: %v",
n.bestHeight, update.height-1, err)
n.bestBlock.Height, update.height-1, err)
}
// Set the bestHeight here in case a chain rewind
// partially completed.
n.bestHeight = uint32(newBestBlock.Height)
n.heightMtx.Unlock()
n.bestBlock = newBestBlock
n.bestBlockMtx.Unlock()
case txUpdate := <-n.txUpdates.ChanOut():
// A new relevant transaction notification has been
@ -570,6 +557,8 @@ func (n *NeutrinoNotifier) historicalConfDetails(confRequest chainntnfs.ConfRequ
// handleBlockConnected applies a chain update for a new block. Any watched
// transactions included this block will processed to either send notifications
// now or after numConfirmations confs.
//
// NOTE: This method must be called with the bestBlockMtx lock held.
func (n *NeutrinoNotifier) handleBlockConnected(newBlock *filteredBlock) error {
// We'll extend the txNotifier's height with the information of this new
// block, which will handle all of the notification logic for us.
@ -588,7 +577,8 @@ func (n *NeutrinoNotifier) handleBlockConnected(newBlock *filteredBlock) error {
// registered clients whom have had notifications fulfilled. Before
// doing so, we'll make sure update our in memory state in order to
// satisfy any client requests based upon the new block.
n.bestHeight = newBlock.height
n.bestBlock.Hash = &newBlock.hash
n.bestBlock.Height = int32(newBlock.height)
n.notifyBlockEpochs(int32(newBlock.height), &newBlock.hash)
return n.txNotifier.NotifyHeight(newBlock.height)
@ -730,9 +720,9 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// to fetch the UTXO from the chain. If we're behind, then we may miss a
// notification dispatch.
for {
n.heightMtx.RLock()
currentHeight := n.bestHeight
n.heightMtx.RUnlock()
n.bestBlockMtx.RLock()
currentHeight := uint32(n.bestBlock.Height)
n.bestBlockMtx.RUnlock()
if currentHeight >= historicalDispatch.StartHeight {
break

@ -89,7 +89,8 @@ func (n *NeutrinoNotifier) UnsafeStart(bestHeight int32,
// Run notificationDispatcher after setting the notifier's best height
// to avoid a race condition.
n.bestHeight = uint32(bestHeight)
n.bestBlock.Hash = bestHash
n.bestBlock.Height = bestHeight
n.wg.Add(1)
go n.notificationDispatcher()