chainntnfs/txnotifier: support reorg detection for scripts

This commit is contained in:
Wilmer Paulino 2018-12-06 21:13:50 -08:00
parent 83c8ccb3eb
commit f4f5c1ef8b
No known key found for this signature in database
GPG Key ID: 6DF57B9F9514972F

@ -1371,11 +1371,11 @@ func (n *TxNotifier) NotifyHeight(height uint32) error {
} }
// DisconnectTip handles the tip of the current chain being disconnected during // DisconnectTip handles the tip of the current chain being disconnected during
// a chain reorganization. If any watched transactions or spending transactions // a chain reorganization. If any watched requests were included in this block,
// for registered outpoints were included in this block, internal structures are // internal structures are updated to ensure confirmation/spend notifications
// updated to ensure confirmation/spend notifications are consumed (if not // are consumed (if not already), and reorg notifications are dispatched
// already), and reorg notifications are dispatched instead. Confirmation/spend // instead. Confirmation/spend notifications will be dispatched again upon block
// notifications will be dispatched again upon block inclusion. // inclusion.
func (n *TxNotifier) DisconnectTip(blockHeight uint32) error { func (n *TxNotifier) DisconnectTip(blockHeight uint32) error {
select { select {
case <-n.quit: case <-n.quit:
@ -1395,19 +1395,19 @@ func (n *TxNotifier) DisconnectTip(blockHeight uint32) error {
n.reorgDepth++ n.reorgDepth++
// With the block disconnected, we'll update the confirm and spend hints // With the block disconnected, we'll update the confirm and spend hints
// for our transactions and outpoints to reflect the new height, except // for our notification requests to reflect the new height, except for
// for those that have confirmed/spent at previous heights. // those that have confirmed/spent at previous heights.
n.updateHints(blockHeight) n.updateHints(blockHeight)
// We'll go through all of our watched transactions and attempt to drain // We'll go through all of our watched confirmation requests and attempt
// their notification channels to ensure sending notifications to the // to drain their notification channels to ensure sending notifications
// clients is always non-blocking. // to the clients is always non-blocking.
for initialHeight, txHashes := range n.txsByInitialHeight { for initialHeight, txHashes := range n.confsByInitialHeight {
for txHash := range txHashes { for txHash := range txHashes {
// If the transaction has been reorged out of the chain, // If the transaction/output script has been reorged out
// we'll make sure to remove the cached confirmation // of the chain, we'll make sure to remove the cached
// details to prevent notifying clients with old // confirmation details to prevent notifying clients
// information. // with old information.
confSet := n.confNotifications[txHash] confSet := n.confNotifications[txHash]
if initialHeight == blockHeight { if initialHeight == blockHeight {
confSet.details = nil confSet.details = nil
@ -1424,10 +1424,11 @@ func (n *TxNotifier) DisconnectTip(blockHeight uint32) error {
default: default:
} }
// Then, we'll check if the current transaction // Then, we'll check if the current
// was included in the block currently being // transaction/output script was included in the
// disconnected. If it was, we'll need to // block currently being disconnected. If it
// dispatch a reorg notification to the client. // was, we'll need to dispatch a reorg
// notification to the client.
if initialHeight == blockHeight { if initialHeight == blockHeight {
err := n.dispatchConfReorg( err := n.dispatchConfReorg(
ntfn, blockHeight, ntfn, blockHeight,
@ -1440,15 +1441,15 @@ func (n *TxNotifier) DisconnectTip(blockHeight uint32) error {
} }
} }
// We'll also go through our watched outpoints and attempt to drain // We'll also go through our watched spend requests and attempt to drain
// their dispatched notifications to ensure dispatching notifications to // their dispatched notifications to ensure dispatching notifications to
// clients later on is always non-blocking. We're only interested in // clients later on is always non-blocking. We're only interested in
// outpoints whose spending transaction was included at the height being // requests whose spending transaction was included at the height being
// disconnected. // disconnected.
for op := range n.opsBySpendHeight[blockHeight] { for op := range n.spendsByHeight[blockHeight] {
// Since the spending transaction is being reorged out of the // Since the spending transaction is being reorged out of the
// chain, we'll need to clear out the spending details of the // chain, we'll need to clear out the spending details of the
// outpoint. // request.
spendSet := n.spendNotifications[op] spendSet := n.spendNotifications[op]
spendSet.details = nil spendSet.details = nil
@ -1462,12 +1463,12 @@ func (n *TxNotifier) DisconnectTip(blockHeight uint32) error {
} }
} }
// Finally, we can remove the transactions that were confirmed and the // Finally, we can remove the requests that were confirmed and/or spent
// outpoints that were spent at the height being disconnected. We'll // at the height being disconnected. We'll still continue to track them
// still continue to track them until they have been confirmed/spent and // until they have been confirmed/spent and are no longer under the risk
// are no longer under the risk of being reorged out of the chain again. // of being reorged out of the chain again.
delete(n.txsByInitialHeight, blockHeight) delete(n.confsByInitialHeight, blockHeight)
delete(n.opsBySpendHeight, blockHeight) delete(n.spendsByHeight, blockHeight)
return nil return nil
} }
@ -1568,10 +1569,10 @@ func (n *TxNotifier) unspentOutPoints() []wire.OutPoint {
func (n *TxNotifier) dispatchConfReorg(ntfn *ConfNtfn, func (n *TxNotifier) dispatchConfReorg(ntfn *ConfNtfn,
heightDisconnected uint32) error { heightDisconnected uint32) error {
// If the transaction's confirmation notification has yet to be // If the request's confirmation notification has yet to be dispatched,
// dispatched, we'll need to clear its entry within the // we'll need to clear its entry within the ntfnsByConfirmHeight index
// ntfnsByConfirmHeight index to prevent from notifying the client once // to prevent from notifying the client once the notifier reaches the
// the notifier reaches the confirmation height. // confirmation height.
if !ntfn.dispatched { if !ntfn.dispatched {
confHeight := heightDisconnected + ntfn.NumConfirmations - 1 confHeight := heightDisconnected + ntfn.NumConfirmations - 1
ntfnSet, exists := n.ntfnsByConfirmHeight[confHeight] ntfnSet, exists := n.ntfnsByConfirmHeight[confHeight]