mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
[DEV-34] Modified blockindex.go to account for multiple previous hashes and changed accept.go to reflect those changes.
This commit is contained in:
parent
ab75fcf5fb
commit
4260d37158
@ -28,7 +28,7 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags)
|
||||
numPrevHashes := prevHeader.NumPrevBlocks
|
||||
prevHashes := prevHeader.PrevBlocks
|
||||
|
||||
var isMainChain bool
|
||||
nodes := make([]blockNode, numPrevHashes)
|
||||
for i := byte(0); i < numPrevHashes; i++ {
|
||||
prevHash := prevHashes[i]
|
||||
node := b.index.LookupNode(&prevHash)
|
||||
@ -40,56 +40,55 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags)
|
||||
return false, ruleError(ErrInvalidAncestorBlock, str)
|
||||
}
|
||||
|
||||
blockHeight := node.height + 1
|
||||
block.SetHeight(blockHeight)
|
||||
nodes = append(nodes, *node)
|
||||
}
|
||||
|
||||
// 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, node, flags)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
firstNode := nodes[0]
|
||||
blockHeight := firstNode.height + 1
|
||||
block.SetHeight(blockHeight)
|
||||
|
||||
// Insert the block into the database if it's not already there. Even
|
||||
// though it is possible the block will ultimately fail to connect, it
|
||||
// has already passed all proof-of-work and validity tests which means
|
||||
// it would be prohibitively expensive for an attacker to fill up the
|
||||
// disk with a bunch of blocks that fail to connect. This is necessary
|
||||
// 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
|
||||
}
|
||||
// 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)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Create a new block node for the block and add it to the node index. Even
|
||||
// if the block ultimately gets connected to the main chain, it starts out
|
||||
// on a side chain.
|
||||
blockHeader := &block.MsgBlock().Header
|
||||
newNode := newBlockNode(blockHeader, node)
|
||||
newNode.status = statusDataStored
|
||||
// Insert the block into the database if it's not already there. Even
|
||||
// though it is possible the block will ultimately fail to connect, it
|
||||
// has already passed all proof-of-work and validity tests which means
|
||||
// it would be prohibitively expensive for an attacker to fill up the
|
||||
// disk with a bunch of blocks that fail to connect. This is necessary
|
||||
// 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)
|
||||
err = b.index.flushToDB()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Create a new block node for the block and add it to the node index. Even
|
||||
// if the block ultimately gets connected to the main chain, it starts out
|
||||
// on a side chain.
|
||||
blockHeader := &block.MsgBlock().Header
|
||||
newNode := newBlockNode(blockHeader, nodes)
|
||||
newNode.status = statusDataStored
|
||||
|
||||
// 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
|
||||
}
|
||||
b.index.AddNode(newNode)
|
||||
err = b.index.flushToDB()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !isMainChain {
|
||||
break
|
||||
}
|
||||
// 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
|
||||
}
|
||||
|
||||
// Notify the caller that the new block was accepted into the block
|
||||
|
@ -71,8 +71,11 @@ type blockNode struct {
|
||||
// hundreds of thousands of these in memory, so a few extra bytes of
|
||||
// padding adds up.
|
||||
|
||||
// parent is the parent block for this node.
|
||||
parent *blockNode
|
||||
// numParents is the amount of parent blocks for this node.
|
||||
numParents byte
|
||||
|
||||
// parents is the parent blocks for this node.
|
||||
parents []blockNode
|
||||
|
||||
// hash is the double sha 256 of the block.
|
||||
hash daghash.Hash
|
||||
@ -101,13 +104,16 @@ type blockNode struct {
|
||||
status blockStatus
|
||||
}
|
||||
|
||||
// initBlockNode initializes a block node from the given header and parent node,
|
||||
// calculating the height and workSum from the respective fields on the parent.
|
||||
// initBlockNode initializes a block node from the given header and parent nodes,
|
||||
// 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, parent *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,
|
||||
@ -115,19 +121,19 @@ func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *block
|
||||
timestamp: blockHeader.Timestamp.Unix(),
|
||||
merkleRoot: blockHeader.MerkleRoot,
|
||||
}
|
||||
if parent != nil {
|
||||
node.parent = parent
|
||||
if numParents > 0 {
|
||||
parent := parents[0]
|
||||
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 and parent
|
||||
// node, 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.
|
||||
func newBlockNode(blockHeader *wire.BlockHeader, parent *blockNode) *blockNode {
|
||||
func newBlockNode(blockHeader *wire.BlockHeader, parents []blockNode) *blockNode {
|
||||
var node blockNode
|
||||
initBlockNode(&node, blockHeader, parent)
|
||||
initBlockNode(&node, blockHeader, parents)
|
||||
return &node
|
||||
}
|
||||
|
||||
@ -136,17 +142,19 @@ func newBlockNode(blockHeader *wire.BlockHeader, parent *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.
|
||||
prevHash := &zeroHash
|
||||
if node.parent != nil {
|
||||
prevHash = &node.parent.hash
|
||||
prevHashes := make([]daghash.Hash, node.numParents)
|
||||
for _, parent := range node.parents {
|
||||
prevHashes = append(prevHashes, parent.hash)
|
||||
}
|
||||
|
||||
return wire.BlockHeader{
|
||||
Version: node.version,
|
||||
PrevBlock: *prevHash,
|
||||
MerkleRoot: node.merkleRoot,
|
||||
Timestamp: time.Unix(node.timestamp, 0),
|
||||
Bits: node.bits,
|
||||
Nonce: node.nonce,
|
||||
Version: node.version,
|
||||
NumPrevBlocks: node.numParents,
|
||||
PrevBlocks: prevHashes,
|
||||
MerkleRoot: node.merkleRoot,
|
||||
Timestamp: time.Unix(node.timestamp, 0),
|
||||
Bits: node.bits,
|
||||
Nonce: node.nonce,
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,7 +170,7 @@ func (node *blockNode) Ancestor(height int32) *blockNode {
|
||||
}
|
||||
|
||||
n := node
|
||||
for ; n != nil && n.height != height; n = n.parent {
|
||||
for ; n != nil && n.height != height; n = &n.parents[0] {
|
||||
// Intentionally left blank
|
||||
}
|
||||
|
||||
@ -192,7 +200,7 @@ func (node *blockNode) CalcPastMedianTime() time.Time {
|
||||
timestamps[i] = iterNode.timestamp
|
||||
numNodes++
|
||||
|
||||
iterNode = iterNode.parent
|
||||
iterNode = &iterNode.parents[0]
|
||||
}
|
||||
|
||||
// Prune the slice to the actual number of available timestamps which
|
||||
|
Loading…
x
Reference in New Issue
Block a user