Repository: decred/dcrd
Pull request #2493 (2020-12-09 07:22:59)

multi: Use best state snapshot next stake diff.
The current best state snapshot was updated a long time ago to include the next required stake difficulty.  This updates the RPC server, block manager, and broadcast pruning logic in server to make use of that versus making an explicit call.

It also removes the no longer used method from the `rpcserver.Chain` interface, the block manager infrastructure, and related test code accordingly.


Patch:
diff --git a/blockmanager.go b/blockmanager.go
index 2e8a771a..f54c3c72 100644
--- a/blockmanager.go
+++ b/blockmanager.go
@@ -147,19 +147,6 @@ type requestFromPeerResponse struct {
 	err error
 }
 
-// calcNextReqStakeDifficultyResponse is a response sent to the reply channel of a
-// calcNextReqStakeDifficultyMsg query.
-type calcNextReqStakeDifficultyResponse struct {
-	stakeDifficulty int64
-	err             error
-}
-
-// calcNextReqStakeDifficultyMsg is a message type to be sent across the message
-// channel for requesting the required stake difficulty of the next block.
-type calcNextReqStakeDifficultyMsg struct {
-	reply chan calcNextReqStakeDifficultyResponse
-}
-
 // tipGenerationResponse is a response sent to the reply channel of a
 // tipGenerationMsg query.
 type tipGenerationResponse struct {
@@ -1713,13 +1700,6 @@ out:
 					err: err,
 				}
 
-			case calcNextReqStakeDifficultyMsg:
-				stakeDiff, err := b.cfg.Chain.CalcNextRequiredStakeDifficulty()
-				msg.reply <- calcNextReqStakeDifficultyResponse{
-					stakeDifficulty: stakeDiff,
-					err:             err,
-				}
-
 			case forceReorganizationMsg:
 				err := b.cfg.Chain.ForceHeadReorganization(
 					msg.formerBest, msg.newBest)
@@ -2417,18 +2397,6 @@ func (b *blockManager) requestFromPeer(p *peerpkg.Peer, blocks, txs []*chainhash
 	return nil
 }
 
-// CalcNextRequiredStakeDifficulty calculates the required Stake difficulty for
-// the next block after the current main chain.  This function makes use of
-// CalcNextRequiredStakeDifficulty on an internal instance of a block chain.  It is
-// funneled through the block manager since blockchain is not safe for concurrent
-// access.
-func (b *blockManager) CalcNextRequiredStakeDifficulty() (int64, error) {
-	reply := make(chan calcNextReqStakeDifficultyResponse)
-	b.msgChan <- calcNextReqStakeDifficultyMsg{reply: reply}
-	response := <-reply
-	return response.stakeDifficulty, response.err
-}
-
 // ForceReorganization forces a reorganization of the block chain to the block
 // hash requested, so long as it matches up with the current organization of the
 // best chain.  It is funneled through the block manager since blockchain is not
diff --git a/internal/rpcserver/interface.go b/internal/rpcserver/interface.go
index 902c58cb..5ea85e8d 100644
--- a/internal/rpcserver/interface.go
+++ b/internal/rpcserver/interface.go
@@ -251,11 +251,6 @@ type Chain interface {
 	// main chain.
 	BlockHeightByHash(hash *chainhash.Hash) (int64, error)
 
-	// CalcNextRequiredStakeDifficulty calculates the required stake difficulty for
-	// the block after the end of the current best chain based on the active stake
-	// difficulty retarget rules.
-	CalcNextRequiredStakeDifficulty() (int64, error)
-
 	// CalcWantHeight calculates the height of the final block of the previous
 	// interval given a block height.
 	CalcWantHeight(interval, height int64) int64
diff --git a/internal/rpcserver/rpcserver.go b/internal/rpcserver/rpcserver.go
index 297d3b8f..f9043586 100644
--- a/internal/rpcserver/rpcserver.go
+++ b/internal/rpcserver/rpcserver.go
@@ -2527,18 +2527,12 @@ func handleGetMiningInfo(ctx context.Context, s *Server, cmd interface{}) (inter
 	}
 
 	best := s.cfg.Chain.BestSnapshot()
-	nextStakeDiff, err := s.cfg.Chain.CalcNextRequiredStakeDifficulty()
-	if err != nil {
-		return nil, rpcInternalError(err.Error(),
-			"Could not calculate next stake difficulty")
-	}
-
 	result := types.GetMiningInfoResult{
 		Blocks:           best.Height,
 		CurrentBlockSize: best.BlockSize,
 		CurrentBlockTx:   best.NumTxns,
 		Difficulty:       getDifficultyRatio(best.Bits, s.cfg.ChainParams),
-		StakeDifficulty:  nextStakeDiff,
+		StakeDifficulty:  best.NextStakeDiff,
 		Generate:         s.cfg.CPUMiner.IsMining(),
 		GenProcLimit:     s.cfg.CPUMiner.NumWorkers(),
 		HashesPerSec:     int64(s.cfg.CPUMiner.HashesPerSecond()),
@@ -2961,21 +2955,11 @@ func handleGetStakeDifficulty(_ context.Context, s *Server, cmd interface{}) (in
 			Message: "Error getting stake difficulty: " + err.Error(),
 		}
 	}
-	currentSdiff := dcrutil.Amount(blockHeader.SBits)
-
-	nextSdiff, err := chain.CalcNextRequiredStakeDifficulty()
-	if err != nil {
-		context := "Could not calculate next stake difficulty"
-		return nil, rpcInternalError(err.Error(), context)
-	}
-	nextSdiffAmount := dcrutil.Amount(nextSdiff)
-
-	sDiffResult := &types.GetStakeDifficultyResult{
-		CurrentStakeDifficulty: currentSdiff.ToCoin(),
-		NextStakeDifficulty:    nextSdiffAmount.ToCoin(),
+	result := types.GetStakeDifficultyResult{
+		CurrentStakeDifficulty: dcrutil.Amount(blockHeader.SBits).ToCoin(),
+		NextStakeDifficulty:    dcrutil.Amount(best.NextStakeDiff).ToCoin(),
 	}
-
-	return sDiffResult, nil
+	return result, nil
 }
 
 // convertVersionMap translates a map[int]int into a sorted array of
diff --git a/internal/rpcserver/rpcwebsocket.go b/internal/rpcserver/rpcwebsocket.go
index b0be3574..d64bece0 100644
--- a/internal/rpcserver/rpcwebsocket.go
+++ b/internal/rpcserver/rpcwebsocket.go
@@ -2222,16 +2222,10 @@ func handleRebroadcastMissed(wsc *wsClient, icmd interface{}) (interface{}, erro
 			err.Error(), "")
 	}
 
-	stakeDiff, err := cfg.Chain.CalcNextRequiredStakeDifficulty()
-	if err != nil {
-		return nil, rpcInternalError("Could not calculate next stake "+
-			"difficulty "+err.Error(), "")
-	}
-
 	missedTicketsNtfn := &blockchain.TicketNotificationsData{
 		Hash:            best.Hash,
 		Height:          best.Height,
-		StakeDifficulty: stakeDiff,
+		StakeDifficulty: best.NextStakeDiff,
 		TicketsSpent:    []chainhash.Hash{},
 		TicketsMissed:   mt,
 		TicketsNew:      []chainhash.Hash{},
diff --git a/server.go b/server.go
index 191f4131..c2af4d41 100644
--- a/server.go
+++ b/server.go
@@ -2606,14 +2606,6 @@ out:
 
 			case broadcastPruneInventory:
 				best := s.chain.BestSnapshot()
-				nextStakeDiff, err :=
-					s.chain.CalcNextRequiredStakeDifficulty()
-				if err != nil {
-					srvrLog.Errorf("Failed to get next stake difficulty: %v",
-						err)
-					break
-				}
-
 				isTreasuryEnabled, err := s.chain.IsTreasuryAgendaActive(&best.Hash)
 				if err != nil {
 					srvrLog.Errorf("Could not obtain treasury agenda status: %v",
@@ -2633,7 +2625,7 @@ out:
 					// Remove the ticket rebroadcast if the amount not equal to
 					// the current stake difficulty.
 					if txType == stake.TxTypeSStx &&
-						tx.MsgTx().TxOut[0].Value != nextStakeDiff {
+						tx.MsgTx().TxOut[0].Value != best.NextStakeDiff {
 						delete(pendingInvs, iv)
 						srvrLog.Debugf("Pending ticket purchase broadcast "+
 							"inventory for tx %v removed. Ticket value not "+


Test patch:
diff --git a/internal/rpcserver/rpcserverhandlers_test.go b/internal/rpcserver/rpcserverhandlers_test.go
index e88e05f2..ac0da0e3 100644
--- a/internal/rpcserver/rpcserverhandlers_test.go
+++ b/internal/rpcserver/rpcserverhandlers_test.go
@@ -125,66 +125,65 @@ type tspendVotes struct {
 
 // testRPCChain provides a mock block chain by implementing the Chain interface.
 type testRPCChain struct {
-	bestSnapshot                    *blockchain.BestState
-	blockByHash                     *dcrutil.Block
-	blockByHashErr                  error
-	blockByHeight                   *dcrutil.Block
-	blockByHeightErr                error
-	blockHashByHeight               *chainhash.Hash
-	blockHashByHeightErr            error
-	blockHeightByHash               int64
-	blockHeightByHashErr            error
-	calcNextRequiredStakeDifficulty int64
-	calcWantHeight                  int64
-	chainTips                       []blockchain.ChainTipInfo
-	chainWork                       *big.Int
-	chainWorkErr                    error
-	checkExpiredTickets             []bool
-	checkLiveTicket                 bool
-	checkLiveTickets                []bool
-	checkMissedTickets              []bool
-	convertUtxosToMinimalOutputs    []*stake.MinimalOutput
-	countVoteVersion                uint32
-	countVoteVersionErr             error
-	estimateNextStakeDifficultyFn   func(newTickets int64, useMaxTickets bool) (diff int64, err error)
-	fetchUtxoEntry                  UtxoEntry
-	fetchUtxoStats                  *blockchain.UtxoStats
-	getStakeVersions                []blockchain.StakeVersions
-	getStakeVersionsErr             error
-	getVoteCounts                   blockchain.VoteCounts
-	getVoteCountsErr                error
-	getVoteInfo                     *blockchain.VoteInfo
-	getVoteInfoErr                  error
-	headerByHash                    wire.BlockHeader
-	headerByHashErr                 error
-	headerByHeight                  wire.BlockHeader
-	headerByHeightErr               error
-	heightRangeFn                   func(startHeight, endHeight int64) ([]chainhash.Hash, error)
-	isCurrent                       bool
-	liveTickets                     []chainhash.Hash
-	liveTicketsErr                  error
-	locateHeaders                   []wire.BlockHeader
-	lotteryDataForBlock             []chainhash.Hash
-	mainChainHasBlock               bool
-	maxBlockSize                    int64
-	maxBlockSizeErr                 error
-	minedTSpendBlocks               []chainhash.Hash
-	missedTickets                   []chainhash.Hash
-	missedTicketsErr                error
-	nextThresholdState              blockchain.ThresholdStateTuple
-	nextThresholdStateErr           error
-	stateLastChangedHeight          int64
-	stateLastChangedHeightErr       error
-	ticketPoolValue                 dcrutil.Amount
-	ticketPoolValueErr              error
-	ticketsWithAddress              []chainhash.Hash
-	ticketsWithAddressErr           error
-	tipGeneration                   []chainhash.Hash
-	treasuryBalance                 *blockchain.TreasuryBalanceInfo
-	treasuryBalanceErr              error
-	tspendVotes                     tspendVotes
-	treasuryActive                  bool
-	treasuryActiveErr               error
+	bestSnapshot                  *blockchain.BestState
+	blockByHash                   *dcrutil.Block
+	blockByHashErr                error
+	blockByHeight                 *dcrutil.Block
+	blockByHeightErr              error
+	blockHashByHeight             *chainhash.Hash
+	blockHashByHeightErr          error
+	blockHeightByHash             int64
+	blockHeightByHashErr          error
+	calcWantHeight                int64
+	chainTips                     []blockchain.ChainTipInfo
+	chainWork                     *big.Int
+	chainWorkErr                  error
+	checkExpiredTickets           []bool
+	checkLiveTicket               bool
+	checkLiveTickets              []bool
+	checkMissedTickets            []bool
+	convertUtxosToMinimalOutputs  []*stake.MinimalOutput
+	countVoteVersion              uint32
+	countVoteVersionErr           error
+	estimateNextStakeDifficultyFn func(newTickets int64, useMaxTickets bool) (diff int64, err error)
+	fetchUtxoEntry                UtxoEntry
+	fetchUtxoStats                *blockchain.UtxoStats
+	getStakeVersions              []blockchain.StakeVersions
+	getStakeVersionsErr           error
+	getVoteCounts                 blockchain.VoteCounts
+	getVoteCountsErr              error
+	getVoteInfo                   *blockchain.VoteInfo
+	getVoteInfoErr                error
+	headerByHash                  wire.BlockHeader
+	headerByHashErr               error
+	headerByHeight                wire.BlockHeader
+	headerByHeightErr             error
+	heightRangeFn                 func(startHeight, endHeight int64) ([]chainhash.Hash, error)
+	isCurrent                     bool
+	liveTickets                   []chainhash.Hash
+	liveTicketsErr                error
+	locateHeaders                 []wire.BlockHeader
+	lotteryDataForBlock           []chainhash.Hash
+	mainChainHasBlock             bool
+	maxBlockSize                  int64
+	maxBlockSizeErr               error
+	minedTSpendBlocks             []chainhash.Hash
+	missedTickets                 []chainhash.Hash
+	missedTicketsErr              error
+	nextThresholdState            blockchain.ThresholdStateTuple
+	nextThresholdStateErr         error
+	stateLastChangedHeight        int64
+	stateLastChangedHeightErr     error
+	ticketPoolValue               dcrutil.Amount
+	ticketPoolValueErr            error
+	ticketsWithAddress            []chainhash.Hash
+	ticketsWithAddressErr         error
+	tipGeneration                 []chainhash.Hash
+	treasuryBalance               *blockchain.TreasuryBalanceInfo
+	treasuryBalanceErr            error
+	tspendVotes                   tspendVotes
+	treasuryActive                bool
+	treasuryActiveErr             error
 }
 
 // BestSnapshot returns a mocked blockchain.BestState.
@@ -212,11 +211,6 @@ func (c *testRPCChain) BlockHeightByHash(hash *chainhash.Hash) (int64, error) {
 	return c.blockHeightByHash, c.blockHeightByHashErr
 }
 
-// CalcNextRequiredStakeDifficulty returns a mocked required stake difficulty.
-func (c *testRPCChain) CalcNextRequiredStakeDifficulty() (int64, error) {
-	return c.calcNextRequiredStakeDifficulty, nil
-}
-
 // CalcWantHeight returns a mocked height of the final block of the previous
 // interval given a block height.
 func (c *testRPCChain) CalcWantHeight(interval, height int64) int64 {
@@ -1403,12 +1397,11 @@ func defaultMockRPCChain() *testRPCChain {
 			TotalSubsidy:   1122503888072909,
 			NextFinalState: [6]byte{0xdc, 0x2a, 0x4f, 0x6e, 0x60, 0xb3},
 		},
-		blockByHash:                     blk,
-		blockByHeight:                   blk,
-		blockHashByHeight:               blkHash,
-		blockHeightByHash:               blkHeight,
-		calcNextRequiredStakeDifficulty: 14428162590,
-		calcWantHeight:                  431487,
+		blockByHash:       blk,
+		blockByHeight:     blk,
+		blockHashByHeight: blkHash,
+		blockHeightByHash: blkHeight,
+		calcWantHeight:    431487,
 		chainTips: []blockchain.ChainTipInfo{{
 			Height:    blkHeight,
 			Hash:      *blkHash,