mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
159 lines
4.5 KiB
Go
159 lines
4.5 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.SubmitBlockAlsoIfNonDAA(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 {
|
|
block, found, err := testConsensus.GetBlock(hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !found {
|
|
return nil, errors.Errorf("block %s is missing", hash)
|
|
}
|
|
|
|
return block, nil
|
|
}
|
|
|
|
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)
|
|
}
|