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
|
blocksWithTrustedDataDAAWindowStore model.BlocksWithTrustedDataDAAWindowStore
|
||||||
|
|
||||||
consensusEventsChan chan externalapi.ConsensusEvent
|
consensusEventsChan chan externalapi.ConsensusEvent
|
||||||
virtualNotUpdated bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *consensus) ValidateAndInsertBlockWithTrustedData(block *externalapi.BlockWithTrustedData, validateUTXO bool) error {
|
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
|
// ValidateAndInsertBlock validates the given block and, if valid, applies it
|
||||||
// to the current state
|
// 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()
|
s.lock.Lock()
|
||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
_, err := s.validateAndInsertBlockNoLock(block, shouldValidateAgainstUTXO)
|
_, err := s.validateAndInsertBlockNoLock(block, updateVirtual)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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) {
|
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)
|
virtualChangeSet, blockStatus, err := s.blockProcessor.ValidateAndInsertBlock(block, updateVirtual)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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)
|
err = s.sendBlockAddedEvent(block, blockStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
func (s *consensus) sendVirtualChangedEvent(virtualChangeSet *externalapi.VirtualChangeSet, wasVirtualUpdated bool) error {
|
||||||
if !wasVirtualUpdated || s.consensusEventsChan == nil {
|
if !wasVirtualUpdated || s.consensusEventsChan == nil || virtualChangeSet == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -895,7 +889,7 @@ func (s *consensus) ResolveVirtual(progressReportCallback func(uint64, uint64))
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
if i%10 == 0 {
|
if i%10 == 0 && progressReportCallback != nil {
|
||||||
virtualDAAScore, err := s.GetVirtualDAAScore()
|
virtualDAAScore, err := s.GetVirtualDAAScore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -931,7 +925,6 @@ func (s *consensus) resolveVirtualNoLock(maxBlocksToResolve uint64) (bool, error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
s.virtualNotUpdated = !isCompletelyResolved
|
|
||||||
|
|
||||||
stagingArea := model.NewStagingArea()
|
stagingArea := model.NewStagingArea()
|
||||||
err = s.pruningManager.UpdatePruningPointByVirtual(stagingArea)
|
err = s.pruningManager.UpdatePruningPointByVirtual(stagingArea)
|
||||||
|
|||||||
@ -5,7 +5,7 @@ type Consensus interface {
|
|||||||
Init(skipAddingGenesis bool) error
|
Init(skipAddingGenesis bool) error
|
||||||
BuildBlock(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlock, error)
|
BuildBlock(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlock, error)
|
||||||
BuildBlockTemplate(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlockTemplate, 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
|
ValidateAndInsertBlockWithTrustedData(block *BlockWithTrustedData, validateUTXO bool) error
|
||||||
ValidateTransactionAndPopulateWithConsensusData(transaction *DomainTransaction) error
|
ValidateTransactionAndPopulateWithConsensusData(transaction *DomainTransaction) error
|
||||||
ImportPruningPoints(pruningPoints []BlockHeader) error
|
ImportPruningPoints(pruningPoints []BlockHeader) error
|
||||||
|
|||||||
@ -63,24 +63,6 @@ func (csm *consensusStateManager) ResolveVirtual(maxBlocksToResolve uint64) (*ex
|
|||||||
|
|
||||||
readStagingArea := model.NewStagingArea()
|
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()
|
pendingTip, pendingTipStatus, err := csm.findNextPendingTip()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user