mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-05-23 07:16:47 +00:00
127 lines
3.8 KiB
Go
127 lines
3.8 KiB
Go
package syncmanager
|
|
|
|
import (
|
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
"github.com/kaspanet/kaspad/util/mstime"
|
|
)
|
|
|
|
// 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_000 // 5 minutes
|
|
|
|
func (sm *syncManager) syncInfo() (*externalapi.SyncInfo, error) {
|
|
syncState, err := sm.resolveSyncState()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var ibdRootUTXOBlockHash *externalapi.DomainHash
|
|
if syncState == externalapi.SyncStateMissingUTXOSet {
|
|
ibdRootUTXOBlockHash, err = sm.consensusStateManager.HeaderTipsPruningPoint()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
headerCount := sm.getHeaderCount()
|
|
blockCount := sm.getBlockCount()
|
|
|
|
return &externalapi.SyncInfo{
|
|
State: syncState,
|
|
IBDRootUTXOBlockHash: ibdRootUTXOBlockHash,
|
|
HeaderCount: headerCount,
|
|
BlockCount: blockCount,
|
|
}, nil
|
|
}
|
|
|
|
func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) {
|
|
hasTips, err := sm.headerTipsStore.HasTips(sm.databaseContext)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if !hasTips {
|
|
return externalapi.SyncStateMissingGenesis, nil
|
|
}
|
|
|
|
headerVirtualSelectedParentHash, err := sm.headerVirtualSelectedParentHash()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
isSynced, err := sm.areHeaderTipsSynced(headerVirtualSelectedParentHash)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if !isSynced {
|
|
return externalapi.SyncStateHeadersFirst, nil
|
|
}
|
|
|
|
virtualSelectedParentHash, err := sm.virtualSelectedParentHash()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if *virtualSelectedParentHash == *headerVirtualSelectedParentHash {
|
|
return externalapi.SyncStateRelay, nil
|
|
}
|
|
|
|
// Once the header tips are synced, check the status of
|
|
// the pruning point from the point of view of the header
|
|
// tips. We check it against StatusValid (rather than
|
|
// StatusHeaderOnly) because once we do receive the
|
|
// 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.SyncStateMissingUTXOSet, nil
|
|
}
|
|
|
|
return externalapi.SyncStateMissingBlockBodies, nil
|
|
}
|
|
|
|
func (sm *syncManager) virtualSelectedParentHash() (*externalapi.DomainHash, error) {
|
|
virtualGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, model.VirtualBlockHash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return virtualGHOSTDAGData.SelectedParent, 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) areHeaderTipsSynced(headerVirtualSelectedParentHash *externalapi.DomainHash) (bool, error) {
|
|
virtualSelectedParentHeader, err := sm.blockHeaderStore.BlockHeader(sm.databaseContext, headerVirtualSelectedParentHash)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
virtualSelectedParentTimeInMilliseconds := virtualSelectedParentHeader.TimeInMilliseconds
|
|
|
|
nowInMilliseconds := mstime.Now().UnixMilliseconds()
|
|
timeDifference := nowInMilliseconds - virtualSelectedParentTimeInMilliseconds
|
|
|
|
maxTimeDifference := areHeaderTipsSyncedMaxTimeDifference * sm.targetTimePerBlock
|
|
|
|
return timeDifference <= maxTimeDifference, nil
|
|
}
|
|
|
|
func (sm *syncManager) getHeaderCount() uint64 {
|
|
return sm.blockHeaderStore.Count()
|
|
}
|
|
|
|
func (sm *syncManager) getBlockCount() uint64 {
|
|
return sm.blockStore.Count()
|
|
}
|