blockchain: Notify stake states after connected block

When an accepted block is attached to the main chain, potentially
three notifications are emitted: NTBlockConnected,
NTSpentAndMissedTickets, and NTNewTickets.  This change moves
NTBlockConnected to being the first notification, followed by
NTSpentAndMissedTickets and NTNewTickets.

This is important for applications which react to the stake
notifications since they will have already been notified of the most
recently connected block.  For example, dcrwallet uses the
spentandmissedtickets JSON-RPC notification to create revocation
transactions for missed votes.  However, if the missed tickets are
notified before the connected block, a race is possible where the
revocations are rejected as they double spend a vote on what wallet
believes is still the main chain tip block.

This is considered a patch bump to the JSON-RPC API semantic version
due to affecting and improving the ordering of the blockconnected and
spentandmissedtickets notifications.
This commit is contained in:
Josh Rickmar 2018-11-05 13:22:38 -05:00 committed by Dave Collins
parent 13b69e2c84
commit abcd805c63
2 changed files with 12 additions and 12 deletions

View File

@ -884,6 +884,16 @@ func (b *BlockChain) connectBlock(node *blockNode, block, parent *dcrutil.Block,
b.stateSnapshot = state
b.stateLock.Unlock()
// Assemble the current block and the parent into a slice.
blockAndParent := []*dcrutil.Block{block, parent}
// Notify the caller that the block was connected to the main chain.
// The caller would typically want to react with actions such as
// updating wallets.
b.chainLock.Unlock()
b.sendNotification(NTBlockConnected, blockAndParent)
b.chainLock.Lock()
// Send stake notifications about the new block.
if node.height >= b.chainParams.StakeEnabledHeight {
nextStakeDiff, err := b.calcNextRequiredStakeDifficulty(node)
@ -913,16 +923,6 @@ func (b *BlockChain) connectBlock(node *blockNode, block, parent *dcrutil.Block,
})
}
// Assemble the current block and the parent into a slice.
blockAndParent := []*dcrutil.Block{block, parent}
// Notify the caller that the block was connected to the main chain.
// The caller would typically want to react with actions such as
// updating wallets.
b.chainLock.Unlock()
b.sendNotification(NTBlockConnected, blockAndParent)
b.chainLock.Lock()
// Optimization: Before checkpoints, immediately dump the parent's stake
// node because we no longer need it.
if node.height < b.chainParams.LatestCheckpointHeight() {

View File

@ -53,10 +53,10 @@ import (
// API version constants
const (
jsonrpcSemverString = "4.0.0"
jsonrpcSemverString = "4.0.1"
jsonrpcSemverMajor = 4
jsonrpcSemverMinor = 0
jsonrpcSemverPatch = 0
jsonrpcSemverPatch = 1
)
const (