From 479bfdead83a35aaf488da92bf8ceeb3fe0bdf29 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 24 Feb 2018 17:33:13 -0600 Subject: [PATCH] blockchain: Reduce GetGeneration to TipGeneration. This replaces the GetGeneration function which allowed getting the entire generation (all children stemming from the same parent) of an arbitrary bock with TipGeneration which only returns the same information for the tip block. This is being done because the function is only used for mining purposes to get the generation of the current tip. The code is simplified by reducing its scope to its actual purpose as an initial benefit. It also provides much better optimization opportunities later. --- blockchain/chain.go | 36 ++++++++++++++++-------------------- blockmanager.go | 31 +++++++++++++++---------------- mining.go | 2 +- rpcserver.go | 2 +- server.go | 2 +- 5 files changed, 34 insertions(+), 39 deletions(-) diff --git a/blockchain/chain.go b/blockchain/chain.go index 032a0ace..4dc755a3 100644 --- a/blockchain/chain.go +++ b/blockchain/chain.go @@ -468,23 +468,13 @@ func (b *BlockChain) addOrphanBlock(block *dcrutil.Block) { b.prevOrphans[*prevHash] = append(b.prevOrphans[*prevHash], oBlock) } -// getGeneration gets a generation of blocks who all have the same parent by -// taking a hash as input, locating its parent node, and then returning all -// children for that parent node including the hash passed. This can then be -// used by the mempool downstream to locate all potential block template -// parents. -func (b *BlockChain) getGeneration(h chainhash.Hash) ([]chainhash.Hash, error) { - // This typically happens because the main chain has recently - // reorganized and the block the miner is looking at is on - // a fork. Usually it corrects itself after failure. - node, err := b.findNode(&h, maxSearchDepth) - if err != nil { - return nil, fmt.Errorf("couldn't find block node in best chain: %v", - err.Error()) - } - - // Get the parent of this node. - p, err := b.index.PrevNodeFromNode(node) +// tipGeneration returns the entire generation of blocks stemming from the +// parent of the current tip. +// +// This function MUST be called with the chain lock held (for reads). +func (b *BlockChain) tipGeneration() ([]chainhash.Hash, error) { + // Get the parent of this tip. + p, err := b.index.PrevNodeFromNode(b.bestNode) if err != nil { return nil, fmt.Errorf("block is orphan (parent missing)") } @@ -502,9 +492,15 @@ func (b *BlockChain) getGeneration(h chainhash.Hash) ([]chainhash.Hash, error) { return allChildren, nil } -// GetGeneration is the exported version of getGeneration. -func (b *BlockChain) GetGeneration(hash chainhash.Hash) ([]chainhash.Hash, error) { - return b.getGeneration(hash) +// TipGeneration returns the entire generation of blocks stemming from the +// parent of the current tip. +// +// The function is safe for concurrent access. +func (b *BlockChain) TipGeneration() ([]chainhash.Hash, error) { + b.chainLock.Lock() + children, err := b.tipGeneration() + b.chainLock.Unlock() + return children, err } // findNode finds the node scaling backwards from best chain or return an diff --git a/blockmanager.go b/blockmanager.go index 4c87379b..f792ed30 100644 --- a/blockmanager.go +++ b/blockmanager.go @@ -163,19 +163,18 @@ type calcNextReqStakeDifficultyMsg struct { reply chan calcNextReqStakeDifficultyResponse } -// getGenerationResponse is a response sent to the reply channel of a -// getGenerationMsg query. -type getGenerationResponse struct { +// tipGenerationResponse is a response sent to the reply channel of a +// tipGenerationMsg query. +type tipGenerationResponse struct { hashes []chainhash.Hash err error } -// getGenerationMsg is a message type to be sent across the message +// tipGenerationMsg is a message type to be sent across the message // channel for requesting the required the entire generation of a // block node. -type getGenerationMsg struct { - hash chainhash.Hash - reply chan getGenerationResponse +type tipGenerationMsg struct { + reply chan tipGenerationResponse } // forceReorganizationResponse is a response sent to the reply channel of a @@ -1761,9 +1760,9 @@ out: err: err, } - case getGenerationMsg: - g, err := b.chain.GetGeneration(msg.hash) - msg.reply <- getGenerationResponse{ + case tipGenerationMsg: + g, err := b.chain.TipGeneration() + msg.reply <- tipGenerationResponse{ hashes: g, err: err, } @@ -2453,12 +2452,12 @@ func (b *blockManager) ForceReorganization(formerBest, newBest chainhash.Hash) e return response.err } -// GetGeneration returns the hashes of all the children of a parent for the -// block hash that is passed to the function. It is funneled through the block -// manager since blockchain is not safe for concurrent access. -func (b *blockManager) GetGeneration(h chainhash.Hash) ([]chainhash.Hash, error) { - reply := make(chan getGenerationResponse) - b.msgChan <- getGenerationMsg{hash: h, reply: reply} +// TipGeneration returns the hashes of all the children of the current best +// chain tip. It is funneled through the block manager since blockchain is not +// safe for concurrent access. +func (b *blockManager) TipGeneration() ([]chainhash.Hash, error) { + reply := make(chan tipGenerationResponse) + b.msgChan <- tipGenerationMsg{reply: reply} response := <-reply return response.hashes, response.err } diff --git a/mining.go b/mining.go index b72baa3f..270caed7 100644 --- a/mining.go +++ b/mining.go @@ -1193,7 +1193,7 @@ func NewBlockTemplate(policy *mining.Policy, server *server, if nextBlockHeight >= stakeValidationHeight { // Obtain the entire generation of blocks stemming from this parent. - children, err := blockManager.GetGeneration(*prevHash) + children, err := blockManager.TipGeneration() if err != nil { return nil, miningRuleError(ErrFailedToGetGeneration, err.Error()) } diff --git a/rpcserver.go b/rpcserver.go index 56e5f3aa..9d80e229 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -4380,7 +4380,7 @@ func handleRebroadcastMissed(s *rpcServer, cmd interface{}, closeChan <-chan str // handleRebroadcastWinners implements the rebroadcastwinners command. func handleRebroadcastWinners(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { hash, height := s.server.blockManager.chainState.Best() - blocks, err := s.server.blockManager.GetGeneration(*hash) + blocks, err := s.server.blockManager.TipGeneration() if err != nil { return nil, rpcInternalError("Could not get generation "+ err.Error(), "") diff --git a/server.go b/server.go index 1513b026..7d9b547b 100644 --- a/server.go +++ b/server.go @@ -463,7 +463,7 @@ func (sp *serverPeer) OnGetMiningState(p *peer.Peer, msg *wire.MsgGetMiningState // Obtain the entire generation of blocks stemming from the parent of // the current tip. - children, err := bm.GetGeneration(*newest) + children, err := bm.TipGeneration() if err != nil { peerLog.Warnf("failed to access block manager to get the generation "+ "for a mining state request (block: %v): %v", newest, err)