fix crash on unlock generate/invalidate loop
This commit is contained in:
parent
eb686cfa9e
commit
2df74a828f
3 changed files with 19 additions and 6 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue