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

150 lines
4.3 KiB
Go

package mine
import (
"math/rand"
"path/filepath"
"strings"
"time"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/domain/consensus/utils/mining"
"github.com/kaspanet/kaspad/stability-tests/common/rpc"
"github.com/pkg/errors"
)
// FromFile mines all blocks as described by `jsonFile`
func FromFile(jsonFile string, consensusConfig *consensus.Config, rpcClient *rpc.Client, dataDir string) error {
log.Infof("Mining blocks from JSON file %s from data directory %s", jsonFile, dataDir)
blockChan, err := readBlocks(jsonFile)
if err != nil {
return err
}
return mineBlocks(consensusConfig, rpcClient, blockChan, dataDir)
}
func mineBlocks(consensusConfig *consensus.Config, rpcClient *rpc.Client, blockChan <-chan JSONBlock, dataDir string) error {
mdb, err := newMiningDB(dataDir)
if err != nil {
return err
}
dbPath := filepath.Join(dataDir, "db")
factory := consensus.NewFactory()
factory.SetTestDataDir(dbPath)
testConsensus, tearDownFunc, err := factory.NewTestConsensus(consensusConfig, "minejson")
if err != nil {
return err
}
defer tearDownFunc(true)
info, err := testConsensus.GetSyncInfo()
if err != nil {
return err
}
log.Infof("Starting with data directory with %d headers and %d blocks", info.HeaderCount, info.BlockCount)
err = mdb.putID("0", consensusConfig.GenesisHash)
if err != nil {
return err
}
totalBlocksSubmitted := 0
lastLogTime := time.Now()
rpcWaitInInterval := 0 * time.Second
for blockData := range blockChan {
if hash := mdb.hashByID(blockData.ID); hash != nil {
_, err := rpcClient.GetBlock(hash.String(), false)
if err == nil {
continue
}
if !strings.Contains(err.Error(), "not found") {
return err
}
}
block, err := mineOrFetchBlock(blockData, mdb, testConsensus)
if err != nil {
return err
}
beforeSubmitBlockTime := time.Now()
rejectReason, err := rpcClient.SubmitBlock(block)
if err != nil {
return errors.Wrap(err, "error in SubmitBlock")
}
if rejectReason != appmessage.RejectReasonNone {
return errors.Errorf("block rejected in SubmitBlock")
}
rpcWaitInInterval += time.Since(beforeSubmitBlockTime)
totalBlocksSubmitted++
const logInterval = 1000
if totalBlocksSubmitted%logInterval == 0 {
intervalDuration := time.Since(lastLogTime)
blocksPerSecond := logInterval / intervalDuration.Seconds()
log.Infof("It took %s to submit %d blocks (%f blocks/sec) while %s of it it waited for RPC response"+
" (total blocks sent %d)", intervalDuration, logInterval, blocksPerSecond, rpcWaitInInterval,
totalBlocksSubmitted)
rpcWaitInInterval = 0
lastLogTime = time.Now()
}
blockHash := consensushashing.BlockHash(block)
log.Tracef("Submitted block %s with hash %s", blockData.ID, blockHash)
}
return nil
}
func mineOrFetchBlock(blockData JSONBlock, mdb *miningDB, testConsensus testapi.TestConsensus) (*externalapi.DomainBlock, error) {
hash := mdb.hashByID(blockData.ID)
if mdb.hashByID(blockData.ID) != nil {
return testConsensus.GetBlock(hash)
}
parentHashes := make([]*externalapi.DomainHash, len(blockData.Parents))
for i, parentID := range blockData.Parents {
parentHashes[i] = mdb.hashByID(parentID)
}
block, _, err := testConsensus.BuildBlockWithParents(parentHashes,
&externalapi.DomainCoinbaseData{ScriptPublicKey: &externalapi.ScriptPublicKey{}}, []*externalapi.DomainTransaction{})
if err != nil {
return nil, errors.Wrap(err, "error in BuildBlockWithParents")
}
if !testConsensus.DAGParams().SkipProofOfWork {
SolveBlock(block)
}
_, err = testConsensus.ValidateAndInsertBlock(block, true)
if err != nil {
return nil, errors.Wrap(err, "error in ValidateAndInsertBlock")
}
blockHash := consensushashing.BlockHash(block)
err = mdb.putID(blockData.ID, blockHash)
if err != nil {
return nil, err
}
err = mdb.updateLastMinedBlock(blockData.ID)
if err != nil {
return nil, err
}
return block, nil
}
var random = rand.New(rand.NewSource(time.Now().UnixNano()))
// SolveBlock increments the given block's nonce until it matches the difficulty requirements in its bits field
func SolveBlock(block *externalapi.DomainBlock) {
mining.SolveBlock(block, random)
}