diff --git a/blockchain/accept.go b/blockchain/accept.go index 1d68b5608..2e877bd6c 100644 --- a/blockchain/accept.go +++ b/blockchain/accept.go @@ -63,13 +63,8 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) // Create a new block node for the block and add it to the in-memory // block chain (could be either a side chain or the main chain). blockHeader := &block.MsgBlock().Header - newNode := newBlockNode(blockHeader, blockHeight) + newNode := newBlockNode(blockHeader, prevNode) newNode.status = statusDataStored - if prevNode != nil { - newNode.parent = prevNode - newNode.height = blockHeight - newNode.workSum.Add(prevNode.workSum, newNode.workSum) - } b.index.AddNode(newNode) // Connect the passed block to the chain while respecting proper chain diff --git a/blockchain/blockindex.go b/blockchain/blockindex.go index e9be63b30..f3a060f17 100644 --- a/blockchain/blockindex.go +++ b/blockchain/blockindex.go @@ -101,33 +101,33 @@ type blockNode struct { status blockStatus } -// initBlockNode initializes a block node from the given header and height. The -// node is completely disconnected from the chain and the workSum value is just -// the work for the passed block. The work sum must be updated accordingly when -// the node is inserted into a chain. -// +// initBlockNode initializes a block node from the given header and parent node, +// calculating the height and workSum from the respective fields on the parent. // This function is NOT safe for concurrent access. It must only be called when // initially creating a node. -func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, height int32) { +func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *blockNode) { *node = blockNode{ hash: blockHeader.BlockHash(), workSum: CalcWork(blockHeader.Bits), - height: height, version: blockHeader.Version, bits: blockHeader.Bits, nonce: blockHeader.Nonce, timestamp: blockHeader.Timestamp.Unix(), merkleRoot: blockHeader.MerkleRoot, } + if parent != nil { + node.parent = parent + node.height = parent.height + 1 + node.workSum = node.workSum.Add(parent.workSum, node.workSum) + } } -// newBlockNode returns a new block node for the given block header. It is -// completely disconnected from the chain and the workSum value is just the work -// for the passed block. The work sum must be updated accordingly when the node -// is inserted into a chain. -func newBlockNode(blockHeader *wire.BlockHeader, height int32) *blockNode { +// newBlockNode returns a new block node for the given block header and parent +// node, calculating the height and workSum from the respective fields on the +// parent. This function is NOT safe for concurrent access. +func newBlockNode(blockHeader *wire.BlockHeader, parent *blockNode) *blockNode { var node blockNode - initBlockNode(&node, blockHeader, height) + initBlockNode(&node, blockHeader, parent) return &node } diff --git a/blockchain/chainio.go b/blockchain/chainio.go index 85c910abb..d7ff6ba19 100644 --- a/blockchain/chainio.go +++ b/blockchain/chainio.go @@ -1071,7 +1071,7 @@ func (b *BlockChain) createChainState() error { genesisBlock := btcutil.NewBlock(b.chainParams.GenesisBlock) genesisBlock.SetHeight(0) header := &genesisBlock.MsgBlock().Header - node := newBlockNode(header, 0) + node := newBlockNode(header, nil) node.status = statusDataStored | statusValid b.bestChain.SetTip(node) @@ -1216,36 +1216,37 @@ func (b *BlockChain) initChainState() error { return err } - // Initialize the block node for the block, connect it, - // and add it to the block index. - node := &blockNodes[i] - initBlockNode(node, &header, 0) - node.status = statusDataStored | statusValid + // Determine the parent block node. Since we iterate block headers + // in order of height, if the blocks are mostly linear there is a + // very good chance the previous header processed is the parent. + var parent *blockNode if lastNode == nil { - if node.hash != *b.chainParams.GenesisHash { + blockHash := header.BlockHash() + if !blockHash.IsEqual(b.chainParams.GenesisHash) { return AssertError(fmt.Sprintf("initChainState: Expected "+ "first entry in block index to be genesis block, "+ - "found %s", header.BlockHash())) + "found %s", blockHash)) } - } else { + } else if header.PrevBlock == lastNode.hash { // Since we iterate block headers in order of height, if the // blocks are mostly linear there is a very good chance the // previous header processed is the parent. - parent := lastNode - if header.PrevBlock != parent.hash { - parent = b.index.LookupNode(&header.PrevBlock) - } + parent = lastNode + } else { + parent = b.index.LookupNode(&header.PrevBlock) if parent == nil { return AssertError(fmt.Sprintf("initChainState: Could "+ "not find parent for block %s", header.BlockHash())) } - - node.parent = parent - node.height = parent.height + 1 - node.workSum = node.workSum.Add(parent.workSum, node.workSum) } + // Initialize the block node for the block, connect it, + // and add it to the block index. + node := &blockNodes[i] + initBlockNode(node, &header, parent) + node.status = statusDataStored | statusValid b.index.AddNode(node) + lastNode = node i++ } diff --git a/blockchain/chainview_test.go b/blockchain/chainview_test.go index 760d31ab1..c59004fda 100644 --- a/blockchain/chainview_test.go +++ b/blockchain/chainview_test.go @@ -27,16 +27,11 @@ func chainedNodes(parent *blockNode, numNodes int) []*blockNode { // This is invalid, but all that is needed is enough to get the // synthetic tests to work. header := wire.BlockHeader{Nonce: testNoncePrng.Uint32()} - height := int32(0) if tip != nil { header.PrevBlock = tip.hash - height = tip.height + 1 } - node := newBlockNode(&header, height) - node.parent = tip - tip = node - - nodes[i] = node + nodes[i] = newBlockNode(&header, tip) + tip = nodes[i] } return nodes } diff --git a/blockchain/common_test.go b/blockchain/common_test.go index 38191c25a..d6eff63df 100644 --- a/blockchain/common_test.go +++ b/blockchain/common_test.go @@ -261,7 +261,7 @@ func (b *BlockChain) TstSetCoinbaseMaturity(maturity uint16) { func newFakeChain(params *chaincfg.Params) *BlockChain { // Create a genesis block node and block index index populated with it // for use when creating the fake chain below. - node := newBlockNode(¶ms.GenesisBlock.Header, 0) + node := newBlockNode(¶ms.GenesisBlock.Header, nil) index := newBlockIndex(nil, params) index.AddNode(node) @@ -291,8 +291,5 @@ func newFakeNode(parent *blockNode, blockVersion int32, bits uint32, timestamp t Bits: bits, Timestamp: timestamp, } - node := newBlockNode(header, parent.height+1) - node.parent = parent - node.workSum.Add(parent.workSum, node.workSum) - return node + return newBlockNode(header, parent) } diff --git a/blockchain/validate.go b/blockchain/validate.go index 1beda89e5..f78d3ae63 100644 --- a/blockchain/validate.go +++ b/blockchain/validate.go @@ -1274,8 +1274,6 @@ func (b *BlockChain) CheckConnectBlockTemplate(block *btcutil.Block) error { // is not needed and thus extra work can be avoided. view := NewUtxoViewpoint() view.SetBestHash(&tip.hash) - newNode := newBlockNode(&header, tip.height+1) - newNode.parent = tip - newNode.workSum = newNode.workSum.Add(tip.workSum, newNode.workSum) + newNode := newBlockNode(&header, tip) return b.checkConnectBlock(newNode, block, view, nil) }