[DEV-34] In blockNode, made parents a pointer slice, got rid of numPrevHashes, and extracted a lookupPreviousNodes function. Changed c-style loops to range loops.

This commit is contained in:
Stas Boutenko 2018-06-24 13:17:43 +03:00
parent b0d766b7ab
commit 57e7ad1287
12 changed files with 64 additions and 58 deletions

View File

@ -24,32 +24,18 @@ import (
func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) (bool, error) { func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) (bool, error) {
// The height of this block is one more than the referenced previous // The height of this block is one more than the referenced previous
// block. // block.
prevHeader := &block.MsgBlock().Header nodes, err := lookupPreviousNodes(block, b)
numPrevHashes := prevHeader.NumPrevBlocks if err != nil {
prevHashes := prevHeader.PrevBlocks return false, err
nodes := make([]blockNode, numPrevHashes)
for i := byte(0); i < numPrevHashes; i++ {
prevHash := prevHashes[i]
node := b.index.LookupNode(&prevHash)
if node == nil {
str := fmt.Sprintf("previous block %s is unknown", prevHashes)
return false, ruleError(ErrPreviousBlockUnknown, str)
} else if b.index.NodeStatus(node).KnownInvalid() {
str := fmt.Sprintf("previous block %s is known to be invalid", prevHashes)
return false, ruleError(ErrInvalidAncestorBlock, str)
} }
nodes = append(nodes, *node) firstNode := nodes[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
}
firstNode := nodes[0]
blockHeight := firstNode.height + 1 blockHeight := firstNode.height + 1
block.SetHeight(blockHeight) block.SetHeight(blockHeight)
// The block must pass all of the validation rules which depend on the // The block must pass all of the validation rules which depend on the
// position of the block within the block chain. // position of the block within the block chain.
err := b.checkBlockContext(block, &firstNode, flags) err = b.checkBlockContext(block, firstNode, flags)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -100,3 +86,24 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags)
return isMainChain, nil return isMainChain, nil
} }
func lookupPreviousNodes(block *btcutil.Block, blockChain *BlockChain) ([]*blockNode, error) {
header := block.MsgBlock().Header
prevHashes := header.PrevBlocks
nodes := make([]*blockNode, len(prevHashes))
for _, prevHash := range prevHashes {
node := blockChain.index.LookupNode(&prevHash)
if node == nil {
str := fmt.Sprintf("previous block %s is unknown", prevHashes)
return nil, ruleError(ErrPreviousBlockUnknown, str)
} else if blockChain.index.NodeStatus(node).KnownInvalid() {
str := fmt.Sprintf("previous block %s is known to be invalid", prevHashes)
return nil, ruleError(ErrInvalidAncestorBlock, str)
}
nodes = append(nodes, node)
}
return nodes, nil
}

View File

@ -71,11 +71,8 @@ type blockNode struct {
// hundreds of thousands of these in memory, so a few extra bytes of // hundreds of thousands of these in memory, so a few extra bytes of
// padding adds up. // padding adds up.
// numParents is the amount of parent blocks for this node.
numParents byte
// parents is the parent blocks for this node. // parents is the parent blocks for this node.
parents []blockNode parents []*blockNode
// hash is the double sha 256 of the block. // hash is the double sha 256 of the block.
hash daghash.Hash hash daghash.Hash
@ -108,12 +105,11 @@ type blockNode struct {
// calculating the height and workSum from the respective fields on the first parent. // calculating the height and workSum from the respective fields on the first parent.
// This function is NOT safe for concurrent access. It must only be called when // This function is NOT safe for concurrent access. It must only be called when
// initially creating a node. // initially creating a node.
func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parents []blockNode) { func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parents []*blockNode) {
numParents := byte(len(parents)) numParents := byte(len(parents))
*node = blockNode{ *node = blockNode{
hash: blockHeader.BlockHash(), hash: blockHeader.BlockHash(),
parents: parents, parents: parents,
numParents: numParents,
workSum: CalcWork(blockHeader.Bits), workSum: CalcWork(blockHeader.Bits),
version: blockHeader.Version, version: blockHeader.Version,
bits: blockHeader.Bits, bits: blockHeader.Bits,
@ -131,7 +127,7 @@ func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parents []blo
// newBlockNode returns a new block node for the given block header and parent // newBlockNode returns a new block node for the given block header and parent
// nodes, calculating the height and workSum from the respective fields on the // nodes, calculating the height and workSum from the respective fields on the
// parent. This function is NOT safe for concurrent access. // parent. This function is NOT safe for concurrent access.
func newBlockNode(blockHeader *wire.BlockHeader, parents []blockNode) *blockNode { func newBlockNode(blockHeader *wire.BlockHeader, parents []*blockNode) *blockNode {
var node blockNode var node blockNode
initBlockNode(&node, blockHeader, parents) initBlockNode(&node, blockHeader, parents)
return &node return &node
@ -142,14 +138,11 @@ func newBlockNode(blockHeader *wire.BlockHeader, parents []blockNode) *blockNode
// This function is safe for concurrent access. // This function is safe for concurrent access.
func (node *blockNode) Header() wire.BlockHeader { func (node *blockNode) Header() wire.BlockHeader {
// No lock is needed because all accessed fields are immutable. // No lock is needed because all accessed fields are immutable.
prevHashes := make([]daghash.Hash, node.numParents) prevHashes := node.prevHashes()
for _, parent := range node.parents {
prevHashes = append(prevHashes, parent.hash)
}
return wire.BlockHeader{ return wire.BlockHeader{
Version: node.version, Version: node.version,
NumPrevBlocks: node.numParents, NumPrevBlocks: byte(len(node.parents)),
PrevBlocks: prevHashes, PrevBlocks: prevHashes,
MerkleRoot: node.merkleRoot, MerkleRoot: node.merkleRoot,
Timestamp: time.Unix(node.timestamp, 0), Timestamp: time.Unix(node.timestamp, 0),
@ -170,7 +163,7 @@ func (node *blockNode) Ancestor(height int32) *blockNode {
} }
n := node n := node
for ; n != nil && n.height != height; n = &n.parents[0] { for ; n != nil && n.height != height; n = n.parents[0] {
// Intentionally left blank // Intentionally left blank
} }
@ -200,7 +193,7 @@ func (node *blockNode) CalcPastMedianTime() time.Time {
timestamps[i] = iterNode.timestamp timestamps[i] = iterNode.timestamp
numNodes++ numNodes++
iterNode = &iterNode.parents[0] iterNode = iterNode.parents[0]
} }
// Prune the slice to the actual number of available timestamps which // Prune the slice to the actual number of available timestamps which
@ -225,6 +218,15 @@ func (node *blockNode) CalcPastMedianTime() time.Time {
return time.Unix(medianTimestamp, 0) return time.Unix(medianTimestamp, 0)
} }
func (node *blockNode) prevHashes() []daghash.Hash {
prevHashes := make([]daghash.Hash, len(node.parents))
for _, parent := range node.parents {
prevHashes = append(prevHashes, parent.hash)
}
return prevHashes
}
// blockIndex provides facilities for keeping track of an in-memory index of the // blockIndex provides facilities for keeping track of an in-memory index of the
// block chain. Although the name block chain suggests a single chain of // block chain. Although the name block chain suggests a single chain of
// blocks, it is actually a tree-shaped structure where any node can have // blocks, it is actually a tree-shaped structure where any node can have

View File

@ -373,7 +373,7 @@ func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx, utxoView
// Obtain the latest BIP9 version bits state for the // Obtain the latest BIP9 version bits state for the
// CSV-package soft-fork deployment. The adherence of sequence // CSV-package soft-fork deployment. The adherence of sequence
// locks depends on the current soft-fork state. // locks depends on the current soft-fork state.
csvState, err := b.deploymentState(&node.parents[0], dagconfig.DeploymentCSV) // TODO: (Stas) This is wrong. Modified only to satisfy compilation. csvState, err := b.deploymentState(node.parents[0], dagconfig.DeploymentCSV) // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -502,7 +502,7 @@ func (b *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List
// Do not reorganize to a known invalid chain. Ancestors deeper than the // Do not reorganize to a known invalid chain. Ancestors deeper than the
// direct parent are checked below but this is a quick check before doing // direct parent are checked below but this is a quick check before doing
// more unnecessary work. // more unnecessary work.
if b.index.NodeStatus(&node.parents[0]).KnownInvalid() { // TODO: (Stas) This is wrong. Modified only to satisfy compilation. if b.index.NodeStatus(node.parents[0]).KnownInvalid() { // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
b.index.SetStatusFlags(node, statusInvalidAncestor) b.index.SetStatusFlags(node, statusInvalidAncestor)
return detachNodes, attachNodes return detachNodes, attachNodes
} }
@ -513,7 +513,7 @@ func (b *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List
// later. // later.
forkNode := b.bestChain.FindFork(node) forkNode := b.bestChain.FindFork(node)
invalidChain := false invalidChain := false
for n := node; n != nil && n != forkNode; n = &n.parents[0] { // TODO: (Stas) This is wrong. Modified only to satisfy compilation. for n := node; n != nil && n != forkNode; n = n.parents[0] { // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
if b.index.NodeStatus(n).KnownInvalid() { if b.index.NodeStatus(n).KnownInvalid() {
invalidChain = true invalidChain = true
break break
@ -536,7 +536,7 @@ func (b *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List
// Start from the end of the main chain and work backwards until the // Start from the end of the main chain and work backwards until the
// common ancestor adding each block to the list of nodes to detach from // common ancestor adding each block to the list of nodes to detach from
// the main chain. // the main chain.
for n := b.bestChain.Tip(); n != nil && n != forkNode; n = &n.parents[0] { // TODO: (Stas) This is wrong. Modified only to satisfy compilation. for n := b.bestChain.Tip(); n != nil && n != forkNode; n = n.parents[0] { // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
detachNodes.PushBack(n) detachNodes.PushBack(n)
} }
@ -684,7 +684,7 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
} }
// Load the previous block since some details for it are needed below. // Load the previous block since some details for it are needed below.
prevNode := &node.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation. prevNode := node.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
var prevBlock *btcutil.Block var prevBlock *btcutil.Block
err := b.db.View(func(dbTx database.Tx) error { err := b.db.View(func(dbTx database.Tx) error {
var err error var err error
@ -762,7 +762,7 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
view.commit() view.commit()
// This node's parent is now the end of the best chain. // This node's parent is now the end of the best chain.
b.bestChain.SetTip(&node.parents[0]) // TODO: (Stas) This is wrong. Modified only to satisfy compilation. b.bestChain.SetTip(node.parents[0]) // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
// Update the state for the best block. Notice how this replaces the // Update the state for the best block. Notice how this replaces the
// entire struct instead of updating the existing one. This effectively // entire struct instead of updating the existing one. This effectively
@ -1355,7 +1355,7 @@ func (b *BlockChain) HeightToHashRange(startHeight int32,
hashes := make([]daghash.Hash, resultsLength) hashes := make([]daghash.Hash, resultsLength)
for i := resultsLength - 1; i >= 0; i-- { for i := resultsLength - 1; i >= 0; i-- {
hashes[i] = node.hash hashes[i] = node.hash
node = &node.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation. node = node.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
} }
return hashes, nil return hashes, nil
} }

View File

@ -1162,7 +1162,7 @@ func (b *BlockChain) initChainState() error {
// Initialize the block node for the block, connect it, // Initialize the block node for the block, connect it,
// and add it to the block index. // and add it to the block index.
node := &blockNodes[i] node := &blockNodes[i]
initBlockNode(node, header, []blockNode{*parent}) // TODO: (Stas) This is wrong. Modified only to satisfy compilation. initBlockNode(node, header, []*blockNode{parent}) // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
node.status = status node.status = status
b.index.addNode(node) b.index.addNode(node)

View File

@ -141,7 +141,7 @@ func (c *chainView) setTip(node *blockNode) {
for node != nil && c.nodes[node.height] != node { for node != nil && c.nodes[node.height] != node {
c.nodes[node.height] = node c.nodes[node.height] = node
node = &node.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation. node = node.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
} }
} }
@ -311,7 +311,7 @@ func (c *chainView) findFork(node *blockNode) *blockNode {
// contain the node or there are no more nodes in which case there is no // contain the node or there are no more nodes in which case there is no
// common node between the two. // common node between the two.
for node != nil && !c.contains(node) { for node != nil && !c.contains(node) {
node = &node.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation. node = node.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
} }
return node return node

View File

@ -31,7 +31,7 @@ func chainedNodes(parent *blockNode, numNodes int) []*blockNode {
if tip != nil { if tip != nil {
header.PrevBlocks = []daghash.Hash{tip.hash} // TODO: (Stas) This is wrong. Modified only to satisfy compilation. header.PrevBlocks = []daghash.Hash{tip.hash} // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
} }
nodes[i] = newBlockNode(&header, []blockNode{*tip}) // TODO: (Stas) This is wrong. Modified only to satisfy compilation. nodes[i] = newBlockNode(&header, []*blockNode{tip}) // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
tip = nodes[i] tip = nodes[i]
} }
return nodes return nodes

View File

@ -380,5 +380,5 @@ func newFakeNode(parent *blockNode, blockVersion int32, bits uint32, timestamp t
Bits: bits, Bits: bits,
Timestamp: timestamp, Timestamp: timestamp,
} }
return newBlockNode(header, []blockNode{*parent}) // TODO: (Stas) This is wrong. Modified only to satisfy compilation. return newBlockNode(header, []*blockNode{parent}) // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
} }

View File

@ -201,7 +201,7 @@ func (b *BlockChain) findPrevTestNetDifficulty(startNode *blockNode) uint32 {
for iterNode != nil && iterNode.height%b.blocksPerRetarget != 0 && for iterNode != nil && iterNode.height%b.blocksPerRetarget != 0 &&
iterNode.bits == b.chainParams.PowLimitBits { iterNode.bits == b.chainParams.PowLimitBits {
iterNode = &iterNode.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation. iterNode = iterNode.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
} }
// Return the found difficulty or the minimum difficulty if no // Return the found difficulty or the minimum difficulty if no

View File

@ -211,11 +211,8 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bo
} }
// Handle orphan blocks. // Handle orphan blocks.
numPrevHashes := blockHeader.NumPrevBlocks
prevHashes := blockHeader.PrevBlocks
allPrevHashesExist := true allPrevHashesExist := true
for i := byte(0); i < numPrevHashes; i++ { for _, prevHash := range blockHeader.PrevBlocks {
prevHash := prevHashes[i]
prevHashExists, err := b.blockExists(&prevHash) prevHashExists, err := b.blockExists(&prevHash)
if err != nil { if err != nil {
return false, false, err return false, false, err

View File

@ -230,7 +230,7 @@ func (b *BlockChain) thresholdState(prevNode *blockNode, checker thresholdCondit
} }
// Get the previous block node. // Get the previous block node.
countNode = &countNode.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation. countNode = countNode.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
} }
// The state is locked in if the number of blocks in the // The state is locked in if the number of blocks in the
@ -316,7 +316,7 @@ func (b *BlockChain) initThresholdCaches() error {
// threshold state for each of them. This will ensure the caches are // threshold state for each of them. This will ensure the caches are
// populated and any states that needed to be recalculated due to // populated and any states that needed to be recalculated due to
// definition changes is done now. // definition changes is done now.
prevNode := &b.bestChain.Tip().parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation. prevNode := b.bestChain.Tip().parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
for bit := uint32(0); bit < vbNumBits; bit++ { for bit := uint32(0); bit < vbNumBits; bit++ {
checker := bitConditionChecker{bit: bit, chain: b} checker := bitConditionChecker{bit: bit, chain: b}
cache := &b.warningCaches[bit] cache := &b.warningCaches[bit]

View File

@ -1141,7 +1141,7 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi
// Enforce CHECKSEQUENCEVERIFY during all block validation checks once // Enforce CHECKSEQUENCEVERIFY during all block validation checks once
// the soft-fork deployment is fully active. // the soft-fork deployment is fully active.
csvState, err := b.deploymentState(&node.parents[0], dagconfig.DeploymentCSV) // TODO: (Stas) This is wrong. Modified only to satisfy compilation. csvState, err := b.deploymentState(node.parents[0], dagconfig.DeploymentCSV) // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
if err != nil { if err != nil {
return err return err
} }
@ -1232,6 +1232,6 @@ func (b *BlockChain) CheckConnectBlockTemplate(block *btcutil.Block) error {
// is not needed and thus extra work can be avoided. // is not needed and thus extra work can be avoided.
view := NewUtxoViewpoint() view := NewUtxoViewpoint()
view.SetBestHash(&tip.hash) view.SetBestHash(&tip.hash)
newNode := newBlockNode(&header, []blockNode{*tip}) // TODO: (Stas) This is wrong. Modified only to satisfy compilation. newNode := newBlockNode(&header, []*blockNode{tip}) // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
return b.checkConnectBlock(newNode, block, view, nil) return b.checkConnectBlock(newNode, block, view, nil)
} }

View File

@ -113,7 +113,7 @@ func (c bitConditionChecker) Condition(node *blockNode) (bool, error) {
return false, nil return false, nil
} }
expectedVersion, err := c.chain.calcNextBlockVersion(&node.parents[0]) // TODO: (Stas) This is wrong. Modified only to satisfy compilation. expectedVersion, err := c.chain.calcNextBlockVersion(node.parents[0]) // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
if err != nil { if err != nil {
return false, err return false, err
} }
@ -241,7 +241,7 @@ func (b *BlockChain) warnUnknownRuleActivations(node *blockNode) error {
for bit := uint32(0); bit < vbNumBits; bit++ { for bit := uint32(0); bit < vbNumBits; bit++ {
checker := bitConditionChecker{bit: bit, chain: b} checker := bitConditionChecker{bit: bit, chain: b}
cache := &b.warningCaches[bit] cache := &b.warningCaches[bit]
state, err := b.thresholdState(&node.parents[0], checker, cache) // TODO: (Stas) This is wrong. Modified only to satisfy compilation. state, err := b.thresholdState(node.parents[0], checker, cache) // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
if err != nil { if err != nil {
return err return err
} }
@ -278,7 +278,7 @@ func (b *BlockChain) warnUnknownVersions(node *blockNode) error {
// Warn if enough previous blocks have unexpected versions. // Warn if enough previous blocks have unexpected versions.
numUpgraded := uint32(0) numUpgraded := uint32(0)
for i := uint32(0); i < unknownVerNumToCheck && node != nil; i++ { for i := uint32(0); i < unknownVerNumToCheck && node != nil; i++ {
expectedVersion, err := b.calcNextBlockVersion(&node.parents[0]) // TODO: (Stas) This is wrong. Modified only to satisfy compilation. expectedVersion, err := b.calcNextBlockVersion(node.parents[0]) // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
if err != nil { if err != nil {
return err return err
} }
@ -288,7 +288,7 @@ func (b *BlockChain) warnUnknownVersions(node *blockNode) error {
numUpgraded++ numUpgraded++
} }
node = &node.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation. node = node.parents[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation.
} }
if numUpgraded > unknownVerWarnNum { if numUpgraded > unknownVerWarnNum {
log.Warn("Unknown block versions are being mined, so new " + log.Warn("Unknown block versions are being mined, so new " +