kaspad/domain/domain.go
Ori Newman d207888b67
Implement pruned headers node (#1787)
* Pruning headers p2p basic structure

* Remove headers-first

* Fix consensus tests except TestValidateAndInsertPruningPointWithSideBlocks and TestValidateAndInsertImportedPruningPoint

* Add virtual genesis

* Implement PruningPointAndItsAnticoneWithMetaData

* Start fixing TestValidateAndInsertImportedPruningPoint

* Fix TestValidateAndInsertImportedPruningPoint

* Fix BlockWindow

* Update p2p and gRPC

* Fix all tests except TestHandleRelayInvs

* Delete TestHandleRelayInvs parts that cover the old IBD flow

* Fix lint errors

* Add p2p_request_ibd_blocks.go

* Clean code

* Make MsgBlockWithMetaData implement its own representation

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

* Fix TestCheckLockTimeVerifyConditionedByAbsoluteTimeWithWrongLockTime

* Fix comments, errors ane names

* Fix window size to the real value

* Check reindex root after each block at TestUpdateReindexRoot

* Remove irrelevant check

* Renames and comments

* Remove redundant argument from sendGetBlockLocator

* Don't delete staging on non-recoverable errors

* Renames and comments

* Remove redundant code

* Commit changes inside ResolveVirtual

* Add comment to IsRecoverableError

* Remove blocksWithMetaDataGHOSTDAGDataStore

* Increase windows pagefile

* Move DeleteStagingConsensus outside of defer

* Get rid of mustAccepted in receiveBlockWithMetaData

* Ban on invalid pruning point

* Rename interface_datastructures_daawindowstore.go to interface_datastructures_blocks_with_meta_data_daa_window_store.go

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

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

* Change virtual genesis hash

* replace the selected parent with virtual genesis on removePrunedBlocksFromGHOSTDAGData

* Get rid of low hash in block locators

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

* Add comments about consensus wrapper

* Don't use separate staging area when resolving resolveBlockStatus

* Fix netsync stability test

* Fix checkResolveVirtual

* Rename ConsensusWrapper->ConsensusReference

* Get rid of blockHeapNode

* Add comment to defaultDifficultyAdjustmentWindowSize

* Add SelectedChild to DAGTraversalManager

* Remove redundant copy

* Rename blockWindowHeap->calculateBlockWindowHeap

* Move isVirtualGenesisOnlyParent to utils

* Change BlockWithMetaData->BlockWithTrustedData

* Get rid of maxReasonLength

* Split IBD to 100 blocks each time

* Fix a bug in calculateBlockWindowHeap

* Switch to trusted data when encountering virtual genesis in blockWithTrustedData

* Move ConsensusReference to domain

* Update ConsensusReference comment

* Add comment

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

204 lines
5.1 KiB
Go

package domain
import (
"github.com/kaspanet/kaspad/domain/consensusreference"
"sync"
"sync/atomic"
"unsafe"
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/miningmanager"
"github.com/kaspanet/kaspad/domain/miningmanager/mempool"
"github.com/kaspanet/kaspad/domain/prefixmanager"
"github.com/kaspanet/kaspad/domain/prefixmanager/prefix"
infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database"
"github.com/pkg/errors"
)
// Domain provides a reference to the domain's external aps
type Domain interface {
MiningManager() miningmanager.MiningManager
Consensus() externalapi.Consensus
StagingConsensus() externalapi.Consensus
InitStagingConsensus() error
CommitStagingConsensus() error
DeleteStagingConsensus() error
}
type domain struct {
miningManager miningmanager.MiningManager
consensus *externalapi.Consensus
stagingConsensus *externalapi.Consensus
stagingConsensusLock sync.RWMutex
consensusConfig *consensus.Config
db infrastructuredatabase.Database
}
func (d *domain) Consensus() externalapi.Consensus {
return *d.consensus
}
func (d *domain) StagingConsensus() externalapi.Consensus {
d.stagingConsensusLock.RLock()
defer d.stagingConsensusLock.RUnlock()
return *d.stagingConsensus
}
func (d *domain) MiningManager() miningmanager.MiningManager {
return d.miningManager
}
func (d *domain) InitStagingConsensus() error {
d.stagingConsensusLock.Lock()
defer d.stagingConsensusLock.Unlock()
_, hasInactivePrefix, err := prefixmanager.InactivePrefix(d.db)
if err != nil {
return err
}
if hasInactivePrefix {
return errors.Errorf("cannot create staging consensus when a staging consensus already exists")
}
activePrefix, exists, err := prefixmanager.ActivePrefix(d.db)
if err != nil {
return err
}
if !exists {
return errors.Errorf("cannot create a staging consensus when there's " +
"no active consensus")
}
inactivePrefix := activePrefix.Flip()
err = prefixmanager.SetPrefixAsInactive(d.db, inactivePrefix)
if err != nil {
return err
}
consensusFactory := consensus.NewFactory()
cfg := *d.consensusConfig
cfg.SkipAddingGenesis = true
consensusInstance, err := consensusFactory.NewConsensus(&cfg, d.db, inactivePrefix)
if err != nil {
return err
}
d.stagingConsensus = &consensusInstance
return nil
}
func (d *domain) CommitStagingConsensus() error {
d.stagingConsensusLock.Lock()
defer d.stagingConsensusLock.Unlock()
dbTx, err := d.db.Begin()
if err != nil {
return err
}
defer dbTx.RollbackUnlessClosed()
inactivePrefix, hasInactivePrefix, err := prefixmanager.InactivePrefix(d.db)
if err != nil {
return err
}
if !hasInactivePrefix {
return errors.Errorf("there's no inactive prefix to commit")
}
activePrefix, exists, err := prefixmanager.ActivePrefix(dbTx)
if err != nil {
return err
}
if !exists {
return errors.Errorf("cannot commit a staging consensus when there's " +
"no active consensus")
}
err = prefixmanager.SetPrefixAsActive(dbTx, inactivePrefix)
if err != nil {
return err
}
err = prefixmanager.SetPrefixAsInactive(dbTx, activePrefix)
if err != nil {
return err
}
err = dbTx.Commit()
if err != nil {
return err
}
// We delete anything associated with the old prefix outside
// of the transaction in order to save memory.
err = prefixmanager.DeleteInactivePrefix(d.db)
if err != nil {
return err
}
tempConsensusPointer := unsafe.Pointer(d.stagingConsensus)
consensusPointer := (*unsafe.Pointer)(unsafe.Pointer(&d.consensus))
atomic.StorePointer(consensusPointer, tempConsensusPointer)
d.stagingConsensus = nil
return nil
}
func (d *domain) DeleteStagingConsensus() error {
d.stagingConsensusLock.Lock()
defer d.stagingConsensusLock.Unlock()
err := prefixmanager.DeleteInactivePrefix(d.db)
if err != nil {
return err
}
d.stagingConsensus = nil
return nil
}
// New instantiates a new instance of a Domain object
func New(consensusConfig *consensus.Config, mempoolConfig *mempool.Config, db infrastructuredatabase.Database) (Domain, error) {
err := prefixmanager.DeleteInactivePrefix(db)
if err != nil {
return nil, err
}
activePrefix, exists, err := prefixmanager.ActivePrefix(db)
if err != nil {
return nil, err
}
if !exists {
activePrefix = &prefix.Prefix{}
err = prefixmanager.SetPrefixAsActive(db, activePrefix)
if err != nil {
return nil, err
}
}
consensusFactory := consensus.NewFactory()
consensusInstance, err := consensusFactory.NewConsensus(consensusConfig, db, activePrefix)
if err != nil {
return nil, err
}
domainInstance := &domain{
consensus: &consensusInstance,
consensusConfig: consensusConfig,
db: db,
}
miningManagerFactory := miningmanager.NewFactory()
// We create a consensus wrapper because the actual consensus might change
consensusReference := consensusreference.NewConsensusReference(&domainInstance.consensus)
domainInstance.miningManager = miningManagerFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempoolConfig)
return domainInstance, nil
}