diff --git a/blockdag/accept.go b/blockdag/accept.go index f956aae43..4716b4b90 100644 --- a/blockdag/accept.go +++ b/blockdag/accept.go @@ -24,32 +24,18 @@ import ( func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) (bool, error) { // The height of this block is one more than the referenced previous // block. - prevHeader := &block.MsgBlock().Header - numPrevHashes := prevHeader.NumPrevBlocks - prevHashes := prevHeader.PrevBlocks - - 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) + nodes, err := lookupPreviousNodes(block, b) + if err != nil { + return false, err } - firstNode := nodes[0] + firstNode := nodes[0] // TODO: (Stas) This is wrong. Modified only to satisfy compilation. blockHeight := firstNode.height + 1 block.SetHeight(blockHeight) // The block must pass all of the validation rules which depend on the // position of the block within the block chain. - err := b.checkBlockContext(block, &firstNode, flags) + err = b.checkBlockContext(block, firstNode, flags) if err != nil { return false, err } @@ -100,3 +86,24 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) 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 +} diff --git a/blockdag/blockindex.go b/blockdag/blockindex.go index bce7f4281..d729465ee 100644 --- a/blockdag/blockindex.go +++ b/blockdag/blockindex.go @@ -71,11 +71,8 @@ type blockNode struct { // hundreds of thousands of these in memory, so a few extra bytes of // padding adds up. - // numParents is the amount of parent blocks for this node. - numParents byte - // parents is the parent blocks for this node. - parents []blockNode + parents []*blockNode // hash is the double sha 256 of the block. hash daghash.Hash @@ -108,12 +105,11 @@ type blockNode struct { // 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 // 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)) *node = blockNode{ hash: blockHeader.BlockHash(), parents: parents, - numParents: numParents, workSum: CalcWork(blockHeader.Bits), version: blockHeader.Version, 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 // nodes, 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, parents []blockNode) *blockNode { +func newBlockNode(blockHeader *wire.BlockHeader, parents []*blockNode) *blockNode { var node blockNode initBlockNode(&node, blockHeader, parents) return &node @@ -142,14 +138,11 @@ func newBlockNode(blockHeader *wire.BlockHeader, parents []blockNode) *blockNode // This function is safe for concurrent access. func (node *blockNode) Header() wire.BlockHeader { // No lock is needed because all accessed fields are immutable. - prevHashes := make([]daghash.Hash, node.numParents) - for _, parent := range node.parents { - prevHashes = append(prevHashes, parent.hash) - } + prevHashes := node.prevHashes() return wire.BlockHeader{ Version: node.version, - NumPrevBlocks: node.numParents, + NumPrevBlocks: byte(len(node.parents)), PrevBlocks: prevHashes, MerkleRoot: node.merkleRoot, Timestamp: time.Unix(node.timestamp, 0), @@ -170,7 +163,7 @@ func (node *blockNode) Ancestor(height int32) *blockNode { } 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 } @@ -200,7 +193,7 @@ func (node *blockNode) CalcPastMedianTime() time.Time { timestamps[i] = iterNode.timestamp numNodes++ - iterNode = &iterNode.parents[0] + iterNode = iterNode.parents[0] } // 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) } +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 // 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 diff --git a/blockdag/chain.go b/blockdag/chain.go index 11f948005..9538e3e9e 100644 --- a/blockdag/chain.go +++ b/blockdag/chain.go @@ -373,7 +373,7 @@ func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx, utxoView // Obtain the latest BIP9 version bits state for the // CSV-package soft-fork deployment. The adherence of sequence // 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 { 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 // direct parent are checked below but this is a quick check before doing // 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) return detachNodes, attachNodes } @@ -513,7 +513,7 @@ func (b *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List // later. forkNode := b.bestChain.FindFork(node) 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() { invalidChain = true 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 // common ancestor adding each block to the list of nodes to detach from // 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) } @@ -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. - 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 err := b.db.View(func(dbTx database.Tx) error { var err error @@ -762,7 +762,7 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view view.commit() // 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 // 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) for i := resultsLength - 1; i >= 0; i-- { 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 } diff --git a/blockdag/chainio.go b/blockdag/chainio.go index 41d087048..a7d184683 100644 --- a/blockdag/chainio.go +++ b/blockdag/chainio.go @@ -1162,7 +1162,7 @@ func (b *BlockChain) initChainState() error { // Initialize the block node for the block, connect it, // and add it to the block index. 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 b.index.addNode(node) diff --git a/blockdag/chainview.go b/blockdag/chainview.go index c1174b5d8..816a8fd33 100644 --- a/blockdag/chainview.go +++ b/blockdag/chainview.go @@ -141,7 +141,7 @@ func (c *chainView) setTip(node *blockNode) { for node != nil && 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 // common node between the two. 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 diff --git a/blockdag/chainview_test.go b/blockdag/chainview_test.go index 2467142a9..19a84e6e0 100644 --- a/blockdag/chainview_test.go +++ b/blockdag/chainview_test.go @@ -31,7 +31,7 @@ func chainedNodes(parent *blockNode, numNodes int) []*blockNode { if tip != nil { 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] } return nodes diff --git a/blockdag/common_test.go b/blockdag/common_test.go index 897a47067..08b45370c 100644 --- a/blockdag/common_test.go +++ b/blockdag/common_test.go @@ -380,5 +380,5 @@ func newFakeNode(parent *blockNode, blockVersion int32, bits uint32, timestamp t Bits: bits, 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. } diff --git a/blockdag/difficulty.go b/blockdag/difficulty.go index 2aede64b5..ee67237bd 100644 --- a/blockdag/difficulty.go +++ b/blockdag/difficulty.go @@ -201,7 +201,7 @@ func (b *BlockChain) findPrevTestNetDifficulty(startNode *blockNode) uint32 { for iterNode != nil && iterNode.height%b.blocksPerRetarget != 0 && 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 diff --git a/blockdag/process.go b/blockdag/process.go index 69e61b354..a5ccebc5b 100644 --- a/blockdag/process.go +++ b/blockdag/process.go @@ -211,11 +211,8 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bo } // Handle orphan blocks. - numPrevHashes := blockHeader.NumPrevBlocks - prevHashes := blockHeader.PrevBlocks allPrevHashesExist := true - for i := byte(0); i < numPrevHashes; i++ { - prevHash := prevHashes[i] + for _, prevHash := range blockHeader.PrevBlocks { prevHashExists, err := b.blockExists(&prevHash) if err != nil { return false, false, err diff --git a/blockdag/thresholdstate.go b/blockdag/thresholdstate.go index d4a6da922..ee3f2a476 100644 --- a/blockdag/thresholdstate.go +++ b/blockdag/thresholdstate.go @@ -230,7 +230,7 @@ func (b *BlockChain) thresholdState(prevNode *blockNode, checker thresholdCondit } // 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 @@ -316,7 +316,7 @@ func (b *BlockChain) initThresholdCaches() error { // threshold state for each of them. This will ensure the caches are // populated and any states that needed to be recalculated due to // 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++ { checker := bitConditionChecker{bit: bit, chain: b} cache := &b.warningCaches[bit] diff --git a/blockdag/validate.go b/blockdag/validate.go index 50706aab4..4c5affb5d 100644 --- a/blockdag/validate.go +++ b/blockdag/validate.go @@ -1141,7 +1141,7 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi // Enforce CHECKSEQUENCEVERIFY during all block validation checks once // 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 { return err } @@ -1232,6 +1232,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, []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) } diff --git a/blockdag/versionbits.go b/blockdag/versionbits.go index 78426b65a..c705858e8 100644 --- a/blockdag/versionbits.go +++ b/blockdag/versionbits.go @@ -113,7 +113,7 @@ func (c bitConditionChecker) Condition(node *blockNode) (bool, error) { 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 { return false, err } @@ -241,7 +241,7 @@ func (b *BlockChain) warnUnknownRuleActivations(node *blockNode) error { for bit := uint32(0); bit < vbNumBits; bit++ { checker := bitConditionChecker{bit: bit, chain: b} 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 { return err } @@ -278,7 +278,7 @@ func (b *BlockChain) warnUnknownVersions(node *blockNode) error { // Warn if enough previous blocks have unexpected versions. numUpgraded := uint32(0) 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 { return err } @@ -288,7 +288,7 @@ func (b *BlockChain) warnUnknownVersions(node *blockNode) error { 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 { log.Warn("Unknown block versions are being mined, so new " +