mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-07 14:46:44 +00:00
New headers first flow (#1211)
* 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
This commit is contained in:
parent
6926a7ab81
commit
48e1a2c396
@ -212,7 +212,6 @@ func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([
|
|||||||
return missingParentsError.MissingParentHashes, nil
|
return missingParentsError.MissingParentHashes, nil
|
||||||
}
|
}
|
||||||
log.Warnf("Rejected block %s from %s: %s", blockHash, flow.peer, err)
|
log.Warnf("Rejected block %s from %s: %s", blockHash, flow.peer, err)
|
||||||
|
|
||||||
return nil, protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash)
|
return nil, protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash)
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -35,7 +35,7 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if syncInfo.State == externalapi.SyncStateAwaitingUTXOSet {
|
if syncInfo.IsAwaitingUTXOSet {
|
||||||
found, err := flow.fetchMissingUTXOSet(syncInfo.IBDRootUTXOBlockHash)
|
found, err := flow.fetchMissingUTXOSet(syncInfo.IBDRootUTXOBlockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -190,8 +190,8 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHash) (bool, error) {
|
func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHash) (succeed bool, err error) {
|
||||||
err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootUTXOSetAndBlock(ibdRootHash))
|
err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootUTXOSetAndBlock(ibdRootHash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -205,17 +205,23 @@ func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.Do
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
err = flow.Domain().Consensus().ValidateAndInsertPruningPoint(block, utxoSet)
|
||||||
if err != nil {
|
|
||||||
blockHash := consensushashing.BlockHash(block)
|
|
||||||
return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "got invalid block %s during IBD", blockHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = flow.Domain().Consensus().SetPruningPointUTXOSet(utxoSet)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "error with IBD root UTXO set")
|
return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "error with IBD root UTXO set")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syncInfo, err := flow.Domain().Consensus().GetSyncInfo()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Find a better way to deal with finality conflicts.
|
||||||
|
if syncInfo.IsAwaitingUTXOSet {
|
||||||
|
log.Warnf("Still awaiting for UTXO set. This can happen only because the given pruning point violates " +
|
||||||
|
"finality. If this keeps happening delete the data directory and restart your node.")
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,25 +25,25 @@ type consensus struct {
|
|||||||
dagTraversalManager model.DAGTraversalManager
|
dagTraversalManager model.DAGTraversalManager
|
||||||
difficultyManager model.DifficultyManager
|
difficultyManager model.DifficultyManager
|
||||||
ghostdagManager model.GHOSTDAGManager
|
ghostdagManager model.GHOSTDAGManager
|
||||||
headerTipsManager model.HeaderTipsManager
|
headerTipsManager model.HeadersSelectedTipManager
|
||||||
mergeDepthManager model.MergeDepthManager
|
mergeDepthManager model.MergeDepthManager
|
||||||
pruningManager model.PruningManager
|
pruningManager model.PruningManager
|
||||||
reachabilityManager model.ReachabilityManager
|
reachabilityManager model.ReachabilityManager
|
||||||
finalityManager model.FinalityManager
|
finalityManager model.FinalityManager
|
||||||
|
|
||||||
acceptanceDataStore model.AcceptanceDataStore
|
acceptanceDataStore model.AcceptanceDataStore
|
||||||
blockStore model.BlockStore
|
blockStore model.BlockStore
|
||||||
blockHeaderStore model.BlockHeaderStore
|
blockHeaderStore model.BlockHeaderStore
|
||||||
pruningStore model.PruningStore
|
pruningStore model.PruningStore
|
||||||
ghostdagDataStore model.GHOSTDAGDataStore
|
ghostdagDataStore model.GHOSTDAGDataStore
|
||||||
blockRelationStore model.BlockRelationStore
|
blockRelationStore model.BlockRelationStore
|
||||||
blockStatusStore model.BlockStatusStore
|
blockStatusStore model.BlockStatusStore
|
||||||
consensusStateStore model.ConsensusStateStore
|
consensusStateStore model.ConsensusStateStore
|
||||||
headerTipsStore model.HeaderTipsStore
|
headersSelectedTipStore model.HeaderSelectedTipStore
|
||||||
multisetStore model.MultisetStore
|
multisetStore model.MultisetStore
|
||||||
reachabilityDataStore model.ReachabilityDataStore
|
reachabilityDataStore model.ReachabilityDataStore
|
||||||
utxoDiffStore model.UTXODiffStore
|
utxoDiffStore model.UTXODiffStore
|
||||||
finalityStore model.FinalityStore
|
finalityStore model.FinalityStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildBlock builds a block over the current state, with the transactions
|
// BuildBlock builds a block over the current state, with the transactions
|
||||||
@ -138,12 +138,6 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap
|
|||||||
|
|
||||||
blockInfo.BlueScore = ghostdagData.BlueScore()
|
blockInfo.BlueScore = ghostdagData.BlueScore()
|
||||||
|
|
||||||
isBlockInHeaderPruningPointFuture, err := s.syncManager.IsBlockInHeaderPruningPointFuture(blockHash)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
blockInfo.IsBlockInHeaderPruningPointFuture = isBlockInHeaderPruningPointFuture
|
|
||||||
|
|
||||||
return blockInfo, nil
|
return blockInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,11 +177,11 @@ func (s *consensus) GetPruningPointUTXOSet(expectedPruningPointHash *externalapi
|
|||||||
return serializedUTXOSet, nil
|
return serializedUTXOSet, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *consensus) SetPruningPointUTXOSet(serializedUTXOSet []byte) error {
|
func (s *consensus) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
return s.consensusStateManager.SetPruningPointUTXOSet(serializedUTXOSet)
|
return s.blockProcessor.ValidateAndInsertPruningPoint(newPruningPoint, serializedUTXOSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) {
|
func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) {
|
||||||
@ -201,27 +195,6 @@ func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error)
|
|||||||
return s.blockStore.Block(s.databaseContext, virtualGHOSTDAGData.SelectedParent())
|
return s.blockStore.Block(s.databaseContext, virtualGHOSTDAGData.SelectedParent())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) {
|
|
||||||
s.lock.Lock()
|
|
||||||
defer s.lock.Unlock()
|
|
||||||
|
|
||||||
return s.syncManager.CreateBlockLocator(lowHash, highHash, limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) {
|
|
||||||
s.lock.Lock()
|
|
||||||
defer s.lock.Unlock()
|
|
||||||
|
|
||||||
return s.syncManager.FindNextBlockLocatorBoundaries(blockLocator)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) {
|
|
||||||
s.lock.Lock()
|
|
||||||
defer s.lock.Unlock()
|
|
||||||
|
|
||||||
return s.syncManager.GetSyncInfo()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *consensus) Tips() ([]*externalapi.DomainHash, error) {
|
func (s *consensus) Tips() ([]*externalapi.DomainHash, error) {
|
||||||
return s.consensusStateStore.Tips(s.databaseContext)
|
return s.consensusStateStore.Tips(s.databaseContext)
|
||||||
}
|
}
|
||||||
@ -246,3 +219,24 @@ func (s *consensus) GetVirtualInfo() (*externalapi.VirtualInfo, error) {
|
|||||||
PastMedianTime: pastMedianTime,
|
PastMedianTime: pastMedianTime,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
return s.syncManager.CreateBlockLocator(lowHash, highHash, limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
return s.syncManager.FindNextBlockLocatorBoundaries(blockLocator)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) {
|
||||||
|
s.lock.Lock()
|
||||||
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
|
return s.syncManager.GetSyncInfo()
|
||||||
|
}
|
||||||
|
@ -42,9 +42,6 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
|
|||||||
if info.BlockStatus != externalapi.StatusInvalid {
|
if info.BlockStatus != externalapi.StatusInvalid {
|
||||||
t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusInvalid, info.BlockStatus)
|
t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusInvalid, info.BlockStatus)
|
||||||
}
|
}
|
||||||
if info.IsBlockInHeaderPruningPointFuture != false {
|
|
||||||
t.Fatalf("Expected IsBlockInHeaderPruningPointFuture=false, instead found: %t", info.IsBlockInHeaderPruningPointFuture)
|
|
||||||
}
|
|
||||||
|
|
||||||
emptyCoinbase := externalapi.DomainCoinbaseData{}
|
emptyCoinbase := externalapi.DomainCoinbaseData{}
|
||||||
validBlock, err := consensus.BuildBlock(&emptyCoinbase, nil)
|
validBlock, err := consensus.BuildBlock(&emptyCoinbase, nil)
|
||||||
@ -68,9 +65,6 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
|
|||||||
if info.BlockStatus != externalapi.StatusValid {
|
if info.BlockStatus != externalapi.StatusValid {
|
||||||
t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusValid, info.BlockStatus)
|
t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusValid, info.BlockStatus)
|
||||||
}
|
}
|
||||||
if info.IsBlockInHeaderPruningPointFuture != true {
|
|
||||||
t.Fatalf("Expected IsBlockInHeaderPruningPointFuture=true, instead found: %t", info.IsBlockInHeaderPruningPointFuture)
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
package headersselectedtipstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/database/serialization"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys"
|
||||||
|
)
|
||||||
|
|
||||||
|
var headerSelectedTipKey = dbkeys.MakeBucket().Key([]byte("headers-selected-tip"))
|
||||||
|
|
||||||
|
type headerSelectedTipStore struct {
|
||||||
|
staging *externalapi.DomainHash
|
||||||
|
cache *externalapi.DomainHash
|
||||||
|
}
|
||||||
|
|
||||||
|
// New instantiates a new HeaderSelectedTipStore
|
||||||
|
func New() model.HeaderSelectedTipStore {
|
||||||
|
return &headerSelectedTipStore{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hts *headerSelectedTipStore) Has(dbContext model.DBReader) (bool, error) {
|
||||||
|
if hts.staging != nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if hts.cache != nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbContext.Has(headerSelectedTipKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hts *headerSelectedTipStore) Discard() {
|
||||||
|
hts.staging = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hts *headerSelectedTipStore) Commit(dbTx model.DBTransaction) error {
|
||||||
|
if hts.staging == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedTipBytes, err := hts.serializeHeadersSelectedTip(hts.staging)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = dbTx.Put(headerSelectedTipKey, selectedTipBytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hts.cache = hts.staging
|
||||||
|
|
||||||
|
hts.Discard()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hts *headerSelectedTipStore) Stage(selectedTip *externalapi.DomainHash) {
|
||||||
|
hts.staging = selectedTip.Clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hts *headerSelectedTipStore) IsStaged() bool {
|
||||||
|
return hts.staging != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hts *headerSelectedTipStore) HeadersSelectedTip(dbContext model.DBReader) (*externalapi.DomainHash, error) {
|
||||||
|
if hts.staging != nil {
|
||||||
|
return hts.staging.Clone(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if hts.cache != nil {
|
||||||
|
return hts.cache.Clone(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedTipBytes, err := dbContext.Get(headerSelectedTipKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedTip, err := hts.deserializeHeadersSelectedTip(selectedTipBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hts.cache = selectedTip
|
||||||
|
return hts.cache.Clone(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hts *headerSelectedTipStore) serializeHeadersSelectedTip(selectedTip *externalapi.DomainHash) ([]byte, error) {
|
||||||
|
return proto.Marshal(serialization.DomainHashToDbHash(selectedTip))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hts *headerSelectedTipStore) deserializeHeadersSelectedTip(selectedTipBytes []byte) (*externalapi.DomainHash, error) {
|
||||||
|
dbHash := &serialization.DbHash{}
|
||||||
|
err := proto.Unmarshal(selectedTipBytes, dbHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return serialization.DbHashToDomainHash(dbHash)
|
||||||
|
}
|
@ -1,101 +0,0 @@
|
|||||||
package headertipsstore
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/database/serialization"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/dbkeys"
|
|
||||||
)
|
|
||||||
|
|
||||||
var headerTipsKey = dbkeys.MakeBucket().Key([]byte("header-tips"))
|
|
||||||
|
|
||||||
type headerTipsStore struct {
|
|
||||||
staging []*externalapi.DomainHash
|
|
||||||
cache []*externalapi.DomainHash
|
|
||||||
}
|
|
||||||
|
|
||||||
// New instantiates a new HeaderTipsStore
|
|
||||||
func New() model.HeaderTipsStore {
|
|
||||||
return &headerTipsStore{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hts *headerTipsStore) HasTips(dbContext model.DBReader) (bool, error) {
|
|
||||||
if len(hts.staging) > 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(hts.cache) > 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return dbContext.Has(headerTipsKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hts *headerTipsStore) Discard() {
|
|
||||||
hts.staging = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hts *headerTipsStore) Commit(dbTx model.DBTransaction) error {
|
|
||||||
if hts.staging == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
tipsBytes, err := hts.serializeTips(hts.staging)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = dbTx.Put(headerTipsKey, tipsBytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hts.cache = hts.staging
|
|
||||||
|
|
||||||
hts.Discard()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hts *headerTipsStore) Stage(tips []*externalapi.DomainHash) {
|
|
||||||
hts.staging = externalapi.CloneHashes(tips)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hts *headerTipsStore) IsStaged() bool {
|
|
||||||
return hts.staging != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hts *headerTipsStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) {
|
|
||||||
if hts.staging != nil {
|
|
||||||
return externalapi.CloneHashes(hts.staging), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if hts.cache != nil {
|
|
||||||
return externalapi.CloneHashes(hts.cache), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
tipsBytes, err := dbContext.Get(headerTipsKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tips, err := hts.deserializeTips(tipsBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
hts.cache = tips
|
|
||||||
return externalapi.CloneHashes(tips), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hts *headerTipsStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) {
|
|
||||||
dbTips := serialization.HeaderTipsToDBHeaderTips(tips)
|
|
||||||
return proto.Marshal(dbTips)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hts *headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash, error) {
|
|
||||||
dbTips := &serialization.DbHeaderTips{}
|
|
||||||
err := proto.Unmarshal(tipsBytes, dbTips)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return serialization.DBHeaderTipsToHeaderTips(dbTips)
|
|
||||||
}
|
|
@ -17,7 +17,7 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/consensusstatestore"
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/consensusstatestore"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/finalitystore"
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/finalitystore"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/ghostdagdatastore"
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/ghostdagdatastore"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headertipsstore"
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headersselectedtipstore"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/multisetstore"
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/multisetstore"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/pruningstore"
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/pruningstore"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/reachabilitydatastore"
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/reachabilitydatastore"
|
||||||
@ -32,7 +32,7 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/processes/dagtopologymanager"
|
"github.com/kaspanet/kaspad/domain/consensus/processes/dagtopologymanager"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/processes/difficultymanager"
|
"github.com/kaspanet/kaspad/domain/consensus/processes/difficultymanager"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
|
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/processes/headertipsmanager"
|
"github.com/kaspanet/kaspad/domain/consensus/processes/headersselectedtipmanager"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/processes/mergedepthmanager"
|
"github.com/kaspanet/kaspad/domain/consensus/processes/mergedepthmanager"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/processes/pastmediantimemanager"
|
"github.com/kaspanet/kaspad/domain/consensus/processes/pastmediantimemanager"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/processes/pruningmanager"
|
"github.com/kaspanet/kaspad/domain/consensus/processes/pruningmanager"
|
||||||
@ -81,7 +81,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
|||||||
utxoDiffStore := utxodiffstore.New(200)
|
utxoDiffStore := utxodiffstore.New(200)
|
||||||
consensusStateStore := consensusstatestore.New()
|
consensusStateStore := consensusstatestore.New()
|
||||||
ghostdagDataStore := ghostdagdatastore.New(10_000)
|
ghostdagDataStore := ghostdagdatastore.New(10_000)
|
||||||
headerTipsStore := headertipsstore.New()
|
headersSelectedTipStore := headersselectedtipstore.New()
|
||||||
finalityStore := finalitystore.New(200)
|
finalityStore := finalitystore.New(200)
|
||||||
|
|
||||||
// Processes
|
// Processes
|
||||||
@ -139,7 +139,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
|||||||
dagParams.CoinbasePayloadScriptPublicKeyMaxLength,
|
dagParams.CoinbasePayloadScriptPublicKeyMaxLength,
|
||||||
ghostdagDataStore,
|
ghostdagDataStore,
|
||||||
acceptanceDataStore)
|
acceptanceDataStore)
|
||||||
headerTipsManager := headertipsmanager.New(dbManager, dagTopologyManager, ghostdagManager, headerTipsStore)
|
headerTipsManager := headersselectedtipmanager.New(dbManager, dagTopologyManager, ghostdagManager, headersSelectedTipStore)
|
||||||
genesisHash := dagParams.GenesisHash
|
genesisHash := dagParams.GenesisHash
|
||||||
finalityManager := finalitymanager.New(
|
finalityManager := finalitymanager.New(
|
||||||
dbManager,
|
dbManager,
|
||||||
@ -211,7 +211,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
|||||||
blockRelationStore,
|
blockRelationStore,
|
||||||
acceptanceDataStore,
|
acceptanceDataStore,
|
||||||
blockHeaderStore,
|
blockHeaderStore,
|
||||||
headerTipsStore)
|
headersSelectedTipStore,
|
||||||
|
pruningStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -225,6 +226,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
|||||||
ghostdagDataStore,
|
ghostdagDataStore,
|
||||||
pruningStore,
|
pruningStore,
|
||||||
blockStatusStore,
|
blockStatusStore,
|
||||||
|
headersSelectedTipStore,
|
||||||
multisetStore,
|
multisetStore,
|
||||||
acceptanceDataStore,
|
acceptanceDataStore,
|
||||||
blockStore,
|
blockStore,
|
||||||
@ -236,17 +238,16 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
|||||||
syncManager := syncmanager.New(
|
syncManager := syncmanager.New(
|
||||||
dbManager,
|
dbManager,
|
||||||
genesisHash,
|
genesisHash,
|
||||||
dagParams.TargetTimePerBlock.Milliseconds(),
|
|
||||||
dagTraversalManager,
|
dagTraversalManager,
|
||||||
dagTopologyManager,
|
dagTopologyManager,
|
||||||
ghostdagManager,
|
ghostdagManager,
|
||||||
consensusStateManager,
|
pruningManager,
|
||||||
|
|
||||||
ghostdagDataStore,
|
ghostdagDataStore,
|
||||||
blockStatusStore,
|
blockStatusStore,
|
||||||
blockHeaderStore,
|
blockHeaderStore,
|
||||||
headerTipsStore,
|
blockStore,
|
||||||
blockStore)
|
pruningStore)
|
||||||
|
|
||||||
blockBuilder := blockbuilder.New(
|
blockBuilder := blockbuilder.New(
|
||||||
dbManager,
|
dbManager,
|
||||||
@ -287,7 +288,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
|||||||
reachabilityDataStore,
|
reachabilityDataStore,
|
||||||
utxoDiffStore,
|
utxoDiffStore,
|
||||||
blockHeaderStore,
|
blockHeaderStore,
|
||||||
headerTipsStore,
|
headersSelectedTipStore,
|
||||||
finalityStore)
|
finalityStore)
|
||||||
|
|
||||||
c := &consensus{
|
c := &consensus{
|
||||||
@ -312,19 +313,19 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
|||||||
reachabilityManager: reachabilityManager,
|
reachabilityManager: reachabilityManager,
|
||||||
finalityManager: finalityManager,
|
finalityManager: finalityManager,
|
||||||
|
|
||||||
acceptanceDataStore: acceptanceDataStore,
|
acceptanceDataStore: acceptanceDataStore,
|
||||||
blockStore: blockStore,
|
blockStore: blockStore,
|
||||||
blockHeaderStore: blockHeaderStore,
|
blockHeaderStore: blockHeaderStore,
|
||||||
pruningStore: pruningStore,
|
pruningStore: pruningStore,
|
||||||
ghostdagDataStore: ghostdagDataStore,
|
ghostdagDataStore: ghostdagDataStore,
|
||||||
blockStatusStore: blockStatusStore,
|
blockStatusStore: blockStatusStore,
|
||||||
blockRelationStore: blockRelationStore,
|
blockRelationStore: blockRelationStore,
|
||||||
consensusStateStore: consensusStateStore,
|
consensusStateStore: consensusStateStore,
|
||||||
headerTipsStore: headerTipsStore,
|
headersSelectedTipStore: headersSelectedTipStore,
|
||||||
multisetStore: multisetStore,
|
multisetStore: multisetStore,
|
||||||
reachabilityDataStore: reachabilityDataStore,
|
reachabilityDataStore: reachabilityDataStore,
|
||||||
utxoDiffStore: utxoDiffStore,
|
utxoDiffStore: utxoDiffStore,
|
||||||
finalityStore: finalityStore,
|
finalityStore: finalityStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
genesisInfo, err := c.GetBlockInfo(genesisHash)
|
genesisInfo, err := c.GetBlockInfo(genesisHash)
|
||||||
|
@ -5,6 +5,4 @@ type BlockInfo struct {
|
|||||||
Exists bool
|
Exists bool
|
||||||
BlockStatus BlockStatus
|
BlockStatus BlockStatus
|
||||||
BlueScore uint64
|
BlueScore uint64
|
||||||
|
|
||||||
IsBlockInHeaderPruningPointFuture bool
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ type Consensus interface {
|
|||||||
GetHashesBetween(lowHash, highHash *DomainHash) ([]*DomainHash, error)
|
GetHashesBetween(lowHash, highHash *DomainHash) ([]*DomainHash, error)
|
||||||
GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error)
|
GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error)
|
||||||
GetPruningPointUTXOSet(expectedPruningPointHash *DomainHash) ([]byte, error)
|
GetPruningPointUTXOSet(expectedPruningPointHash *DomainHash) ([]byte, error)
|
||||||
SetPruningPointUTXOSet(serializedUTXOSet []byte) error
|
ValidateAndInsertPruningPoint(newPruningPoint *DomainBlock, serializedUTXOSet []byte) error
|
||||||
GetVirtualSelectedParent() (*DomainBlock, error)
|
GetVirtualSelectedParent() (*DomainBlock, error)
|
||||||
CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error)
|
CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error)
|
||||||
FindNextBlockLocatorBoundaries(blockLocator BlockLocator) (lowHash, highHash *DomainHash, err error)
|
FindNextBlockLocatorBoundaries(blockLocator BlockLocator) (lowHash, highHash *DomainHash, err error)
|
||||||
|
@ -1,37 +1,8 @@
|
|||||||
package externalapi
|
package externalapi
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// Each of the following represent one of the possible sync
|
|
||||||
// states of the consensus
|
|
||||||
const (
|
|
||||||
SyncStateSynced SyncState = iota
|
|
||||||
SyncStateAwaitingGenesis
|
|
||||||
SyncStateAwaitingUTXOSet
|
|
||||||
SyncStateAwaitingBlockBodies
|
|
||||||
)
|
|
||||||
|
|
||||||
// SyncState represents the current sync state of the consensus
|
|
||||||
type SyncState uint8
|
|
||||||
|
|
||||||
func (s SyncState) String() string {
|
|
||||||
switch s {
|
|
||||||
case SyncStateSynced:
|
|
||||||
return "SyncStateSynced"
|
|
||||||
case SyncStateAwaitingGenesis:
|
|
||||||
return "SyncStateAwaitingGenesis"
|
|
||||||
case SyncStateAwaitingUTXOSet:
|
|
||||||
return "SyncStateAwaitingUTXOSet"
|
|
||||||
case SyncStateAwaitingBlockBodies:
|
|
||||||
return "SyncStateAwaitingBlockBodies"
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("<unknown state (%d)>", s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SyncInfo holds info about the current sync state of the consensus
|
// SyncInfo holds info about the current sync state of the consensus
|
||||||
type SyncInfo struct {
|
type SyncInfo struct {
|
||||||
State SyncState
|
IsAwaitingUTXOSet bool
|
||||||
IBDRootUTXOBlockHash *DomainHash
|
IBDRootUTXOBlockHash *DomainHash
|
||||||
HeaderCount uint64
|
HeaderCount uint64
|
||||||
BlockCount uint64
|
BlockCount uint64
|
||||||
|
@ -2,11 +2,11 @@ package model
|
|||||||
|
|
||||||
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
|
||||||
// HeaderTipsStore represents a store of the header tips
|
// HeaderSelectedTipStore represents a store of the headers selected tip
|
||||||
type HeaderTipsStore interface {
|
type HeaderSelectedTipStore interface {
|
||||||
Store
|
Store
|
||||||
Stage(tips []*externalapi.DomainHash)
|
Stage(selectedTip *externalapi.DomainHash)
|
||||||
IsStaged() bool
|
IsStaged() bool
|
||||||
Tips(dbContext DBReader) ([]*externalapi.DomainHash, error)
|
HeadersSelectedTip(dbContext DBReader) (*externalapi.DomainHash, error)
|
||||||
HasTips(dbContext DBReader) (bool, error)
|
Has(dbContext DBReader) (bool, error)
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,5 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|||||||
// BlockProcessor is responsible for processing incoming blocks
|
// BlockProcessor is responsible for processing incoming blocks
|
||||||
type BlockProcessor interface {
|
type BlockProcessor interface {
|
||||||
ValidateAndInsertBlock(block *externalapi.DomainBlock) error
|
ValidateAndInsertBlock(block *externalapi.DomainBlock) error
|
||||||
|
ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,9 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|||||||
|
|
||||||
// ConsensusStateManager manages the node's consensus state
|
// ConsensusStateManager manages the node's consensus state
|
||||||
type ConsensusStateManager interface {
|
type ConsensusStateManager interface {
|
||||||
AddBlockToVirtual(blockHash *externalapi.DomainHash) error
|
AddBlock(blockHash *externalapi.DomainHash) error
|
||||||
PopulateTransactionWithUTXOEntries(transaction *externalapi.DomainTransaction) error
|
PopulateTransactionWithUTXOEntries(transaction *externalapi.DomainTransaction) error
|
||||||
SetPruningPointUTXOSet(serializedUTXOSet []byte) error
|
UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error
|
||||||
RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error)
|
RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error)
|
||||||
HeaderTipsPruningPoint() (*externalapi.DomainHash, error)
|
|
||||||
CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, AcceptanceData, Multiset, error)
|
CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, AcceptanceData, Multiset, error)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|||||||
|
|
||||||
// FinalityManager provides method to validate that a block does not violate finality
|
// FinalityManager provides method to validate that a block does not violate finality
|
||||||
type FinalityManager interface {
|
type FinalityManager interface {
|
||||||
IsViolatingFinality(blockHash *externalapi.DomainHash) (bool, error)
|
|
||||||
VirtualFinalityPoint() (*externalapi.DomainHash, error)
|
VirtualFinalityPoint() (*externalapi.DomainHash, error)
|
||||||
FinalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error)
|
FinalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error)
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,7 @@ package model
|
|||||||
|
|
||||||
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
|
||||||
// HeaderTipsManager manages the state of the header tips
|
// HeadersSelectedTipManager manages the state of the headers selected tip
|
||||||
type HeaderTipsManager interface {
|
type HeadersSelectedTipManager interface {
|
||||||
AddHeaderTip(hash *externalapi.DomainHash) error
|
AddHeaderTip(hash *externalapi.DomainHash) error
|
||||||
SelectedTip() (*externalapi.DomainHash, error)
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
|
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
|
||||||
// PruningManager resolves and manages the current pruning point
|
// PruningManager resolves and manages the current pruning point
|
||||||
type PruningManager interface {
|
type PruningManager interface {
|
||||||
FindNextPruningPoint() error
|
UpdatePruningPointByVirtual() error
|
||||||
|
CalculatePruningPointByHeaderSelectedTip() (*externalapi.DomainHash, error)
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,5 @@ type SyncManager interface {
|
|||||||
GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error)
|
GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error)
|
||||||
CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error)
|
CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error)
|
||||||
FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error)
|
FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error)
|
||||||
IsBlockInHeaderPruningPointFuture(blockHash *externalapi.DomainHash) (bool, error)
|
|
||||||
GetSyncInfo() (*externalapi.SyncInfo, error)
|
GetSyncInfo() (*externalapi.SyncInfo, error)
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ type TestConsensus interface {
|
|||||||
BlockStore() model.BlockStore
|
BlockStore() model.BlockStore
|
||||||
ConsensusStateStore() model.ConsensusStateStore
|
ConsensusStateStore() model.ConsensusStateStore
|
||||||
GHOSTDAGDataStore() model.GHOSTDAGDataStore
|
GHOSTDAGDataStore() model.GHOSTDAGDataStore
|
||||||
HeaderTipsStore() model.HeaderTipsStore
|
HeaderTipsStore() model.HeaderSelectedTipStore
|
||||||
MultisetStore() model.MultisetStore
|
MultisetStore() model.MultisetStore
|
||||||
PruningStore() model.PruningStore
|
PruningStore() model.PruningStore
|
||||||
ReachabilityDataStore() model.ReachabilityDataStore
|
ReachabilityDataStore() model.ReachabilityDataStore
|
||||||
@ -46,7 +46,7 @@ type TestConsensus interface {
|
|||||||
DAGTraversalManager() model.DAGTraversalManager
|
DAGTraversalManager() model.DAGTraversalManager
|
||||||
DifficultyManager() model.DifficultyManager
|
DifficultyManager() model.DifficultyManager
|
||||||
GHOSTDAGManager() model.GHOSTDAGManager
|
GHOSTDAGManager() model.GHOSTDAGManager
|
||||||
HeaderTipsManager() model.HeaderTipsManager
|
HeaderTipsManager() model.HeadersSelectedTipManager
|
||||||
MergeDepthManager() model.MergeDepthManager
|
MergeDepthManager() model.MergeDepthManager
|
||||||
PastMedianTimeManager() model.PastMedianTimeManager
|
PastMedianTimeManager() model.PastMedianTimeManager
|
||||||
PruningManager() model.PruningManager
|
PruningManager() model.PruningManager
|
||||||
|
@ -21,22 +21,22 @@ type blockProcessor struct {
|
|||||||
ghostdagManager model.GHOSTDAGManager
|
ghostdagManager model.GHOSTDAGManager
|
||||||
pastMedianTimeManager model.PastMedianTimeManager
|
pastMedianTimeManager model.PastMedianTimeManager
|
||||||
coinbaseManager model.CoinbaseManager
|
coinbaseManager model.CoinbaseManager
|
||||||
headerTipsManager model.HeaderTipsManager
|
headerTipsManager model.HeadersSelectedTipManager
|
||||||
syncManager model.SyncManager
|
syncManager model.SyncManager
|
||||||
|
|
||||||
acceptanceDataStore model.AcceptanceDataStore
|
acceptanceDataStore model.AcceptanceDataStore
|
||||||
blockStore model.BlockStore
|
blockStore model.BlockStore
|
||||||
blockStatusStore model.BlockStatusStore
|
blockStatusStore model.BlockStatusStore
|
||||||
blockRelationStore model.BlockRelationStore
|
blockRelationStore model.BlockRelationStore
|
||||||
multisetStore model.MultisetStore
|
multisetStore model.MultisetStore
|
||||||
ghostdagDataStore model.GHOSTDAGDataStore
|
ghostdagDataStore model.GHOSTDAGDataStore
|
||||||
consensusStateStore model.ConsensusStateStore
|
consensusStateStore model.ConsensusStateStore
|
||||||
pruningStore model.PruningStore
|
pruningStore model.PruningStore
|
||||||
reachabilityDataStore model.ReachabilityDataStore
|
reachabilityDataStore model.ReachabilityDataStore
|
||||||
utxoDiffStore model.UTXODiffStore
|
utxoDiffStore model.UTXODiffStore
|
||||||
blockHeaderStore model.BlockHeaderStore
|
blockHeaderStore model.BlockHeaderStore
|
||||||
headerTipsStore model.HeaderTipsStore
|
headersSelectedTipStore model.HeaderSelectedTipStore
|
||||||
finalityStore model.FinalityStore
|
finalityStore model.FinalityStore
|
||||||
|
|
||||||
stores []model.Store
|
stores []model.Store
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ func New(
|
|||||||
pastMedianTimeManager model.PastMedianTimeManager,
|
pastMedianTimeManager model.PastMedianTimeManager,
|
||||||
ghostdagManager model.GHOSTDAGManager,
|
ghostdagManager model.GHOSTDAGManager,
|
||||||
coinbaseManager model.CoinbaseManager,
|
coinbaseManager model.CoinbaseManager,
|
||||||
headerTipsManager model.HeaderTipsManager,
|
headerTipsManager model.HeadersSelectedTipManager,
|
||||||
syncManager model.SyncManager,
|
syncManager model.SyncManager,
|
||||||
|
|
||||||
acceptanceDataStore model.AcceptanceDataStore,
|
acceptanceDataStore model.AcceptanceDataStore,
|
||||||
@ -68,7 +68,7 @@ func New(
|
|||||||
reachabilityDataStore model.ReachabilityDataStore,
|
reachabilityDataStore model.ReachabilityDataStore,
|
||||||
utxoDiffStore model.UTXODiffStore,
|
utxoDiffStore model.UTXODiffStore,
|
||||||
blockHeaderStore model.BlockHeaderStore,
|
blockHeaderStore model.BlockHeaderStore,
|
||||||
headerTipsStore model.HeaderTipsStore,
|
headersSelectedTipStore model.HeaderSelectedTipStore,
|
||||||
finalityStore model.FinalityStore,
|
finalityStore model.FinalityStore,
|
||||||
) model.BlockProcessor {
|
) model.BlockProcessor {
|
||||||
|
|
||||||
@ -86,20 +86,20 @@ func New(
|
|||||||
headerTipsManager: headerTipsManager,
|
headerTipsManager: headerTipsManager,
|
||||||
syncManager: syncManager,
|
syncManager: syncManager,
|
||||||
|
|
||||||
consensusStateManager: consensusStateManager,
|
consensusStateManager: consensusStateManager,
|
||||||
acceptanceDataStore: acceptanceDataStore,
|
acceptanceDataStore: acceptanceDataStore,
|
||||||
blockStore: blockStore,
|
blockStore: blockStore,
|
||||||
blockStatusStore: blockStatusStore,
|
blockStatusStore: blockStatusStore,
|
||||||
blockRelationStore: blockRelationStore,
|
blockRelationStore: blockRelationStore,
|
||||||
multisetStore: multisetStore,
|
multisetStore: multisetStore,
|
||||||
ghostdagDataStore: ghostdagDataStore,
|
ghostdagDataStore: ghostdagDataStore,
|
||||||
consensusStateStore: consensusStateStore,
|
consensusStateStore: consensusStateStore,
|
||||||
pruningStore: pruningStore,
|
pruningStore: pruningStore,
|
||||||
reachabilityDataStore: reachabilityDataStore,
|
reachabilityDataStore: reachabilityDataStore,
|
||||||
utxoDiffStore: utxoDiffStore,
|
utxoDiffStore: utxoDiffStore,
|
||||||
blockHeaderStore: blockHeaderStore,
|
blockHeaderStore: blockHeaderStore,
|
||||||
headerTipsStore: headerTipsStore,
|
headersSelectedTipStore: headersSelectedTipStore,
|
||||||
finalityStore: finalityStore,
|
finalityStore: finalityStore,
|
||||||
|
|
||||||
stores: []model.Store{
|
stores: []model.Store{
|
||||||
consensusStateStore,
|
consensusStateStore,
|
||||||
@ -114,7 +114,7 @@ func New(
|
|||||||
reachabilityDataStore,
|
reachabilityDataStore,
|
||||||
utxoDiffStore,
|
utxoDiffStore,
|
||||||
blockHeaderStore,
|
blockHeaderStore,
|
||||||
headerTipsStore,
|
headersSelectedTipStore,
|
||||||
finalityStore,
|
finalityStore,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -128,3 +128,10 @@ func (bp *blockProcessor) ValidateAndInsertBlock(block *externalapi.DomainBlock)
|
|||||||
|
|
||||||
return bp.validateAndInsertBlock(block)
|
return bp.validateAndInsertBlock(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bp *blockProcessor) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
||||||
|
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateAndInsertPruningPoint")
|
||||||
|
defer onEnd()
|
||||||
|
|
||||||
|
return bp.validateAndInsertPruningPoint(newPruningPoint, serializedUTXOSet)
|
||||||
|
}
|
||||||
|
@ -11,36 +11,16 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type insertMode uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
insertModeGenesis insertMode = iota
|
|
||||||
insertModeHeader
|
|
||||||
insertModeBlockBody
|
|
||||||
insertModeBlock
|
|
||||||
)
|
|
||||||
|
|
||||||
func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) error {
|
func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) error {
|
||||||
blockHash := consensushashing.HeaderHash(block.Header)
|
blockHash := consensushashing.HeaderHash(block.Header)
|
||||||
log.Debugf("Validating block %s", blockHash)
|
err := bp.validateBlock(block)
|
||||||
|
|
||||||
insertMode, err := bp.validateAgainstSyncStateAndResolveInsertMode(block)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bp.checkBlockStatus(blockHash, insertMode)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bp.validateBlock(block, insertMode)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bp.discardAllChanges()
|
bp.discardAllChanges()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if insertMode == insertModeHeader {
|
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
||||||
|
if isHeaderOnlyBlock {
|
||||||
bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly)
|
bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly)
|
||||||
} else {
|
} else {
|
||||||
bp.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification)
|
bp.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification)
|
||||||
@ -54,43 +34,38 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var oldHeadersSelectedTip *externalapi.DomainHash
|
var oldHeadersSelectedTip *externalapi.DomainHash
|
||||||
if insertMode != insertModeGenesis {
|
isGenesis := *blockHash != *bp.genesisHash
|
||||||
|
if isGenesis {
|
||||||
var err error
|
var err error
|
||||||
oldHeadersSelectedTip, err = bp.headerTipsManager.SelectedTip()
|
oldHeadersSelectedTip, err = bp.headersSelectedTipStore.HeadersSelectedTip(bp.databaseContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if insertMode == insertModeHeader {
|
err = bp.headerTipsManager.AddHeaderTip(blockHash)
|
||||||
err = bp.headerTipsManager.AddHeaderTip(blockHash)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
} else if insertMode == insertModeBlock || insertMode == insertModeGenesis {
|
if !isHeaderOnlyBlock {
|
||||||
// Attempt to add the block to the virtual
|
// Attempt to add the block to the virtual
|
||||||
err = bp.consensusStateManager.AddBlockToVirtual(blockHash)
|
err = bp.consensusStateManager.AddBlock(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tips, err := bp.consensusStateStore.Tips(bp.databaseContext)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
bp.headerTipsStore.Stage(tips)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if insertMode != insertModeGenesis {
|
if isGenesis {
|
||||||
err := bp.updateReachabilityReindexRoot(oldHeadersSelectedTip)
|
err := bp.updateReachabilityReindexRoot(oldHeadersSelectedTip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if insertMode == insertModeBlock {
|
if !isHeaderOnlyBlock {
|
||||||
// Trigger pruning, which will check if the pruning point changed and delete the data if it did.
|
// Trigger pruning, which will check if the pruning point changed and delete the data if it did.
|
||||||
err = bp.pruningManager.FindNextPruningPoint()
|
err = bp.pruningManager.UpdatePruningPointByVirtual()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -115,8 +90,8 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
|
|||||||
logClosureErr = err
|
logClosureErr = err
|
||||||
return fmt.Sprintf("Failed to get sync info: %s", err)
|
return fmt.Sprintf("Failed to get sync info: %s", err)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("New virtual's blue score: %d. Sync state: %s. Block count: %d. Header count: %d",
|
return fmt.Sprintf("New virtual's blue score: %d. Is awaiting UTXO set: %t. Block count: %d. Header count: %d",
|
||||||
virtualGhostDAGData.BlueScore(), syncInfo.State, syncInfo.BlockCount, syncInfo.HeaderCount)
|
virtualGhostDAGData.BlueScore(), syncInfo.IsAwaitingUTXOSet, syncInfo.BlockCount, syncInfo.HeaderCount)
|
||||||
}))
|
}))
|
||||||
if logClosureErr != nil {
|
if logClosureErr != nil {
|
||||||
return logClosureErr
|
return logClosureErr
|
||||||
@ -125,64 +100,12 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *blockProcessor) validateAgainstSyncStateAndResolveInsertMode(block *externalapi.DomainBlock) (insertMode, error) {
|
|
||||||
syncInfo, err := bp.syncManager.GetSyncInfo()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
syncState := syncInfo.State
|
|
||||||
|
|
||||||
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
|
||||||
blockHash := consensushashing.HeaderHash(block.Header)
|
|
||||||
if syncState == externalapi.SyncStateAwaitingGenesis {
|
|
||||||
if isHeaderOnlyBlock {
|
|
||||||
return 0, errors.Errorf("Got a header-only block while awaiting genesis")
|
|
||||||
}
|
|
||||||
if *blockHash != *bp.genesisHash {
|
|
||||||
return 0, errors.Errorf("Received a non-genesis block while awaiting genesis")
|
|
||||||
}
|
|
||||||
return insertModeGenesis, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if isHeaderOnlyBlock {
|
|
||||||
return insertModeHeader, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if syncState == externalapi.SyncStateAwaitingUTXOSet {
|
|
||||||
headerTipsPruningPoint, err := bp.consensusStateManager.HeaderTipsPruningPoint()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if *blockHash != *headerTipsPruningPoint {
|
|
||||||
return 0, errors.Errorf("cannot insert blocks other than the header pruning point " +
|
|
||||||
"while awaiting the UTXO set")
|
|
||||||
}
|
|
||||||
return insertModeBlock, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if syncState == externalapi.SyncStateAwaitingBlockBodies {
|
|
||||||
headerTips, err := bp.headerTipsStore.Tips(bp.databaseContext)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
selectedHeaderTip, err := bp.ghostdagManager.ChooseSelectedParent(headerTips...)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if *selectedHeaderTip != *blockHash {
|
|
||||||
return insertModeBlockBody, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return insertModeBlock, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool {
|
func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool {
|
||||||
return len(block.Transactions) == 0
|
return len(block.Transactions) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *externalapi.DomainHash) error {
|
func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *externalapi.DomainHash) error {
|
||||||
headersSelectedTip, err := bp.headerTipsManager.SelectedTip()
|
headersSelectedTip, err := bp.headersSelectedTipStore.HeadersSelectedTip(bp.databaseContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -194,7 +117,9 @@ func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *e
|
|||||||
return bp.reachabilityManager.UpdateReindexRoot(headersSelectedTip)
|
return bp.reachabilityManager.UpdateReindexRoot(headersSelectedTip)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode insertMode) error {
|
func (bp *blockProcessor) checkBlockStatus(block *externalapi.DomainBlock) error {
|
||||||
|
hash := consensushashing.BlockHash(block)
|
||||||
|
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
||||||
exists, err := bp.blockStatusStore.Exists(bp.databaseContext, hash)
|
exists, err := bp.blockStatusStore.Exists(bp.databaseContext, hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -212,12 +137,12 @@ func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode in
|
|||||||
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 := mode != insertModeHeader && status == externalapi.StatusHeaderOnly
|
isBlockBodyAfterBlockHeader := !isHeaderOnlyBlock && status == externalapi.StatusHeaderOnly
|
||||||
if !isBlockBodyAfterBlockHeader {
|
if !isBlockBodyAfterBlockHeader {
|
||||||
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash)
|
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
isDuplicateHeader := mode == insertModeHeader && status == externalapi.StatusHeaderOnly
|
isDuplicateHeader := isHeaderOnlyBlock && status == externalapi.StatusHeaderOnly
|
||||||
if isDuplicateHeader {
|
if isDuplicateHeader {
|
||||||
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash)
|
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash)
|
||||||
}
|
}
|
||||||
@ -225,57 +150,16 @@ func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode in
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode insertMode) error {
|
|
||||||
blockHash := consensushashing.HeaderHash(block.Header)
|
|
||||||
hasHeader, err := bp.hasHeader(blockHash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hasHeader {
|
|
||||||
bp.blockHeaderStore.Stage(blockHash, block.Header)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(block)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bp.validatePruningPointViolationAndProofOfWorkAndDifficulty(block, mode)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If in-context validations fail, discard all changes and store the
|
|
||||||
// block with StatusInvalid.
|
|
||||||
err = bp.validatePostProofOfWork(block, mode)
|
|
||||||
if err != nil {
|
|
||||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
|
||||||
bp.discardAllChanges()
|
|
||||||
hash := consensushashing.BlockHash(block)
|
|
||||||
bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid)
|
|
||||||
commitErr := bp.commitAllChanges()
|
|
||||||
if commitErr != nil {
|
|
||||||
return commitErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) error {
|
func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) error {
|
||||||
blockHash := consensushashing.BlockHash(block)
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
|
||||||
hasHeader, err := bp.hasHeader(blockHash)
|
hasValidatedOnlyHeader, err := bp.hasValidatedOnlyHeader(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasHeader {
|
if hasValidatedOnlyHeader {
|
||||||
|
log.Debugf("Block %s header was already validated, so skip the rest of validatePreProofOfWork", blockHash)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,41 +170,43 @@ func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *blockProcessor) validatePruningPointViolationAndProofOfWorkAndDifficulty(block *externalapi.DomainBlock, mode insertMode) error {
|
func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock) error {
|
||||||
blockHash := consensushashing.HeaderHash(block.Header)
|
|
||||||
if mode != insertModeHeader {
|
|
||||||
// We stage the block here since we need it for parent validation
|
|
||||||
bp.blockStore.Stage(blockHash, block)
|
|
||||||
}
|
|
||||||
return bp.blockValidator.ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock, mode insertMode) error {
|
|
||||||
blockHash := consensushashing.BlockHash(block)
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
|
||||||
if mode != insertModeHeader {
|
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
||||||
|
if !isHeaderOnlyBlock {
|
||||||
|
bp.blockStore.Stage(blockHash, block)
|
||||||
err := bp.blockValidator.ValidateBodyInIsolation(blockHash)
|
err := bp.blockValidator.ValidateBodyInIsolation(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasHeader, err := bp.hasHeader(blockHash)
|
hasValidatedHeader, err := bp.hasValidatedOnlyHeader(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hasHeader {
|
if !hasValidatedHeader {
|
||||||
err = bp.blockValidator.ValidateHeaderInContext(blockHash)
|
err = bp.blockValidator.ValidateHeaderInContext(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isHeaderOnlyBlock {
|
||||||
|
err = bp.blockValidator.ValidateBodyInContext(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Tracef("Skipping ValidateBodyInContext for block %s because it's header only", blockHash)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *blockProcessor) hasHeader(blockHash *externalapi.DomainHash) (bool, error) {
|
func (bp *blockProcessor) hasValidatedOnlyHeader(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
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
package blockprocessor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (bp *blockProcessor) validateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
||||||
|
log.Info("Checking that the given pruning point is the expected pruning point")
|
||||||
|
|
||||||
|
expectedNewPruningPointHash, err := bp.pruningManager.CalculatePruningPointByHeaderSelectedTip()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newPruningPointHash := consensushashing.BlockHash(newPruningPoint)
|
||||||
|
|
||||||
|
if *expectedNewPruningPointHash != *newPruningPointHash {
|
||||||
|
return errors.Wrapf(ruleerrors.ErrUnexpectedPruningPoint, "expected pruning point %s but got %s",
|
||||||
|
expectedNewPruningPointHash, newPruningPointHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
err = bp.validateBlockAndDiscardChanges(newPruningPoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bp.consensusStateManager.UpdatePruningPoint(newPruningPoint, serializedUTXOSet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bp.ValidateAndInsertBlock(newPruningPoint)
|
||||||
|
}
|
67
domain/consensus/processes/blockprocessor/validateblock.go
Normal file
67
domain/consensus/processes/blockprocessor/validateblock.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package blockprocessor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (bp *blockProcessor) validateBlockAndDiscardChanges(block *externalapi.DomainBlock) error {
|
||||||
|
defer bp.discardAllChanges()
|
||||||
|
return bp.validateBlock(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock) error {
|
||||||
|
blockHash := consensushashing.HeaderHash(block.Header)
|
||||||
|
log.Debugf("Validating block %s", blockHash)
|
||||||
|
|
||||||
|
err := bp.checkBlockStatus(block)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hasValidatedHeader, err := bp.hasValidatedOnlyHeader(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasValidatedHeader {
|
||||||
|
log.Tracef("Staging block %s header", blockHash)
|
||||||
|
bp.blockHeaderStore.Stage(blockHash, block.Header)
|
||||||
|
} else {
|
||||||
|
log.Tracef("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(block)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasValidatedHeader {
|
||||||
|
err = bp.blockValidator.ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If in-context validations fail, discard all changes and store the
|
||||||
|
// block with StatusInvalid.
|
||||||
|
err = bp.validatePostProofOfWork(block)
|
||||||
|
if err != nil {
|
||||||
|
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
|
bp.discardAllChanges()
|
||||||
|
hash := consensushashing.BlockHash(block)
|
||||||
|
bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid)
|
||||||
|
commitErr := bp.commitAllChanges()
|
||||||
|
if commitErr != nil {
|
||||||
|
return commitErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package blockvalidator
|
package blockvalidator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
@ -13,6 +14,9 @@ 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) error {
|
||||||
|
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateBodyInContext")
|
||||||
|
defer onEnd()
|
||||||
|
|
||||||
return v.checkBlockTransactionsFinalized(blockHash)
|
return v.checkBlockTransactionsFinalized(blockHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,12 +8,16 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateBodyInIsolation validates block bodies in isolation from the current
|
// ValidateBodyInIsolation validates block bodies in isolation from the current
|
||||||
// consensus state
|
// consensus state
|
||||||
func (v *blockValidator) ValidateBodyInIsolation(blockHash *externalapi.DomainHash) error {
|
func (v *blockValidator) ValidateBodyInIsolation(blockHash *externalapi.DomainHash) error {
|
||||||
|
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateBodyInContext")
|
||||||
|
defer onEnd()
|
||||||
|
|
||||||
block, err := v.blockStore.Block(v.databaseContext, blockHash)
|
block, err := v.blockStore.Block(v.databaseContext, blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -4,23 +4,27 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateHeaderInContext validates block headers in the context of the current
|
// ValidateHeaderInContext validates block headers in the context of the current
|
||||||
// consensus state
|
// consensus state
|
||||||
func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHash) error {
|
func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHash) error {
|
||||||
|
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateHeaderInContext")
|
||||||
|
defer onEnd()
|
||||||
|
|
||||||
header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash)
|
header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
isHeadersOnlyBlock, err := v.isHeadersOnlyBlock(blockHash)
|
hasValidatedHeader, err := v.hasValidatedHeader(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isHeadersOnlyBlock {
|
if !hasValidatedHeader {
|
||||||
err = v.ghostdagManager.GHOSTDAG(blockHash)
|
err = v.ghostdagManager.GHOSTDAG(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -60,7 +64,7 @@ func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHa
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *blockValidator) isHeadersOnlyBlock(blockHash *externalapi.DomainHash) (bool, error) {
|
func (v *blockValidator) hasValidatedHeader(blockHash *externalapi.DomainHash) (bool, error) {
|
||||||
exists, err := v.blockStatusStore.Exists(v.databaseContext, blockHash)
|
exists, err := v.blockStatusStore.Exists(v.databaseContext, blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
"github.com/kaspanet/kaspad/util/mstime"
|
"github.com/kaspanet/kaspad/util/mstime"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -11,6 +12,9 @@ import (
|
|||||||
// ValidateHeaderInIsolation validates block headers in isolation from the current
|
// ValidateHeaderInIsolation validates block headers in isolation from the current
|
||||||
// consensus state
|
// consensus state
|
||||||
func (v *blockValidator) ValidateHeaderInIsolation(blockHash *externalapi.DomainHash) error {
|
func (v *blockValidator) ValidateHeaderInIsolation(blockHash *externalapi.DomainHash) error {
|
||||||
|
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateHeaderInIsolation")
|
||||||
|
defer onEnd()
|
||||||
|
|
||||||
header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash)
|
header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
7
domain/consensus/processes/blockvalidator/log.go
Normal file
7
domain/consensus/processes/blockvalidator/log.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package blockvalidator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log, _ = logger.Get(logger.SubsystemTags.BLVL)
|
@ -5,11 +5,15 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model/pow"
|
"github.com/kaspanet/kaspad/domain/consensus/model/pow"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
"github.com/kaspanet/kaspad/util"
|
"github.com/kaspanet/kaspad/util"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *blockValidator) ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash *externalapi.DomainHash) error {
|
func (v *blockValidator) ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash *externalapi.DomainHash) error {
|
||||||
|
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidatePruningPointViolationAndProofOfWorkAndDifficulty")
|
||||||
|
defer onEnd()
|
||||||
|
|
||||||
header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash)
|
header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -102,7 +106,7 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader)
|
|||||||
func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, header *externalapi.DomainBlockHeader) error {
|
func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, header *externalapi.DomainBlockHeader) error {
|
||||||
missingParentHashes := []*externalapi.DomainHash{}
|
missingParentHashes := []*externalapi.DomainHash{}
|
||||||
|
|
||||||
isFullBlock, err := v.blockStore.HasBlock(v.databaseContext, blockHash)
|
hasBlockBody, err := v.blockStore.HasBlock(v.databaseContext, blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -117,12 +121,31 @@ func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, he
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if isFullBlock {
|
parentStatus, err := v.blockStatusStore.Get(v.databaseContext, parent)
|
||||||
parentStatus, err := v.blockStatusStore.Get(v.databaseContext, parent)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
if parentStatus == externalapi.StatusInvalid {
|
||||||
|
return errors.Wrapf(ruleerrors.ErrInvalidAncestorBlock, "parent %s is invalid", parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasBlockBody {
|
||||||
if parentStatus == externalapi.StatusHeaderOnly {
|
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)
|
missingParentHashes = append(missingParentHashes, parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,41 +8,41 @@ import (
|
|||||||
// AddBlockToVirtual submits the given block to be added to the
|
// AddBlockToVirtual 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) AddBlockToVirtual(blockHash *externalapi.DomainHash) error {
|
func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) error {
|
||||||
log.Tracef("AddBlockToVirtual start for block %s", blockHash)
|
log.Tracef("AddBlock start for block %s", blockHash)
|
||||||
defer log.Tracef("AddBlockToVirtual end for block %s", blockHash)
|
defer log.Tracef("AddBlock end for block %s", blockHash)
|
||||||
|
|
||||||
log.Tracef("Resolving whether the block %s is the next virtual selected parent", blockHash)
|
log.Tracef("Resolving whether the block %s is the next virtual selected parent", blockHash)
|
||||||
isNextVirtualSelectedParent, err := csm.isNextVirtualSelectedParent(blockHash)
|
isCandidateToBeNextVirtualSelectedParent, err := csm.isCandidateToBeNextVirtualSelectedParent(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if isNextVirtualSelectedParent {
|
if isCandidateToBeNextVirtualSelectedParent {
|
||||||
log.Tracef("Block %s is the new virtual. Resolving its block status", blockHash)
|
// It's important to check for finality violation before resolving the block status, because the status of
|
||||||
blockStatus, err := csm.resolveBlockStatus(blockHash)
|
// blocks with a selected chain that doesn't contain the pruning point cannot be resolved because they will
|
||||||
|
// eventually try to fetch UTXO diffs from the past of the pruning point.
|
||||||
|
log.Tracef("Block %s is candidate to be the next virtual selected parent. Resolving whether it violates "+
|
||||||
|
"finality", blockHash)
|
||||||
|
isViolatingFinality, shouldNotify, err := csm.isViolatingFinality(blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if blockStatus == externalapi.StatusValid {
|
if shouldNotify {
|
||||||
log.Tracef("Block %s is tentatively valid. Resolving whether it violates finality", blockHash)
|
//TODO: Send finality conflict notification
|
||||||
err = csm.checkFinalityViolation(blockHash)
|
log.Warnf("Finality Violation Detected! Block %s violates finality!", blockHash)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-fetch the block status for logging purposes
|
|
||||||
// because it could've been changed in
|
|
||||||
// checkFinalityViolation
|
|
||||||
blockStatus, err = csm.blockStatusStore.Get(csm.databaseContext, blockHash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Block %s is the next virtual selected parent. "+
|
if !isViolatingFinality {
|
||||||
"Its resolved status is `%s`", blockHash, blockStatus)
|
log.Tracef("Block %s doesn't violate finality. Resolving its block status", blockHash)
|
||||||
|
blockStatus, err := csm.resolveBlockStatus(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Block %s resolved to status `%s`", blockHash, blockStatus)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Block %s is not the next virtual selected parent, "+
|
log.Debugf("Block %s is not the next virtual selected parent, "+
|
||||||
"therefore its status remains `%s`", blockHash, externalapi.StatusUTXOPendingVerification)
|
"therefore its status remains `%s`", blockHash, externalapi.StatusUTXOPendingVerification)
|
||||||
@ -64,9 +64,9 @@ func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.Domai
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (csm *consensusStateManager) isNextVirtualSelectedParent(blockHash *externalapi.DomainHash) (bool, error) {
|
func (csm *consensusStateManager) isCandidateToBeNextVirtualSelectedParent(blockHash *externalapi.DomainHash) (bool, error) {
|
||||||
log.Tracef("isNextVirtualSelectedParent start for block %s", blockHash)
|
log.Tracef("isCandidateToBeNextVirtualSelectedParent start for block %s", blockHash)
|
||||||
defer log.Tracef("isNextVirtualSelectedParent end for block %s", blockHash)
|
defer log.Tracef("isCandidateToBeNextVirtualSelectedParent end for block %s", blockHash)
|
||||||
|
|
||||||
if *blockHash == *csm.genesisHash {
|
if *blockHash == *csm.genesisHash {
|
||||||
log.Tracef("Block %s is the genesis block, therefore it is "+
|
log.Tracef("Block %s is the genesis block, therefore it is "+
|
||||||
|
@ -2,23 +2,65 @@ package consensusstatemanager
|
|||||||
|
|
||||||
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
|
||||||
func (csm *consensusStateManager) checkFinalityViolation(
|
func (csm *consensusStateManager) isViolatingFinality(blockHash *externalapi.DomainHash) (isViolatingFinality bool,
|
||||||
blockHash *externalapi.DomainHash) error {
|
shouldSendNotification bool, err error) {
|
||||||
|
|
||||||
log.Tracef("checkFinalityViolation start for block %s", blockHash)
|
log.Tracef("isViolatingFinality start for block %s", blockHash)
|
||||||
defer log.Tracef("checkFinalityViolation end for block %s", blockHash)
|
defer log.Tracef("isViolatingFinality end for block %s", blockHash)
|
||||||
|
|
||||||
isViolatingFinality, err := csm.finalityManager.IsViolatingFinality(blockHash)
|
if *blockHash == *csm.genesisHash {
|
||||||
if err != nil {
|
log.Tracef("Block %s is the genesis block, "+
|
||||||
return err
|
"and does not violate finality by definition", blockHash)
|
||||||
|
return false, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if isViolatingFinality {
|
var finalityPoint *externalapi.DomainHash
|
||||||
csm.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification)
|
virtualFinalityPoint, err := csm.finalityManager.VirtualFinalityPoint()
|
||||||
log.Warnf("Finality Violation Detected! Block %s violates finality!", blockHash)
|
if err != nil {
|
||||||
return nil
|
return false, false, err
|
||||||
|
}
|
||||||
|
log.Tracef("The virtual finality point is: %s", virtualFinalityPoint)
|
||||||
|
|
||||||
|
// There can be a situation where the virtual points close to the pruning point (or even in the past
|
||||||
|
// of the pruning point before calling validateAndInsertBlock for the pruning point block) and the
|
||||||
|
// finality point from the virtual point-of-view is in the past of the pruning point.
|
||||||
|
// In such situation we override the finality point to be the pruning point to avoid situations where
|
||||||
|
// the virtual selected parent chain don't include the pruning point.
|
||||||
|
pruningPoint, err := csm.pruningStore.PruningPoint(csm.databaseContext)
|
||||||
|
if err != nil {
|
||||||
|
return false, false, err
|
||||||
|
}
|
||||||
|
log.Tracef("The pruning point is: %s", pruningPoint)
|
||||||
|
|
||||||
|
isFinalityPointInPastOfPruningPoint, err := csm.dagTopologyManager.IsAncestorOf(virtualFinalityPoint, pruningPoint)
|
||||||
|
if err != nil {
|
||||||
|
return false, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isFinalityPointInPastOfPruningPoint {
|
||||||
|
finalityPoint = virtualFinalityPoint
|
||||||
|
} else {
|
||||||
|
log.Tracef("The virtual finality point is %s in the past of the pruning point, so finality is validated "+
|
||||||
|
"using the pruning point", virtualFinalityPoint)
|
||||||
|
finalityPoint = pruningPoint
|
||||||
|
}
|
||||||
|
|
||||||
|
isInSelectedParentChainOfFinalityPoint, err := csm.dagTopologyManager.IsInSelectedParentChainOf(finalityPoint,
|
||||||
|
blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return false, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isInSelectedParentChainOfFinalityPoint {
|
||||||
|
if !isFinalityPointInPastOfPruningPoint {
|
||||||
|
return true, true, nil
|
||||||
|
}
|
||||||
|
// On IBD it's pretty normal to get blocks in the anticone of the pruning
|
||||||
|
// point, so we don't notify on cases when the pruning point is in the future
|
||||||
|
// of the finality point.
|
||||||
|
return true, false, nil
|
||||||
}
|
}
|
||||||
log.Tracef("Block %s does not violate finality", blockHash)
|
log.Tracef("Block %s does not violate finality", blockHash)
|
||||||
|
|
||||||
return nil
|
return false, false, nil
|
||||||
}
|
}
|
||||||
|
@ -25,16 +25,17 @@ type consensusStateManager struct {
|
|||||||
mergeDepthManager model.MergeDepthManager
|
mergeDepthManager model.MergeDepthManager
|
||||||
finalityManager model.FinalityManager
|
finalityManager model.FinalityManager
|
||||||
|
|
||||||
headerTipsStore model.HeaderTipsStore
|
headersSelectedTipStore model.HeaderSelectedTipStore
|
||||||
blockStatusStore model.BlockStatusStore
|
blockStatusStore model.BlockStatusStore
|
||||||
ghostdagDataStore model.GHOSTDAGDataStore
|
ghostdagDataStore model.GHOSTDAGDataStore
|
||||||
consensusStateStore model.ConsensusStateStore
|
consensusStateStore model.ConsensusStateStore
|
||||||
multisetStore model.MultisetStore
|
multisetStore model.MultisetStore
|
||||||
blockStore model.BlockStore
|
blockStore model.BlockStore
|
||||||
utxoDiffStore model.UTXODiffStore
|
utxoDiffStore model.UTXODiffStore
|
||||||
blockRelationStore model.BlockRelationStore
|
blockRelationStore model.BlockRelationStore
|
||||||
acceptanceDataStore model.AcceptanceDataStore
|
acceptanceDataStore model.AcceptanceDataStore
|
||||||
blockHeaderStore model.BlockHeaderStore
|
blockHeaderStore model.BlockHeaderStore
|
||||||
|
pruningStore model.PruningStore
|
||||||
|
|
||||||
stores []model.Store
|
stores []model.Store
|
||||||
}
|
}
|
||||||
@ -68,7 +69,8 @@ func New(
|
|||||||
blockRelationStore model.BlockRelationStore,
|
blockRelationStore model.BlockRelationStore,
|
||||||
acceptanceDataStore model.AcceptanceDataStore,
|
acceptanceDataStore model.AcceptanceDataStore,
|
||||||
blockHeaderStore model.BlockHeaderStore,
|
blockHeaderStore model.BlockHeaderStore,
|
||||||
headerTipsStore model.HeaderTipsStore) (model.ConsensusStateManager, error) {
|
headersSelectedTipStore model.HeaderSelectedTipStore,
|
||||||
|
pruningStore model.PruningStore) (model.ConsensusStateManager, error) {
|
||||||
|
|
||||||
csm := &consensusStateManager{
|
csm := &consensusStateManager{
|
||||||
pruningDepth: pruningDepth,
|
pruningDepth: pruningDepth,
|
||||||
@ -89,16 +91,17 @@ func New(
|
|||||||
mergeDepthManager: mergeDepthManager,
|
mergeDepthManager: mergeDepthManager,
|
||||||
finalityManager: finalityManager,
|
finalityManager: finalityManager,
|
||||||
|
|
||||||
multisetStore: multisetStore,
|
multisetStore: multisetStore,
|
||||||
blockStore: blockStore,
|
blockStore: blockStore,
|
||||||
blockStatusStore: blockStatusStore,
|
blockStatusStore: blockStatusStore,
|
||||||
ghostdagDataStore: ghostdagDataStore,
|
ghostdagDataStore: ghostdagDataStore,
|
||||||
consensusStateStore: consensusStateStore,
|
consensusStateStore: consensusStateStore,
|
||||||
utxoDiffStore: utxoDiffStore,
|
utxoDiffStore: utxoDiffStore,
|
||||||
blockRelationStore: blockRelationStore,
|
blockRelationStore: blockRelationStore,
|
||||||
acceptanceDataStore: acceptanceDataStore,
|
acceptanceDataStore: acceptanceDataStore,
|
||||||
blockHeaderStore: blockHeaderStore,
|
blockHeaderStore: blockHeaderStore,
|
||||||
headerTipsStore: headerTipsStore,
|
headersSelectedTipStore: headersSelectedTipStore,
|
||||||
|
pruningStore: pruningStore,
|
||||||
|
|
||||||
stores: []model.Store{
|
stores: []model.Store{
|
||||||
consensusStateStore,
|
consensusStateStore,
|
||||||
@ -111,7 +114,8 @@ func New(
|
|||||||
consensusStateStore,
|
consensusStateStore,
|
||||||
utxoDiffStore,
|
utxoDiffStore,
|
||||||
blockHeaderStore,
|
blockHeaderStore,
|
||||||
headerTipsStore,
|
headersSelectedTipStore,
|
||||||
|
pruningStore,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
"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/serialization"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization"
|
||||||
@ -12,18 +13,11 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var virtualHeaderHash = &externalapi.DomainHash{
|
func (csm *consensusStateManager) UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
onEnd := logger.LogAndMeasureExecutionTime(log, "UpdatePruningPoint")
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
|
||||||
}
|
|
||||||
|
|
||||||
func (csm *consensusStateManager) SetPruningPointUTXOSet(serializedUTXOSet []byte) error {
|
|
||||||
onEnd := logger.LogAndMeasureExecutionTime(log, "SetPruningPointUTXOSet")
|
|
||||||
defer onEnd()
|
defer onEnd()
|
||||||
|
|
||||||
err := csm.setPruningPointUTXOSet(serializedUTXOSet)
|
err := csm.updatePruningPoint(newPruningPoint, serializedUTXOSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
csm.discardSetPruningPointUTXOSetChanges()
|
csm.discardSetPruningPointUTXOSetChanges()
|
||||||
return err
|
return err
|
||||||
@ -32,15 +26,23 @@ func (csm *consensusStateManager) SetPruningPointUTXOSet(serializedUTXOSet []byt
|
|||||||
return csm.commitSetPruningPointUTXOSetAll()
|
return csm.commitSetPruningPointUTXOSetAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byte) error {
|
func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
|
||||||
log.Tracef("setPruningPointUTXOSet start")
|
log.Tracef("updatePruningPoint start")
|
||||||
defer log.Tracef("setPruningPointUTXOSet end")
|
defer log.Tracef("updatePruningPoint end")
|
||||||
|
|
||||||
headerTipsPruningPoint, err := csm.HeaderTipsPruningPoint()
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Tracef("The pruning point of the header tips is: %s", headerTipsPruningPoint)
|
|
||||||
|
if isViolatingFinality {
|
||||||
|
log.Warnf("Finality Violation Detected! The suggest pruning point %s violates finality!", newPruningPointHash)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
protoUTXOSet := &utxoserialization.ProtoUTXOSet{}
|
protoUTXOSet := &utxoserialization.ProtoUTXOSet{}
|
||||||
err = proto.Unmarshal(serializedUTXOSet, protoUTXOSet)
|
err = proto.Unmarshal(serializedUTXOSet, protoUTXOSet)
|
||||||
@ -54,24 +56,24 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
|
|||||||
}
|
}
|
||||||
log.Tracef("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash())
|
log.Tracef("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash())
|
||||||
|
|
||||||
headerTipsPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, headerTipsPruningPoint)
|
newPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, newPruningPointHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Tracef("The multiset in the header of the header tip pruning point: %s",
|
log.Tracef("The UTXO commitment of the pruning point: %s",
|
||||||
headerTipsPruningPointHeader.UTXOCommitment)
|
newPruningPointHeader.UTXOCommitment)
|
||||||
|
|
||||||
if headerTipsPruningPointHeader.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", headerTipsPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash())
|
"point UTXO set is %s but got %s", newPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash())
|
||||||
}
|
}
|
||||||
log.Tracef("Header tip pruning point multiset validation passed")
|
log.Tracef("The new pruning point UTXO commitment validation passed")
|
||||||
|
|
||||||
log.Tracef("Staging the parent hashes for the header tips pruning point as the DAG tips")
|
log.Tracef("Staging the parent hashes for pruning point as the DAG tips")
|
||||||
csm.consensusStateStore.StageTips(headerTipsPruningPointHeader.ParentHashes)
|
csm.consensusStateStore.StageTips(newPruningPointHeader.ParentHashes)
|
||||||
|
|
||||||
log.Tracef("Setting the parent hashes for the header tips pruning point as the virtual parents")
|
log.Tracef("Setting the parent hashes for the header tips pruning point as the virtual parents")
|
||||||
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, headerTipsPruningPointHeader.ParentHashes)
|
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, newPruningPointHeader.ParentHashes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -82,6 +84,13 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
|
|||||||
return err
|
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)
|
err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -93,8 +102,11 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("Staging the status of the header tips pruning point as %s", externalapi.StatusValid)
|
log.Tracef("Staging the new pruning point and its UTXO set")
|
||||||
csm.blockStatusStore.Stage(headerTipsPruningPoint, externalapi.StatusValid)
|
csm.pruningStore.Stage(newPruningPointHash, serializedUTXOSet)
|
||||||
|
|
||||||
|
log.Tracef("Staging the new pruning point as %s", externalapi.StatusValid)
|
||||||
|
csm.blockStatusStore.Stage(newPruningPointHash, externalapi.StatusValid)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,34 +157,3 @@ func (p protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoE
|
|||||||
func protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet *utxoserialization.ProtoUTXOSet) model.ReadOnlyUTXOSetIterator {
|
func protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet *utxoserialization.ProtoUTXOSet) model.ReadOnlyUTXOSetIterator {
|
||||||
return &protoUTXOSetIterator{utxoSet: protoUTXOSet}
|
return &protoUTXOSetIterator{utxoSet: protoUTXOSet}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainHash, error) {
|
|
||||||
log.Tracef("HeaderTipsPruningPoint start")
|
|
||||||
defer log.Tracef("HeaderTipsPruningPoint end")
|
|
||||||
|
|
||||||
headerTips, err := csm.headerTipsStore.Tips(csm.databaseContext)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
log.Tracef("The current header tips are: %s", headerTips)
|
|
||||||
|
|
||||||
log.Tracef("Temporarily staging the parents of the virtual header to be the header tips: %s", headerTips)
|
|
||||||
csm.blockRelationStore.StageBlockRelation(virtualHeaderHash, &model.BlockRelations{
|
|
||||||
Parents: headerTips,
|
|
||||||
})
|
|
||||||
|
|
||||||
defer csm.blockRelationStore.Discard()
|
|
||||||
|
|
||||||
err = csm.ghostdagManager.GHOSTDAG(virtualHeaderHash)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer csm.ghostdagDataStore.Discard()
|
|
||||||
|
|
||||||
pruningPoint, err := csm.dagTraversalManager.BlockAtDepth(virtualHeaderHash, csm.pruningDepth)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
log.Tracef("The block at depth %d from %s is: %s", csm.pruningDepth, virtualHeaderHash, pruningPoint)
|
|
||||||
return pruningPoint, nil
|
|
||||||
}
|
|
@ -47,7 +47,7 @@ func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blo
|
|||||||
log.Tracef("Coinbase transaction validation passed for block %s", blockHash)
|
log.Tracef("Coinbase transaction validation passed for block %s", blockHash)
|
||||||
|
|
||||||
log.Tracef("Validating transactions against past UTXO for block %s", blockHash)
|
log.Tracef("Validating transactions against past UTXO for block %s", blockHash)
|
||||||
err = csm.validateBlockTransactionsAgainstPastUTXO(block, blockHash, pastUTXODiff)
|
err = csm.validateBlockTransactionsAgainstPastUTXO(block, pastUTXODiff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -57,8 +57,9 @@ func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block *externalapi.DomainBlock,
|
func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block *externalapi.DomainBlock,
|
||||||
blockHash *externalapi.DomainHash, pastUTXODiff model.UTXODiff) error {
|
pastUTXODiff model.UTXODiff) error {
|
||||||
|
|
||||||
|
blockHash := consensushashing.BlockHash(block)
|
||||||
log.Tracef("validateBlockTransactionsAgainstPastUTXO start for block %s", blockHash)
|
log.Tracef("validateBlockTransactionsAgainstPastUTXO start for block %s", blockHash)
|
||||||
defer log.Tracef("validateBlockTransactionsAgainstPastUTXO end for block %s", blockHash)
|
defer log.Tracef("validateBlockTransactionsAgainstPastUTXO end for block %s", blockHash)
|
||||||
|
|
||||||
|
@ -2,9 +2,9 @@ package dagtraversalmanager
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// dagTraversalManager exposes methods for travering blocks
|
// dagTraversalManager exposes methods for travering blocks
|
||||||
@ -100,6 +100,11 @@ func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if highBlockGHOSTDAGData.BlueScore() < blueScore {
|
||||||
|
return nil, errors.Errorf("the given blue score %d is higher than block %s blue score of %d",
|
||||||
|
blueScore, highHash, highBlockGHOSTDAGData.BlueScore())
|
||||||
|
}
|
||||||
|
|
||||||
currentHash := highHash
|
currentHash := highHash
|
||||||
currentBlockGHOSTDAGData := highBlockGHOSTDAGData
|
currentBlockGHOSTDAGData := highBlockGHOSTDAGData
|
||||||
iterator := dtm.SelectedParentIterator(highHash)
|
iterator := dtm.SelectedParentIterator(highHash)
|
||||||
@ -112,7 +117,7 @@ func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash
|
|||||||
if selectedParentBlockGHOSTDAGData.BlueScore() < blueScore {
|
if selectedParentBlockGHOSTDAGData.BlueScore() < blueScore {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
currentHash = selectedParentBlockGHOSTDAGData.SelectedParent()
|
currentHash = currentBlockGHOSTDAGData.SelectedParent()
|
||||||
currentBlockGHOSTDAGData = selectedParentBlockGHOSTDAGData
|
currentBlockGHOSTDAGData = selectedParentBlockGHOSTDAGData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,31 +35,6 @@ func New(databaseContext model.DBReader,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fm *finalityManager) IsViolatingFinality(blockHash *externalapi.DomainHash) (bool, error) {
|
|
||||||
if *blockHash == *fm.genesisHash {
|
|
||||||
log.Tracef("Block %s is the genesis block, "+
|
|
||||||
"and does not violate finality by definition", blockHash)
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
log.Tracef("isViolatingFinality start for block %s", blockHash)
|
|
||||||
defer log.Tracef("isViolatingFinality end for block %s", blockHash)
|
|
||||||
|
|
||||||
virtualFinalityPoint, err := fm.VirtualFinalityPoint()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
log.Tracef("The virtual finality point is: %s", virtualFinalityPoint)
|
|
||||||
|
|
||||||
isInSelectedParentChain, err := fm.dagTopologyManager.IsInSelectedParentChainOf(virtualFinalityPoint, blockHash)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
log.Tracef("Is the virtual finality point %s "+
|
|
||||||
"in the selected parent chain of %s: %t", virtualFinalityPoint, blockHash, isInSelectedParentChain)
|
|
||||||
|
|
||||||
return !isInSelectedParentChain, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fm *finalityManager) VirtualFinalityPoint() (*externalapi.DomainHash, error) {
|
func (fm *finalityManager) VirtualFinalityPoint() (*externalapi.DomainHash, error) {
|
||||||
log.Tracef("virtualFinalityPoint start")
|
log.Tracef("virtualFinalityPoint start")
|
||||||
defer log.Tracef("virtualFinalityPoint end")
|
defer log.Tracef("virtualFinalityPoint end")
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
package headersselectedtipmanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type headerTipsManager struct {
|
||||||
|
databaseContext model.DBReader
|
||||||
|
|
||||||
|
dagTopologyManager model.DAGTopologyManager
|
||||||
|
ghostdagManager model.GHOSTDAGManager
|
||||||
|
headersSelectedTipStore model.HeaderSelectedTipStore
|
||||||
|
}
|
||||||
|
|
||||||
|
// New instantiates a new HeadersSelectedTipManager
|
||||||
|
func New(databaseContext model.DBReader,
|
||||||
|
dagTopologyManager model.DAGTopologyManager,
|
||||||
|
ghostdagManager model.GHOSTDAGManager,
|
||||||
|
headersSelectedTipStore model.HeaderSelectedTipStore) model.HeadersSelectedTipManager {
|
||||||
|
|
||||||
|
return &headerTipsManager{
|
||||||
|
databaseContext: databaseContext,
|
||||||
|
dagTopologyManager: dagTopologyManager,
|
||||||
|
ghostdagManager: ghostdagManager,
|
||||||
|
headersSelectedTipStore: headersSelectedTipStore,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *headerTipsManager) AddHeaderTip(hash *externalapi.DomainHash) error {
|
||||||
|
hasSelectedTip, err := h.headersSelectedTipStore.Has(h.databaseContext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasSelectedTip {
|
||||||
|
h.headersSelectedTipStore.Stage(hash)
|
||||||
|
} else {
|
||||||
|
headersSelectedTip, err := h.headersSelectedTipStore.HeadersSelectedTip(h.databaseContext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newHeadersSelectedTip, err := h.ghostdagManager.ChooseSelectedParent(headersSelectedTip, hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if *newHeadersSelectedTip != *headersSelectedTip {
|
||||||
|
h.headersSelectedTipStore.Stage(newHeadersSelectedTip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,59 +0,0 @@
|
|||||||
package headertipsmanager
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
type headerTipsManager struct {
|
|
||||||
databaseContext model.DBReader
|
|
||||||
dagTopologyManager model.DAGTopologyManager
|
|
||||||
ghostdagManager model.GHOSTDAGManager
|
|
||||||
headerTipsStore model.HeaderTipsStore
|
|
||||||
}
|
|
||||||
|
|
||||||
// New instantiates a new HeaderTipsManager
|
|
||||||
func New(databaseContext model.DBReader,
|
|
||||||
dagTopologyManager model.DAGTopologyManager,
|
|
||||||
ghostdagManager model.GHOSTDAGManager,
|
|
||||||
headerTipsStore model.HeaderTipsStore) model.HeaderTipsManager {
|
|
||||||
return &headerTipsManager{
|
|
||||||
databaseContext: databaseContext,
|
|
||||||
dagTopologyManager: dagTopologyManager,
|
|
||||||
ghostdagManager: ghostdagManager,
|
|
||||||
headerTipsStore: headerTipsStore,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h headerTipsManager) AddHeaderTip(hash *externalapi.DomainHash) error {
|
|
||||||
tips := []*externalapi.DomainHash{}
|
|
||||||
hasTips, err := h.headerTipsStore.HasTips(h.databaseContext)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasTips {
|
|
||||||
var err error
|
|
||||||
tips, err = h.headerTipsStore.Tips(h.databaseContext)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newTips := make([]*externalapi.DomainHash, 0, len(tips)+1)
|
|
||||||
for _, tip := range tips {
|
|
||||||
isAncestorOf, err := h.dagTopologyManager.IsAncestorOf(tip, hash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isAncestorOf {
|
|
||||||
newTips = append(newTips, tip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newTips = append(newTips, hash)
|
|
||||||
h.headerTipsStore.Stage(newTips)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package headertipsmanager
|
|
||||||
|
|
||||||
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
||||||
|
|
||||||
func (h headerTipsManager) SelectedTip() (*externalapi.DomainHash, error) {
|
|
||||||
tips, err := h.headerTipsStore.Tips(h.databaseContext)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedTip, err := h.ghostdagManager.ChooseSelectedParent(tips...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return selectedTip, nil
|
|
||||||
}
|
|
5
domain/consensus/processes/pruningmanager/log.go
Normal file
5
domain/consensus/processes/pruningmanager/log.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package pruningmanager
|
||||||
|
|
||||||
|
import "github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
|
|
||||||
|
var log, _ = logger.Get(logger.SubsystemTags.PRNM)
|
@ -11,13 +11,14 @@ import (
|
|||||||
type pruningManager struct {
|
type pruningManager struct {
|
||||||
databaseContext model.DBReader
|
databaseContext model.DBReader
|
||||||
|
|
||||||
dagTraversalManager model.DAGTraversalManager
|
dagTraversalManager model.DAGTraversalManager
|
||||||
dagTopologyManager model.DAGTopologyManager
|
dagTopologyManager model.DAGTopologyManager
|
||||||
consensusStateManager model.ConsensusStateManager
|
consensusStateManager model.ConsensusStateManager
|
||||||
consensusStateStore model.ConsensusStateStore
|
consensusStateStore model.ConsensusStateStore
|
||||||
ghostdagDataStore model.GHOSTDAGDataStore
|
ghostdagDataStore model.GHOSTDAGDataStore
|
||||||
pruningStore model.PruningStore
|
pruningStore model.PruningStore
|
||||||
blockStatusStore model.BlockStatusStore
|
blockStatusStore model.BlockStatusStore
|
||||||
|
headerSelectedTipStore model.HeaderSelectedTipStore
|
||||||
|
|
||||||
multiSetStore model.MultisetStore
|
multiSetStore model.MultisetStore
|
||||||
acceptanceDataStore model.AcceptanceDataStore
|
acceptanceDataStore model.AcceptanceDataStore
|
||||||
@ -40,6 +41,7 @@ func New(
|
|||||||
ghostdagDataStore model.GHOSTDAGDataStore,
|
ghostdagDataStore model.GHOSTDAGDataStore,
|
||||||
pruningStore model.PruningStore,
|
pruningStore model.PruningStore,
|
||||||
blockStatusStore model.BlockStatusStore,
|
blockStatusStore model.BlockStatusStore,
|
||||||
|
headerSelectedTipStore model.HeaderSelectedTipStore,
|
||||||
|
|
||||||
multiSetStore model.MultisetStore,
|
multiSetStore model.MultisetStore,
|
||||||
acceptanceDataStore model.AcceptanceDataStore,
|
acceptanceDataStore model.AcceptanceDataStore,
|
||||||
@ -52,27 +54,28 @@ func New(
|
|||||||
) model.PruningManager {
|
) model.PruningManager {
|
||||||
|
|
||||||
return &pruningManager{
|
return &pruningManager{
|
||||||
databaseContext: databaseContext,
|
databaseContext: databaseContext,
|
||||||
dagTraversalManager: dagTraversalManager,
|
dagTraversalManager: dagTraversalManager,
|
||||||
dagTopologyManager: dagTopologyManager,
|
dagTopologyManager: dagTopologyManager,
|
||||||
consensusStateManager: consensusStateManager,
|
consensusStateManager: consensusStateManager,
|
||||||
consensusStateStore: consensusStateStore,
|
consensusStateStore: consensusStateStore,
|
||||||
ghostdagDataStore: ghostdagDataStore,
|
ghostdagDataStore: ghostdagDataStore,
|
||||||
pruningStore: pruningStore,
|
pruningStore: pruningStore,
|
||||||
blockStatusStore: blockStatusStore,
|
blockStatusStore: blockStatusStore,
|
||||||
multiSetStore: multiSetStore,
|
multiSetStore: multiSetStore,
|
||||||
acceptanceDataStore: acceptanceDataStore,
|
acceptanceDataStore: acceptanceDataStore,
|
||||||
blocksStore: blocksStore,
|
blocksStore: blocksStore,
|
||||||
utxoDiffStore: utxoDiffStore,
|
utxoDiffStore: utxoDiffStore,
|
||||||
genesisHash: genesisHash,
|
headerSelectedTipStore: headerSelectedTipStore,
|
||||||
pruningDepth: pruningDepth,
|
genesisHash: genesisHash,
|
||||||
finalityInterval: finalityInterval,
|
pruningDepth: pruningDepth,
|
||||||
|
finalityInterval: finalityInterval,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindNextPruningPoint finds the next pruning point from the
|
// FindNextPruningPoint finds the next pruning point from the
|
||||||
// given blockHash
|
// given blockHash
|
||||||
func (pm *pruningManager) FindNextPruningPoint() error {
|
func (pm *pruningManager) UpdatePruningPointByVirtual() error {
|
||||||
hasPruningPoint, err := pm.pruningStore.HasPruningPoint(pm.databaseContext)
|
hasPruningPoint, err := pm.pruningStore.HasPruningPoint(pm.databaseContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -95,40 +98,41 @@ func (pm *pruningManager) FindNextPruningPoint() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtualSelectedParent, err := pm.ghostdagDataStore.Get(pm.databaseContext, virtual.SelectedParent())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
currentPGhost, err := pm.ghostdagDataStore.Get(pm.databaseContext, currentP)
|
currentPGhost, err := pm.ghostdagDataStore.Get(pm.databaseContext, currentP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
currentPBlueScore := currentPGhost.BlueScore()
|
currentPBlueScore := currentPGhost.BlueScore()
|
||||||
// Because the pruning point changes only once per finality, then there's no need to even check for that if a finality interval hasn't passed.
|
// Because the pruning point changes only once per finality, then there's no need to even check for that if a finality interval hasn't passed.
|
||||||
if virtual.BlueScore() <= currentPBlueScore+pm.finalityInterval {
|
if virtualSelectedParent.BlueScore() <= currentPBlueScore+pm.finalityInterval {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// This means the pruning point is still genesis.
|
// This means the pruning point is still genesis.
|
||||||
if virtual.BlueScore() <= pm.pruningDepth+pm.finalityInterval {
|
if virtualSelectedParent.BlueScore() <= pm.pruningDepth+pm.finalityInterval {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// get Virtual(pruningDepth)
|
// get Virtual(pruningDepth)
|
||||||
candidatePHash, err := pm.dagTraversalManager.BlockAtDepth(model.VirtualBlockHash, pm.pruningDepth)
|
newPruningPoint, err := pm.calculatePruningPointFromBlock(model.VirtualBlockHash)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
candidatePGhost, err := pm.ghostdagDataStore.Get(pm.databaseContext, candidatePHash)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actually check if the pruning point changed
|
if *newPruningPoint != *currentP {
|
||||||
if (currentPBlueScore / pm.finalityInterval) < (candidatePGhost.BlueScore() / pm.finalityInterval) {
|
err = pm.savePruningPoint(newPruningPoint)
|
||||||
err = pm.savePruningPoint(candidatePHash)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return pm.deletePastBlocks(candidatePHash)
|
return pm.deletePastBlocks(newPruningPoint)
|
||||||
}
|
}
|
||||||
return pm.deletePastBlocks(currentP)
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) error {
|
func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) error {
|
||||||
@ -233,6 +237,30 @@ func (pm *pruningManager) deleteBlock(blockHash *externalapi.DomainHash) (alread
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pm *pruningManager) CalculatePruningPointByHeaderSelectedTip() (*externalapi.DomainHash, error) {
|
||||||
|
headersSelectedTip, err := pm.headerSelectedTipStore.HeadersSelectedTip(pm.databaseContext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pm.calculatePruningPointFromBlock(headersSelectedTip)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pm *pruningManager) calculatePruningPointFromBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) {
|
||||||
|
ghostdagData, err := pm.ghostdagDataStore.Get(pm.databaseContext, blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetBlueScore := uint64(0)
|
||||||
|
if ghostdagData.BlueScore() > pm.pruningDepth {
|
||||||
|
// The target blue is calculated by calculating ghostdagData.BlueScore() - pm.pruningDepth and rounding
|
||||||
|
// down with the precision of finality interval.
|
||||||
|
targetBlueScore = ((ghostdagData.BlueScore() - pm.pruningDepth) / pm.finalityInterval) * pm.finalityInterval
|
||||||
|
}
|
||||||
|
return pm.dagTraversalManager.LowestChainBlockAboveOrEqualToBlueScore(blockHash, targetBlueScore)
|
||||||
|
}
|
||||||
|
|
||||||
func serializeUTXOSetIterator(iter model.ReadOnlyUTXOSetIterator) ([]byte, error) {
|
func serializeUTXOSetIterator(iter model.ReadOnlyUTXOSetIterator) ([]byte, error) {
|
||||||
serializedUtxo, err := utxoserialization.ReadOnlyUTXOSetToProtoUTXOSet(iter)
|
serializedUtxo, err := utxoserialization.ReadOnlyUTXOSetToProtoUTXOSet(iter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -159,7 +159,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
|||||||
factory := consensus.NewFactory()
|
factory := consensus.NewFactory()
|
||||||
tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot")
|
tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewTestConsensus: %s", err)
|
t.Fatalf("NewTestConsensus: %+v", err)
|
||||||
}
|
}
|
||||||
defer tearDown()
|
defer tearDown()
|
||||||
|
|
||||||
|
@ -99,26 +99,26 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
|
func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
|
||||||
headerTipsPruningPoint, err := sm.consensusStateManager.HeaderTipsPruningPoint()
|
pruningPoint, err := sm.pruningStore.PruningPoint(sm.databaseContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedChildIterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, headerTipsPruningPoint)
|
selectedChildIterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, pruningPoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
lowHash := headerTipsPruningPoint
|
lowHash := pruningPoint
|
||||||
foundHeaderOnlyBlock := false
|
foundHeaderOnlyBlock := false
|
||||||
for selectedChildIterator.Next() {
|
for selectedChildIterator.Next() {
|
||||||
selectedChild := selectedChildIterator.Get()
|
selectedChild := selectedChildIterator.Get()
|
||||||
selectedChildStatus, err := sm.blockStatusStore.Get(sm.databaseContext, selectedChild)
|
hasBlock, err := sm.blockStore.HasBlock(sm.databaseContext, selectedChild)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if selectedChildStatus == externalapi.StatusHeaderOnly {
|
if !hasBlock {
|
||||||
foundHeaderOnlyBlock = true
|
foundHeaderOnlyBlock = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -167,24 +167,3 @@ func (sm *syncManager) isHeaderOnlyBlock(blockHash *externalapi.DomainHash) (boo
|
|||||||
|
|
||||||
return status == externalapi.StatusHeaderOnly, nil
|
return status == externalapi.StatusHeaderOnly, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *syncManager) isBlockInHeaderPruningPointFuture(blockHash *externalapi.DomainHash) (bool, error) {
|
|
||||||
if *blockHash == *sm.genesisBlockHash {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
exists, err := sm.blockStatusStore.Exists(sm.databaseContext, blockHash)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
headerTipsPruningPoint, err := sm.consensusStateManager.HeaderTipsPruningPoint()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sm.dagTopologyManager.IsAncestorOf(headerTipsPruningPoint, blockHash)
|
|
||||||
}
|
|
||||||
|
@ -4,84 +4,43 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// areHeaderTipsSyncedMaxTimeDifference is the number of blocks from
|
|
||||||
// the header virtual selected parent (estimated by timestamps) for
|
|
||||||
// kaspad to be considered not synced
|
|
||||||
const areHeaderTipsSyncedMaxTimeDifference = 300 // 5 minutes
|
|
||||||
|
|
||||||
func (sm *syncManager) syncInfo() (*externalapi.SyncInfo, error) {
|
func (sm *syncManager) syncInfo() (*externalapi.SyncInfo, error) {
|
||||||
syncState, err := sm.resolveSyncState()
|
isAwaitingUTXOSet, ibdRootUTXOBlockHash, err := sm.isAwaitingUTXOSet()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ibdRootUTXOBlockHash *externalapi.DomainHash
|
|
||||||
if syncState == externalapi.SyncStateAwaitingUTXOSet {
|
|
||||||
ibdRootUTXOBlockHash, err = sm.consensusStateManager.HeaderTipsPruningPoint()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
headerCount := sm.getHeaderCount()
|
headerCount := sm.getHeaderCount()
|
||||||
blockCount := sm.getBlockCount()
|
blockCount := sm.getBlockCount()
|
||||||
|
|
||||||
return &externalapi.SyncInfo{
|
return &externalapi.SyncInfo{
|
||||||
State: syncState,
|
IsAwaitingUTXOSet: isAwaitingUTXOSet,
|
||||||
IBDRootUTXOBlockHash: ibdRootUTXOBlockHash,
|
IBDRootUTXOBlockHash: ibdRootUTXOBlockHash,
|
||||||
HeaderCount: headerCount,
|
HeaderCount: headerCount,
|
||||||
BlockCount: blockCount,
|
BlockCount: blockCount,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) {
|
func (sm *syncManager) isAwaitingUTXOSet() (isAwaitingUTXOSet bool, ibdRootUTXOBlockHash *externalapi.DomainHash,
|
||||||
hasTips, err := sm.headerTipsStore.HasTips(sm.databaseContext)
|
err error) {
|
||||||
|
|
||||||
|
pruningPointByHeaders, err := sm.pruningManager.CalculatePruningPointByHeaderSelectedTip()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return false, nil, err
|
||||||
}
|
|
||||||
if !hasTips {
|
|
||||||
return externalapi.SyncStateAwaitingGenesis, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
headerVirtualSelectedParentHash, err := sm.headerVirtualSelectedParentHash()
|
pruningPoint, err := sm.pruningStore.PruningPoint(sm.databaseContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return false, nil, err
|
||||||
}
|
|
||||||
headerVirtualSelectedParentStatus, err := sm.blockStatusStore.Get(sm.databaseContext, headerVirtualSelectedParentHash)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if headerVirtualSelectedParentStatus != externalapi.StatusHeaderOnly {
|
|
||||||
return externalapi.SyncStateSynced, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once the header tips are synced, check the status of
|
// If the pruning point by headers is different from the current point
|
||||||
// the pruning point from the point of view of the header
|
// it means we need to request the new pruning point UTXO set.
|
||||||
// tips. We check it against StatusValid (rather than
|
if *pruningPoint != *pruningPointByHeaders {
|
||||||
// StatusHeaderOnly) because once we do receive the
|
return true, pruningPointByHeaders, nil
|
||||||
// UTXO set of said pruning point, the state is explicitly
|
|
||||||
// set to StatusValid.
|
|
||||||
headerTipsPruningPoint, err := sm.consensusStateManager.HeaderTipsPruningPoint()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
headerTipsPruningPointStatus, err := sm.blockStatusStore.Get(sm.databaseContext, headerTipsPruningPoint)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if headerTipsPruningPointStatus != externalapi.StatusValid {
|
|
||||||
return externalapi.SyncStateAwaitingUTXOSet, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return externalapi.SyncStateAwaitingBlockBodies, nil
|
return false, nil, nil
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *syncManager) headerVirtualSelectedParentHash() (*externalapi.DomainHash, error) {
|
|
||||||
headerTips, err := sm.headerTipsStore.Tips(sm.databaseContext)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return sm.ghostdagManager.ChooseSelectedParent(headerTips...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *syncManager) getHeaderCount() uint64 {
|
func (sm *syncManager) getHeaderCount() uint64 {
|
||||||
|
@ -7,53 +7,50 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type syncManager struct {
|
type syncManager struct {
|
||||||
databaseContext model.DBReader
|
databaseContext model.DBReader
|
||||||
genesisBlockHash *externalapi.DomainHash
|
genesisBlockHash *externalapi.DomainHash
|
||||||
targetTimePerBlock int64
|
|
||||||
|
|
||||||
dagTraversalManager model.DAGTraversalManager
|
dagTraversalManager model.DAGTraversalManager
|
||||||
dagTopologyManager model.DAGTopologyManager
|
dagTopologyManager model.DAGTopologyManager
|
||||||
ghostdagManager model.GHOSTDAGManager
|
ghostdagManager model.GHOSTDAGManager
|
||||||
consensusStateManager model.ConsensusStateManager
|
pruningManager model.PruningManager
|
||||||
|
|
||||||
ghostdagDataStore model.GHOSTDAGDataStore
|
ghostdagDataStore model.GHOSTDAGDataStore
|
||||||
blockStatusStore model.BlockStatusStore
|
blockStatusStore model.BlockStatusStore
|
||||||
blockHeaderStore model.BlockHeaderStore
|
blockHeaderStore model.BlockHeaderStore
|
||||||
headerTipsStore model.HeaderTipsStore
|
|
||||||
blockStore model.BlockStore
|
blockStore model.BlockStore
|
||||||
|
pruningStore model.PruningStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// New instantiates a new SyncManager
|
// New instantiates a new SyncManager
|
||||||
func New(
|
func New(
|
||||||
databaseContext model.DBReader,
|
databaseContext model.DBReader,
|
||||||
genesisBlockHash *externalapi.DomainHash,
|
genesisBlockHash *externalapi.DomainHash,
|
||||||
targetTimePerBlock int64,
|
|
||||||
dagTraversalManager model.DAGTraversalManager,
|
dagTraversalManager model.DAGTraversalManager,
|
||||||
dagTopologyManager model.DAGTopologyManager,
|
dagTopologyManager model.DAGTopologyManager,
|
||||||
ghostdagManager model.GHOSTDAGManager,
|
ghostdagManager model.GHOSTDAGManager,
|
||||||
consensusStateManager model.ConsensusStateManager,
|
pruningManager model.PruningManager,
|
||||||
|
|
||||||
ghostdagDataStore model.GHOSTDAGDataStore,
|
ghostdagDataStore model.GHOSTDAGDataStore,
|
||||||
blockStatusStore model.BlockStatusStore,
|
blockStatusStore model.BlockStatusStore,
|
||||||
blockHeaderStore model.BlockHeaderStore,
|
blockHeaderStore model.BlockHeaderStore,
|
||||||
headerTipsStore model.HeaderTipsStore,
|
blockStore model.BlockStore,
|
||||||
blockStore model.BlockStore) model.SyncManager {
|
pruningStore model.PruningStore) model.SyncManager {
|
||||||
|
|
||||||
return &syncManager{
|
return &syncManager{
|
||||||
databaseContext: databaseContext,
|
databaseContext: databaseContext,
|
||||||
genesisBlockHash: genesisBlockHash,
|
genesisBlockHash: genesisBlockHash,
|
||||||
targetTimePerBlock: targetTimePerBlock,
|
|
||||||
|
|
||||||
dagTraversalManager: dagTraversalManager,
|
dagTraversalManager: dagTraversalManager,
|
||||||
dagTopologyManager: dagTopologyManager,
|
dagTopologyManager: dagTopologyManager,
|
||||||
ghostdagManager: ghostdagManager,
|
ghostdagManager: ghostdagManager,
|
||||||
consensusStateManager: consensusStateManager,
|
pruningManager: pruningManager,
|
||||||
|
|
||||||
ghostdagDataStore: ghostdagDataStore,
|
ghostdagDataStore: ghostdagDataStore,
|
||||||
blockStatusStore: blockStatusStore,
|
blockStatusStore: blockStatusStore,
|
||||||
blockHeaderStore: blockHeaderStore,
|
blockHeaderStore: blockHeaderStore,
|
||||||
headerTipsStore: headerTipsStore,
|
|
||||||
blockStore: blockStore,
|
blockStore: blockStore,
|
||||||
|
pruningStore: pruningStore,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,13 +68,6 @@ func (sm *syncManager) GetMissingBlockBodyHashes(highHash *externalapi.DomainHas
|
|||||||
return sm.missingBlockBodyHashes(highHash)
|
return sm.missingBlockBodyHashes(highHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *syncManager) IsBlockInHeaderPruningPointFuture(blockHash *externalapi.DomainHash) (bool, error) {
|
|
||||||
onEnd := logger.LogAndMeasureExecutionTime(log, "IsBlockInHeaderPruningPointFuture")
|
|
||||||
defer onEnd()
|
|
||||||
|
|
||||||
return sm.isBlockInHeaderPruningPointFuture(blockHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *syncManager) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) {
|
func (sm *syncManager) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) {
|
||||||
onEnd := logger.LogAndMeasureExecutionTime(log, "CreateBlockLocator")
|
onEnd := logger.LogAndMeasureExecutionTime(log, "CreateBlockLocator")
|
||||||
defer onEnd()
|
defer onEnd()
|
||||||
|
@ -237,6 +237,8 @@ var (
|
|||||||
|
|
||||||
//ErrBlockIsTooMuchInTheFuture indicates that the block timestamp is too much in the future.
|
//ErrBlockIsTooMuchInTheFuture indicates that the block timestamp is too much in the future.
|
||||||
ErrBlockIsTooMuchInTheFuture = newRuleError("ErrBlockIsTooMuchInTheFuture")
|
ErrBlockIsTooMuchInTheFuture = newRuleError("ErrBlockIsTooMuchInTheFuture")
|
||||||
|
|
||||||
|
ErrUnexpectedPruningPoint = newRuleError("ErrUnexpectedPruningPoint")
|
||||||
)
|
)
|
||||||
|
|
||||||
// RuleError identifies a rule violation. It is used to indicate that
|
// RuleError identifies a rule violation. It is used to indicate that
|
||||||
|
@ -37,8 +37,8 @@ func (tc *testConsensus) GHOSTDAGDataStore() model.GHOSTDAGDataStore {
|
|||||||
return tc.ghostdagDataStore
|
return tc.ghostdagDataStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *testConsensus) HeaderTipsStore() model.HeaderTipsStore {
|
func (tc *testConsensus) HeaderTipsStore() model.HeaderSelectedTipStore {
|
||||||
return tc.headerTipsStore
|
return tc.headersSelectedTipStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *testConsensus) MultisetStore() model.MultisetStore {
|
func (tc *testConsensus) MultisetStore() model.MultisetStore {
|
||||||
@ -93,7 +93,7 @@ func (tc *testConsensus) GHOSTDAGManager() model.GHOSTDAGManager {
|
|||||||
return tc.ghostdagManager
|
return tc.ghostdagManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *testConsensus) HeaderTipsManager() model.HeaderTipsManager {
|
func (tc *testConsensus) HeaderTipsManager() model.HeadersSelectedTipManager {
|
||||||
return tc.headerTipsManager
|
return tc.headerTipsManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +83,11 @@ func (networkFlags *NetworkFlags) ResolveNetwork(parser *flags.Parser) error {
|
|||||||
return errors.Errorf("Mainnet has not launched yet, use --testnet to run in testnet mode")
|
return errors.Errorf("Mainnet has not launched yet, use --testnet to run in testnet mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err := networkFlags.overrideDAGParams()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ var (
|
|||||||
snvrLog = BackendLog.Logger("SNVR")
|
snvrLog = BackendLog.Logger("SNVR")
|
||||||
wsvcLog = BackendLog.Logger("WSVC")
|
wsvcLog = BackendLog.Logger("WSVC")
|
||||||
reacLog = BackendLog.Logger("REAC")
|
reacLog = BackendLog.Logger("REAC")
|
||||||
|
prnmLog = BackendLog.Logger("PRNM")
|
||||||
|
blvlLog = BackendLog.Logger("BLVL")
|
||||||
)
|
)
|
||||||
|
|
||||||
// SubsystemTags is an enum of all sub system tags
|
// SubsystemTags is an enum of all sub system tags
|
||||||
@ -85,7 +87,9 @@ var SubsystemTags = struct {
|
|||||||
DNSS,
|
DNSS,
|
||||||
SNVR,
|
SNVR,
|
||||||
WSVC,
|
WSVC,
|
||||||
REAC string
|
REAC,
|
||||||
|
PRNM,
|
||||||
|
BLVL string
|
||||||
}{
|
}{
|
||||||
ADXR: "ADXR",
|
ADXR: "ADXR",
|
||||||
AMGR: "AMGR",
|
AMGR: "AMGR",
|
||||||
@ -115,6 +119,8 @@ var SubsystemTags = struct {
|
|||||||
SNVR: "SNVR",
|
SNVR: "SNVR",
|
||||||
WSVC: "WSVC",
|
WSVC: "WSVC",
|
||||||
REAC: "REAC",
|
REAC: "REAC",
|
||||||
|
PRNM: "PRNM",
|
||||||
|
BLVL: "BLVL",
|
||||||
}
|
}
|
||||||
|
|
||||||
// subsystemLoggers maps each subsystem identifier to its associated logger.
|
// subsystemLoggers maps each subsystem identifier to its associated logger.
|
||||||
@ -147,6 +153,8 @@ var subsystemLoggers = map[string]*Logger{
|
|||||||
SubsystemTags.SNVR: snvrLog,
|
SubsystemTags.SNVR: snvrLog,
|
||||||
SubsystemTags.WSVC: wsvcLog,
|
SubsystemTags.WSVC: wsvcLog,
|
||||||
SubsystemTags.REAC: reacLog,
|
SubsystemTags.REAC: reacLog,
|
||||||
|
SubsystemTags.PRNM: prnmLog,
|
||||||
|
SubsystemTags.BLVL: blvlLog,
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitLog attaches log file and error log file to the backend log.
|
// InitLog attaches log file and error log file to the backend log.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user