kaspad/domain/consensus/factory.go
stasatdaglabs 7f899b0d09
[NOD-1579] Improve the IBD mechanism (#1174)
* [NOD-1579] Remove selected tip hash messages.

* [NOD-1579] Start moving IBD stuff into blockrelay.

* [NOD-1579] Rename relaytransactions to transactionrelay.

* [NOD-1579] Move IBD files into blockrelay.

* [NOD-1579] Remove flow stuff from ibd.go.

* [NOD-1579] Bring back IsInIBD().

* [NOD-1579] Simplify block relay flow.

* [NOD-1579] Check orphan pool for missing parents to avoid unnecessary processing.

* [NOD-1579] Implement processOrphan.

* [NOD-1579] Implement addToOrphanSetAndRequestMissingParents.

* [NOD-1579] Fix TestIBD.

* [NOD-1579] Implement isBlockInOrphanResolutionRange.

* [NOD-1579] Implement limited block locators.

* [NOD-1579] Add some comments.

* [NOD-1579] Specifically check for StatusHeaderOnly in blockrelay.

* [NOD-1579] Simplify runIBDIfNotRunning.

* [NOD-1579] Don't run IBD if it is already running.

* [NOD-1579] Fix a comment.

* [NOD-1579] Rename mode to syncInfo.

* [NOD-1579] Simplify validateAndInsertBlock.

* [NOD-1579] Fix bad SyncStateSynced condition.

* [NOD-1579] Implement validateAgainstSyncStateAndResolveInsertMode.

* [NOD-1579] Use insertModeHeader.

* [NOD-1579] Add logs to TrySetIBDRunning and UnsetIBDRunning.

* [NOD-1579] Implement and use dequeueIncomingMessageAndSkipInvs.

* [NOD-1579] Fix a log.

* [NOD-1579] Fix a bug in createBlockLocator.

* [NOD-1579] Rename a variable.

* [NOD-1579] Fix a slew of bugs in missingBlockBodyHashes and selectedChildIterator.

* [NOD-1579] Fix bad chunk size in syncMissingBlockBodies.

* [NOD-1579] Remove maxOrphanBlueScoreDiff.

* [NOD-1579] Fix merge errors.

* [NOD-1579] Remove a debug log.

* [NOD-1579] Add logs.

* [NOD-1579] Make various go quality tools happy.

* [NOD-1579] Fix a typo in a variable name.

* [NOD-1579] Fix full blocks over header-only blocks not failing the missing-parents validation.

* [NOD-1579] Add an error log about a condition that should never happen.

* [NOD-1579] Check all antiPast hashes instead of just the lowHash's anticone to filter for header-only blocks.

* [NOD-1579] Remove the nil stuff from GetBlockLocator.

* [NOD-1579] Remove superfluous condition in handleRelayInvsFlow.start().

* [NOD-1579] Return a boolean from requestBlock instead of comparing to nil.

* [NOD-1579] Fix a bad log.Debugf.

* [NOD-1579] Remove a redundant check.

* [NOD-1579] Change an info log to a warning log.

* [NOD-1579] Move OnNewBlock out of relayBlock.

* [NOD-1579] Remove redundant exists check from runIBDIfNotRunning.

* [NOD-1579] Fix bad call to OnNewBlock.

* [NOD-1579] Remove an impossible check.

* [NOD-1579] Added a log.

* [NOD-1579] Rename insertModeBlockWithoutUpdatingVirtual to insertModeBlockBody.

* [NOD-1579] Add a check for duplicate headers.

* [NOD-1579] Added a comment.

* [NOD-1579] Tighten a stop condition.

* [NOD-1579] Simplify a log.

* [NOD-1579] Clarify a log.

* [NOD-1579] Move a log.
2020-12-06 16:23:56 +02:00

372 lines
11 KiB
Go

package consensus
import (
"io/ioutil"
"os"
"sync"
"github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager"
"github.com/kaspanet/kaspad/infrastructure/db/database/ldb"
consensusdatabase "github.com/kaspanet/kaspad/domain/consensus/database"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/acceptancedatastore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/blockheaderstore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/blockrelationstore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/blockstatusstore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/blockstore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/consensusstatestore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/ghostdagdatastore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headertipsstore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/multisetstore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/pruningstore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/reachabilitydatastore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/utxodiffstore"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
"github.com/kaspanet/kaspad/domain/consensus/processes/blockbuilder"
"github.com/kaspanet/kaspad/domain/consensus/processes/blockprocessor"
"github.com/kaspanet/kaspad/domain/consensus/processes/blockvalidator"
"github.com/kaspanet/kaspad/domain/consensus/processes/coinbasemanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/dagtopologymanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/difficultymanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/headertipsmanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/mergedepthmanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/pastmediantimemanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/pruningmanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/reachabilitymanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/syncmanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/transactionvalidator"
"github.com/kaspanet/kaspad/domain/dagconfig"
infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database"
)
// Factory instantiates new Consensuses
type Factory interface {
NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error)
NewTestConsensus(dagParams *dagconfig.Params, testName string) (tc testapi.TestConsensus, teardown func(), err error)
NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string) (
tc testapi.TestConsensus, teardown func(), err error)
}
type factory struct{}
// NewFactory creates a new Consensus factory
func NewFactory() Factory {
return &factory{}
}
// NewConsensus instantiates a new Consensus
func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error) {
dbManager := consensusdatabase.New(db)
// Data Structures
acceptanceDataStore := acceptancedatastore.New(200)
blockStore, err := blockstore.New(dbManager, 200)
if err != nil {
return nil, err
}
blockHeaderStore, err := blockheaderstore.New(dbManager, 10_000)
if err != nil {
return nil, err
}
blockRelationStore := blockrelationstore.New(200)
blockStatusStore := blockstatusstore.New(200)
multisetStore := multisetstore.New(200)
pruningStore := pruningstore.New()
reachabilityDataStore := reachabilitydatastore.New(200)
utxoDiffStore := utxodiffstore.New(200)
consensusStateStore := consensusstatestore.New()
ghostdagDataStore := ghostdagdatastore.New(10_000)
headerTipsStore := headertipsstore.New()
// Processes
reachabilityManager := reachabilitymanager.New(
dbManager,
ghostdagDataStore,
reachabilityDataStore)
dagTopologyManager := dagtopologymanager.New(
dbManager,
reachabilityManager,
blockRelationStore)
ghostdagManager := ghostdagmanager.New(
dbManager,
dagTopologyManager,
ghostdagDataStore,
blockHeaderStore,
dagParams.K)
dagTraversalManager := dagtraversalmanager.New(
dbManager,
dagTopologyManager,
ghostdagDataStore,
ghostdagManager)
pastMedianTimeManager := pastmediantimemanager.New(
dagParams.TimestampDeviationTolerance,
dbManager,
dagTraversalManager,
blockHeaderStore,
ghostdagDataStore)
transactionValidator := transactionvalidator.New(dagParams.BlockCoinbaseMaturity,
dagParams.EnableNonNativeSubnetworks,
dagParams.MassPerTxByte,
dagParams.MassPerScriptPubKeyByte,
dagParams.MassPerSigOp,
dagParams.MaxCoinbasePayloadLength,
dbManager,
pastMedianTimeManager,
ghostdagDataStore)
difficultyManager := difficultymanager.New(
dbManager,
ghostdagManager,
ghostdagDataStore,
blockHeaderStore,
dagTopologyManager,
dagTraversalManager,
dagParams.PowMax,
dagParams.DifficultyAdjustmentWindowSize,
dagParams.DisableDifficultyAdjustment,
dagParams.TargetTimePerBlock,
dagParams.GenesisHash)
coinbaseManager := coinbasemanager.New(
dbManager,
dagParams.SubsidyReductionInterval,
dagParams.BaseSubsidy,
dagParams.CoinbasePayloadScriptPublicKeyMaxLength,
ghostdagDataStore,
acceptanceDataStore)
headerTipsManager := headertipsmanager.New(dbManager, dagTopologyManager, ghostdagManager, headerTipsStore)
genesisHash := dagParams.GenesisHash
mergeDepthManager := mergedepthmanager.New(
dagParams.FinalityDepth(),
dbManager,
dagTopologyManager,
dagTraversalManager,
ghostdagDataStore)
blockValidator := blockvalidator.New(
dagParams.PowMax,
dagParams.SkipProofOfWork,
genesisHash,
dagParams.EnableNonNativeSubnetworks,
dagParams.MaxBlockSize,
dagParams.MergeSetSizeLimit,
dagParams.MaxBlockParents,
dbManager,
difficultyManager,
pastMedianTimeManager,
transactionValidator,
ghostdagManager,
dagTopologyManager,
dagTraversalManager,
coinbaseManager,
mergeDepthManager,
pruningStore,
blockStore,
ghostdagDataStore,
blockHeaderStore,
blockStatusStore,
)
consensusStateManager, err := consensusstatemanager.New(
dbManager,
dagParams.FinalityDepth(),
dagParams.PruningDepth(),
dagParams.MaxMassAcceptedByBlock,
dagParams.MaxBlockParents,
dagParams.MergeSetSizeLimit,
genesisHash,
ghostdagManager,
dagTopologyManager,
dagTraversalManager,
pastMedianTimeManager,
transactionValidator,
blockValidator,
reachabilityManager,
coinbaseManager,
mergeDepthManager,
blockStatusStore,
ghostdagDataStore,
consensusStateStore,
multisetStore,
blockStore,
utxoDiffStore,
blockRelationStore,
acceptanceDataStore,
blockHeaderStore,
headerTipsStore)
if err != nil {
return nil, err
}
pruningManager := pruningmanager.New(
dbManager,
dagTraversalManager,
dagTopologyManager,
consensusStateManager,
consensusStateStore,
ghostdagDataStore,
pruningStore,
blockStatusStore,
multisetStore,
acceptanceDataStore,
blockStore,
utxoDiffStore,
genesisHash,
dagParams.FinalityDepth(),
dagParams.PruningDepth())
syncManager := syncmanager.New(
dbManager,
genesisHash,
dagParams.TargetTimePerBlock.Milliseconds(),
dagTraversalManager,
dagTopologyManager,
ghostdagManager,
consensusStateManager,
ghostdagDataStore,
blockStatusStore,
blockHeaderStore,
headerTipsStore,
blockStore)
blockBuilder := blockbuilder.New(
dbManager,
difficultyManager,
pastMedianTimeManager,
coinbaseManager,
consensusStateManager,
ghostdagManager,
acceptanceDataStore,
blockRelationStore,
multisetStore,
ghostdagDataStore,
)
blockProcessor := blockprocessor.New(
genesisHash,
dbManager,
consensusStateManager,
pruningManager,
blockValidator,
dagTopologyManager,
reachabilityManager,
difficultyManager,
pastMedianTimeManager,
ghostdagManager,
coinbaseManager,
headerTipsManager,
syncManager,
acceptanceDataStore,
blockStore,
blockStatusStore,
blockRelationStore,
multisetStore,
ghostdagDataStore,
consensusStateStore,
pruningStore,
reachabilityDataStore,
utxoDiffStore,
blockHeaderStore,
headerTipsStore)
c := &consensus{
lock: &sync.Mutex{},
databaseContext: dbManager,
blockProcessor: blockProcessor,
blockBuilder: blockBuilder,
consensusStateManager: consensusStateManager,
transactionValidator: transactionValidator,
syncManager: syncManager,
pastMedianTimeManager: pastMedianTimeManager,
blockValidator: blockValidator,
coinbaseManager: coinbaseManager,
dagTopologyManager: dagTopologyManager,
dagTraversalManager: dagTraversalManager,
difficultyManager: difficultyManager,
ghostdagManager: ghostdagManager,
headerTipsManager: headerTipsManager,
mergeDepthManager: mergeDepthManager,
pruningManager: pruningManager,
reachabilityManager: reachabilityManager,
acceptanceDataStore: acceptanceDataStore,
blockStore: blockStore,
blockHeaderStore: blockHeaderStore,
pruningStore: pruningStore,
ghostdagDataStore: ghostdagDataStore,
blockStatusStore: blockStatusStore,
blockRelationStore: blockRelationStore,
consensusStateStore: consensusStateStore,
headerTipsStore: headerTipsStore,
multisetStore: multisetStore,
reachabilityDataStore: reachabilityDataStore,
utxoDiffStore: utxoDiffStore,
}
genesisInfo, err := c.GetBlockInfo(genesisHash)
if err != nil {
return nil, err
}
if !genesisInfo.Exists {
err = c.ValidateAndInsertBlock(dagParams.GenesisBlock)
if err != nil {
return nil, err
}
}
return c, nil
}
func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) (
tc testapi.TestConsensus, teardown func(), err error) {
dataDir, err := ioutil.TempDir("", testName)
if err != nil {
return nil, nil, err
}
return f.NewTestConsensusWithDataDir(dagParams, dataDir)
}
func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string) (
tc testapi.TestConsensus, teardown func(), err error) {
db, err := ldb.NewLevelDB(dataDir)
if err != nil {
return nil, nil, err
}
consensusAsInterface, err := f.NewConsensus(dagParams, db)
if err != nil {
return nil, nil, err
}
consensusAsImplementation := consensusAsInterface.(*consensus)
testConsensusStateManager := consensusstatemanager.NewTestConsensusStateManager(consensusAsImplementation.consensusStateManager)
testTransactionValidator := transactionvalidator.NewTestTransactionValidator(consensusAsImplementation.transactionValidator)
tstConsensus := &testConsensus{
consensus: consensusAsImplementation,
testConsensusStateManager: testConsensusStateManager,
testReachabilityManager: reachabilitymanager.NewTestReachabilityManager(consensusAsImplementation.
reachabilityManager),
testTransactionValidator: testTransactionValidator,
}
tstConsensus.testBlockBuilder = blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder, tstConsensus)
teardown = func() {
db.Close()
os.RemoveAll(dataDir)
}
return tstConsensus, teardown, nil
}