mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-11-23 22:15:54 +00:00
Pruning fixes (#1243)
* Pruning related fixes * Rename setBlockStatus->setBlockStatusAfterBlockValidation * Rename StatusValid->StatusUTXOValid * Add comment * Fix typo * Rename hasValidatedOnlyHeader->hasValidatedHeader * Rename checkBlockBodiesExist->checkParentBlockBodiesExist * Add comments and logs * Adding logs * Add logs and assert * Add comment * Fix typo * Fix log
This commit is contained in:
parent
b510fc08a7
commit
04330e71b9
@ -62,8 +62,8 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
|
|||||||
if !info.Exists {
|
if !info.Exists {
|
||||||
t.Fatal("The block is missing")
|
t.Fatal("The block is missing")
|
||||||
}
|
}
|
||||||
if info.BlockStatus != externalapi.StatusValid {
|
if info.BlockStatus != externalapi.StatusUTXOValid {
|
||||||
t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusValid, info.BlockStatus)
|
t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusUTXOValid, info.BlockStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|||||||
@ -55,9 +55,9 @@ func TestFinality(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("TestFinality: Block #%d failed to get info: %+v", i, err)
|
t.Fatalf("TestFinality: Block #%d failed to get info: %+v", i, err)
|
||||||
}
|
}
|
||||||
if blockInfo.BlockStatus != externalapi.StatusValid {
|
if blockInfo.BlockStatus != externalapi.StatusUTXOValid {
|
||||||
t.Fatalf("Block #%d in main chain expected to have status '%s', but got '%s'",
|
t.Fatalf("Block #%d in main chain expected to have status '%s', but got '%s'",
|
||||||
i, externalapi.StatusValid, blockInfo.BlockStatus)
|
i, externalapi.StatusUTXOValid, blockInfo.BlockStatus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,9 +99,9 @@ func TestFinality(t *testing.T) {
|
|||||||
} else if !blockInfo.Exists {
|
} else if !blockInfo.Exists {
|
||||||
t.Fatalf("TestFinality: Failed getting block info, doesn't exists")
|
t.Fatalf("TestFinality: Failed getting block info, doesn't exists")
|
||||||
}
|
}
|
||||||
if blockInfo.BlockStatus != externalapi.StatusValid {
|
if blockInfo.BlockStatus != externalapi.StatusUTXOValid {
|
||||||
t.Fatalf("TestFinality: Overtaking block in side-chain expected to have status '%s', but got '%s'",
|
t.Fatalf("TestFinality: Overtaking block in side-chain expected to have status '%s', but got '%s'",
|
||||||
externalapi.StatusValid, blockInfo.BlockStatus)
|
externalapi.StatusUTXOValid, blockInfo.BlockStatus)
|
||||||
}
|
}
|
||||||
selectedTip, err := consensus.GetVirtualSelectedParent()
|
selectedTip, err := consensus.GetVirtualSelectedParent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -387,14 +387,14 @@ func TestBoundedMergeDepth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lets validate the status of all the interesting blocks
|
// Lets validate the status of all the interesting blocks
|
||||||
if getStatus(consensusReal, pointAtBlueKosherizing) != externalapi.StatusValid {
|
if getStatus(consensusReal, pointAtBlueKosherizing) != externalapi.StatusUTXOValid {
|
||||||
t.Fatalf("TestBoundedMergeDepth: pointAtBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusValid, getStatus(consensusReal, pointAtBlueKosherizing))
|
t.Fatalf("TestBoundedMergeDepth: pointAtBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusUTXOValid, getStatus(consensusReal, pointAtBlueKosherizing))
|
||||||
}
|
}
|
||||||
if getStatus(consensusReal, pointAtRedKosherizing) != externalapi.StatusInvalid {
|
if getStatus(consensusReal, pointAtRedKosherizing) != externalapi.StatusInvalid {
|
||||||
t.Fatalf("TestBoundedMergeDepth: pointAtRedKosherizing expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, pointAtRedKosherizing))
|
t.Fatalf("TestBoundedMergeDepth: pointAtRedKosherizing expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, pointAtRedKosherizing))
|
||||||
}
|
}
|
||||||
if getStatus(consensusReal, transitiveBlueKosherizing) != externalapi.StatusValid {
|
if getStatus(consensusReal, transitiveBlueKosherizing) != externalapi.StatusUTXOValid {
|
||||||
t.Fatalf("TestBoundedMergeDepth: transitiveBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusValid, getStatus(consensusReal, transitiveBlueKosherizing))
|
t.Fatalf("TestBoundedMergeDepth: transitiveBlueKosherizing expected status '%s' but got '%s'", externalapi.StatusUTXOValid, getStatus(consensusReal, transitiveBlueKosherizing))
|
||||||
}
|
}
|
||||||
if getStatus(consensusReal, mergeDepthViolatingBlockBottom) != externalapi.StatusInvalid {
|
if getStatus(consensusReal, mergeDepthViolatingBlockBottom) != externalapi.StatusInvalid {
|
||||||
t.Fatalf("TestBoundedMergeDepth: mergeDepthViolatingBlockBottom expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, mergeDepthViolatingBlockBottom))
|
t.Fatalf("TestBoundedMergeDepth: mergeDepthViolatingBlockBottom expected status '%s' but got '%s'", externalapi.StatusInvalid, getStatus(consensusReal, mergeDepthViolatingBlockBottom))
|
||||||
@ -412,8 +412,8 @@ func TestBoundedMergeDepth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, b := range selectedChain {
|
for i, b := range selectedChain {
|
||||||
if getStatus(consensusReal, b) != externalapi.StatusValid {
|
if getStatus(consensusReal, b) != externalapi.StatusUTXOValid {
|
||||||
t.Fatalf("selectedChain[%d] expected status '%s' but got '%s'", i, externalapi.StatusValid, getStatus(consensusReal, b))
|
t.Fatalf("selectedChain[%d] expected status '%s' but got '%s'", i, externalapi.StatusUTXOValid, getStatus(consensusReal, b))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -12,8 +12,8 @@ const (
|
|||||||
// StatusInvalid indicates that the block is invalid.
|
// StatusInvalid indicates that the block is invalid.
|
||||||
StatusInvalid BlockStatus = iota
|
StatusInvalid BlockStatus = iota
|
||||||
|
|
||||||
// StatusValid indicates that the block has been fully validated.
|
// StatusUTXOValid indicates the block is valid from any UTXO related aspects and has passed all the other validations as well.
|
||||||
StatusValid
|
StatusUTXOValid
|
||||||
|
|
||||||
// StatusUTXOPendingVerification indicates that the block is pending verification against its past UTXO-Set, either
|
// StatusUTXOPendingVerification indicates that the block is pending verification against its past UTXO-Set, either
|
||||||
// because it was not yet verified since the block was never in the selected parent chain, or if the
|
// because it was not yet verified since the block was never in the selected parent chain, or if the
|
||||||
@ -29,7 +29,7 @@ const (
|
|||||||
|
|
||||||
var blockStatusStrings = map[BlockStatus]string{
|
var blockStatusStrings = map[BlockStatus]string{
|
||||||
StatusInvalid: "Invalid",
|
StatusInvalid: "Invalid",
|
||||||
StatusValid: "Valid",
|
StatusUTXOValid: "Valid",
|
||||||
StatusUTXOPendingVerification: "UTXOPendingVerification",
|
StatusUTXOPendingVerification: "UTXOPendingVerification",
|
||||||
StatusDisqualifiedFromChain: "DisqualifiedFromChain",
|
StatusDisqualifiedFromChain: "DisqualifiedFromChain",
|
||||||
StatusHeaderOnly: "HeaderOnly",
|
StatusHeaderOnly: "HeaderOnly",
|
||||||
|
|||||||
@ -10,6 +10,6 @@ type BlockValidator interface {
|
|||||||
ValidateHeaderInIsolation(blockHash *externalapi.DomainHash) error
|
ValidateHeaderInIsolation(blockHash *externalapi.DomainHash) error
|
||||||
ValidateBodyInIsolation(blockHash *externalapi.DomainHash) error
|
ValidateBodyInIsolation(blockHash *externalapi.DomainHash) error
|
||||||
ValidateHeaderInContext(blockHash *externalapi.DomainHash) error
|
ValidateHeaderInContext(blockHash *externalapi.DomainHash) error
|
||||||
ValidateBodyInContext(blockHash *externalapi.DomainHash) error
|
ValidateBodyInContext(blockHash *externalapi.DomainHash, isPruningPoint bool) error
|
||||||
ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash *externalapi.DomainHash) error
|
ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash *externalapi.DomainHash) error
|
||||||
}
|
}
|
||||||
|
|||||||
@ -126,7 +126,7 @@ func (bp *blockProcessor) ValidateAndInsertBlock(block *externalapi.DomainBlock)
|
|||||||
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateAndInsertBlock")
|
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateAndInsertBlock")
|
||||||
defer onEnd()
|
defer onEnd()
|
||||||
|
|
||||||
return bp.validateAndInsertBlock(block)
|
return bp.validateAndInsertBlock(block, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *blockProcessor) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
func (bp *blockProcessor) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
||||||
|
|||||||
@ -11,19 +11,59 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) {
|
func (bp *blockProcessor) setBlockStatusAfterBlockValidation(block *externalapi.DomainBlock, isPruningPoint bool) error {
|
||||||
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
|
||||||
|
exists, err := bp.blockStatusStore.Exists(bp.databaseContext, blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
status, err := bp.blockStatusStore.Get(bp.databaseContext, blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == externalapi.StatusUTXOValid {
|
||||||
|
// A block cannot have status StatusUTXOValid just after finishing bp.validateBlock, because
|
||||||
|
// if it's the case it should have been rejected as duplicate block.
|
||||||
|
// The only exception is the pruning point because its status is manually set before inserting
|
||||||
|
// the block.
|
||||||
|
if !isPruningPoint {
|
||||||
|
return errors.Errorf("block %s that is not the pruning point is not expected to be valid "+
|
||||||
|
"before adding to to the consensus state manager", blockHash)
|
||||||
|
}
|
||||||
|
log.Tracef("Block %s is the pruning point and has status %s, so leaving its status untouched",
|
||||||
|
blockHash, status)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
||||||
|
if isHeaderOnlyBlock {
|
||||||
|
log.Tracef("Block %s is a header-only block so setting its status as %s",
|
||||||
|
blockHash, externalapi.StatusHeaderOnly)
|
||||||
|
bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly)
|
||||||
|
} else {
|
||||||
|
log.Tracef("Block %s has body so setting its status as %s",
|
||||||
|
blockHash, externalapi.StatusUTXOPendingVerification)
|
||||||
|
bp.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock, isPruningPoint bool) (*externalapi.BlockInsertionResult, error) {
|
||||||
blockHash := consensushashing.HeaderHash(block.Header)
|
blockHash := consensushashing.HeaderHash(block.Header)
|
||||||
err := bp.validateBlock(block)
|
err := bp.validateBlock(block, isPruningPoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bp.discardAllChanges()
|
bp.discardAllChanges()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
err = bp.setBlockStatusAfterBlockValidation(block, isPruningPoint)
|
||||||
if isHeaderOnlyBlock {
|
if err != nil {
|
||||||
bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly)
|
return nil, err
|
||||||
} else {
|
|
||||||
bp.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block validations passed, save whatever DAG data was
|
// Block validations passed, save whatever DAG data was
|
||||||
@ -34,8 +74,8 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var oldHeadersSelectedTip *externalapi.DomainHash
|
var oldHeadersSelectedTip *externalapi.DomainHash
|
||||||
isGenesis := *blockHash != *bp.genesisHash
|
isGenesis := *blockHash == *bp.genesisHash
|
||||||
if isGenesis {
|
if !isGenesis {
|
||||||
var err error
|
var err error
|
||||||
oldHeadersSelectedTip, err = bp.headersSelectedTipStore.HeadersSelectedTip(bp.databaseContext)
|
oldHeadersSelectedTip, err = bp.headersSelectedTipStore.HeadersSelectedTip(bp.databaseContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -49,15 +89,21 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var selectedParentChainChanges *externalapi.SelectedParentChainChanges
|
var selectedParentChainChanges *externalapi.SelectedParentChainChanges
|
||||||
|
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
||||||
if !isHeaderOnlyBlock {
|
if !isHeaderOnlyBlock {
|
||||||
// Attempt to add the block to the virtual
|
// There's no need to update the consensus state manager when
|
||||||
selectedParentChainChanges, err = bp.consensusStateManager.AddBlock(blockHash)
|
// processing the pruning point since it was already handled
|
||||||
if err != nil {
|
// in consensusStateManager.UpdatePruningPoint
|
||||||
return nil, err
|
if !isPruningPoint {
|
||||||
|
// Attempt to add the block to the virtual
|
||||||
|
selectedParentChainChanges, err = bp.consensusStateManager.AddBlock(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isGenesis {
|
if !isGenesis {
|
||||||
err := bp.updateReachabilityReindexRoot(oldHeadersSelectedTip)
|
err := bp.updateReachabilityReindexRoot(oldHeadersSelectedTip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -137,14 +183,22 @@ func (bp *blockProcessor) checkBlockStatus(block *externalapi.DomainBlock) error
|
|||||||
return errors.Wrapf(ruleerrors.ErrKnownInvalid, "block %s is a known invalid block", hash)
|
return errors.Wrapf(ruleerrors.ErrKnownInvalid, "block %s is a known invalid block", hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
isBlockBodyAfterBlockHeader := !isHeaderOnlyBlock && status == externalapi.StatusHeaderOnly
|
if !isHeaderOnlyBlock {
|
||||||
if !isBlockBodyAfterBlockHeader {
|
hasBlock, err := bp.blockStore.HasBlock(bp.databaseContext, hash)
|
||||||
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash)
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
isDuplicateHeader := isHeaderOnlyBlock && status == externalapi.StatusHeaderOnly
|
if hasBlock {
|
||||||
if isDuplicateHeader {
|
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash)
|
||||||
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash)
|
}
|
||||||
|
} else {
|
||||||
|
hasHeader, err := bp.blockHeaderStore.HasBlockHeader(bp.databaseContext, hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if hasHeader {
|
||||||
|
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s header already exists", hash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -153,12 +207,12 @@ func (bp *blockProcessor) checkBlockStatus(block *externalapi.DomainBlock) error
|
|||||||
func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) error {
|
func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) error {
|
||||||
blockHash := consensushashing.BlockHash(block)
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
|
||||||
hasValidatedOnlyHeader, err := bp.hasValidatedOnlyHeader(blockHash)
|
hasValidatedHeader, err := bp.hasValidatedHeader(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasValidatedOnlyHeader {
|
if hasValidatedHeader {
|
||||||
log.Debugf("Block %s header was already validated, so skip the rest of validatePreProofOfWork", blockHash)
|
log.Debugf("Block %s header was already validated, so skip the rest of validatePreProofOfWork", blockHash)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -170,7 +224,7 @@ func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock) error {
|
func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock, isPruningPoint bool) error {
|
||||||
blockHash := consensushashing.BlockHash(block)
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
|
||||||
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
||||||
@ -182,7 +236,7 @@ func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasValidatedHeader, err := bp.hasValidatedOnlyHeader(blockHash)
|
hasValidatedHeader, err := bp.hasValidatedHeader(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -195,7 +249,7 @@ func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !isHeaderOnlyBlock {
|
if !isHeaderOnlyBlock {
|
||||||
err = bp.blockValidator.ValidateBodyInContext(blockHash)
|
err = bp.blockValidator.ValidateBodyInContext(blockHash, isPruningPoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -206,7 +260,10 @@ func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *blockProcessor) hasValidatedOnlyHeader(blockHash *externalapi.DomainHash) (bool, error) {
|
// hasValidatedHeader returns whether the block header was validated. It returns
|
||||||
|
// true in any case the block header was validated, whether it was validated as a
|
||||||
|
// header-only block or as a block with body.
|
||||||
|
func (bp *blockProcessor) hasValidatedHeader(blockHash *externalapi.DomainHash) (bool, error) {
|
||||||
exists, err := bp.blockStatusStore.Exists(bp.databaseContext, blockHash)
|
exists, err := bp.blockStatusStore.Exists(bp.databaseContext, blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -221,7 +278,7 @@ func (bp *blockProcessor) hasValidatedOnlyHeader(blockHash *externalapi.DomainHa
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return status == externalapi.StatusHeaderOnly, nil
|
return status != externalapi.StatusInvalid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *blockProcessor) discardAllChanges() {
|
func (bp *blockProcessor) discardAllChanges() {
|
||||||
|
|||||||
@ -24,16 +24,27 @@ func (bp *blockProcessor) validateAndInsertPruningPoint(newPruningPoint *externa
|
|||||||
|
|
||||||
// We have to validate the pruning point block before we set the new pruning point in consensusStateManager.
|
// We have to validate the pruning point block before we set the new pruning point in consensusStateManager.
|
||||||
log.Infof("Validating the new pruning point %s", newPruningPointHash)
|
log.Infof("Validating the new pruning point %s", newPruningPointHash)
|
||||||
err = bp.validateBlockAndDiscardChanges(newPruningPoint)
|
err = bp.validateBlockAndDiscardChanges(newPruningPoint, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Infof("Updating consensus state manager according to the new pruning point %s", newPruningPointHash)
|
||||||
err = bp.consensusStateManager.UpdatePruningPoint(newPruningPoint, serializedUTXOSet)
|
err = bp.consensusStateManager.UpdatePruningPoint(newPruningPoint, serializedUTXOSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = bp.ValidateAndInsertBlock(newPruningPoint)
|
log.Infof("Inserting the new pruning point %s", newPruningPointHash)
|
||||||
return err
|
_, err = bp.validateAndInsertBlock(newPruningPoint, true)
|
||||||
|
if err != nil {
|
||||||
|
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
|
// This should never happen because we already validated the block with bp.validateBlockAndDiscardChanges.
|
||||||
|
// We use Errorf so it won't be identified later on to be a rule error and will eventually cause
|
||||||
|
// the program to panic.
|
||||||
|
return errors.Errorf("validateAndInsertBlock returned unexpected rule error while processing "+
|
||||||
|
"the pruning point: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,12 +7,12 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (bp *blockProcessor) validateBlockAndDiscardChanges(block *externalapi.DomainBlock) error {
|
func (bp *blockProcessor) validateBlockAndDiscardChanges(block *externalapi.DomainBlock, isPruningPoint bool) error {
|
||||||
defer bp.discardAllChanges()
|
defer bp.discardAllChanges()
|
||||||
return bp.validateBlock(block)
|
return bp.validateBlock(block, isPruningPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock) error {
|
func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, isPruningPoint bool) error {
|
||||||
blockHash := consensushashing.HeaderHash(block.Header)
|
blockHash := consensushashing.HeaderHash(block.Header)
|
||||||
log.Debugf("Validating block %s", blockHash)
|
log.Debugf("Validating block %s", blockHash)
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
hasValidatedHeader, err := bp.hasValidatedOnlyHeader(blockHash)
|
hasValidatedHeader, err := bp.hasValidatedHeader(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -50,15 +50,19 @@ func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock) error {
|
|||||||
|
|
||||||
// If in-context validations fail, discard all changes and store the
|
// If in-context validations fail, discard all changes and store the
|
||||||
// block with StatusInvalid.
|
// block with StatusInvalid.
|
||||||
err = bp.validatePostProofOfWork(block)
|
err = bp.validatePostProofOfWork(block, isPruningPoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
bp.discardAllChanges()
|
bp.discardAllChanges()
|
||||||
hash := consensushashing.BlockHash(block)
|
// If we got ErrMissingParents the block shouldn't be considered as invalid
|
||||||
bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid)
|
// because it could be added later on when its parents are present.
|
||||||
commitErr := bp.commitAllChanges()
|
if !errors.As(err, &ruleerrors.ErrMissingParents{}) {
|
||||||
if commitErr != nil {
|
hash := consensushashing.BlockHash(block)
|
||||||
return commitErr
|
bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid)
|
||||||
|
commitErr := bp.commitAllChanges()
|
||||||
|
if commitErr != nil {
|
||||||
|
return commitErr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -13,11 +13,69 @@ import (
|
|||||||
|
|
||||||
// ValidateBodyInContext validates block bodies in the context of the current
|
// ValidateBodyInContext validates block bodies in the context of the current
|
||||||
// consensus state
|
// consensus state
|
||||||
func (v *blockValidator) ValidateBodyInContext(blockHash *externalapi.DomainHash) error {
|
func (v *blockValidator) ValidateBodyInContext(blockHash *externalapi.DomainHash, isPruningPoint bool) error {
|
||||||
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateBodyInContext")
|
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateBodyInContext")
|
||||||
defer onEnd()
|
defer onEnd()
|
||||||
|
|
||||||
return v.checkBlockTransactionsFinalized(blockHash)
|
err := v.checkBlockTransactionsFinalized(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isPruningPoint {
|
||||||
|
err := v.checkParentBlockBodiesExist(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *blockValidator) checkParentBlockBodiesExist(blockHash *externalapi.DomainHash) error {
|
||||||
|
missingParentHashes := []*externalapi.DomainHash{}
|
||||||
|
header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, parent := range header.ParentHashes {
|
||||||
|
hasBlock, err := v.blockStore.HasBlock(v.databaseContext, parent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasBlock {
|
||||||
|
pruningPoint, err := v.pruningStore.PruningPoint(v.databaseContext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
isInPastOfPruningPoint, err := v.dagTopologyManager.IsAncestorOf(parent, pruningPoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a block parent is in the past of the pruning point
|
||||||
|
// it means its body will never be used, so it's ok if
|
||||||
|
// it's missing.
|
||||||
|
// This will usually happen during IBD when getting the blocks
|
||||||
|
// in the pruning point anticone.
|
||||||
|
if isInPastOfPruningPoint {
|
||||||
|
log.Debugf("Block %s parent %s is missing a body, but is in the past of the pruning point",
|
||||||
|
blockHash, parent)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Block %s parent %s is missing a body", blockHash, parent)
|
||||||
|
|
||||||
|
missingParentHashes = append(missingParentHashes, parent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(missingParentHashes) > 0 {
|
||||||
|
return ruleerrors.NewErrMissingParents(missingParentHashes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi.DomainHash) error {
|
func (v *blockValidator) checkBlockTransactionsFinalized(blockHash *externalapi.DomainHash) error {
|
||||||
|
|||||||
@ -19,7 +19,7 @@ func (v *blockValidator) ValidatePruningPointViolationAndProofOfWorkAndDifficult
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = v.checkParentsExist(blockHash, header)
|
err = v.checkParentHeadersExist(header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -103,14 +103,8 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, header *externalapi.DomainBlockHeader) error {
|
func (v *blockValidator) checkParentHeadersExist(header *externalapi.DomainBlockHeader) error {
|
||||||
missingParentHashes := []*externalapi.DomainHash{}
|
missingParentHashes := []*externalapi.DomainHash{}
|
||||||
|
|
||||||
hasBlockBody, err := v.blockStore.HasBlock(v.databaseContext, blockHash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, parent := range header.ParentHashes {
|
for _, parent := range header.ParentHashes {
|
||||||
parentHeaderExists, err := v.blockHeaderStore.HasBlockHeader(v.databaseContext, parent)
|
parentHeaderExists, err := v.blockHeaderStore.HasBlockHeader(v.databaseContext, parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -129,26 +123,6 @@ func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, he
|
|||||||
if parentStatus == externalapi.StatusInvalid {
|
if parentStatus == externalapi.StatusInvalid {
|
||||||
return errors.Wrapf(ruleerrors.ErrInvalidAncestorBlock, "parent %s is invalid", parent)
|
return errors.Wrapf(ruleerrors.ErrInvalidAncestorBlock, "parent %s is invalid", parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasBlockBody {
|
|
||||||
if parentStatus == externalapi.StatusHeaderOnly {
|
|
||||||
pruningPoint, err := v.pruningStore.PruningPoint(v.databaseContext)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
isInPastOfPruningPoint, err := v.dagTopologyManager.IsAncestorOf(parent, pruningPoint)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if isInPastOfPruningPoint {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
missingParentHashes = append(missingParentHashes, parent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(missingParentHashes) > 0 {
|
if len(missingParentHashes) > 0 {
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddBlockToVirtual submits the given block to be added to the
|
// AddBlock submits the given block to be added to the
|
||||||
// current virtual. This process may result in a new virtual block
|
// current virtual. This process may result in a new virtual block
|
||||||
// getting created
|
// getting created
|
||||||
func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) {
|
func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) {
|
||||||
|
|||||||
@ -256,10 +256,10 @@ func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *external
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if blockStatus != externalapi.StatusValid {
|
if blockStatus != externalapi.StatusUTXOValid {
|
||||||
return nil, errors.Errorf(
|
return nil, errors.Errorf(
|
||||||
"block %s, has status '%s', and therefore can't restore it's UTXO set. Only blocks with status '%s' can be restored.",
|
"block %s, has status '%s', and therefore can't restore it's UTXO set. Only blocks with status '%s' can be restored.",
|
||||||
blockHash, blockStatus, externalapi.StatusValid)
|
blockHash, blockStatus, externalapi.StatusUTXOValid)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("RestorePastUTXOSetIterator start for block %s", blockHash)
|
log.Tracef("RestorePastUTXOSetIterator start for block %s", blockHash)
|
||||||
|
|||||||
@ -88,7 +88,7 @@ func (csm *consensusStateManager) selectVirtualSelectedParent(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if selectedParentCandidateStatus == externalapi.StatusValid {
|
if selectedParentCandidateStatus == externalapi.StatusUTXOValid {
|
||||||
log.Tracef("Block %s is valid. Returning it as the selected parent", selectedParentCandidate)
|
log.Tracef("Block %s is valid. Returning it as the selected parent", selectedParentCandidate)
|
||||||
return selectedParentCandidate, nil
|
return selectedParentCandidate, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,8 +72,8 @@ func (csm *consensusStateManager) findSelectedParentStatus(unverifiedBlocks []*e
|
|||||||
lastUnverifiedBlock := unverifiedBlocks[len(unverifiedBlocks)-1]
|
lastUnverifiedBlock := unverifiedBlocks[len(unverifiedBlocks)-1]
|
||||||
if *lastUnverifiedBlock == *csm.genesisHash {
|
if *lastUnverifiedBlock == *csm.genesisHash {
|
||||||
log.Tracef("the most recent unverified block is the genesis block, "+
|
log.Tracef("the most recent unverified block is the genesis block, "+
|
||||||
"which by definition has status: %s", externalapi.StatusValid)
|
"which by definition has status: %s", externalapi.StatusUTXOValid)
|
||||||
return externalapi.StatusValid, nil
|
return externalapi.StatusUTXOValid, nil
|
||||||
}
|
}
|
||||||
lastUnverifiedBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, lastUnverifiedBlock)
|
lastUnverifiedBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, lastUnverifiedBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -164,7 +164,7 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalap
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return externalapi.StatusValid, nil
|
return externalapi.StatusUTXOValid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (csm *consensusStateManager) removeAncestorsFromVirtualDiffParentsAndAssignDiffChild(
|
func (csm *consensusStateManager) removeAncestorsFromVirtualDiffParentsAndAssignDiffChild(
|
||||||
|
|||||||
@ -70,8 +70,8 @@ func TestDoubleSpends(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error getting status of goodBlock1: %+v", err)
|
t.Fatalf("Error getting status of goodBlock1: %+v", err)
|
||||||
}
|
}
|
||||||
if goodBlock1Status != externalapi.StatusValid {
|
if goodBlock1Status != externalapi.StatusUTXOValid {
|
||||||
t.Fatalf("GoodBlock1 status expected to be '%s', but is '%s'", externalapi.StatusValid, goodBlock1Status)
|
t.Fatalf("GoodBlock1 status expected to be '%s', but is '%s'", externalapi.StatusUTXOValid, goodBlock1Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// To check that a block containing the same transaction already in it's past is disqualified:
|
// To check that a block containing the same transaction already in it's past is disqualified:
|
||||||
@ -145,8 +145,8 @@ func TestDoubleSpends(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error getting status of goodBlock: %+v", err)
|
t.Fatalf("Error getting status of goodBlock: %+v", err)
|
||||||
}
|
}
|
||||||
if goodBlock2Status != externalapi.StatusValid {
|
if goodBlock2Status != externalapi.StatusUTXOValid {
|
||||||
t.Fatalf("GoodBlock2 status expected to be '%s', but is '%s'", externalapi.StatusValid, goodBlock2Status)
|
t.Fatalf("GoodBlock2 status expected to be '%s', but is '%s'", externalapi.StatusUTXOValid, goodBlock2Status)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -167,7 +167,7 @@ func TestResolveBlockStatusSanity(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error getting genesis status: %s", err)
|
t.Fatalf("error getting genesis status: %s", err)
|
||||||
}
|
}
|
||||||
if genesisStatus != externalapi.StatusValid {
|
if genesisStatus != externalapi.StatusUTXOValid {
|
||||||
t.Fatalf("genesis is unexpectedly non-valid. Its status is: %s", genesisStatus)
|
t.Fatalf("genesis is unexpectedly non-valid. Its status is: %s", genesisStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +185,7 @@ func TestResolveBlockStatusSanity(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error getting block %d (%s) status: %s", i, addedBlockHash, err)
|
t.Fatalf("error getting block %d (%s) status: %s", i, addedBlockHash, err)
|
||||||
}
|
}
|
||||||
if blockStatus != externalapi.StatusValid {
|
if blockStatus != externalapi.StatusUTXOValid {
|
||||||
t.Fatalf("block %d (%s) is unexpectedly non-valid. Its status is: %s", i, addedBlockHash, blockStatus)
|
t.Fatalf("block %d (%s) is unexpectedly non-valid. Its status is: %s", i, addedBlockHash, blockStatus)
|
||||||
}
|
}
|
||||||
currentHash = addedBlockHash
|
currentHash = addedBlockHash
|
||||||
@ -224,13 +224,13 @@ func TestResolveBlockStatusSanity(t *testing.T) {
|
|||||||
allHashes = append(allHashes, addedBlockHash)
|
allHashes = append(allHashes, addedBlockHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that all the blocks in the DAG now have StatusValid
|
// Make sure that all the blocks in the DAG now have StatusUTXOValid
|
||||||
for _, hash := range allHashes {
|
for _, hash := range allHashes {
|
||||||
blockStatus, err := consensus.BlockStatusStore().Get(consensus.DatabaseContext(), hash)
|
blockStatus, err := consensus.BlockStatusStore().Get(consensus.DatabaseContext(), hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error getting block %s status: %s", hash, err)
|
t.Fatalf("error getting block %s status: %s", hash, err)
|
||||||
}
|
}
|
||||||
if blockStatus != externalapi.StatusValid {
|
if blockStatus != externalapi.StatusUTXOValid {
|
||||||
t.Fatalf("block %s is unexpectedly non-valid. Its status is: %s", hash, blockStatus)
|
t.Fatalf("block %s is unexpectedly non-valid. Its status is: %s", hash, blockStatus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,59 +54,69 @@ func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalap
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Tracef("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash())
|
log.Debugf("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash())
|
||||||
|
|
||||||
newPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, newPruningPointHash)
|
newPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, newPruningPointHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Tracef("The UTXO commitment of the pruning point: %s",
|
log.Debugf("The UTXO commitment of the pruning point: %s",
|
||||||
newPruningPointHeader.UTXOCommitment)
|
newPruningPointHeader.UTXOCommitment)
|
||||||
|
|
||||||
if newPruningPointHeader.UTXOCommitment != *utxoSetMultiSet.Hash() {
|
if newPruningPointHeader.UTXOCommitment != *utxoSetMultiSet.Hash() {
|
||||||
return errors.Wrapf(ruleerrors.ErrBadPruningPointUTXOSet, "the expected multiset hash of the pruning "+
|
return errors.Wrapf(ruleerrors.ErrBadPruningPointUTXOSet, "the expected multiset hash of the pruning "+
|
||||||
"point UTXO set is %s but got %s", newPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash())
|
"point UTXO set is %s but got %s", newPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash())
|
||||||
}
|
}
|
||||||
log.Tracef("The new pruning point UTXO commitment validation passed")
|
log.Debugf("The new pruning point UTXO commitment validation passed")
|
||||||
|
|
||||||
log.Tracef("Staging the parent hashes for pruning point as the DAG tips")
|
newTips := []*externalapi.DomainHash{newPruningPointHash}
|
||||||
csm.consensusStateStore.StageTips(newPruningPointHeader.ParentHashes)
|
|
||||||
|
|
||||||
log.Tracef("Setting the parent hashes for the header tips pruning point as the virtual parents")
|
log.Debugf("Staging the the pruning point as the only DAG tip")
|
||||||
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, newPruningPointHeader.ParentHashes)
|
csm.consensusStateStore.StageTips(newTips)
|
||||||
if err != nil {
|
|
||||||
return err
|
log.Debugf("Setting the pruning point as the only virtual parent")
|
||||||
}
|
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, newTips)
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debugf("Calculating GHOSTDAG for the new virtual")
|
||||||
err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash)
|
err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("Updating the header tips pruning point diff parents with an empty UTXO diff")
|
log.Debugf("Staging the virtual UTXO set")
|
||||||
err = csm.updateVirtualDiffParents(utxo.NewUTXODiff())
|
err = csm.consensusStateStore.StageVirtualUTXOSet(protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("Staging the new pruning point and its UTXO set")
|
log.Debugf("Deleting all the existing virtual diff parents")
|
||||||
|
csm.consensusStateStore.StageVirtualDiffParents(nil)
|
||||||
|
|
||||||
|
log.Debugf("Updating the new pruning point to be the new virtual diff parent with an empty diff")
|
||||||
|
err = csm.stageDiff(newPruningPointHash, utxo.NewUTXODiff(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Staging the new pruning point and its UTXO set")
|
||||||
csm.pruningStore.Stage(newPruningPointHash, serializedUTXOSet)
|
csm.pruningStore.Stage(newPruningPointHash, serializedUTXOSet)
|
||||||
|
|
||||||
log.Tracef("Staging the new pruning point as %s", externalapi.StatusValid)
|
// Before we manually mark the new pruning point as valid, we validate that all of its transactions are valid
|
||||||
csm.blockStatusStore.Stage(newPruningPointHash, externalapi.StatusValid)
|
// against the provided UTXO set.
|
||||||
|
log.Debugf("Validating that the pruning point is UTXO valid")
|
||||||
|
err = csm.validateBlockTransactionsAgainstPastUTXO(newPruningPoint, utxo.NewUTXODiff())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Staging the new pruning point as %s", externalapi.StatusUTXOValid)
|
||||||
|
csm.blockStatusStore.Stage(newPruningPointHash, externalapi.StatusUTXOValid)
|
||||||
|
|
||||||
|
log.Debugf("Staging the new pruning point multiset")
|
||||||
|
csm.multisetStore.Stage(newPruningPointHash, utxoSetMultiSet)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user