fix crash on unlock generate/invalidate loop

This commit is contained in:
Brannon King 2021-11-26 11:36:30 -05:00 committed by Roy Lee
parent eb686cfa9e
commit 2df74a828f
3 changed files with 19 additions and 6 deletions

View file

@ -84,9 +84,11 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags)
// Notify the caller that the new block was accepted into the block // Notify the caller that the new block was accepted into the block
// chain. The caller would typically want to react by relaying the // chain. The caller would typically want to react by relaying the
// inventory to other peers. // inventory to other peers.
b.notificationSendLock.Lock()
defer b.notificationSendLock.Unlock()
b.chainLock.Unlock() b.chainLock.Unlock()
defer b.chainLock.Lock()
b.sendNotification(NTBlockAccepted, block) b.sendNotification(NTBlockAccepted, block)
b.chainLock.Lock()
return isMainChain, nil return isMainChain, nil
} }

View file

@ -116,6 +116,12 @@ type BlockChain struct {
// fields in this struct below this point. // fields in this struct below this point.
chainLock sync.RWMutex chainLock sync.RWMutex
// notificationSendLock helps us only process one block at a time.
// It's definitely a hack. DCRD has much better structure in this regard.
// Without this you will get an error if you invalidate a block and then generate more right after.
// Taken from https://github.com/gcash/bchd/pull/308
notificationSendLock sync.Mutex
// These fields are related to the memory block index. They both have // These fields are related to the memory block index. They both have
// their own locks, however they are often also protected by the chain // their own locks, however they are often also protected by the chain
// lock to help prevent logic races when blocks are being processed. // lock to help prevent logic races when blocks are being processed.
@ -683,9 +689,11 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
// Notify the caller that the block was connected to the main chain. // Notify the caller that the block was connected to the main chain.
// The caller would typically want to react with actions such as // The caller would typically want to react with actions such as
// updating wallets. // updating wallets.
b.notificationSendLock.Lock()
defer b.notificationSendLock.Unlock()
b.chainLock.Unlock() b.chainLock.Unlock()
defer b.chainLock.Lock()
b.sendNotification(NTBlockConnected, block) b.sendNotification(NTBlockConnected, block)
b.chainLock.Lock()
return nil return nil
} }
@ -808,9 +816,11 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
// Notify the caller that the block was disconnected from the main // Notify the caller that the block was disconnected from the main
// chain. The caller would typically want to react with actions such as // chain. The caller would typically want to react with actions such as
// updating wallets. // updating wallets.
b.notificationSendLock.Lock()
defer b.notificationSendLock.Unlock()
b.chainLock.Unlock() b.chainLock.Unlock()
defer b.chainLock.Lock()
b.sendNotification(NTBlockDisconnected, block) b.sendNotification(NTBlockDisconnected, block)
b.chainLock.Lock()
return nil return nil
} }
@ -1646,6 +1656,8 @@ func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Has
// //
// This function is safe for concurrent access. // This function is safe for concurrent access.
func (b *BlockChain) InvalidateBlock(hash *chainhash.Hash) error { func (b *BlockChain) InvalidateBlock(hash *chainhash.Hash) error {
b.chainLock.Lock()
defer b.chainLock.Unlock()
return b.invalidateBlock(hash) return b.invalidateBlock(hash)
} }
@ -1671,8 +1683,6 @@ func (b *BlockChain) invalidateBlock(hash *chainhash.Hash) error {
b.index.SetStatusFlags(node, statusValidateFailed) b.index.SetStatusFlags(node, statusValidateFailed)
b.index.UnsetStatusFlags(node, statusValid) b.index.UnsetStatusFlags(node, statusValid)
b.chainLock.Lock()
defer b.chainLock.Unlock()
detachNodes, attachNodes := b.getReorganizeNodes(node.parent) detachNodes, attachNodes := b.getReorganizeNodes(node.parent)
err := b.reorganizeChain(detachNodes, attachNodes) err := b.reorganizeChain(detachNodes, attachNodes)
@ -1727,6 +1737,7 @@ func (b *BlockChain) reconsiderBlock(hash *chainhash.Hash) error {
firstNode = n firstNode = n
} }
// do we need an rlock on chainstate for this section?
var blk *btcutil.Block var blk *btcutil.Block
err := b.db.View(func(dbTx database.Tx) error { err := b.db.View(func(dbTx database.Tx) error {
var err error var err error

View file

@ -275,7 +275,7 @@ func (ef *FeeEstimator) RegisterBlock(block *btcutil.Block) error {
// This shouldn't happen but check just in case to avoid // This shouldn't happen but check just in case to avoid
// an out-of-bounds array index later. // an out-of-bounds array index later.
if blocksToConfirm >= estimateFeeDepth { if blocksToConfirm >= estimateFeeDepth || blocksToConfirm < 0 {
continue continue
} }