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)