Files
kaspad/blockdag/finality.go
stasatdaglabs 0653e59e16 [NOD-1190] Refactor process.go (#858)
* [NOD-1190] Move non-processBlock stuff out of process.go.

* [NOD-1190] Move everything out of accept.go.

* [NOD-1190] Move all processBlock functions to process.go.

* [NOD-1190] Move orphan stuff to orphan.go.

* [NOD-1190] Remove thresholdstate stuff.

* [NOD-1190] Move isSynced to sync_rate.go.

* [NOD-1190] Move delayed block stuff to delayed_blocks.go.

* [NOD-1190] Rename orphans.go to orphaned_blocks.go.

* [NOD-1190] Move non-BlockDAG structs out of dag.go.

* [NOD-1190] Remove unused fields.

* [NOD-1190] Fixup BlockDAG.New a bit.

* [NOD-1190] Move sequence lock stuff to sequence_lock.go

* [NOD-1190] Move some multiset stuff out of dag.go.

* [NOD-1190] Move finality stuff out of dag.go.

* [NOD-1190] Move blocklocator stuff out of dag.go.

* [NOD-1190] Move confirmation stuff out of dag.go.

* [NOD-1190] Move utxo and selected parent chain stuff out of dag.go.

* [NOD-1190] Move BlockDAG lock functions to the beginning of dag.go.

* [NOD-1190] Move verifyAndBuildUTXO out of process.go.

* [NOD-1190] Extract handleProcessBlockError to a function.

* [NOD-1190] Remove daglock unlock in notifyBlockAccepted.

* [NOD-1190] Extract checkDuplicateBlock to a method.

* [NOD-1190] Fix merge errors.

* [NOD-1190] Remove unused parameter from CalcSequenceLock.

* [NOD-1190] Extract processBlock contents into functions.

* [NOD-1190] Fix parent delayed blocks not marking their children as delayed

* [NOD-1190] Fix TestProcessDelayedBlocks.

* [NOD-1190] Extract stuff in maybeAcceptBlock to separate functions.

* [NOD-1190] Rename handleProcessBlockError to handleConnectBlockError.

* [NOD-1190] Remove some comments.

* [NOD-1190] Use lowercase in error messages.

* [NOD-1190] Rename createNewBlockNode to createBlockNodeFromBlock.

* [NOD-1190] Rename orphaned_blocks.go to orpan_blocks.go.

* [NOD-1190] Extract validateUTXOCommitment to a separate function.

* [NOD-1190] Fix a bug in validateUTXOCommitment.

* [NOD-1190] Rename checkBlockTxsFinalized to checkBlockTransactionsFinalized.

* [NOD-1190] Add a comment over createBlockNodeFromBlock.

* [NOD-1190] Fold validateAllTxsFinalized into checkBlockTransactionsFinalized.

* [NOD-1190] Return parents from checkBlockParents.

* [NOD-1190] Remove the processBlock prefix from the functions that had it.

* [NOD-1190] Begin extracting functions out of checkTransactionSanity.

* [NOD-1190] Finish extracting functions out of checkTransactionSanity.

* [NOD-1190] Remove an unused parameter.

* [NOD-1190] Fix merge errors.

* [NOD-1190] Added an explanation as to why we change the nonce in TestProcessDelayedBlocks.

* [NOD-1190] Fix a comment.

* [NOD-1190] Fix a comment.

* [NOD-1190] Fix a typo.

* [NOD-1190] Replace checkBlockParents with handleLookupParentNodesError.
2020-08-13 13:33:43 +03:00

114 lines
3.7 KiB
Go

package blockdag
import (
"fmt"
"github.com/kaspanet/kaspad/util/daghash"
)
// LastFinalityPointHash returns the hash of the last finality point
func (dag *BlockDAG) LastFinalityPointHash() *daghash.Hash {
if dag.lastFinalityPoint == nil {
return nil
}
return dag.lastFinalityPoint.hash
}
// FinalityInterval is the interval that determines the finality window of the DAG.
func (dag *BlockDAG) FinalityInterval() uint64 {
return uint64(dag.Params.FinalityDuration / dag.Params.TargetTimePerBlock)
}
// checkFinalityViolation checks the new block does not violate the finality rules
// specifically - the new block selectedParent chain should contain the old finality point.
func (dag *BlockDAG) checkFinalityViolation(newNode *blockNode) error {
// the genesis block can not violate finality rules
if newNode.isGenesis() {
return nil
}
// Because newNode doesn't have reachability data we
// need to check if the last finality point is in the
// selected parent chain of newNode.selectedParent, so
// we explicitly check if newNode.selectedParent is
// the finality point.
if dag.lastFinalityPoint == newNode.selectedParent {
return nil
}
isInSelectedChain, err := dag.isInSelectedParentChainOf(dag.lastFinalityPoint, newNode.selectedParent)
if err != nil {
return err
}
if !isInSelectedChain {
return ruleError(ErrFinality, "the last finality point is not in the selected parent chain of this block")
}
return nil
}
// updateFinalityPoint updates the dag's last finality point if necessary.
func (dag *BlockDAG) updateFinalityPoint() {
selectedTip := dag.selectedTip()
// if the selected tip is the genesis block - it should be the new finality point
if selectedTip.isGenesis() {
dag.lastFinalityPoint = selectedTip
return
}
// We are looking for a new finality point only if the new block's finality score is higher
// by 2 than the existing finality point's
if selectedTip.finalityScore(dag) < dag.lastFinalityPoint.finalityScore(dag)+2 {
return
}
var currentNode *blockNode
for currentNode = selectedTip.selectedParent; ; currentNode = currentNode.selectedParent {
// We look for the first node in the selected parent chain that has a higher finality score than the last finality point.
if currentNode.selectedParent.finalityScore(dag) == dag.lastFinalityPoint.finalityScore(dag) {
break
}
}
dag.lastFinalityPoint = currentNode
spawn("dag.finalizeNodesBelowFinalityPoint", func() {
dag.finalizeNodesBelowFinalityPoint(true)
})
}
func (dag *BlockDAG) finalizeNodesBelowFinalityPoint(deleteDiffData bool) {
queue := make([]*blockNode, 0, len(dag.lastFinalityPoint.parents))
for parent := range dag.lastFinalityPoint.parents {
queue = append(queue, parent)
}
var nodesToDelete []*blockNode
if deleteDiffData {
nodesToDelete = make([]*blockNode, 0, dag.FinalityInterval())
}
for len(queue) > 0 {
var current *blockNode
current, queue = queue[0], queue[1:]
if !current.isFinalized {
current.isFinalized = true
if deleteDiffData {
nodesToDelete = append(nodesToDelete, current)
}
for parent := range current.parents {
queue = append(queue, parent)
}
}
}
if deleteDiffData {
err := dag.utxoDiffStore.removeBlocksDiffData(dag.databaseContext, nodesToDelete)
if err != nil {
panic(fmt.Sprintf("Error removing diff data from utxoDiffStore: %s", err))
}
}
}
// IsKnownFinalizedBlock returns whether the block is below the finality point.
// IsKnownFinalizedBlock might be false-negative because node finality status is
// updated in a separate goroutine. To get a definite answer if a block
// is finalized or not, use dag.checkFinalityViolation.
func (dag *BlockDAG) IsKnownFinalizedBlock(blockHash *daghash.Hash) bool {
node, ok := dag.index.LookupNode(blockHash)
return ok && node.isFinalized
}