diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index e368a404a..ed39f2865 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -558,7 +558,7 @@ func dagStores(config *Config, reachabilityDataStores := make([]model.ReachabilityDataStore, constants.MaxBlockLevel+1) ghostdagDataStores := make([]model.GHOSTDAGDataStore, constants.MaxBlockLevel+1) - ghostdagDataCacheSize := pruningWindowSizeForCaches + ghostdagDataCacheSize := pruningWindowSizeForCaches * 2 if ghostdagDataCacheSize < config.DifficultyAdjustmentWindowSize { ghostdagDataCacheSize = config.DifficultyAdjustmentWindowSize } @@ -567,7 +567,7 @@ func dagStores(config *Config, prefixBucket := prefixBucket.Bucket([]byte{byte(i)}) if i == 0 { blockRelationStores[i] = blockrelationstore.New(prefixBucket, pruningWindowSizePlusFinalityDepthForCache, preallocateCaches) - reachabilityDataStores[i] = reachabilitydatastore.New(prefixBucket, pruningWindowSizePlusFinalityDepthForCache, preallocateCaches) + reachabilityDataStores[i] = reachabilitydatastore.New(prefixBucket, pruningWindowSizePlusFinalityDepthForCache*2, preallocateCaches) ghostdagDataStores[i] = ghostdagdatastore.New(prefixBucket, ghostdagDataCacheSize, preallocateCaches) } else { blockRelationStores[i] = blockrelationstore.New(prefixBucket, 200, false) diff --git a/domain/consensus/model/interface_processes_pruningmanager.go b/domain/consensus/model/interface_processes_pruningmanager.go index 873173aae..4b7cfe5b4 100644 --- a/domain/consensus/model/interface_processes_pruningmanager.go +++ b/domain/consensus/model/interface_processes_pruningmanager.go @@ -13,7 +13,5 @@ type PruningManager interface { UpdatePruningPointIfRequired() error PruneAllBlocksBelow(stagingArea *StagingArea, pruningPointHash *externalapi.DomainHash) error PruningPointAndItsAnticoneWithTrustedData() ([]*externalapi.BlockWithTrustedData, error) - NextPruningPointAndCandidateByBlockHash(stagingArea *StagingArea, - blockHash *externalapi.DomainHash) (*externalapi.DomainHash, *externalapi.DomainHash, error) ExpectedHeaderPruningPoint(stagingArea *StagingArea, blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) } diff --git a/domain/consensus/processes/pruningmanager/pruningmanager.go b/domain/consensus/processes/pruningmanager/pruningmanager.go index 1ca0ed6cc..590a3521b 100644 --- a/domain/consensus/processes/pruningmanager/pruningmanager.go +++ b/domain/consensus/processes/pruningmanager/pruningmanager.go @@ -138,7 +138,7 @@ func (pm *pruningManager) UpdatePruningPointByVirtual(stagingArea *model.Staging return err } - newPruningPoint, newCandidate, err := pm.NextPruningPointAndCandidateByBlockHash(stagingArea, virtualGHOSTDAGData.SelectedParent()) + newPruningPoint, newCandidate, err := pm.nextPruningPointAndCandidateByBlockHash(stagingArea, virtualGHOSTDAGData.SelectedParent(), nil) if err != nil { return err } @@ -169,10 +169,10 @@ func (pm *pruningManager) UpdatePruningPointByVirtual(stagingArea *model.Staging return nil } -func (pm *pruningManager) NextPruningPointAndCandidateByBlockHash(stagingArea *model.StagingArea, - blockHash *externalapi.DomainHash) (*externalapi.DomainHash, *externalapi.DomainHash, error) { +func (pm *pruningManager) nextPruningPointAndCandidateByBlockHash(stagingArea *model.StagingArea, + blockHash, suggestedLowHash *externalapi.DomainHash) (*externalapi.DomainHash, *externalapi.DomainHash, error) { - onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.NextPruningPointAndCandidateByBlockHash") + onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.nextPruningPointAndCandidateByBlockHash") defer onEnd() currentCandidate, err := pm.pruningPointCandidate(stagingArea) @@ -180,6 +180,26 @@ func (pm *pruningManager) NextPruningPointAndCandidateByBlockHash(stagingArea *m return nil, nil, err } + lowHash := currentCandidate + if suggestedLowHash != nil { + isSuggestedLowHashInSelectedParentChainOfCurrentCandidate, err := pm.dagTopologyManager.IsInSelectedParentChainOf(stagingArea, suggestedLowHash, currentCandidate) + if err != nil { + return nil, nil, err + } + + if !isSuggestedLowHashInSelectedParentChainOfCurrentCandidate { + isCurrentCandidateInSelectedParentChainOfSuggestedLowHash, err := pm.dagTopologyManager.IsInSelectedParentChainOf(stagingArea, currentCandidate, suggestedLowHash) + if err != nil { + return nil, nil, err + } + + if !isCurrentCandidateInSelectedParentChainOfSuggestedLowHash { + panic(errors.Errorf("suggested low hash %s is not on the same selected chain as the pruning candidate %s", suggestedLowHash, currentCandidate)) + } + lowHash = suggestedLowHash + } + } + ghostdagData, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, blockHash, false) if err != nil { return nil, nil, err @@ -198,7 +218,7 @@ func (pm *pruningManager) NextPruningPointAndCandidateByBlockHash(stagingArea *m // We iterate until the selected parent of the given block, in order to allow a situation where the given block hash // belongs to the virtual. This shouldn't change anything since the max blue score difference between a block and its // selected parent is K, and K << pm.pruningDepth. - iterator, err := pm.dagTraversalManager.SelectedChildIterator(stagingArea, ghostdagData.SelectedParent(), currentCandidate) + iterator, err := pm.dagTraversalManager.SelectedChildIterator(stagingArea, ghostdagData.SelectedParent(), lowHash) if err != nil { return nil, nil, err } @@ -960,11 +980,43 @@ func (pm *pruningManager) blockWithTrustedData(stagingArea *model.StagingArea, b } func (pm *pruningManager) ExpectedHeaderPruningPoint(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) { - nextOrCurrentPruningPoint, _, err := pm.NextPruningPointAndCandidateByBlockHash(stagingArea, blockHash) + ghostdagData, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, blockHash, false) if err != nil { return nil, err } + if ghostdagData.SelectedParent().Equal(pm.genesisHash) { + return pm.genesisHash, nil + } + + selectedParentHeader, err := pm.blockHeaderStore.BlockHeader(pm.databaseContext, stagingArea, ghostdagData.SelectedParent()) + if err != nil { + return nil, err + } + + selectedParentPruningPointHeader, err := pm.blockHeaderStore.BlockHeader(pm.databaseContext, stagingArea, selectedParentHeader.PruningPoint()) + if err != nil { + return nil, err + } + + nextOrCurrentPruningPoint := selectedParentHeader.PruningPoint() + if pm.finalityScore(ghostdagData.BlueScore()) > pm.finalityScore(selectedParentPruningPointHeader.BlueScore()+pm.pruningDepth) { + var suggestedLowHash *externalapi.DomainHash + hasReachabilityData, err := pm.reachabilityDataStore.HasReachabilityData(pm.databaseContext, stagingArea, selectedParentHeader.PruningPoint()) + if err != nil { + return nil, err + } + + if hasReachabilityData { + suggestedLowHash = selectedParentHeader.PruningPoint() + } + + nextOrCurrentPruningPoint, _, err = pm.nextPruningPointAndCandidateByBlockHash(stagingArea, blockHash, suggestedLowHash) + if err != nil { + return nil, err + } + } + isHeaderPruningPoint, err := pm.isPruningPointInPruningDepth(stagingArea, blockHash, nextOrCurrentPruningPoint) if err != nil { return nil, err