[DEV-25] Modified accept.go to account for multiple previous hashes..

This commit is contained in:
Stas Boutenko 2018-06-20 13:49:43 +03:00
parent 6917fac21e
commit bc5edffc92

View File

@ -24,61 +24,72 @@ 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.
prevHash := &block.MsgBlock().Header.PrevBlock prevHeader := &block.MsgBlock().Header
prevNode := b.index.LookupNode(prevHash) numPrevHashes := prevHeader.NumPrevBlocks
if prevNode == nil { prevHashes := prevHeader.PrevBlocks
str := fmt.Sprintf("previous block %s is unknown", prevHash)
return false, ruleError(ErrPreviousBlockUnknown, str)
} else if b.index.NodeStatus(prevNode).KnownInvalid() {
str := fmt.Sprintf("previous block %s is known to be invalid", prevHash)
return false, ruleError(ErrInvalidAncestorBlock, str)
}
blockHeight := prevNode.height + 1 var isMainChain bool
block.SetHeight(blockHeight) 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)
}
// The block must pass all of the validation rules which depend on the blockHeight := node.height + 1
// position of the block within the block chain. block.SetHeight(blockHeight)
err := b.checkBlockContext(block, prevNode, flags)
if err != nil {
return false, err
}
// Insert the block into the database if it's not already there. Even // The block must pass all of the validation rules which depend on the
// though it is possible the block will ultimately fail to connect, it // position of the block within the block chain.
// has already passed all proof-of-work and validity tests which means err := b.checkBlockContext(block, node, flags)
// it would be prohibitively expensive for an attacker to fill up the if err != nil {
// disk with a bunch of blocks that fail to connect. This is necessary return false, err
// since it allows block download to be decoupled from the much more }
// expensive connection logic. It also has some other nice properties
// such as making blocks that never become part of the main chain or
// blocks that fail to connect available for further analysis.
err = b.db.Update(func(dbTx database.Tx) error {
return dbStoreBlock(dbTx, block)
})
if err != nil {
return false, err
}
// Create a new block node for the block and add it to the node index. Even // Insert the block into the database if it's not already there. Even
// if the block ultimately gets connected to the main chain, it starts out // though it is possible the block will ultimately fail to connect, it
// on a side chain. // has already passed all proof-of-work and validity tests which means
blockHeader := &block.MsgBlock().Header // it would be prohibitively expensive for an attacker to fill up the
newNode := newBlockNode(blockHeader, prevNode) // disk with a bunch of blocks that fail to connect. This is necessary
newNode.status = statusDataStored // since it allows block download to be decoupled from the much more
// expensive connection logic. It also has some other nice properties
// such as making blocks that never become part of the main chain or
// blocks that fail to connect available for further analysis.
err = b.db.Update(func(dbTx database.Tx) error {
return dbStoreBlock(dbTx, block)
})
if err != nil {
return false, err
}
b.index.AddNode(newNode) // Create a new block node for the block and add it to the node index. Even
err = b.index.flushToDB() // if the block ultimately gets connected to the main chain, it starts out
if err != nil { // on a side chain.
return false, err blockHeader := &block.MsgBlock().Header
} newNode := newBlockNode(blockHeader, node)
newNode.status = statusDataStored
// Connect the passed block to the chain while respecting proper chain b.index.AddNode(newNode)
// selection according to the chain with the most proof of work. This err = b.index.flushToDB()
// also handles validation of the transaction scripts. if err != nil {
isMainChain, err := b.connectBestChain(newNode, block, flags) return false, err
if err != nil { }
return false, err
// Connect the passed block to the chain while respecting proper chain
// selection according to the chain with the most proof of work. This
// also handles validation of the transaction scripts.
isMainChain, err := b.connectBestChain(newNode, block, flags)
if err != nil {
return false, err
}
if !isMainChain {
break
}
} }
// Notify the caller that the new block was accepted into the block // Notify the caller that the new block was accepted into the block