@@ -116,6 +116,12 @@ type BlockChain struct {
116116 // fields in this struct below this point.
117117 chainLock sync.RWMutex
118118
119+ // notificationSendLock helps us only process one block at a time.
120+ // It's definitely a hack. DCRD has much better structure in this regard.
121+ // Without this you will get an error if you invalidate a block and then generate more right after.
122+ // Taken from https://github.com/gcash/bchd/pull/308
123+ notificationSendLock sync.Mutex
124+
119125 // These fields are related to the memory block index. They both have
120126 // their own locks, however they are often also protected by the chain
121127 // lock to help prevent logic races when blocks are being processed.
@@ -683,9 +689,11 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
683689 // Notify the caller that the block was connected to the main chain.
684690 // The caller would typically want to react with actions such as
685691 // updating wallets.
692+ b .notificationSendLock .Lock ()
693+ defer b .notificationSendLock .Unlock ()
686694 b .chainLock .Unlock ()
695+ defer b .chainLock .Lock ()
687696 b .sendNotification (NTBlockConnected , block )
688- b .chainLock .Lock ()
689697
690698 return nil
691699}
@@ -808,9 +816,11 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
808816 // Notify the caller that the block was disconnected from the main
809817 // chain. The caller would typically want to react with actions such as
810818 // updating wallets.
819+ b .notificationSendLock .Lock ()
820+ defer b .notificationSendLock .Unlock ()
811821 b .chainLock .Unlock ()
822+ defer b .chainLock .Lock ()
812823 b .sendNotification (NTBlockDisconnected , block )
813- b .chainLock .Lock ()
814824
815825 return nil
816826}
@@ -1646,6 +1656,8 @@ func (b *BlockChain) LocateHeaders(locator BlockLocator, hashStop *chainhash.Has
16461656//
16471657// This function is safe for concurrent access.
16481658func (b * BlockChain ) InvalidateBlock (hash * chainhash.Hash ) error {
1659+ b .chainLock .Lock ()
1660+ defer b .chainLock .Unlock ()
16491661 return b .invalidateBlock (hash )
16501662}
16511663
@@ -1671,8 +1683,6 @@ func (b *BlockChain) invalidateBlock(hash *chainhash.Hash) error {
16711683 b .index .SetStatusFlags (node , statusValidateFailed )
16721684 b .index .UnsetStatusFlags (node , statusValid )
16731685
1674- b .chainLock .Lock ()
1675- defer b .chainLock .Unlock ()
16761686 detachNodes , attachNodes := b .getReorganizeNodes (node .parent )
16771687
16781688 err := b .reorganizeChain (detachNodes , attachNodes )
@@ -1727,6 +1737,7 @@ func (b *BlockChain) reconsiderBlock(hash *chainhash.Hash) error {
17271737 firstNode = n
17281738 }
17291739
1740+ // do we need an rlock on chainstate for this section?
17301741 var blk * btcutil.Block
17311742 err := b .db .View (func (dbTx database.Tx ) error {
17321743 var err error
0 commit comments