chainntnfs: modify watched transactions by height to use a set
In this commit, we avoid storing extra copies of a transaction when multiple clients register to be notified for the same transaction. We do this by using a set, which only stores unique elements.
This commit is contained in:
parent
486694a84e
commit
09f8a72897
@ -67,11 +67,11 @@ type TxConfNotifier struct {
|
|||||||
// hash.
|
// hash.
|
||||||
confNotifications map[chainhash.Hash][]*ConfNtfn
|
confNotifications map[chainhash.Hash][]*ConfNtfn
|
||||||
|
|
||||||
// confTxsByInitialHeight is an index of watched transactions by the height
|
// txsByInitialHeight is an index of watched transactions by the height
|
||||||
// that they are included at in the blockchain. This is tracked so that
|
// that they are included at in the blockchain. This is tracked so that
|
||||||
// incorrect notifications are not sent if a transaction is reorganized out
|
// incorrect notifications are not sent if a transaction is reorganized
|
||||||
// of the chain and so that negative confirmations can be recognized.
|
// out of the chain and so that negative confirmations can be recognized.
|
||||||
confTxsByInitialHeight map[uint32][]*chainhash.Hash
|
txsByInitialHeight map[uint32]map[chainhash.Hash]struct{}
|
||||||
|
|
||||||
// ntfnsByConfirmHeight is an index of notification requests by the height
|
// ntfnsByConfirmHeight is an index of notification requests by the height
|
||||||
// at which the transaction will have sufficient confirmations.
|
// at which the transaction will have sufficient confirmations.
|
||||||
@ -89,7 +89,7 @@ func NewTxConfNotifier(startHeight uint32, reorgSafetyLimit uint32) *TxConfNotif
|
|||||||
currentHeight: startHeight,
|
currentHeight: startHeight,
|
||||||
reorgSafetyLimit: reorgSafetyLimit,
|
reorgSafetyLimit: reorgSafetyLimit,
|
||||||
confNotifications: make(map[chainhash.Hash][]*ConfNtfn),
|
confNotifications: make(map[chainhash.Hash][]*ConfNtfn),
|
||||||
confTxsByInitialHeight: make(map[uint32][]*chainhash.Hash),
|
txsByInitialHeight: make(map[uint32]map[chainhash.Hash]struct{}),
|
||||||
ntfnsByConfirmHeight: make(map[uint32]map[*ConfNtfn]struct{}),
|
ntfnsByConfirmHeight: make(map[uint32]map[*ConfNtfn]struct{}),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
}
|
}
|
||||||
@ -138,14 +138,18 @@ func (tcn *TxConfNotifier) Register(ntfn *ConfNtfn, txConf *TxConfirmation) erro
|
|||||||
ntfnSet[ntfn] = struct{}{}
|
ntfnSet[ntfn] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unless the transaction is finalized, include transaction information in
|
// As a final check, we'll also watch the transaction if it's still
|
||||||
// confNotifications and confTxsByInitialHeight in case the tx gets
|
// possible for it to get reorganized out of the chain.
|
||||||
// reorganized out of the chain.
|
|
||||||
if txConf.BlockHeight+tcn.reorgSafetyLimit > tcn.currentHeight {
|
if txConf.BlockHeight+tcn.reorgSafetyLimit > tcn.currentHeight {
|
||||||
tcn.confNotifications[*ntfn.TxID] =
|
tcn.confNotifications[*ntfn.TxID] =
|
||||||
append(tcn.confNotifications[*ntfn.TxID], ntfn)
|
append(tcn.confNotifications[*ntfn.TxID], ntfn)
|
||||||
tcn.confTxsByInitialHeight[txConf.BlockHeight] =
|
|
||||||
append(tcn.confTxsByInitialHeight[txConf.BlockHeight], ntfn.TxID)
|
txSet, exists := tcn.txsByInitialHeight[txConf.BlockHeight]
|
||||||
|
if !exists {
|
||||||
|
txSet = make(map[chainhash.Hash]struct{})
|
||||||
|
tcn.txsByInitialHeight[txConf.BlockHeight] = txSet
|
||||||
|
}
|
||||||
|
txSet[*ntfn.TxID] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -194,8 +198,12 @@ func (tcn *TxConfNotifier) ConnectTip(blockHash *chainhash.Hash,
|
|||||||
}
|
}
|
||||||
ntfnSet[ntfn] = struct{}{}
|
ntfnSet[ntfn] = struct{}{}
|
||||||
|
|
||||||
tcn.confTxsByInitialHeight[blockHeight] =
|
txSet, exists := tcn.txsByInitialHeight[blockHeight]
|
||||||
append(tcn.confTxsByInitialHeight[blockHeight], tx.Hash())
|
if !exists {
|
||||||
|
txSet = make(map[chainhash.Hash]struct{})
|
||||||
|
tcn.txsByInitialHeight[blockHeight] = txSet
|
||||||
|
}
|
||||||
|
txSet[*txHash] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,14 +222,14 @@ func (tcn *TxConfNotifier) ConnectTip(blockHash *chainhash.Hash,
|
|||||||
delete(tcn.ntfnsByConfirmHeight, tcn.currentHeight)
|
delete(tcn.ntfnsByConfirmHeight, tcn.currentHeight)
|
||||||
|
|
||||||
// Clear entries from confNotifications and confTxsByInitialHeight. We
|
// Clear entries from confNotifications and confTxsByInitialHeight. We
|
||||||
// assume that reorgs deeper than the reorg safety limit do not happen, so
|
// assume that reorgs deeper than the reorg safety limit do not happen,
|
||||||
// we can clear out entries for the block that is now mature.
|
// so we can clear out entries for the block that is now mature.
|
||||||
if tcn.currentHeight >= tcn.reorgSafetyLimit {
|
if tcn.currentHeight >= tcn.reorgSafetyLimit {
|
||||||
matureBlockHeight := tcn.currentHeight - tcn.reorgSafetyLimit
|
matureBlockHeight := tcn.currentHeight - tcn.reorgSafetyLimit
|
||||||
for _, txHash := range tcn.confTxsByInitialHeight[matureBlockHeight] {
|
for txHash := range tcn.txsByInitialHeight[matureBlockHeight] {
|
||||||
delete(tcn.confNotifications, *txHash)
|
delete(tcn.confNotifications, txHash)
|
||||||
}
|
}
|
||||||
delete(tcn.confTxsByInitialHeight, matureBlockHeight)
|
delete(tcn.txsByInitialHeight, matureBlockHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -273,7 +281,10 @@ func (tcn *TxConfNotifier) DisconnectTip(blockHeight uint32) error {
|
|||||||
delete(ntfnSet, ntfn)
|
delete(ntfnSet, ntfn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(tcn.confTxsByInitialHeight, blockHeight)
|
|
||||||
|
// Finally, we can remove the transactions we're currently watching that
|
||||||
|
// were included in this block height.
|
||||||
|
delete(tcn.txsByInitialHeight, blockHeight)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user