Ori Newman d207888b67
Implement pruned headers node (#1787)
* Pruning headers p2p basic structure

* Remove headers-first

* Fix consensus tests except TestValidateAndInsertPruningPointWithSideBlocks and TestValidateAndInsertImportedPruningPoint

* Add virtual genesis

* Implement PruningPointAndItsAnticoneWithMetaData

* Start fixing TestValidateAndInsertImportedPruningPoint

* Fix TestValidateAndInsertImportedPruningPoint

* Fix BlockWindow

* Update p2p and gRPC

* Fix all tests except TestHandleRelayInvs

* Delete TestHandleRelayInvs parts that cover the old IBD flow

* Fix lint errors

* Add p2p_request_ibd_blocks.go

* Clean code

* Make MsgBlockWithMetaData implement its own representation

* Remove redundant check if highest share block is below the pruning point

* Fix TestCheckLockTimeVerifyConditionedByAbsoluteTimeWithWrongLockTime

* Fix comments, errors ane names

* Fix window size to the real value

* Check reindex root after each block at TestUpdateReindexRoot

* Remove irrelevant check

* Renames and comments

* Remove redundant argument from sendGetBlockLocator

* Don't delete staging on non-recoverable errors

* Renames and comments

* Remove redundant code

* Commit changes inside ResolveVirtual

* Add comment to IsRecoverableError

* Remove blocksWithMetaDataGHOSTDAGDataStore

* Increase windows pagefile

* Move DeleteStagingConsensus outside of defer

* Get rid of mustAccepted in receiveBlockWithMetaData

* Ban on invalid pruning point

* Rename interface_datastructures_daawindowstore.go to interface_datastructures_blocks_with_meta_data_daa_window_store.go

* * Change GetVirtualSelectedParentChainFromBlockResponseMessage and VirtualSelectedParentChainChangedNotificationMessage to show only added block hashes
*  Remove ResolveVirtual
* Use externalapi.ConsensusWrapper inside MiningManager
* Fix pruningmanager.blockwithmetadata

* Set pruning point selected child when importing the pruning point UTXO set

* Change virtual genesis hash

* replace the selected parent with virtual genesis on removePrunedBlocksFromGHOSTDAGData

* Get rid of low hash in block locators

* Remove +1 from everywhere we use difficultyAdjustmentWindowSize and increase the default value by one

* Add comments about consensus wrapper

* Don't use separate staging area when resolving resolveBlockStatus

* Fix netsync stability test

* Fix checkResolveVirtual

* Rename ConsensusWrapper->ConsensusReference

* Get rid of blockHeapNode

* Add comment to defaultDifficultyAdjustmentWindowSize

* Add SelectedChild to DAGTraversalManager

* Remove redundant copy

* Rename blockWindowHeap->calculateBlockWindowHeap

* Move isVirtualGenesisOnlyParent to utils

* Change BlockWithMetaData->BlockWithTrustedData

* Get rid of maxReasonLength

* Split IBD to 100 blocks each time

* Fix a bug in calculateBlockWindowHeap

* Switch to trusted data when encountering virtual genesis in blockWithTrustedData

* Move ConsensusReference to domain

* Update ConsensusReference comment

* Add comment

* Rename shouldNotAddGenesis->skipAddingGenesis
2021-07-26 12:24:07 +03:00

86 lines
3.2 KiB
Go

package blockprocessor
import (
"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/util/staging"
"github.com/pkg/errors"
)
func (bp *blockProcessor) validateBlock(stagingArea *model.StagingArea, block *externalapi.DomainBlock, isBlockWithTrustedData bool) error {
blockHash := consensushashing.HeaderHash(block.Header)
log.Debugf("Validating block %s", blockHash)
// Since genesis has a lot of special cases validation rules, we make sure it's not added unintentionally
// on uninitialized node.
if blockHash.Equal(bp.genesisHash) && bp.blockStore.Count(stagingArea) != 0 {
return errors.Wrapf(ruleerrors.ErrGenesisOnInitializedConsensus, "Cannot add genesis to an initialized consensus")
}
err := bp.checkBlockStatus(stagingArea, block)
if err != nil {
return err
}
hasValidatedHeader, err := bp.hasValidatedHeader(stagingArea, blockHash)
if err != nil {
return err
}
if !hasValidatedHeader {
log.Debugf("Staging block %s header", blockHash)
bp.blockHeaderStore.Stage(stagingArea, blockHash, block.Header)
} else {
log.Debugf("Block %s header is already known, so no need to stage it", blockHash)
}
// If any validation until (included) proof-of-work fails, simply
// return an error without writing anything in the database.
// This is to prevent spamming attacks.
err = bp.validatePreProofOfWork(stagingArea, block)
if err != nil {
return err
}
if !hasValidatedHeader {
err = bp.blockValidator.ValidatePruningPointViolationAndProofOfWorkAndDifficulty(stagingArea, blockHash, isBlockWithTrustedData)
if err != nil {
return err
}
}
// If in-context validations fail, discard all changes and store the
// block with StatusInvalid.
err = bp.validatePostProofOfWork(stagingArea, block, isBlockWithTrustedData)
if err != nil {
if errors.As(err, &ruleerrors.RuleError{}) {
// We mark invalid blocks with status externalapi.StatusInvalid except in the
// case of the following errors:
// ErrMissingParents - If we got ErrMissingParents the block shouldn't be
// considered as invalid because it could be added later on when its
// parents are present.
// ErrBadMerkleRoot - if we get ErrBadMerkleRoot we shouldn't mark the
// block as invalid because later on we can get the block with
// transactions that fits the merkle root.
// ErrPrunedBlock - ErrPrunedBlock is an error that rejects a block body and
// not the block as a whole, so we shouldn't mark it as invalid.
if !errors.As(err, &ruleerrors.ErrMissingParents{}) &&
!errors.Is(err, ruleerrors.ErrBadMerkleRoot) &&
!errors.Is(err, ruleerrors.ErrPrunedBlock) {
// Use a new stagingArea so we save only the block status
stagingArea := model.NewStagingArea()
hash := consensushashing.BlockHash(block)
bp.blockStatusStore.Stage(stagingArea, hash, externalapi.StatusInvalid)
commitErr := staging.CommitAllChanges(bp.databaseContext, stagingArea)
if commitErr != nil {
return commitErr
}
}
}
return err
}
return nil
}