mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
743 lines
24 KiB
Go
743 lines
24 KiB
Go
package consensus
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"sync"
|
|
|
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/blockwindowheapslicestore"
|
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/daawindowstore"
|
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/mergedepthrootstore"
|
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
|
"github.com/kaspanet/kaspad/domain/consensus/processes/blockparentbuilder"
|
|
parentssanager "github.com/kaspanet/kaspad/domain/consensus/processes/parentsmanager"
|
|
"github.com/kaspanet/kaspad/domain/consensus/processes/pruningproofmanager"
|
|
"github.com/kaspanet/kaspad/util/staging"
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/kaspanet/kaspad/domain/prefixmanager/prefix"
|
|
"github.com/kaspanet/kaspad/util/txmass"
|
|
|
|
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/daablocksstore"
|
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/finalitystore"
|
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/ghostdagdatastore"
|
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headersselectedchainstore"
|
|
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headersselectedtipstore"
|
|
"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/dagtraversalmanager"
|
|
"github.com/kaspanet/kaspad/domain/consensus/processes/difficultymanager"
|
|
"github.com/kaspanet/kaspad/domain/consensus/processes/finalitymanager"
|
|
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
|
|
"github.com/kaspanet/kaspad/domain/consensus/processes/headersselectedtipmanager"
|
|
"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"
|
|
"github.com/kaspanet/kaspad/infrastructure/db/database/ldb"
|
|
)
|
|
|
|
const (
|
|
defaultTestLeveldbCacheSizeMiB = 8
|
|
defaultPreallocateCaches = true
|
|
defaultTestPreallocateCaches = false
|
|
)
|
|
|
|
// Config is the full config required to run consensus
|
|
type Config struct {
|
|
dagconfig.Params
|
|
// IsArchival tells the consensus if it should not prune old blocks
|
|
IsArchival bool
|
|
// EnableSanityCheckPruningUTXOSet checks the full pruning point utxo set against the commitment at every pruning movement
|
|
EnableSanityCheckPruningUTXOSet bool
|
|
|
|
SkipAddingGenesis bool
|
|
}
|
|
|
|
// Factory instantiates new Consensuses
|
|
type Factory interface {
|
|
NewConsensus(config *Config, db infrastructuredatabase.Database, dbPrefix *prefix.Prefix,
|
|
consensusEventsChan chan externalapi.ConsensusEvent) (
|
|
externalapi.Consensus, bool, error)
|
|
NewTestConsensus(config *Config, testName string) (
|
|
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error)
|
|
|
|
SetTestDataDir(dataDir string)
|
|
SetTestGHOSTDAGManager(ghostdagConstructor GHOSTDAGManagerConstructor)
|
|
SetTestLevelDBCacheSize(cacheSizeMiB int)
|
|
SetTestPreAllocateCache(preallocateCaches bool)
|
|
SetTestPastMedianTimeManager(medianTimeConstructor PastMedianTimeManagerConstructor)
|
|
SetTestDifficultyManager(difficultyConstructor DifficultyManagerConstructor)
|
|
}
|
|
|
|
type factory struct {
|
|
dataDir string
|
|
ghostdagConstructor GHOSTDAGManagerConstructor
|
|
pastMedianTimeConsructor PastMedianTimeManagerConstructor
|
|
difficultyConstructor DifficultyManagerConstructor
|
|
cacheSizeMiB *int
|
|
preallocateCaches *bool
|
|
}
|
|
|
|
// NewFactory creates a new Consensus factory
|
|
func NewFactory() Factory {
|
|
return &factory{
|
|
ghostdagConstructor: ghostdagmanager.New,
|
|
pastMedianTimeConsructor: pastmediantimemanager.New,
|
|
difficultyConstructor: difficultymanager.New,
|
|
}
|
|
}
|
|
|
|
// NewConsensus instantiates a new Consensus
|
|
func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Database, dbPrefix *prefix.Prefix,
|
|
consensusEventsChan chan externalapi.ConsensusEvent) (
|
|
consensusInstance externalapi.Consensus, shouldMigrate bool, err error) {
|
|
|
|
dbManager := consensusdatabase.New(db)
|
|
prefixBucket := consensusdatabase.MakeBucket(dbPrefix.Serialize())
|
|
|
|
pruningWindowSizeForCaches := int(config.PruningDepth())
|
|
|
|
var preallocateCaches bool
|
|
if f.preallocateCaches != nil {
|
|
preallocateCaches = *f.preallocateCaches
|
|
} else {
|
|
preallocateCaches = defaultPreallocateCaches
|
|
}
|
|
|
|
// This is used for caches that are used as part of deletePastBlocks that need to traverse until
|
|
// the previous pruning point.
|
|
pruningWindowSizePlusFinalityDepthForCache := int(config.PruningDepth() + config.FinalityDepth())
|
|
|
|
// Data Structures
|
|
mergeDepthRootStore := mergedepthrootstore.New(prefixBucket, 200, preallocateCaches)
|
|
daaWindowStore := daawindowstore.New(prefixBucket, 10_000, preallocateCaches)
|
|
acceptanceDataStore := acceptancedatastore.New(prefixBucket, 200, preallocateCaches)
|
|
blockStore, err := blockstore.New(dbManager, prefixBucket, 200, preallocateCaches)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
blockHeaderStore, err := blockheaderstore.New(dbManager, prefixBucket, 10_000, preallocateCaches)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
blockStatusStore := blockstatusstore.New(prefixBucket, pruningWindowSizePlusFinalityDepthForCache, preallocateCaches)
|
|
multisetStore := multisetstore.New(prefixBucket, 200, preallocateCaches)
|
|
pruningStore := pruningstore.New(prefixBucket, 2, preallocateCaches)
|
|
utxoDiffStore := utxodiffstore.New(prefixBucket, 200, preallocateCaches)
|
|
consensusStateStore := consensusstatestore.New(prefixBucket, 10_000, preallocateCaches)
|
|
|
|
headersSelectedTipStore := headersselectedtipstore.New(prefixBucket)
|
|
finalityStore := finalitystore.New(prefixBucket, 200, preallocateCaches)
|
|
headersSelectedChainStore := headersselectedchainstore.New(prefixBucket, pruningWindowSizeForCaches, preallocateCaches)
|
|
daaBlocksStore := daablocksstore.New(prefixBucket, pruningWindowSizeForCaches, int(config.FinalityDepth()), preallocateCaches)
|
|
windowHeapSliceStore := blockwindowheapslicestore.New(2000, preallocateCaches)
|
|
|
|
newReachabilityDataStore := reachabilitydatastore.New(prefixBucket, pruningWindowSizePlusFinalityDepthForCache*2, preallocateCaches)
|
|
blockRelationStores, reachabilityDataStores, ghostdagDataStores := dagStores(config, prefixBucket, pruningWindowSizePlusFinalityDepthForCache, pruningWindowSizeForCaches, preallocateCaches)
|
|
oldReachabilityManager := reachabilitymanager.New(
|
|
dbManager,
|
|
ghostdagDataStores[0],
|
|
reachabilityDataStores[0])
|
|
isOldReachabilityInitialized, err := reachabilityDataStores[0].HasReachabilityData(dbManager, model.NewStagingArea(), model.VirtualGenesisBlockHash)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
newReachabilityManager := reachabilitymanager.New(
|
|
dbManager,
|
|
ghostdagDataStores[0],
|
|
newReachabilityDataStore)
|
|
reachabilityManager := newReachabilityManager
|
|
if isOldReachabilityInitialized {
|
|
reachabilityManager = oldReachabilityManager
|
|
} else {
|
|
for i := range reachabilityDataStores {
|
|
reachabilityDataStores[i] = newReachabilityDataStore
|
|
}
|
|
}
|
|
reachabilityDataStore := reachabilityDataStores[0]
|
|
|
|
dagTopologyManagers, ghostdagManagers, dagTraversalManagers := f.dagProcesses(config, dbManager, blockHeaderStore, daaWindowStore, windowHeapSliceStore, blockRelationStores, reachabilityDataStores, ghostdagDataStores, isOldReachabilityInitialized)
|
|
|
|
blockRelationStore := blockRelationStores[0]
|
|
|
|
ghostdagDataStore := ghostdagDataStores[0]
|
|
|
|
dagTopologyManager := dagTopologyManagers[0]
|
|
ghostdagManager := ghostdagManagers[0]
|
|
dagTraversalManager := dagTraversalManagers[0]
|
|
|
|
// Processes
|
|
parentsManager := parentssanager.New(config.GenesisHash, config.MaxBlockLevel)
|
|
blockParentBuilder := blockparentbuilder.New(
|
|
dbManager,
|
|
blockHeaderStore,
|
|
dagTopologyManager,
|
|
parentsManager,
|
|
reachabilityDataStore,
|
|
pruningStore,
|
|
|
|
config.GenesisHash,
|
|
config.MaxBlockLevel,
|
|
)
|
|
|
|
txMassCalculator := txmass.NewCalculator(config.MassPerTxByte, config.MassPerScriptPubKeyByte, config.MassPerSigOp)
|
|
|
|
pastMedianTimeManager := f.pastMedianTimeConsructor(
|
|
config.TimestampDeviationTolerance,
|
|
dbManager,
|
|
dagTraversalManager,
|
|
blockHeaderStore,
|
|
ghostdagDataStore,
|
|
config.GenesisHash)
|
|
transactionValidator := transactionvalidator.New(config.BlockCoinbaseMaturity,
|
|
config.EnableNonNativeSubnetworks,
|
|
config.MaxCoinbasePayloadLength,
|
|
config.K,
|
|
config.CoinbasePayloadScriptPublicKeyMaxLength,
|
|
dbManager,
|
|
pastMedianTimeManager,
|
|
ghostdagDataStore,
|
|
daaBlocksStore,
|
|
txMassCalculator)
|
|
difficultyManager := f.difficultyConstructor(
|
|
dbManager,
|
|
ghostdagManager,
|
|
ghostdagDataStore,
|
|
blockHeaderStore,
|
|
daaBlocksStore,
|
|
dagTopologyManager,
|
|
dagTraversalManager,
|
|
config.PowMax,
|
|
config.DifficultyAdjustmentWindowSize,
|
|
config.DisableDifficultyAdjustment,
|
|
config.TargetTimePerBlock,
|
|
config.GenesisHash,
|
|
config.GenesisBlock.Header.Bits())
|
|
coinbaseManager := coinbasemanager.New(
|
|
dbManager,
|
|
|
|
config.SubsidyGenesisReward,
|
|
config.PreDeflationaryPhaseBaseSubsidy,
|
|
config.CoinbasePayloadScriptPublicKeyMaxLength,
|
|
config.GenesisHash,
|
|
config.DeflationaryPhaseDaaScore,
|
|
config.DeflationaryPhaseBaseSubsidy,
|
|
|
|
dagTraversalManager,
|
|
ghostdagDataStore,
|
|
acceptanceDataStore,
|
|
daaBlocksStore,
|
|
blockStore,
|
|
pruningStore,
|
|
blockHeaderStore)
|
|
headerTipsManager := headersselectedtipmanager.New(dbManager, dagTopologyManager, dagTraversalManager,
|
|
ghostdagManager, headersSelectedTipStore, headersSelectedChainStore)
|
|
genesisHash := config.GenesisHash
|
|
finalityManager := finalitymanager.New(
|
|
dbManager,
|
|
dagTopologyManager,
|
|
finalityStore,
|
|
ghostdagDataStore,
|
|
pruningStore,
|
|
genesisHash,
|
|
config.FinalityDepth())
|
|
mergeDepthManager := mergedepthmanager.New(
|
|
dbManager,
|
|
dagTopologyManager,
|
|
dagTraversalManager,
|
|
finalityManager,
|
|
genesisHash,
|
|
config.MergeDepth,
|
|
ghostdagDataStore,
|
|
mergeDepthRootStore,
|
|
daaBlocksStore,
|
|
pruningStore,
|
|
finalityStore)
|
|
consensusStateManager, err := consensusstatemanager.New(
|
|
dbManager,
|
|
config.MaxBlockParents,
|
|
config.MergeSetSizeLimit,
|
|
genesisHash,
|
|
|
|
ghostdagManager,
|
|
dagTopologyManager,
|
|
dagTraversalManager,
|
|
pastMedianTimeManager,
|
|
transactionValidator,
|
|
coinbaseManager,
|
|
mergeDepthManager,
|
|
finalityManager,
|
|
difficultyManager,
|
|
|
|
blockStatusStore,
|
|
ghostdagDataStore,
|
|
consensusStateStore,
|
|
multisetStore,
|
|
blockStore,
|
|
utxoDiffStore,
|
|
blockRelationStore,
|
|
acceptanceDataStore,
|
|
blockHeaderStore,
|
|
headersSelectedTipStore,
|
|
pruningStore,
|
|
daaBlocksStore)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
pruningManager := pruningmanager.New(
|
|
dbManager,
|
|
dagTraversalManager,
|
|
dagTopologyManager,
|
|
consensusStateManager,
|
|
finalityManager,
|
|
|
|
consensusStateStore,
|
|
ghostdagDataStore,
|
|
pruningStore,
|
|
blockStatusStore,
|
|
headersSelectedTipStore,
|
|
multisetStore,
|
|
acceptanceDataStore,
|
|
blockStore,
|
|
blockHeaderStore,
|
|
utxoDiffStore,
|
|
daaBlocksStore,
|
|
reachabilityDataStore,
|
|
daaWindowStore,
|
|
|
|
config.IsArchival,
|
|
genesisHash,
|
|
config.FinalityDepth(),
|
|
config.PruningDepth(),
|
|
config.EnableSanityCheckPruningUTXOSet,
|
|
config.K,
|
|
config.DifficultyAdjustmentWindowSize,
|
|
)
|
|
|
|
blockValidator := blockvalidator.New(
|
|
config.PowMax,
|
|
config.SkipProofOfWork,
|
|
genesisHash,
|
|
config.EnableNonNativeSubnetworks,
|
|
config.MaxBlockMass,
|
|
config.MergeSetSizeLimit,
|
|
config.MaxBlockParents,
|
|
config.TimestampDeviationTolerance,
|
|
config.TargetTimePerBlock,
|
|
config.MaxBlockLevel,
|
|
|
|
dbManager,
|
|
difficultyManager,
|
|
pastMedianTimeManager,
|
|
transactionValidator,
|
|
ghostdagManagers,
|
|
dagTopologyManagers,
|
|
dagTraversalManager,
|
|
coinbaseManager,
|
|
mergeDepthManager,
|
|
reachabilityManager,
|
|
finalityManager,
|
|
blockParentBuilder,
|
|
pruningManager,
|
|
parentsManager,
|
|
|
|
pruningStore,
|
|
blockStore,
|
|
ghostdagDataStores,
|
|
blockHeaderStore,
|
|
blockStatusStore,
|
|
reachabilityDataStore,
|
|
consensusStateStore,
|
|
daaBlocksStore,
|
|
|
|
txMassCalculator,
|
|
)
|
|
|
|
syncManager := syncmanager.New(
|
|
dbManager,
|
|
genesisHash,
|
|
config.MergeSetSizeLimit,
|
|
dagTraversalManager,
|
|
dagTopologyManager,
|
|
ghostdagManager,
|
|
pruningManager,
|
|
|
|
ghostdagDataStore,
|
|
blockStatusStore,
|
|
blockHeaderStore,
|
|
blockStore,
|
|
pruningStore,
|
|
headersSelectedChainStore)
|
|
|
|
blockBuilder := blockbuilder.New(
|
|
dbManager,
|
|
genesisHash,
|
|
|
|
difficultyManager,
|
|
pastMedianTimeManager,
|
|
coinbaseManager,
|
|
consensusStateManager,
|
|
ghostdagManager,
|
|
transactionValidator,
|
|
finalityManager,
|
|
blockParentBuilder,
|
|
pruningManager,
|
|
|
|
acceptanceDataStore,
|
|
blockRelationStore,
|
|
multisetStore,
|
|
ghostdagDataStore,
|
|
daaBlocksStore,
|
|
)
|
|
|
|
blockProcessor := blockprocessor.New(
|
|
genesisHash,
|
|
config.TargetTimePerBlock,
|
|
config.MaxBlockLevel,
|
|
dbManager,
|
|
consensusStateManager,
|
|
pruningManager,
|
|
blockValidator,
|
|
dagTopologyManager,
|
|
reachabilityManager,
|
|
difficultyManager,
|
|
pastMedianTimeManager,
|
|
coinbaseManager,
|
|
headerTipsManager,
|
|
syncManager,
|
|
|
|
acceptanceDataStore,
|
|
blockStore,
|
|
blockStatusStore,
|
|
blockRelationStore,
|
|
multisetStore,
|
|
ghostdagDataStore,
|
|
consensusStateStore,
|
|
pruningStore,
|
|
reachabilityDataStore,
|
|
utxoDiffStore,
|
|
blockHeaderStore,
|
|
headersSelectedTipStore,
|
|
finalityStore,
|
|
headersSelectedChainStore,
|
|
daaBlocksStore,
|
|
daaWindowStore)
|
|
|
|
pruningProofManager := pruningproofmanager.New(
|
|
dbManager,
|
|
dagTopologyManagers,
|
|
ghostdagManagers,
|
|
reachabilityManager,
|
|
dagTraversalManagers,
|
|
parentsManager,
|
|
pruningManager,
|
|
|
|
ghostdagDataStores,
|
|
pruningStore,
|
|
blockHeaderStore,
|
|
blockStatusStore,
|
|
finalityStore,
|
|
consensusStateStore,
|
|
blockRelationStore,
|
|
reachabilityDataStore,
|
|
|
|
genesisHash,
|
|
config.K,
|
|
config.PruningProofM,
|
|
config.MaxBlockLevel,
|
|
)
|
|
|
|
c := &consensus{
|
|
lock: &sync.Mutex{},
|
|
databaseContext: dbManager,
|
|
|
|
genesisBlock: config.GenesisBlock,
|
|
genesisHash: config.GenesisHash,
|
|
|
|
expectedDAAWindowDurationInMilliseconds: config.TargetTimePerBlock.Milliseconds() *
|
|
int64(config.DifficultyAdjustmentWindowSize),
|
|
|
|
blockProcessor: blockProcessor,
|
|
blockBuilder: blockBuilder,
|
|
consensusStateManager: consensusStateManager,
|
|
transactionValidator: transactionValidator,
|
|
syncManager: syncManager,
|
|
pastMedianTimeManager: pastMedianTimeManager,
|
|
blockValidator: blockValidator,
|
|
coinbaseManager: coinbaseManager,
|
|
dagTopologyManagers: dagTopologyManagers,
|
|
dagTraversalManager: dagTraversalManager,
|
|
difficultyManager: difficultyManager,
|
|
ghostdagManagers: ghostdagManagers,
|
|
headerTipsManager: headerTipsManager,
|
|
mergeDepthManager: mergeDepthManager,
|
|
pruningManager: pruningManager,
|
|
reachabilityManager: reachabilityManager,
|
|
finalityManager: finalityManager,
|
|
pruningProofManager: pruningProofManager,
|
|
|
|
acceptanceDataStore: acceptanceDataStore,
|
|
blockStore: blockStore,
|
|
blockHeaderStore: blockHeaderStore,
|
|
pruningStore: pruningStore,
|
|
ghostdagDataStores: ghostdagDataStores,
|
|
blockStatusStore: blockStatusStore,
|
|
blockRelationStores: blockRelationStores,
|
|
consensusStateStore: consensusStateStore,
|
|
headersSelectedTipStore: headersSelectedTipStore,
|
|
multisetStore: multisetStore,
|
|
reachabilityDataStore: reachabilityDataStore,
|
|
utxoDiffStore: utxoDiffStore,
|
|
finalityStore: finalityStore,
|
|
headersSelectedChainStore: headersSelectedChainStore,
|
|
daaBlocksStore: daaBlocksStore,
|
|
blocksWithTrustedDataDAAWindowStore: daaWindowStore,
|
|
|
|
consensusEventsChan: consensusEventsChan,
|
|
virtualNotUpdated: true,
|
|
}
|
|
|
|
if isOldReachabilityInitialized {
|
|
return c, true, nil
|
|
}
|
|
|
|
err = c.Init(config.SkipAddingGenesis)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
err = consensusStateManager.RecoverUTXOIfRequired()
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
err = pruningManager.ClearImportedPruningPointData()
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
err = pruningManager.UpdatePruningPointIfRequired()
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
// If the virtual moved before shutdown but the pruning point hasn't, we
|
|
// move it if needed.
|
|
stagingArea := model.NewStagingArea()
|
|
err = pruningManager.UpdatePruningPointByVirtual(stagingArea)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
err = staging.CommitAllChanges(dbManager, stagingArea)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
err = pruningManager.UpdatePruningPointIfRequired()
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
return c, false, nil
|
|
}
|
|
|
|
func (f *factory) NewTestConsensus(config *Config, testName string) (
|
|
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) {
|
|
datadir := f.dataDir
|
|
if datadir == "" {
|
|
datadir, err = ioutil.TempDir("", testName)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
var cacheSizeMiB int
|
|
if f.cacheSizeMiB != nil {
|
|
cacheSizeMiB = *f.cacheSizeMiB
|
|
} else {
|
|
cacheSizeMiB = defaultTestLeveldbCacheSizeMiB
|
|
}
|
|
if f.preallocateCaches == nil {
|
|
f.SetTestPreAllocateCache(defaultTestPreallocateCaches)
|
|
}
|
|
db, err := ldb.NewLevelDB(datadir, cacheSizeMiB)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
testConsensusDBPrefix := &prefix.Prefix{}
|
|
consensusAsInterface, shouldMigrate, err := f.NewConsensus(config, db, testConsensusDBPrefix, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
if shouldMigrate {
|
|
return nil, nil, errors.Errorf("A fresh consensus should never return shouldMigrate=true")
|
|
}
|
|
|
|
consensusAsImplementation := consensusAsInterface.(*consensus)
|
|
testConsensusStateManager := consensusstatemanager.NewTestConsensusStateManager(consensusAsImplementation.consensusStateManager)
|
|
testTransactionValidator := transactionvalidator.NewTestTransactionValidator(consensusAsImplementation.transactionValidator)
|
|
|
|
tstConsensus := &testConsensus{
|
|
dagParams: &config.Params,
|
|
consensus: consensusAsImplementation,
|
|
database: db,
|
|
testConsensusStateManager: testConsensusStateManager,
|
|
testReachabilityManager: reachabilitymanager.NewTestReachabilityManager(consensusAsImplementation.
|
|
reachabilityManager),
|
|
testTransactionValidator: testTransactionValidator,
|
|
}
|
|
tstConsensus.testBlockBuilder = blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder, tstConsensus)
|
|
teardown = func(keepDataDir bool) {
|
|
db.Close()
|
|
if !keepDataDir {
|
|
err := os.RemoveAll(f.dataDir)
|
|
if err != nil {
|
|
log.Errorf("Error removing data directory for test consensus: %s", err)
|
|
}
|
|
}
|
|
}
|
|
return tstConsensus, teardown, nil
|
|
}
|
|
|
|
func (f *factory) SetTestDataDir(dataDir string) {
|
|
f.dataDir = dataDir
|
|
}
|
|
|
|
func (f *factory) SetTestGHOSTDAGManager(ghostdagConstructor GHOSTDAGManagerConstructor) {
|
|
f.ghostdagConstructor = ghostdagConstructor
|
|
}
|
|
|
|
func (f *factory) SetTestPastMedianTimeManager(medianTimeConstructor PastMedianTimeManagerConstructor) {
|
|
f.pastMedianTimeConsructor = medianTimeConstructor
|
|
}
|
|
|
|
// SetTestDifficultyManager is a setter for the difficultyManager field on the factory.
|
|
func (f *factory) SetTestDifficultyManager(difficultyConstructor DifficultyManagerConstructor) {
|
|
f.difficultyConstructor = difficultyConstructor
|
|
}
|
|
|
|
func (f *factory) SetTestLevelDBCacheSize(cacheSizeMiB int) {
|
|
f.cacheSizeMiB = &cacheSizeMiB
|
|
}
|
|
func (f *factory) SetTestPreAllocateCache(preallocateCaches bool) {
|
|
f.preallocateCaches = &preallocateCaches
|
|
}
|
|
|
|
func dagStores(config *Config,
|
|
prefixBucket model.DBBucket,
|
|
pruningWindowSizePlusFinalityDepthForCache, pruningWindowSizeForCaches int,
|
|
preallocateCaches bool) ([]model.BlockRelationStore, []model.ReachabilityDataStore, []model.GHOSTDAGDataStore) {
|
|
|
|
blockRelationStores := make([]model.BlockRelationStore, config.MaxBlockLevel+1)
|
|
reachabilityDataStores := make([]model.ReachabilityDataStore, config.MaxBlockLevel+1)
|
|
ghostdagDataStores := make([]model.GHOSTDAGDataStore, config.MaxBlockLevel+1)
|
|
|
|
ghostdagDataCacheSize := pruningWindowSizeForCaches * 2
|
|
if ghostdagDataCacheSize < config.DifficultyAdjustmentWindowSize {
|
|
ghostdagDataCacheSize = config.DifficultyAdjustmentWindowSize
|
|
}
|
|
|
|
for i := 0; i <= config.MaxBlockLevel; i++ {
|
|
prefixBucket := prefixBucket.Bucket([]byte{byte(i)})
|
|
if i == 0 {
|
|
blockRelationStores[i] = blockrelationstore.New(prefixBucket, pruningWindowSizePlusFinalityDepthForCache, preallocateCaches)
|
|
reachabilityDataStores[i] = reachabilitydatastore.New(prefixBucket, pruningWindowSizePlusFinalityDepthForCache*2, preallocateCaches)
|
|
ghostdagDataStores[i] = ghostdagdatastore.New(prefixBucket, ghostdagDataCacheSize, preallocateCaches)
|
|
} else {
|
|
blockRelationStores[i] = blockrelationstore.New(prefixBucket, 200, false)
|
|
reachabilityDataStores[i] = reachabilitydatastore.New(prefixBucket, pruningWindowSizePlusFinalityDepthForCache, false)
|
|
ghostdagDataStores[i] = ghostdagdatastore.New(prefixBucket, 200, false)
|
|
}
|
|
}
|
|
|
|
return blockRelationStores, reachabilityDataStores, ghostdagDataStores
|
|
}
|
|
|
|
func (f *factory) dagProcesses(config *Config,
|
|
dbManager model.DBManager,
|
|
blockHeaderStore model.BlockHeaderStore,
|
|
daaWindowStore model.BlocksWithTrustedDataDAAWindowStore,
|
|
windowHeapSliceStore model.WindowHeapSliceStore,
|
|
blockRelationStores []model.BlockRelationStore,
|
|
reachabilityDataStores []model.ReachabilityDataStore,
|
|
ghostdagDataStores []model.GHOSTDAGDataStore,
|
|
isOldReachabilityInitialized bool) (
|
|
[]model.DAGTopologyManager,
|
|
[]model.GHOSTDAGManager,
|
|
[]model.DAGTraversalManager,
|
|
) {
|
|
|
|
reachabilityManagers := make([]model.ReachabilityManager, config.MaxBlockLevel+1)
|
|
dagTopologyManagers := make([]model.DAGTopologyManager, config.MaxBlockLevel+1)
|
|
ghostdagManagers := make([]model.GHOSTDAGManager, config.MaxBlockLevel+1)
|
|
dagTraversalManagers := make([]model.DAGTraversalManager, config.MaxBlockLevel+1)
|
|
|
|
newReachabilityManager := reachabilitymanager.New(
|
|
dbManager,
|
|
ghostdagDataStores[0],
|
|
reachabilityDataStores[0])
|
|
|
|
for i := 0; i <= config.MaxBlockLevel; i++ {
|
|
if isOldReachabilityInitialized {
|
|
reachabilityManagers[i] = reachabilitymanager.New(
|
|
dbManager,
|
|
ghostdagDataStores[i],
|
|
reachabilityDataStores[i])
|
|
} else {
|
|
reachabilityManagers[i] = newReachabilityManager
|
|
}
|
|
|
|
dagTopologyManagers[i] = dagtopologymanager.New(
|
|
dbManager,
|
|
reachabilityManagers[i],
|
|
blockRelationStores[i],
|
|
ghostdagDataStores[i])
|
|
|
|
ghostdagManagers[i] = f.ghostdagConstructor(
|
|
dbManager,
|
|
dagTopologyManagers[i],
|
|
ghostdagDataStores[i],
|
|
blockHeaderStore,
|
|
config.K,
|
|
config.GenesisHash)
|
|
|
|
dagTraversalManagers[i] = dagtraversalmanager.New(
|
|
dbManager,
|
|
dagTopologyManagers[i],
|
|
ghostdagDataStores[i],
|
|
reachabilityManagers[i],
|
|
ghostdagManagers[i],
|
|
daaWindowStore,
|
|
windowHeapSliceStore,
|
|
config.GenesisHash,
|
|
config.DifficultyAdjustmentWindowSize)
|
|
}
|
|
|
|
return dagTopologyManagers, ghostdagManagers, dagTraversalManagers
|
|
}
|