mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-05-22 23:07:04 +00:00

* Get rid of insertMode * Rename AddBlockToVirtual->AddBlock * When F is not in the future of P, enforce finality with P and not with F. * Don't allow blocks with invalid parents or with missing block body * Check finality violation before checking block status * Implement CalculateIndependentPruningPoint * Move checkBlockStatus to validateBlock * Add ValidateBlock to block processor interface * Adjust SetPruningPoint to the new IBD flow * Add pruning store to CSM's constructor * Flip wrong condition on AddHeaderTip * Fix func (hts *headerSelectedTipStore) Has * Fix block stage order * Call to ValidateBodyInContext from validatePostProofOfWork * Enable overrideDAGParams * Update log * Rename SetPruningPoint to ValidateAndInsertPruningPoint and move most of its logic inside block processor * Rename hasValidatedHeader->hasValidatedOnlyHeader * Fix typo * Name return values for fetchMissingUTXOSet * Add comment * Return ErrMissingParents when block body is missing * Add logs and comments * Fix merge error * Fix pruning point calculation to be by virtual selected parent * Replace CalculateIndependentPruningPoint to CalculatePruningPointByHeaderSelectedTip * Fix isAwaitingUTXOSet to check pruning point by headers * Change isAwaitingUTXOSet indication * Remove IsBlockInHeaderPruningPointFuture from BlockInfo * Fix LowestChainBlockAboveOrEqualToBlueScore * Add validateNewPruningPointTransactions * Add validateNewPruningAgainstPastUTXO * Rename set_pruning_utxo_set.go to update_pruning_utxo_set.go * Check missing block body hashes by missing block instead of status * Validate pruning point against past UTXO with the pruning point as block hash * Remove virtualHeaderHash * Fix comment * Fix imports
160 lines
5.1 KiB
Go
160 lines
5.1 KiB
Go
package consensusstatemanager
|
|
|
|
import (
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/serialization"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization"
|
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
func (csm *consensusStateManager) UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
|
onEnd := logger.LogAndMeasureExecutionTime(log, "UpdatePruningPoint")
|
|
defer onEnd()
|
|
|
|
err := csm.updatePruningPoint(newPruningPoint, serializedUTXOSet)
|
|
if err != nil {
|
|
csm.discardSetPruningPointUTXOSetChanges()
|
|
return err
|
|
}
|
|
|
|
return csm.commitSetPruningPointUTXOSetAll()
|
|
}
|
|
|
|
func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
|
log.Tracef("updatePruningPoint start")
|
|
defer log.Tracef("updatePruningPoint end")
|
|
|
|
newPruningPointHash := consensushashing.BlockHash(newPruningPoint)
|
|
|
|
// We ignore the shouldSendNotification return value because we always want to send finality conflict notification
|
|
// in case the new pruning point violates finality
|
|
isViolatingFinality, _, err := csm.isViolatingFinality(newPruningPointHash)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if isViolatingFinality {
|
|
log.Warnf("Finality Violation Detected! The suggest pruning point %s violates finality!", newPruningPointHash)
|
|
return nil
|
|
}
|
|
|
|
protoUTXOSet := &utxoserialization.ProtoUTXOSet{}
|
|
err = proto.Unmarshal(serializedUTXOSet, protoUTXOSet)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
utxoSetMultiSet, err := calcMultisetFromProtoUTXOSet(protoUTXOSet)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Tracef("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash())
|
|
|
|
newPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, newPruningPointHash)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Tracef("The UTXO commitment of the pruning point: %s",
|
|
newPruningPointHeader.UTXOCommitment)
|
|
|
|
if newPruningPointHeader.UTXOCommitment != *utxoSetMultiSet.Hash() {
|
|
return errors.Wrapf(ruleerrors.ErrBadPruningPointUTXOSet, "the expected multiset hash of the pruning "+
|
|
"point UTXO set is %s but got %s", newPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash())
|
|
}
|
|
log.Tracef("The new pruning point UTXO commitment validation passed")
|
|
|
|
log.Tracef("Staging the parent hashes for pruning point as the DAG tips")
|
|
csm.consensusStateStore.StageTips(newPruningPointHeader.ParentHashes)
|
|
|
|
log.Tracef("Setting the parent hashes for the header tips pruning point as the virtual parents")
|
|
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, newPruningPointHeader.ParentHashes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Tracef("Staging the virtual UTXO set")
|
|
err = csm.consensusStateStore.StageVirtualUTXOSet(protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Before we manually mark the new pruning point as valid, we validate that all of its transactions are valid
|
|
// against the provided UTXO set.
|
|
err = csm.validateBlockTransactionsAgainstPastUTXO(newPruningPoint, utxo.NewUTXODiff())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Tracef("Updating the header tips pruning point diff parents with an empty UTXO diff")
|
|
err = csm.updateVirtualDiffParents(utxo.NewUTXODiff())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Tracef("Staging the new pruning point and its UTXO set")
|
|
csm.pruningStore.Stage(newPruningPointHash, serializedUTXOSet)
|
|
|
|
log.Tracef("Staging the new pruning point as %s", externalapi.StatusValid)
|
|
csm.blockStatusStore.Stage(newPruningPointHash, externalapi.StatusValid)
|
|
return nil
|
|
}
|
|
|
|
func (csm *consensusStateManager) discardSetPruningPointUTXOSetChanges() {
|
|
for _, store := range csm.stores {
|
|
store.Discard()
|
|
}
|
|
}
|
|
|
|
func (csm *consensusStateManager) commitSetPruningPointUTXOSetAll() error {
|
|
dbTx, err := csm.databaseContext.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, store := range csm.stores {
|
|
err = store.Commit(dbTx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return dbTx.Commit()
|
|
}
|
|
|
|
type protoUTXOSetIterator struct {
|
|
utxoSet *utxoserialization.ProtoUTXOSet
|
|
index int
|
|
}
|
|
|
|
func (p protoUTXOSetIterator) Next() bool {
|
|
p.index++
|
|
return p.index < len(p.utxoSet.Utxos)
|
|
}
|
|
|
|
func (p protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) {
|
|
entry, outpoint, err := utxo.DeserializeUTXO(p.utxoSet.Utxos[p.index].EntryOutpointPair)
|
|
if err != nil {
|
|
if serialization.IsMalformedError(err) {
|
|
return nil, nil, errors.Wrap(ruleerrors.ErrMalformedUTXO, "malformed utxo")
|
|
}
|
|
return nil, nil, err
|
|
}
|
|
|
|
return outpoint, entry, nil
|
|
}
|
|
|
|
func protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet *utxoserialization.ProtoUTXOSet) model.ReadOnlyUTXOSetIterator {
|
|
return &protoUTXOSetIterator{utxoSet: protoUTXOSet}
|
|
}
|