mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-09-13 04:50:11 +00:00

* Add VirtualBlueHashes to BlockDAG * Refactor TestGHOSTDAG to read DAGs from json files * Added a new DAG for the ghostdag test suite * Pass BehaviorFlags to delayed blocks
98 lines
3.3 KiB
Go
98 lines
3.3 KiB
Go
package blockdag
|
|
|
|
import (
|
|
"github.com/kaspanet/kaspad/util"
|
|
"github.com/kaspanet/kaspad/util/daghash"
|
|
"github.com/kaspanet/kaspad/util/mstime"
|
|
"github.com/pkg/errors"
|
|
"time"
|
|
)
|
|
|
|
// delayedBlock represents a block which has a delayed timestamp and will be processed at processTime
|
|
type delayedBlock struct {
|
|
block *util.Block
|
|
processTime mstime.Time
|
|
flags BehaviorFlags
|
|
}
|
|
|
|
func (dag *BlockDAG) isKnownDelayedBlock(hash *daghash.Hash) bool {
|
|
_, exists := dag.delayedBlocks[*hash]
|
|
return exists
|
|
}
|
|
|
|
func (dag *BlockDAG) addDelayedBlock(block *util.Block, flags BehaviorFlags, delay time.Duration) error {
|
|
processTime := dag.Now().Add(delay)
|
|
log.Debugf("Adding block to delayed blocks queue (block hash: %s, process time: %s)", block.Hash().String(), processTime)
|
|
delayedBlock := &delayedBlock{
|
|
block: block,
|
|
processTime: processTime,
|
|
flags: flags,
|
|
}
|
|
|
|
dag.delayedBlocks[*block.Hash()] = delayedBlock
|
|
dag.delayedBlocksQueue.Push(delayedBlock)
|
|
return dag.processDelayedBlocks()
|
|
}
|
|
|
|
// processDelayedBlocks loops over all delayed blocks and processes blocks which are due.
|
|
// This method is invoked after processing a block (ProcessBlock method).
|
|
func (dag *BlockDAG) processDelayedBlocks() error {
|
|
// Check if the delayed block with the earliest process time should be processed
|
|
for dag.delayedBlocksQueue.Len() > 0 {
|
|
earliestDelayedBlockProcessTime := dag.peekDelayedBlock().processTime
|
|
if earliestDelayedBlockProcessTime.After(dag.Now()) {
|
|
break
|
|
}
|
|
delayedBlock := dag.popDelayedBlock()
|
|
_, _, err := dag.processBlockNoLock(delayedBlock.block, delayedBlock.flags|BFAfterDelay)
|
|
if err != nil {
|
|
log.Errorf("Error while processing delayed block (block %s): %s", delayedBlock.block.Hash().String(), err)
|
|
// Rule errors should not be propagated as they refer only to the delayed block,
|
|
// while this function runs in the context of another block
|
|
if !errors.As(err, &RuleError{}) {
|
|
return err
|
|
}
|
|
}
|
|
log.Debugf("Processed delayed block (block %s)", delayedBlock.block.Hash().String())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// popDelayedBlock removes the topmost (delayed block with earliest process time) of the queue and returns it.
|
|
func (dag *BlockDAG) popDelayedBlock() *delayedBlock {
|
|
delayedBlock := dag.delayedBlocksQueue.pop()
|
|
delete(dag.delayedBlocks, *delayedBlock.block.Hash())
|
|
return delayedBlock
|
|
}
|
|
|
|
func (dag *BlockDAG) peekDelayedBlock() *delayedBlock {
|
|
return dag.delayedBlocksQueue.peek()
|
|
}
|
|
|
|
// maxDelayOfParents returns the maximum delay of the given block hashes.
|
|
// Note that delay could be 0, but isDelayed will return true. This is the case where the parent process time is due.
|
|
func (dag *BlockDAG) maxDelayOfParents(parentHashes []*daghash.Hash) (delay time.Duration, isDelayed bool) {
|
|
for _, parentHash := range parentHashes {
|
|
if delayedParent, exists := dag.delayedBlocks[*parentHash]; exists {
|
|
isDelayed = true
|
|
parentDelay := delayedParent.processTime.Sub(dag.Now())
|
|
if parentDelay > delay {
|
|
delay = parentDelay
|
|
}
|
|
}
|
|
}
|
|
|
|
return delay, isDelayed
|
|
}
|
|
|
|
func (dag *BlockDAG) shouldBlockBeDelayed(block *util.Block) (delay time.Duration, isDelayed bool) {
|
|
header := &block.MsgBlock().Header
|
|
|
|
maxTimestamp := dag.Now().Add(time.Duration(dag.TimestampDeviationTolerance) * dag.Params.TargetTimePerBlock)
|
|
if header.Timestamp.After(maxTimestamp) {
|
|
return header.Timestamp.Sub(maxTimestamp), true
|
|
}
|
|
return 0, false
|
|
}
|