Compare commits

...

9 Commits

Author SHA1 Message Date
msutton
79ed4537ee bump to version 0.12.4 2022-07-08 17:30:01 +03:00
msutton
09186a414a Make sure the block at the split point is reversed to new chain as well 2022-07-08 17:23:59 +03:00
msutton
9c732e6878 Return nil changeset when nothing happened 2022-07-08 16:33:19 +03:00
msutton
4308d097b7 When finally resolved, set virtual parents properly 2022-07-08 16:20:46 +03:00
msutton
bc0e74e357 Be more defensive at resolving virtual when adding a block 2022-07-08 16:04:42 +03:00
msutton
d17f52d87a Fixes a deep bug in the resolve virtual process 2022-07-08 15:52:12 +03:00
msutton
52e5aa9fab nil changeset is not expected when err=nil 2022-07-08 11:39:31 +03:00
msutton
92e0051b3b Change consensus API to a single ResolveVirtual call 2022-07-08 11:38:39 +03:00
msutton
fa20e016cb Illustrate the bug through prints 2022-06-30 17:45:07 +03:00
11 changed files with 329 additions and 155 deletions

View File

@@ -686,37 +686,28 @@ func (flow *handleIBDFlow) banIfBlockIsHeaderOnly(block *externalapi.DomainBlock
}
func (flow *handleIBDFlow) resolveVirtual(estimatedVirtualDAAScoreTarget uint64) error {
virtualDAAScoreStart, err := flow.Domain().Consensus().GetVirtualDAAScore()
err := flow.Domain().Consensus().ResolveVirtual(func(virtualDAAScoreStart uint64, virtualDAAScore uint64) {
var percents int
if estimatedVirtualDAAScoreTarget-virtualDAAScoreStart <= 0 {
percents = 100
} else {
percents = int(float64(virtualDAAScore-virtualDAAScoreStart) / float64(estimatedVirtualDAAScoreTarget-virtualDAAScoreStart) * 100)
}
if percents < 0 {
percents = 0
} else if percents > 100 {
percents = 100
}
log.Infof("Resolving virtual. Estimated progress: %d%%", percents)
})
if err != nil {
return err
}
for i := 0; ; i++ {
if i%10 == 0 {
virtualDAAScore, err := flow.Domain().Consensus().GetVirtualDAAScore()
if err != nil {
return err
}
var percents int
if estimatedVirtualDAAScoreTarget-virtualDAAScoreStart <= 0 {
percents = 100
} else {
percents = int(float64(virtualDAAScore-virtualDAAScoreStart) / float64(estimatedVirtualDAAScoreTarget-virtualDAAScoreStart) * 100)
}
log.Infof("Resolving virtual. Estimated progress: %d%%", percents)
}
isCompletelyResolved, err := flow.Domain().Consensus().ResolveVirtual()
if err != nil {
return err
}
if isCompletelyResolved {
log.Infof("Resolved virtual")
err = flow.OnNewBlockTemplate()
if err != nil {
return err
}
return nil
}
log.Infof("Resolved virtual")
err = flow.OnNewBlockTemplate()
if err != nil {
return err
}
return nil
}

View File

@@ -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
}
@@ -888,15 +882,42 @@ func (s *consensus) PopulateMass(transaction *externalapi.DomainTransaction) {
s.transactionValidator.PopulateMass(transaction)
}
func (s *consensus) ResolveVirtual() (bool, error) {
func (s *consensus) ResolveVirtual(progressReportCallback func(uint64, uint64)) error {
virtualDAAScoreStart, err := s.GetVirtualDAAScore()
if err != nil {
return err
}
for i := 0; ; i++ {
if i%10 == 0 && progressReportCallback != nil {
virtualDAAScore, err := s.GetVirtualDAAScore()
if err != nil {
return err
}
progressReportCallback(virtualDAAScoreStart, virtualDAAScore)
}
// In order to prevent a situation that the consensus lock is held for too much time, we
// release the lock each time resolve 100 blocks.
// Note: maxBlocksToResolve should be smaller than finality interval in order to avoid a situation
// where UpdatePruningPointByVirtual skips a pruning point.
isCompletelyResolved, err := s.resolveVirtualChunkWithLock(100)
if err != nil {
return err
}
if isCompletelyResolved {
break
}
}
return nil
}
func (s *consensus) resolveVirtualChunkWithLock(maxBlocksToResolve uint64) (bool, error) {
s.lock.Lock()
defer s.lock.Unlock()
// In order to prevent a situation that the consensus lock is held for too much time, we
// release the lock each time resolve 100 blocks.
// Note: maxBlocksToResolve should be smaller than finality interval in order to avoid a situation
// where UpdatePruningPointByVirtual skips a pruning point.
return s.resolveVirtualNoLock(100)
return s.resolveVirtualNoLock(maxBlocksToResolve)
}
func (s *consensus) resolveVirtualNoLock(maxBlocksToResolve uint64) (bool, error) {
@@ -904,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)

View File

@@ -589,18 +589,13 @@ func TestFinalityResolveVirtual(t *testing.T) {
}
}
for i := 0; ; i++ {
isCompletelyResolved, err := tc.ResolveVirtual()
if err != nil {
panic(err)
}
if isCompletelyResolved {
t.Log("Resolved virtual")
break
}
err = tc.ResolveVirtual(nil)
if err != nil {
panic(err)
}
t.Log("Resolved virtual")
sideChainTipGHOSTDAGData, err = tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), stagingArea, sideChainTipHash, false)
if err != nil {
panic(err)

View File

@@ -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
@@ -48,7 +48,7 @@ type Consensus interface {
Anticone(blockHash *DomainHash) ([]*DomainHash, error)
EstimateNetworkHashesPerSecond(startHash *DomainHash, windowSize int) (uint64, error)
PopulateMass(transaction *DomainTransaction)
ResolveVirtual() (bool, error)
ResolveVirtual(progressReportCallback func(uint64, uint64)) error
BlockDAAWindowHashes(blockHash *DomainHash) ([]*DomainHash, error)
TrustedDataDataDAAHeader(trustedBlockHash, daaBlockHash *DomainHash, daaBlockWindowIndex uint64) (*TrustedDataDataDAAHeader, error)
TrustedBlockAssociatedGHOSTDAGDataBlockHashes(blockHash *DomainHash) ([]*DomainHash, error)

View File

@@ -5,22 +5,19 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/kaspanet/kaspad/util/staging"
"github.com/pkg/errors"
"sort"
)
func (csm *consensusStateManager) ResolveVirtual(maxBlocksToResolve uint64) (*externalapi.VirtualChangeSet, bool, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "csm.ResolveVirtual")
defer onEnd()
readStagingArea := model.NewStagingArea()
tips, err := csm.consensusStateStore.Tips(readStagingArea, csm.databaseContext)
func (csm *consensusStateManager) findNextPendingTip(stagingArea *model.StagingArea) (*externalapi.DomainHash, externalapi.BlockStatus, error) {
tips, err := csm.consensusStateStore.Tips(stagingArea, csm.databaseContext)
if err != nil {
return nil, false, err
return nil, externalapi.StatusInvalid, err
}
var sortErr error
sort.Slice(tips, func(i, j int) bool {
selectedParent, err := csm.ghostdagManager.ChooseSelectedParent(readStagingArea, tips[i], tips[j])
selectedParent, err := csm.ghostdagManager.ChooseSelectedParent(stagingArea, tips[i], tips[j])
if err != nil {
sortErr = err
return false
@@ -29,16 +26,14 @@ func (csm *consensusStateManager) ResolveVirtual(maxBlocksToResolve uint64) (*ex
return selectedParent.Equal(tips[i])
})
if sortErr != nil {
return nil, false, sortErr
return nil, externalapi.StatusInvalid, sortErr
}
var selectedTip *externalapi.DomainHash
isCompletelyResolved := true
for _, tip := range tips {
log.Debugf("Resolving tip %s", tip)
isViolatingFinality, shouldNotify, err := csm.isViolatingFinality(readStagingArea, tip)
isViolatingFinality, shouldNotify, err := csm.isViolatingFinality(stagingArea, tip)
if err != nil {
return nil, false, err
return nil, externalapi.StatusInvalid, err
}
if isViolatingFinality {
@@ -49,55 +44,136 @@ func (csm *consensusStateManager) ResolveVirtual(maxBlocksToResolve uint64) (*ex
continue
}
resolveStagingArea := model.NewStagingArea()
unverifiedBlocks, err := csm.getUnverifiedChainBlocks(resolveStagingArea, tip)
status, err := csm.blockStatusStore.Get(csm.databaseContext, stagingArea, tip)
if err != nil {
return nil, false, err
return nil, externalapi.StatusInvalid, err
}
resolveTip := tip
hasMoreUnverifiedThanMax := maxBlocksToResolve != 0 && uint64(len(unverifiedBlocks)) > maxBlocksToResolve
if hasMoreUnverifiedThanMax {
resolveTip = unverifiedBlocks[uint64(len(unverifiedBlocks))-maxBlocksToResolve]
log.Debugf("Has more than %d blocks to resolve. Changing the resolve tip to %s", maxBlocksToResolve, resolveTip)
}
blockStatus, reversalData, err := csm.resolveBlockStatus(resolveStagingArea, resolveTip, true)
if err != nil {
return nil, false, err
}
if blockStatus == externalapi.StatusUTXOValid {
selectedTip = resolveTip
isCompletelyResolved = !hasMoreUnverifiedThanMax
err = staging.CommitAllChanges(csm.databaseContext, resolveStagingArea)
if err != nil {
return nil, false, err
}
if reversalData != nil {
err = csm.ReverseUTXODiffs(resolveTip, reversalData)
if err != nil {
return nil, false, err
}
}
break
if status == externalapi.StatusUTXOValid || status == externalapi.StatusUTXOPendingVerification {
return tip, status, nil
}
}
if selectedTip == nil {
log.Warnf("Non of the DAG tips are valid")
return nil, true, nil
return nil, externalapi.StatusInvalid, nil
}
func (csm *consensusStateManager) getLowerTips(stagingArea *model.StagingArea, pendingTip *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
tips, err := csm.consensusStateStore.Tips(stagingArea, csm.databaseContext)
if err != nil {
return nil, err
}
oldVirtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, readStagingArea, model.VirtualBlockHash, false)
lowerTips := []*externalapi.DomainHash{pendingTip}
for _, tip := range tips {
if tip.Equal(pendingTip) {
continue
}
selectedParent, err := csm.ghostdagManager.ChooseSelectedParent(stagingArea, tip, pendingTip)
if err != nil {
return nil, err
}
if selectedParent.Equal(pendingTip) {
lowerTips = append(lowerTips, tip)
}
}
return lowerTips, nil
}
func (csm *consensusStateManager) ResolveVirtual(maxBlocksToResolve uint64) (*externalapi.VirtualChangeSet, bool, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "csm.ResolveVirtual")
defer onEnd()
readStagingArea := model.NewStagingArea()
pendingTip, pendingTipStatus, err := csm.findNextPendingTip(readStagingArea)
if err != nil {
return nil, false, err
}
if pendingTip == nil {
log.Warnf("Non of the DAG tips are valid")
return nil, true, nil
}
prevVirtualSelectedParent, err := csm.virtualSelectedParent(readStagingArea)
if err != nil {
return nil, false, err
}
if pendingTipStatus == externalapi.StatusUTXOValid && prevVirtualSelectedParent.Equal(pendingTip) {
return nil, true, nil
}
// Resolve a chunk from the pending chain
resolveStagingArea := model.NewStagingArea()
unverifiedBlocks, err := csm.getUnverifiedChainBlocks(resolveStagingArea, pendingTip)
if err != nil {
return nil, false, err
}
intermediateTip := pendingTip
// Too many blocks to verify, so we only process a chunk and return
if maxBlocksToResolve != 0 && uint64(len(unverifiedBlocks)) > maxBlocksToResolve {
intermediateTipIndex := uint64(len(unverifiedBlocks)) - maxBlocksToResolve
intermediateTip = unverifiedBlocks[intermediateTipIndex]
isNewVirtualSelectedParent, err := csm.isNewSelectedTip(readStagingArea, intermediateTip, prevVirtualSelectedParent)
if err != nil {
return nil, false, err
}
// We must find an intermediate tip which wins previous virtual selected parent
// even if we process more than `maxBlocksToResolve` for that.
// Otherwise, internal UTXO diff logic gets all messed up
for !isNewVirtualSelectedParent {
if intermediateTipIndex == 0 {
return nil, false, errors.Errorf(
"Expecting the pending tip %s to overcome the previous selected parent %s", pendingTip, prevVirtualSelectedParent)
}
intermediateTipIndex--
intermediateTip = unverifiedBlocks[intermediateTipIndex]
isNewVirtualSelectedParent, err = csm.isNewSelectedTip(readStagingArea, intermediateTip, prevVirtualSelectedParent)
if err != nil {
return nil, false, err
}
}
log.Debugf("Has more than %d blocks to resolve. Changing the resolve tip to %s", maxBlocksToResolve, intermediateTip)
}
intermediateTipStatus, reversalData, err := csm.resolveBlockStatus(
resolveStagingArea, intermediateTip, true)
if err != nil {
return nil, false, err
}
if intermediateTipStatus == externalapi.StatusUTXOValid {
err = staging.CommitAllChanges(csm.databaseContext, resolveStagingArea)
if err != nil {
return nil, false, err
}
if reversalData != nil {
err = csm.ReverseUTXODiffs(intermediateTip, reversalData)
if err != nil {
return nil, false, err
}
}
}
isActualTip := intermediateTip.Equal(pendingTip)
isCompletelyResolved := isActualTip && intermediateTipStatus == externalapi.StatusUTXOValid
updateVirtualStagingArea := model.NewStagingArea()
virtualUTXODiff, err := csm.updateVirtualWithParents(updateVirtualStagingArea, []*externalapi.DomainHash{selectedTip})
// If `isCompletelyResolved`, set virtual correctly with all tips which have less blue work than pending
virtualTipCandidates := []*externalapi.DomainHash{intermediateTip}
if isCompletelyResolved {
virtualTipCandidates, err = csm.getLowerTips(readStagingArea, pendingTip)
if err != nil {
return nil, false, err
}
}
virtualUTXODiff, err := csm.updateVirtualWithParents(updateVirtualStagingArea, virtualTipCandidates)
if err != nil {
return nil, false, err
}
@@ -107,13 +183,14 @@ func (csm *consensusStateManager) ResolveVirtual(maxBlocksToResolve uint64) (*ex
return nil, false, err
}
// TODO: why was `readStagingArea` used here ?
selectedParentChainChanges, err := csm.dagTraversalManager.
CalculateChainPath(readStagingArea, oldVirtualGHOSTDAGData.SelectedParent(), selectedTip)
CalculateChainPath(updateVirtualStagingArea, prevVirtualSelectedParent, pendingTip)
if err != nil {
return nil, false, err
}
virtualParents, err := csm.dagTopologyManager.Parents(readStagingArea, model.VirtualBlockHash)
virtualParents, err := csm.dagTopologyManager.Parents(updateVirtualStagingArea, model.VirtualBlockHash)
if err != nil {
return nil, false, err
}

View File

@@ -233,7 +233,7 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(stagingArea *model.St
return externalapi.StatusUTXOValid, nil, nil
}
oldSelectedTip, err := csm.selectedTip(stagingArea)
oldSelectedTip, err := csm.virtualSelectedParent(stagingArea)
if err != nil {
return 0, nil, err
}
@@ -298,7 +298,7 @@ func (csm *consensusStateManager) isNewSelectedTip(stagingArea *model.StagingAre
return blockHash.Equal(newSelectedTip), nil
}
func (csm *consensusStateManager) selectedTip(stagingArea *model.StagingArea) (*externalapi.DomainHash, error) {
func (csm *consensusStateManager) virtualSelectedParent(stagingArea *model.StagingArea) (*externalapi.DomainHash, error) {
virtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, stagingArea, model.VirtualBlockHash, false)
if err != nil {
return nil, err

View File

@@ -1,6 +1,9 @@
package consensusstatemanager_test
import (
"fmt"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"testing"
@@ -212,3 +215,106 @@ func TestAddGenesisChildAfterTwoResolveVirtualCalls(t *testing.T) {
}
})
}
func TestResolveVirtualMess(t *testing.T) {
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
factory := consensus.NewFactory()
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestAddGenesisChildAfterTwoResolveVirtualCalls")
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown(false)
hashes := []*externalapi.DomainHash{consensusConfig.GenesisHash}
blocks := make(map[externalapi.DomainHash]string)
blocks[*consensusConfig.GenesisHash] = "g"
blocks[*model.VirtualBlockHash] = "v"
//fmt.Printf("%s\n\n", consensusConfig.GenesisHash)
// Create a chain of blocks
const initialChainLength = 6
previousBlockHash := consensusConfig.GenesisHash
for i := 0; i < initialChainLength; i++ {
previousBlockHash, _, err = tc.AddBlock([]*externalapi.DomainHash{previousBlockHash}, nil, nil)
blocks[*previousBlockHash] = fmt.Sprintf("A_%d", i)
hashes = append(hashes, previousBlockHash)
//fmt.Printf("A_%d: %s\n", i, previousBlockHash)
if err != nil {
t.Fatalf("Error mining block no. %d in initial chain: %+v", i, err)
}
}
//fmt.Printf("\n")
// Mine a chain with more blocks, to re-organize the DAG
const reorgChainLength = 20 // initialChainLength + 1
previousBlockHash = consensusConfig.GenesisHash
for i := 0; i < reorgChainLength; i++ {
previousBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{previousBlockHash}, nil, nil)
if err != nil {
t.Fatalf("Error mining block no. %d in re-org chain: %+v", i, err)
}
previousBlockHash = consensushashing.BlockHash(previousBlock)
blocks[*previousBlockHash] = fmt.Sprintf("B_%d", i)
hashes = append(hashes, previousBlockHash)
//fmt.Printf("B_%d: %s\n", i, previousBlockHash)
// Do not UTXO validate in order to resolve virtual later
err = tc.ValidateAndInsertBlock(previousBlock, false)
if err != nil {
t.Fatalf("Error mining block no. %d in re-org chain: %+v", i, err)
}
}
//fmt.Printf("\n")
//printUtxoDiffChildren(t, hashes, tc, blocks)
// Resolve one step
_, err = tc.ResolveVirtualWithMaxParam(3)
if err != nil {
printUtxoDiffChildren(t, hashes, tc, blocks)
t.Fatalf("Error resolving virtual in re-org chain: %+v", err)
}
// Resolve one more step
isCompletelyResolved, err := tc.ResolveVirtualWithMaxParam(3)
if err != nil {
t.Fatalf("Error resolving virtual in re-org chain: %+v", err)
}
// Complete resolving virtual
for !isCompletelyResolved {
isCompletelyResolved, err = tc.ResolveVirtualWithMaxParam(3)
if err != nil {
t.Fatalf("Error resolving virtual in re-org chain: %+v", err)
}
}
//printUtxoDiffChildren(t, hashes, tc, blocks)
})
}
func printUtxoDiffChildren(t *testing.T, hashes []*externalapi.DomainHash, tc testapi.TestConsensus, blocks map[externalapi.DomainHash]string) {
fmt.Printf("\n===============================\nBlock\t\tDiff child\n")
stagingArea := model.NewStagingArea()
for _, block := range hashes {
hasUTXODiffChild, err := tc.UTXODiffStore().HasUTXODiffChild(tc.DatabaseContext(), stagingArea, block)
if err != nil {
t.Fatalf("Error while reading utxo diff store: %+v", err)
}
if hasUTXODiffChild {
utxoDiffChild, err := tc.UTXODiffStore().UTXODiffChild(tc.DatabaseContext(), stagingArea, block)
if err != nil {
t.Fatalf("Error while reading utxo diff store: %+v", err)
}
fmt.Printf("%s\t\t\t%s\n", blocks[*block], blocks[*utxoDiffChild])
} else {
fmt.Printf("%s\n", blocks[*block])
}
}
fmt.Printf("\n===============================\n")
}

View File

@@ -56,12 +56,6 @@ func (csm *consensusStateManager) ReverseUTXODiffs(tipHash *externalapi.DomainHa
return err
}
// We stop reversing when current's UTXODiffChild is not current's SelectedParent
if !currentBlockGHOSTDAGData.SelectedParent().Equal(currentBlockUTXODiffChild) {
log.Debugf("Block %s's UTXODiffChild is not it's selected parent - finish reversing", currentBlock)
break
}
currentUTXODiff := previousUTXODiff.Reversed()
// retrieve current utxoDiff for Bi, to be used by next block
@@ -75,6 +69,12 @@ func (csm *consensusStateManager) ReverseUTXODiffs(tipHash *externalapi.DomainHa
return err
}
// We stop reversing when current's UTXODiffChild is not current's SelectedParent
if !currentBlockGHOSTDAGData.SelectedParent().Equal(currentBlockUTXODiffChild) {
log.Debugf("Block %s's UTXODiffChild is not it's selected parent - finish reversing", currentBlock)
break
}
previousBlock = currentBlock
previousBlockGHOSTDAGData = currentBlockGHOSTDAGData

View File

@@ -110,7 +110,7 @@ func (csm *consensusStateManager) updateSelectedTipUTXODiff(
onEnd := logger.LogAndMeasureExecutionTime(log, "updateSelectedTipUTXODiff")
defer onEnd()
selectedTip, err := csm.selectedTip(stagingArea)
selectedTip, err := csm.virtualSelectedParent(stagingArea)
if err != nil {
return err
}

View File

@@ -214,34 +214,19 @@ func syncConsensuses(syncer, syncee externalapi.Consensus) error {
return err
}
virtualDAAScoreStart, err := syncee.GetVirtualDAAScore()
err = syncer.ResolveVirtual(func(virtualDAAScoreStart uint64, virtualDAAScore uint64) {
if estimatedVirtualDAAScoreTarget-virtualDAAScoreStart <= 0 {
percents = 100
} else {
percents = int(float64(virtualDAAScore-virtualDAAScoreStart) / float64(estimatedVirtualDAAScoreTarget-virtualDAAScoreStart) * 100)
}
log.Infof("Resolving virtual. Estimated progress: %d%%", percents)
})
if err != nil {
return err
}
percents = 0
for i := 0; ; i++ {
if i%10 == 0 {
virtualDAAScore, err := syncee.GetVirtualDAAScore()
if err != nil {
return err
}
newPercents := int(float64(virtualDAAScore-virtualDAAScoreStart) / float64(estimatedVirtualDAAScoreTarget-virtualDAAScoreStart) * 100)
if newPercents > percents {
percents = newPercents
log.Infof("Resolving virtual. Estimated progress: %d%%", percents)
}
}
isCompletelyResolved, err := syncee.ResolveVirtual()
if err != nil {
return err
}
if isCompletelyResolved {
log.Infof("Resolved virtual")
break
}
}
log.Infof("Resolved virtual")
return nil
}

View File

@@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs
const (
appMajor uint = 0
appMinor uint = 12
appPatch uint = 3
appPatch uint = 4
)
// appBuild is defined as a variable so it can be overridden during the build