From c1505b47489a966e5561b485a0ab17eaa5894362 Mon Sep 17 00:00:00 2001 From: Ori Newman Date: Mon, 23 Nov 2020 05:09:39 -0800 Subject: [PATCH] [NOD-1555] Use stageDiff to update virtualDiffParents (#1139) * [NOD-1555] Filter ancestors in updateVirtualDiffParents * [NOD-1555] Use stageDiff to update virtualDiffParents * [NOD-1555] Don't add existing blocks in addToVirtualDiffParents * [NOD-1555] Remove redundant check * [NOD-1555] Fix log and rename removeAncestorsFromVirtualDiffParents->removeAncestorsFromVirtualDiffParentsAndAssignDiffChild * [NOD-1555] Add logs * [NOD-1555] Fix comment * [NOD-1555] Fix logs --- .../blockstatusstore/blockstatusstore.go | 4 +- .../resolve_block_status.go | 56 ++++++------- .../set_pruning_utxo_set.go | 2 +- .../consensusstatemanager/update_virtual.go | 59 +++---------- .../consensusstatemanager/utxo_diffs.go | 84 +++++++++++++++++++ 5 files changed, 126 insertions(+), 79 deletions(-) create mode 100644 domain/consensus/processes/consensusstatemanager/utxo_diffs.go diff --git a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go index 5a3f3fb18..4b62be445 100644 --- a/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go +++ b/domain/consensus/datastructures/blockstatusstore/blockstatusstore.go @@ -62,7 +62,7 @@ func (bss *blockStatusStore) Get(dbContext model.DBReader, blockHash *externalap return 0, err } - return bss.deserializeHeader(statusBytes) + return bss.deserializeBlockStatus(statusBytes) } // Exists returns true if the blockStatus for the given blockHash exists @@ -84,7 +84,7 @@ func (bss *blockStatusStore) serializeBlockStatus(status externalapi.BlockStatus return proto.Marshal(dbBlockStatus) } -func (bss *blockStatusStore) deserializeHeader(statusBytes []byte) (externalapi.BlockStatus, error) { +func (bss *blockStatusStore) deserializeBlockStatus(statusBytes []byte) (externalapi.BlockStatus, error) { dbBlockStatus := &serialization.DbBlockStatus{} err := proto.Unmarshal(statusBytes, dbBlockStatus) if err != nil { diff --git a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go index 086748ad6..57c45e4e7 100644 --- a/domain/consensus/processes/consensusstatemanager/resolve_block_status.go +++ b/domain/consensus/processes/consensusstatemanager/resolve_block_status.go @@ -157,67 +157,67 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap csm.multisetStore.Stage(blockHash, multiset) log.Tracef("Staging the utxoDiff of block %s", blockHash) - err = csm.utxoDiffStore.Stage(blockHash, pastUTXODiff, nil) + err = csm.stageDiff(blockHash, pastUTXODiff, nil) if err != nil { return 0, err } - log.Tracef("Updating the parent utxoDiffs of block %s", blockHash) - err = csm.updateParentDiffs(blockHash, pastUTXODiff) + log.Tracef("Remove block ancestors from virtual diff parents and assign %s as their diff child", blockHash) + err = csm.removeAncestorsFromVirtualDiffParentsAndAssignDiffChild(blockHash, pastUTXODiff) if err != nil { return 0, err } return externalapi.StatusValid, nil } -func (csm *consensusStateManager) updateParentDiffs( - blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff) error { - log.Tracef("updateParentDiffs start for block %s", blockHash) - defer log.Tracef("updateParentDiffs end for block %s", blockHash) - parentHashes, err := csm.dagTopologyManager.Parents(blockHash) +func (csm *consensusStateManager) removeAncestorsFromVirtualDiffParentsAndAssignDiffChild( + blockHash *externalapi.DomainHash, pastUTXODiff *model.UTXODiff) error { + + log.Tracef("removeAncestorsFromVirtualDiffParentsAndAssignDiffChild start for block %s", blockHash) + defer log.Tracef("removeAncestorsFromVirtualDiffParentsAndAssignDiffChild end for block %s", blockHash) + + if *blockHash == *csm.genesisHash { + log.Tracef("Genesis block doesn't have ancestors to remove from the virtual diff parents") + return nil + } + + virtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) if err != nil { return err } - log.Tracef("Parent hashes for block %s are: %s", blockHash, parentHashes) - for _, parentHash := range parentHashes { - // skip all parents that already have a utxo-diff child - parentHasUTXODiffChild, err := csm.utxoDiffStore.HasUTXODiffChild(csm.databaseContext, parentHash) - if err != nil { - return err - } - if parentHasUTXODiffChild { - log.Tracef("Skipping parent %s of block %s because it "+ - "already has a UTXO diff-child", parentHash, blockHash) + for _, virtualDiffParent := range virtualDiffParents { + if *virtualDiffParent == *blockHash { + log.Tracef("Skipping updating virtual diff parent %s "+ + "because it was updated before.", virtualDiffParent) continue } - parentStatus, err := csm.blockStatusStore.Get(csm.databaseContext, parentHash) + isAncestorOfBlock, err := csm.dagTopologyManager.IsAncestorOf(virtualDiffParent, blockHash) if err != nil { return err } - if parentStatus != externalapi.StatusValid { - log.Tracef("Skipping parent %s of block %s because it "+ - "has a non-valid status %s", parentHash, blockHash, parentStatus) + + if !isAncestorOfBlock { + log.Tracef("Skipping block %s because it's not an "+ + "ancestor of %s", virtualDiffParent, blockHash) continue } // parents that didn't have a utxo-diff child until now were actually virtual's diffParents. // Update them to have the new block as their utxo-diff child - log.Tracef("Resolving new UTXO diff of parent %s", parentHash) - parentCurrentDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, parentHash) + log.Tracef("Updating %s to be the diff child of %s", blockHash, virtualDiffParent) + currentDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) if err != nil { return err } - parentNewDiff, err := utxoalgebra.DiffFrom(pastUTXODiff, parentCurrentDiff) + newDiff, err := utxoalgebra.DiffFrom(pastUTXODiff, currentDiff) if err != nil { return err } - log.Tracef("The new UTXO diff parent %s resolved to: %s", parentHash, parentNewDiff) - log.Tracef("Staging the new UTXO diff and diff child for parent %s", parentHash) - err = csm.utxoDiffStore.Stage(parentHash, parentNewDiff, blockHash) + err = csm.stageDiff(virtualDiffParent, newDiff, blockHash) if err != nil { return err } diff --git a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go index 7ccfee5c8..9f8f58913 100644 --- a/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go +++ b/domain/consensus/processes/consensusstatemanager/set_pruning_utxo_set.go @@ -90,7 +90,7 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt } log.Tracef("Updating the header tips pruning point diff parents with an empty UTXO diff") - err = csm.updateVirtualDiffParents(headerTipsPruningPoint, model.NewUTXODiff()) + err = csm.updateVirtualDiffParents(model.NewUTXODiff()) if err != nil { return err } diff --git a/domain/consensus/processes/consensusstatemanager/update_virtual.go b/domain/consensus/processes/consensusstatemanager/update_virtual.go index ee7471510..3a5a36382 100644 --- a/domain/consensus/processes/consensusstatemanager/update_virtual.go +++ b/domain/consensus/processes/consensusstatemanager/update_virtual.go @@ -4,7 +4,6 @@ import ( "github.com/kaspanet/kaspad/domain/consensus/model" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager/utxoalgebra" - "github.com/kaspanet/kaspad/domain/consensus/utils/hashset" ) func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.DomainHash, tips []*externalapi.DomainHash) error { @@ -51,7 +50,7 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain } log.Tracef("Updating the virtual diff parents after adding %s to the DAG", newBlockHash) - err = csm.updateVirtualDiffParents(newBlockHash, virtualUTXODiff) + err = csm.updateVirtualDiffParents(virtualUTXODiff) if err != nil { return err } @@ -59,52 +58,16 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain return nil } -func (csm *consensusStateManager) updateVirtualDiffParents( - newBlockHash *externalapi.DomainHash, virtualUTXODiff *model.UTXODiff) error { +func (csm *consensusStateManager) updateVirtualDiffParents(virtualUTXODiff *model.UTXODiff) error { + log.Tracef("updateVirtualDiffParents start") + defer log.Tracef("updateVirtualDiffParents end") - log.Tracef("updateVirtualDiffParents start for block %s", newBlockHash) - defer log.Tracef("updateVirtualDiffParents end for block %s", newBlockHash) - - var newVirtualDiffParents []*externalapi.DomainHash - if *newBlockHash == *csm.genesisHash { - log.Tracef("Block %s is the genesis, so by definition "+ - "it is the only member of the new virtual diff parents set", newBlockHash) - newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash} - } else { - oldVirtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) - if err != nil { - return err - } - log.Tracef("The old virtual's diff parents are: %s", oldVirtualDiffParents) - - // If the status of the new block is not `Valid` - virtualDiffParents didn't change - status, err := csm.blockStatusStore.Get(csm.databaseContext, newBlockHash) - if err != nil { - return err - } - if status != externalapi.StatusValid { - log.Tracef("The status of the new block %s is non-valid. "+ - "As such, don't change the diff parents of the virtual", newBlockHash) - newVirtualDiffParents = oldVirtualDiffParents - } else { - log.Tracef("Block %s is valid. Updating the virtual diff parents", newBlockHash) - newBlockParentsSlice, err := csm.dagTopologyManager.Parents(newBlockHash) - if err != nil { - return err - } - newBlockParents := hashset.NewFromSlice(newBlockParentsSlice...) - - newVirtualDiffParents = []*externalapi.DomainHash{newBlockHash} - for _, virtualDiffParent := range oldVirtualDiffParents { - if !newBlockParents.Contains(virtualDiffParent) { - newVirtualDiffParents = append(newVirtualDiffParents, virtualDiffParent) - } - } - } + virtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) + if err != nil { + return err } - log.Tracef("The new virtual diff parents are: %s", newVirtualDiffParents) - for _, virtualDiffParent := range newVirtualDiffParents { + for _, virtualDiffParent := range virtualDiffParents { log.Tracef("Calculating new UTXO diff for virtual diff parent %s", virtualDiffParent) virtualDiffParentUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, virtualDiffParent) if err != nil { @@ -114,13 +77,13 @@ func (csm *consensusStateManager) updateVirtualDiffParents( if err != nil { return err } + log.Tracef("Staging new UTXO diff for virtual diff parent %s: %s", virtualDiffParent, newDiff) - err = csm.utxoDiffStore.Stage(virtualDiffParent, newDiff, nil) + err = csm.stageDiff(virtualDiffParent, newDiff, nil) if err != nil { return err } } - log.Tracef("Staging the new virtual UTXO diff parents") - return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) + return nil } diff --git a/domain/consensus/processes/consensusstatemanager/utxo_diffs.go b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go new file mode 100644 index 000000000..385f577ab --- /dev/null +++ b/domain/consensus/processes/consensusstatemanager/utxo_diffs.go @@ -0,0 +1,84 @@ +package consensusstatemanager + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/pkg/errors" +) + +func (csm *consensusStateManager) stageDiff(blockHash *externalapi.DomainHash, + utxoDiff *model.UTXODiff, utxoDiffChild *externalapi.DomainHash) error { + + log.Tracef("stageDiff start for block %s", blockHash) + defer log.Tracef("stageDiff end for block %s", blockHash) + + log.Tracef("Staging block %s as the diff child of %s", utxoDiffChild, blockHash) + err := csm.utxoDiffStore.Stage(blockHash, utxoDiff, utxoDiffChild) + if err != nil { + return err + } + + if utxoDiffChild == nil { + log.Tracef("Adding block %s to the virtual diff parents", blockHash) + return csm.addToVirtualDiffParents(blockHash) + } + + log.Tracef("Removing block %s from the virtual diff parents", blockHash) + return csm.removeFromVirtualDiffParents(blockHash) +} + +func (csm *consensusStateManager) addToVirtualDiffParents(blockHash *externalapi.DomainHash) error { + log.Tracef("addToVirtualDiffParents start for block %s", blockHash) + defer log.Tracef("addToVirtualDiffParents end for block %s", blockHash) + + var oldVirtualDiffParents []*externalapi.DomainHash + if *blockHash != *csm.genesisHash { + var err error + oldVirtualDiffParents, err = csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) + if err != nil { + return err + } + } + + isInVirtualDiffParents := false + for _, diffParent := range oldVirtualDiffParents { + if *diffParent == *blockHash { + isInVirtualDiffParents = true + break + } + } + + if isInVirtualDiffParents { + log.Tracef("Block %s is already a virtual diff parent, so there's no need to add it", blockHash) + return nil + } + + newVirtualDiffParents := append([]*externalapi.DomainHash{blockHash}, oldVirtualDiffParents...) + log.Tracef("Staging virtual diff parents after adding %s to it", blockHash) + return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) +} + +func (csm *consensusStateManager) removeFromVirtualDiffParents(blockHash *externalapi.DomainHash) error { + log.Tracef("removeFromVirtualDiffParents start for block %s", blockHash) + defer log.Tracef("removeFromVirtualDiffParents end for block %s", blockHash) + + oldVirtualDiffParents, err := csm.consensusStateStore.VirtualDiffParents(csm.databaseContext) + if err != nil { + return err + } + + newVirtualDiffParents := make([]*externalapi.DomainHash, 0, len(oldVirtualDiffParents)-1) + for _, diffParent := range oldVirtualDiffParents { + if *diffParent != *blockHash { + newVirtualDiffParents = append(newVirtualDiffParents, diffParent) + } + } + + if len(newVirtualDiffParents) != len(oldVirtualDiffParents)-1 { + return errors.Errorf("expected to remove one member from virtual diff parents and "+ + "have a length of %d but got length of %d", len(oldVirtualDiffParents)-1, len(newVirtualDiffParents)) + } + + log.Tracef("Staging virtual diff parents after removing %s from it", blockHash) + return csm.consensusStateStore.StageVirtualDiffParents(newVirtualDiffParents) +}