mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-11-26 15:35:55 +00:00
Be more defensive at resolving virtual when adding a block
This commit is contained in:
parent
d17f52d87a
commit
bc0e74e357
@ -61,7 +61,6 @@ type consensus struct {
|
||||
blocksWithTrustedDataDAAWindowStore model.BlocksWithTrustedDataDAAWindowStore
|
||||
|
||||
consensusEventsChan chan externalapi.ConsensusEvent
|
||||
virtualNotUpdated bool
|
||||
}
|
||||
|
||||
func (s *consensus) ValidateAndInsertBlockWithTrustedData(block *externalapi.BlockWithTrustedData, validateUTXO bool) error {
|
||||
@ -194,11 +193,24 @@ func (s *consensus) BuildBlockTemplate(coinbaseData *externalapi.DomainCoinbaseD
|
||||
|
||||
// ValidateAndInsertBlock validates the given block and, if valid, applies it
|
||||
// to the current state
|
||||
func (s *consensus) ValidateAndInsertBlock(block *externalapi.DomainBlock, shouldValidateAgainstUTXO bool) error {
|
||||
func (s *consensus) ValidateAndInsertBlock(block *externalapi.DomainBlock, updateVirtual bool) error {
|
||||
|
||||
if updateVirtual {
|
||||
// Make sure virtual is resolved before adding the new block
|
||||
err := s.ResolveVirtual(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return s.validateAndInsertBlockWithLock(block, updateVirtual)
|
||||
}
|
||||
|
||||
func (s *consensus) validateAndInsertBlockWithLock(block *externalapi.DomainBlock, updateVirtual bool) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
_, err := s.validateAndInsertBlockNoLock(block, shouldValidateAgainstUTXO)
|
||||
_, err := s.validateAndInsertBlockNoLock(block, updateVirtual)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -206,29 +218,11 @@ func (s *consensus) ValidateAndInsertBlock(block *externalapi.DomainBlock, shoul
|
||||
}
|
||||
|
||||
func (s *consensus) validateAndInsertBlockNoLock(block *externalapi.DomainBlock, updateVirtual bool) (*externalapi.VirtualChangeSet, error) {
|
||||
// If virtual is in non-updated state, and the caller requests updating virtual -- then we must first
|
||||
// resolve virtual so that the new block can be fully processed properly
|
||||
if updateVirtual && s.virtualNotUpdated {
|
||||
for s.virtualNotUpdated {
|
||||
// We use 10000 << finality interval. See comment in `ResolveVirtual`.
|
||||
// We give up responsiveness of consensus in this rare case.
|
||||
_, err := s.resolveVirtualNoLock(10000) // Note `s.virtualNotUpdated` is updated within the call
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtualChangeSet, blockStatus, err := s.blockProcessor.ValidateAndInsertBlock(block, updateVirtual)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If block has a body, and yet virtual was not updated -- signify that virtual is in non-updated state
|
||||
if !updateVirtual && blockStatus != externalapi.StatusHeaderOnly {
|
||||
s.virtualNotUpdated = true
|
||||
}
|
||||
|
||||
err = s.sendBlockAddedEvent(block, blockStatus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -257,7 +251,7 @@ func (s *consensus) sendBlockAddedEvent(block *externalapi.DomainBlock, blockSta
|
||||
}
|
||||
|
||||
func (s *consensus) sendVirtualChangedEvent(virtualChangeSet *externalapi.VirtualChangeSet, wasVirtualUpdated bool) error {
|
||||
if !wasVirtualUpdated || s.consensusEventsChan == nil {
|
||||
if !wasVirtualUpdated || s.consensusEventsChan == nil || virtualChangeSet == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -895,7 +889,7 @@ func (s *consensus) ResolveVirtual(progressReportCallback func(uint64, uint64))
|
||||
}
|
||||
|
||||
for i := 0; ; i++ {
|
||||
if i%10 == 0 {
|
||||
if i%10 == 0 && progressReportCallback != nil {
|
||||
virtualDAAScore, err := s.GetVirtualDAAScore()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -931,7 +925,6 @@ func (s *consensus) resolveVirtualNoLock(maxBlocksToResolve uint64) (bool, error
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
s.virtualNotUpdated = !isCompletelyResolved
|
||||
|
||||
stagingArea := model.NewStagingArea()
|
||||
err = s.pruningManager.UpdatePruningPointByVirtual(stagingArea)
|
||||
|
||||
@ -5,7 +5,7 @@ type Consensus interface {
|
||||
Init(skipAddingGenesis bool) error
|
||||
BuildBlock(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlock, error)
|
||||
BuildBlockTemplate(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlockTemplate, error)
|
||||
ValidateAndInsertBlock(block *DomainBlock, shouldValidateAgainstUTXO bool) error
|
||||
ValidateAndInsertBlock(block *DomainBlock, updateVirtual bool) error
|
||||
ValidateAndInsertBlockWithTrustedData(block *BlockWithTrustedData, validateUTXO bool) error
|
||||
ValidateTransactionAndPopulateWithConsensusData(transaction *DomainTransaction) error
|
||||
ImportPruningPoints(pruningPoints []BlockHeader) error
|
||||
|
||||
@ -63,24 +63,6 @@ func (csm *consensusStateManager) ResolveVirtual(maxBlocksToResolve uint64) (*ex
|
||||
|
||||
readStagingArea := model.NewStagingArea()
|
||||
|
||||
/*
|
||||
Algo (begin resolve):
|
||||
Go over tips by GHOSTDAG select parent order ignoring UTXO disqualified blocks and finality violating blocks
|
||||
Set pending tip to the first tip
|
||||
if this tip is already UTXO valid, finalize virtual state and return
|
||||
if the tip is UTXO pending, find the earliest UTXO pending block in its chain and set it as position
|
||||
set the tip as resolving virtual pending
|
||||
try resolving a chunk up the chain from position to pending tip
|
||||
|
||||
Algo (continue resolve):
|
||||
Start from position and try to continue resolving another chunk up the chain to pending tip
|
||||
If we encounter a UTXO disqualified block, we should
|
||||
mark the whole chain up to pending tip as disqualified
|
||||
set position and pending tip to the next candidate chain
|
||||
return and let the next call continue the processing
|
||||
If we reach the tip, and it is valid, only then set virtual parents to DAG tips, and clear resolving state
|
||||
*/
|
||||
|
||||
pendingTip, pendingTipStatus, err := csm.findNextPendingTip()
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user