mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-09 15:46:43 +00:00
Cache the miner state (#1844)
* Implement a MinerState to cache the matrix and friends * Modify the miner and related code to use the new MinerCache * Change MinerState to State * Make go lint happy Co-authored-by: Ori Newman <orinewman1@gmail.com> Co-authored-by: Kaspa Profiler <>
This commit is contained in:
parent
cc5248106e
commit
7cdceb6df0
@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
"github.com/kaspanet/kaspad/util"
|
"github.com/kaspanet/kaspad/util"
|
||||||
"github.com/kaspanet/kaspad/util/difficulty"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -143,20 +142,20 @@ func mineNextBlock(mineWhenNotSynced bool) *externalapi.DomainBlock {
|
|||||||
// In the rare case where the nonce space is exhausted for a specific
|
// In the rare case where the nonce space is exhausted for a specific
|
||||||
// block, it'll keep looping the nonce until a new block template
|
// block, it'll keep looping the nonce until a new block template
|
||||||
// is discovered.
|
// is discovered.
|
||||||
block := getBlockForMining(mineWhenNotSynced)
|
block, state := getBlockForMining(mineWhenNotSynced)
|
||||||
targetDifficulty := difficulty.CompactToBig(block.Header.Bits())
|
state.Nonce = nonce
|
||||||
headerForMining := block.Header.ToMutable()
|
|
||||||
headerForMining.SetNonce(nonce)
|
|
||||||
atomic.AddUint64(&hashesTried, 1)
|
atomic.AddUint64(&hashesTried, 1)
|
||||||
if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
|
if state.CheckProofOfWork() {
|
||||||
block.Header = headerForMining.ToImmutable()
|
mutHeader := block.Header.ToMutable()
|
||||||
|
mutHeader.SetNonce(nonce)
|
||||||
|
block.Header = mutHeader.ToImmutable()
|
||||||
log.Infof("Found block %s with parents %s", consensushashing.BlockHash(block), block.Header.DirectParents())
|
log.Infof("Found block %s with parents %s", consensushashing.BlockHash(block), block.Header.DirectParents())
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock {
|
func getBlockForMining(mineWhenNotSynced bool) (*externalapi.DomainBlock, *pow.State) {
|
||||||
tryCount := 0
|
tryCount := 0
|
||||||
|
|
||||||
const sleepTime = 500 * time.Millisecond
|
const sleepTime = 500 * time.Millisecond
|
||||||
@ -166,7 +165,7 @@ func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock {
|
|||||||
tryCount++
|
tryCount++
|
||||||
|
|
||||||
shouldLog := (tryCount-1)%10 == 0
|
shouldLog := (tryCount-1)%10 == 0
|
||||||
template, isSynced := templatemanager.Get()
|
template, state, isSynced := templatemanager.Get()
|
||||||
if template == nil {
|
if template == nil {
|
||||||
if shouldLog {
|
if shouldLog {
|
||||||
log.Info("Waiting for the initial template")
|
log.Info("Waiting for the initial template")
|
||||||
@ -182,7 +181,7 @@ func getBlockForMining(mineWhenNotSynced bool) *externalapi.DomainBlock {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
return template
|
return template, state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,23 +3,26 @@ package templatemanager
|
|||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var currentTemplate *externalapi.DomainBlock
|
var currentTemplate *externalapi.DomainBlock
|
||||||
|
var currentState *pow.State
|
||||||
var isSynced bool
|
var isSynced bool
|
||||||
var lock = &sync.Mutex{}
|
var lock = &sync.Mutex{}
|
||||||
|
|
||||||
// Get returns the template to work on
|
// Get returns the template to work on
|
||||||
func Get() (*externalapi.DomainBlock, bool) {
|
func Get() (*externalapi.DomainBlock, *pow.State, bool) {
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
defer lock.Unlock()
|
defer lock.Unlock()
|
||||||
// Shallow copy the block so when the user replaces the header it won't affect the template here.
|
// Shallow copy the block so when the user replaces the header it won't affect the template here.
|
||||||
if currentTemplate == nil {
|
if currentTemplate == nil {
|
||||||
return nil, false
|
return nil, nil, false
|
||||||
}
|
}
|
||||||
block := *currentTemplate
|
block := *currentTemplate
|
||||||
return &block, isSynced
|
state := *currentState
|
||||||
|
return &block, &state, isSynced
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets the current template to work on
|
// Set sets the current template to work on
|
||||||
@ -31,6 +34,7 @@ func Set(template *appmessage.GetBlockTemplateResponseMessage) error {
|
|||||||
lock.Lock()
|
lock.Lock()
|
||||||
defer lock.Unlock()
|
defer lock.Unlock()
|
||||||
currentTemplate = block
|
currentTemplate = block
|
||||||
|
currentState = pow.NewState(block.Header.ToMutable())
|
||||||
isSynced = template.IsSynced
|
isSynced = template.IsSynced
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/virtual"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/virtual"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
"github.com/kaspanet/kaspad/util/difficulty"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -149,7 +148,8 @@ func (v *blockValidator) validateDifficulty(stagingArea *model.StagingArea,
|
|||||||
// difficulty is not performed.
|
// difficulty is not performed.
|
||||||
func (v *blockValidator) checkProofOfWork(header externalapi.BlockHeader) error {
|
func (v *blockValidator) checkProofOfWork(header externalapi.BlockHeader) error {
|
||||||
// The target difficulty must be larger than zero.
|
// The target difficulty must be larger than zero.
|
||||||
target := difficulty.CompactToBig(header.Bits())
|
state := pow.NewState(header.ToMutable())
|
||||||
|
target := &state.Target
|
||||||
if target.Sign() <= 0 {
|
if target.Sign() <= 0 {
|
||||||
return errors.Wrapf(ruleerrors.ErrNegativeTarget, "block target difficulty of %064x is too low",
|
return errors.Wrapf(ruleerrors.ErrNegativeTarget, "block target difficulty of %064x is too low",
|
||||||
target)
|
target)
|
||||||
@ -163,7 +163,7 @@ func (v *blockValidator) checkProofOfWork(header externalapi.BlockHeader) error
|
|||||||
|
|
||||||
// The block pow must be valid unless the flag to avoid proof of work checks is set.
|
// The block pow must be valid unless the flag to avoid proof of work checks is set.
|
||||||
if !v.skipPoW {
|
if !v.skipPoW {
|
||||||
valid := pow.CheckProofOfWorkWithTarget(header.ToMutable(), target)
|
valid := state.CheckProofOfWork()
|
||||||
if !valid {
|
if !valid {
|
||||||
return errors.Wrap(ruleerrors.ErrInvalidPoW, "block has invalid proof of work")
|
return errors.Wrap(ruleerrors.ErrInvalidPoW, "block has invalid proof of work")
|
||||||
}
|
}
|
||||||
|
@ -111,13 +111,13 @@ func TestPOW(t *testing.T) {
|
|||||||
|
|
||||||
// solveBlockWithWrongPOW increments the given block's nonce until it gets wrong POW (for test!).
|
// solveBlockWithWrongPOW increments the given block's nonce until it gets wrong POW (for test!).
|
||||||
func solveBlockWithWrongPOW(block *externalapi.DomainBlock) *externalapi.DomainBlock {
|
func solveBlockWithWrongPOW(block *externalapi.DomainBlock) *externalapi.DomainBlock {
|
||||||
targetDifficulty := difficulty.CompactToBig(block.Header.Bits())
|
header := block.Header.ToMutable()
|
||||||
headerForMining := block.Header.ToMutable()
|
state := pow.NewState(header)
|
||||||
initialNonce := uint64(0)
|
for i := uint64(0); i < math.MaxUint64; i++ {
|
||||||
for i := initialNonce; i < math.MaxUint64; i++ {
|
state.Nonce = i
|
||||||
headerForMining.SetNonce(i)
|
if !state.CheckProofOfWork() {
|
||||||
if !pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
|
header.SetNonce(state.Nonce)
|
||||||
block.Header = headerForMining.ToImmutable()
|
block.Header = header.ToImmutable()
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,17 @@ import (
|
|||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
||||||
"github.com/kaspanet/kaspad/util/difficulty"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SolveBlock increments the given block's nonce until it matches the difficulty requirements in its bits field
|
// SolveBlock increments the given block's nonce until it matches the difficulty requirements in its bits field
|
||||||
func SolveBlock(block *externalapi.DomainBlock, rd *rand.Rand) {
|
func SolveBlock(block *externalapi.DomainBlock, rd *rand.Rand) {
|
||||||
targetDifficulty := difficulty.CompactToBig(block.Header.Bits())
|
header := block.Header.ToMutable()
|
||||||
headerForMining := block.Header.ToMutable()
|
state := pow.NewState(header)
|
||||||
for i := rd.Uint64(); i < math.MaxUint64; i++ {
|
for state.Nonce = rd.Uint64(); state.Nonce < math.MaxUint64; state.Nonce++ {
|
||||||
headerForMining.SetNonce(i)
|
if state.CheckProofOfWork() {
|
||||||
if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
|
header.SetNonce(state.Nonce)
|
||||||
block.Header = headerForMining.ToImmutable()
|
block.Header = header.ToImmutable()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,52 +12,77 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckProofOfWorkWithTarget check's if the block has a valid PoW according to the provided target
|
// State is an intermediate data structure with pre-computed values to speed up mining.
|
||||||
// it does not check if the difficulty itself is valid or less than the maximum for the appropriate network
|
type State struct {
|
||||||
func CheckProofOfWorkWithTarget(header externalapi.MutableBlockHeader, target *big.Int) bool {
|
mat matrix
|
||||||
// The block pow must be less than the claimed target
|
Timestamp int64
|
||||||
powNum := CalculateProofOfWorkValue(header)
|
Nonce uint64
|
||||||
|
Target big.Int
|
||||||
// The block hash must be less or equal than the claimed target.
|
prePowHash externalapi.DomainHash
|
||||||
return powNum.Cmp(target) <= 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckProofOfWorkByBits check's if the block has a valid PoW according to its Bits field
|
// NewState creates a new state with pre-computed values to speed up mining
|
||||||
// it does not check if the difficulty itself is valid or less than the maximum for the appropriate network
|
// It takes the target from the Bits field
|
||||||
func CheckProofOfWorkByBits(header externalapi.MutableBlockHeader) bool {
|
func NewState(header externalapi.MutableBlockHeader) *State {
|
||||||
return CheckProofOfWorkWithTarget(header, difficulty.CompactToBig(header.Bits()))
|
target := difficulty.CompactToBig(header.Bits())
|
||||||
}
|
|
||||||
|
|
||||||
// CalculateProofOfWorkValue hashes the given header and returns its big.Int value
|
|
||||||
func CalculateProofOfWorkValue(header externalapi.MutableBlockHeader) *big.Int {
|
|
||||||
// Zero out the time and nonce.
|
// Zero out the time and nonce.
|
||||||
timestamp, nonce := header.TimeInMilliseconds(), header.Nonce()
|
timestamp, nonce := header.TimeInMilliseconds(), header.Nonce()
|
||||||
header.SetTimeInMilliseconds(0)
|
header.SetTimeInMilliseconds(0)
|
||||||
header.SetNonce(0)
|
header.SetNonce(0)
|
||||||
|
|
||||||
prePowHash := consensushashing.HeaderHash(header)
|
prePowHash := consensushashing.HeaderHash(header)
|
||||||
matrix := generateMatrix(prePowHash)
|
|
||||||
header.SetTimeInMilliseconds(timestamp)
|
header.SetTimeInMilliseconds(timestamp)
|
||||||
header.SetNonce(nonce)
|
header.SetNonce(nonce)
|
||||||
|
|
||||||
|
return &State{
|
||||||
|
Target: *target,
|
||||||
|
prePowHash: *prePowHash,
|
||||||
|
mat: *generateMatrix(prePowHash),
|
||||||
|
Timestamp: timestamp,
|
||||||
|
Nonce: nonce,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CalculateProofOfWorkValue hashes the internal header and returns its big.Int value
|
||||||
|
func (state *State) CalculateProofOfWorkValue() *big.Int {
|
||||||
// PRE_POW_HASH || TIME || 32 zero byte padding || NONCE
|
// PRE_POW_HASH || TIME || 32 zero byte padding || NONCE
|
||||||
writer := hashes.NewPoWHashWriter()
|
writer := hashes.NewPoWHashWriter()
|
||||||
writer.InfallibleWrite(prePowHash.ByteSlice())
|
writer.InfallibleWrite(state.prePowHash.ByteSlice())
|
||||||
err := serialization.WriteElement(writer, timestamp)
|
err := serialization.WriteElement(writer, state.Timestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error"))
|
panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error"))
|
||||||
}
|
}
|
||||||
zeroes := [32]byte{}
|
zeroes := [32]byte{}
|
||||||
writer.InfallibleWrite(zeroes[:])
|
writer.InfallibleWrite(zeroes[:])
|
||||||
err = serialization.WriteElement(writer, nonce)
|
err = serialization.WriteElement(writer, state.Nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error"))
|
panic(errors.Wrap(err, "this should never happen. Hash digest should never return an error"))
|
||||||
}
|
}
|
||||||
powHash := writer.Finalize()
|
powHash := writer.Finalize()
|
||||||
heavyHash := matrix.HeavyHash(powHash)
|
heavyHash := state.mat.HeavyHash(powHash)
|
||||||
return toBig(heavyHash)
|
return toBig(heavyHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IncrementNonce the nonce in State by 1
|
||||||
|
func (state *State) IncrementNonce() {
|
||||||
|
state.Nonce++
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckProofOfWork check's if the block has a valid PoW according to the provided target
|
||||||
|
// it does not check if the difficulty itself is valid or less than the maximum for the appropriate network
|
||||||
|
func (state *State) CheckProofOfWork() bool {
|
||||||
|
// The block pow must be less than the claimed target
|
||||||
|
powNum := state.CalculateProofOfWorkValue()
|
||||||
|
|
||||||
|
// The block hash must be less or equal than the claimed target.
|
||||||
|
return powNum.Cmp(&state.Target) <= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckProofOfWorkByBits check's if the block has a valid PoW according to its Bits field
|
||||||
|
// it does not check if the difficulty itself is valid or less than the maximum for the appropriate network
|
||||||
|
func CheckProofOfWorkByBits(header externalapi.MutableBlockHeader) bool {
|
||||||
|
return NewState(header).CheckProofOfWork()
|
||||||
|
}
|
||||||
|
|
||||||
// ToBig converts a externalapi.DomainHash into a big.Int treated as a little endian string.
|
// ToBig converts a externalapi.DomainHash into a big.Int treated as a little endian string.
|
||||||
func toBig(hash *externalapi.DomainHash) *big.Int {
|
func toBig(hash *externalapi.DomainHash) *big.Int {
|
||||||
// We treat the Hash as little-endian for PoW purposes, but the big package wants the bytes in big-endian, so reverse them.
|
// We treat the Hash as little-endian for PoW purposes, but the big package wants the bytes in big-endian, so reverse them.
|
||||||
@ -78,7 +103,7 @@ func BlockLevel(header externalapi.BlockHeader) int {
|
|||||||
return constants.MaxBlockLevel
|
return constants.MaxBlockLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
proofOfWorkValue := CalculateProofOfWorkValue(header.ToMutable())
|
proofOfWorkValue := NewState(header.ToMutable()).CalculateProofOfWorkValue()
|
||||||
for blockLevel := 0; ; blockLevel++ {
|
for blockLevel := 0; ; blockLevel++ {
|
||||||
if blockLevel == constants.MaxBlockLevel || proofOfWorkValue.Bit(blockLevel+1) != 0 {
|
if blockLevel == constants.MaxBlockLevel || proofOfWorkValue.Bit(blockLevel+1) != 0 {
|
||||||
return blockLevel
|
return blockLevel
|
||||||
|
@ -7,9 +7,7 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
|
"github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
|
||||||
"github.com/kaspanet/kaspad/stability-tests/common"
|
"github.com/kaspanet/kaspad/stability-tests/common"
|
||||||
"github.com/kaspanet/kaspad/util/difficulty"
|
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
@ -162,17 +160,15 @@ func measureMachineHashNanoseconds(t *testing.T) int64 {
|
|||||||
defer t.Logf("Finished measuring machine hash rate")
|
defer t.Logf("Finished measuring machine hash rate")
|
||||||
|
|
||||||
genesisBlock := dagconfig.DevnetParams.GenesisBlock
|
genesisBlock := dagconfig.DevnetParams.GenesisBlock
|
||||||
targetDifficulty := difficulty.CompactToBig(genesisBlock.Header.Bits())
|
state := pow.NewState(genesisBlock.Header.ToMutable())
|
||||||
headerForMining := genesisBlock.Header.ToMutable()
|
|
||||||
|
|
||||||
machineHashesPerSecondMeasurementDuration := 10 * time.Second
|
machineHashesPerSecondMeasurementDuration := 10 * time.Second
|
||||||
hashes := int64(0)
|
hashes := int64(0)
|
||||||
nonce := rand.Uint64()
|
state.Nonce = rand.Uint64()
|
||||||
loopForDuration(machineHashesPerSecondMeasurementDuration, func(isFinished *bool) {
|
loopForDuration(machineHashesPerSecondMeasurementDuration, func(isFinished *bool) {
|
||||||
headerForMining.SetNonce(nonce)
|
state.CheckProofOfWork()
|
||||||
pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty)
|
|
||||||
hashes++
|
hashes++
|
||||||
nonce++
|
state.IncrementNonce()
|
||||||
})
|
})
|
||||||
|
|
||||||
return machineHashesPerSecondMeasurementDuration.Nanoseconds() / hashes
|
return machineHashesPerSecondMeasurementDuration.Nanoseconds() / hashes
|
||||||
@ -202,17 +198,18 @@ func runDAATest(t *testing.T, testName string, runDuration time.Duration,
|
|||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
loopForDuration(runDuration, func(isFinished *bool) {
|
loopForDuration(runDuration, func(isFinished *bool) {
|
||||||
templateBlock := fetchBlockForMining(t, rpcClient)
|
templateBlock := fetchBlockForMining(t, rpcClient)
|
||||||
targetDifficulty := difficulty.CompactToBig(templateBlock.Header.Bits())
|
|
||||||
headerForMining := templateBlock.Header.ToMutable()
|
headerForMining := templateBlock.Header.ToMutable()
|
||||||
|
minerState := pow.NewState(headerForMining)
|
||||||
|
|
||||||
// Try hashes until we find a valid block
|
// Try hashes until we find a valid block
|
||||||
miningStartTime := time.Now()
|
miningStartTime := time.Now()
|
||||||
nonce := rand.Uint64()
|
minerState.Nonce = rand.Uint64()
|
||||||
for {
|
for {
|
||||||
hashStartTime := time.Now()
|
hashStartTime := time.Now()
|
||||||
|
|
||||||
blockFound := tryNonceForMiningAndIncrementNonce(headerForMining, &nonce, targetDifficulty, templateBlock)
|
if minerState.CheckProofOfWork() {
|
||||||
if blockFound {
|
headerForMining.SetNonce(minerState.Nonce)
|
||||||
|
templateBlock.Header = headerForMining.ToImmutable()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,6 +224,7 @@ func runDAATest(t *testing.T, testName string, runDuration time.Duration,
|
|||||||
if *isFinished {
|
if *isFinished {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
minerState.IncrementNonce()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect stats about block rate
|
// Collect stats about block rate
|
||||||
@ -265,19 +263,6 @@ func fetchBlockForMining(t *testing.T, rpcClient *rpcclient.RPCClient) *external
|
|||||||
return templateBlock
|
return templateBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryNonceForMiningAndIncrementNonce(headerForMining externalapi.MutableBlockHeader, nonce *uint64,
|
|
||||||
targetDifficulty *big.Int, templateBlock *externalapi.DomainBlock) bool {
|
|
||||||
|
|
||||||
headerForMining.SetNonce(*nonce)
|
|
||||||
if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
|
|
||||||
templateBlock.Header = headerForMining.ToImmutable()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
*nonce++
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func waitUntilTargetHashDurationHadElapsed(startTime time.Time, hashStartTime time.Time,
|
func waitUntilTargetHashDurationHadElapsed(startTime time.Time, hashStartTime time.Time,
|
||||||
targetHashNanosecondsFunction func(totalElapsedDuration time.Duration) int64) {
|
targetHashNanosecondsFunction func(totalElapsedDuration time.Duration) int64) {
|
||||||
|
|
||||||
|
@ -4,11 +4,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kaspanet/go-secp256k1"
|
"github.com/kaspanet/go-secp256k1"
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/mining"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
|
||||||
"github.com/kaspanet/kaspad/util"
|
"github.com/kaspanet/kaspad/util"
|
||||||
"github.com/kaspanet/kaspad/util/difficulty"
|
"math/rand"
|
||||||
"math"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
@ -78,8 +76,8 @@ func realMain() error {
|
|||||||
genesisTimestamp := activeConfig().NetParams().GenesisBlock.Header.TimeInMilliseconds()
|
genesisTimestamp := activeConfig().NetParams().GenesisBlock.Header.TimeInMilliseconds()
|
||||||
mutableHeader.SetTimeInMilliseconds(genesisTimestamp + 1000)
|
mutableHeader.SetTimeInMilliseconds(genesisTimestamp + 1000)
|
||||||
block.Header = mutableHeader.ToImmutable()
|
block.Header = mutableHeader.ToImmutable()
|
||||||
solvedBlock := solveBlock(block)
|
mining.SolveBlock(block, rand.New(rand.NewSource(time.Now().UnixNano())))
|
||||||
_, err = rpcClient.SubmitBlock(solvedBlock)
|
_, err = rpcClient.SubmitBlock(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -183,8 +181,8 @@ func mineBlock(rpcClient *rpc.Client, miningAddress util.Address) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
solvedBlock := solveBlock(block)
|
mining.SolveBlock(block, rand.New(rand.NewSource(time.Now().UnixNano())))
|
||||||
_, err = rpcClient.SubmitBlock(solvedBlock)
|
_, err = rpcClient.SubmitBlock(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -200,9 +198,10 @@ func mineTips(numOfTips int, miningAddress util.Address, rpcClient *rpc.Client)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
rd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
for i := 0; i < numOfTips; i++ {
|
for i := 0; i < numOfTips; i++ {
|
||||||
solvedBlock := solveBlock(block)
|
mining.SolveBlock(block, rd)
|
||||||
_, err = rpcClient.SubmitBlock(solvedBlock)
|
_, err = rpcClient.SubmitBlock(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -296,23 +295,6 @@ func getCurrentTipsLength(rpcClient *rpc.Client) (int, error) {
|
|||||||
return len(dagInfo.TipHashes), nil
|
return len(dagInfo.TipHashes), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var latestNonce uint64 = 0 // Use to make the nonce unique.
|
|
||||||
// The nonce is unique for each block in this function.
|
|
||||||
func solveBlock(block *externalapi.DomainBlock) *externalapi.DomainBlock {
|
|
||||||
targetDifficulty := difficulty.CompactToBig(block.Header.Bits())
|
|
||||||
headerForMining := block.Header.ToMutable()
|
|
||||||
maxUInt64 := uint64(math.MaxUint64)
|
|
||||||
for i := latestNonce; i < maxUInt64; i++ {
|
|
||||||
headerForMining.SetNonce(i)
|
|
||||||
if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
|
|
||||||
block.Header = headerForMining.ToImmutable()
|
|
||||||
latestNonce = i + 1
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panic("Failed to solve block!")
|
|
||||||
}
|
|
||||||
|
|
||||||
func killWithSigterm(cmd *exec.Cmd, commandName string) {
|
func killWithSigterm(cmd *exec.Cmd, commandName string) {
|
||||||
err := cmd.Process.Signal(syscall.SIGTERM)
|
err := cmd.Process.Signal(syscall.SIGTERM)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3,6 +3,8 @@ package integration
|
|||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/mining"
|
||||||
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@ -117,7 +119,7 @@ func TestIBDWithPruning(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This should trigger resolving the syncee virtual
|
// This should trigger resolving the syncee virtual
|
||||||
syncerTip := mineNextBlockWithMockTimestamps(t, syncer)
|
syncerTip := mineNextBlockWithMockTimestamps(t, syncer, rand.New(rand.NewSource(time.Now().UnixNano())))
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
synceeSelectedTip, err := syncee.rpcClient.GetSelectedTipHash()
|
synceeSelectedTip, err := syncee.rpcClient.GetSelectedTipHash()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -184,12 +186,13 @@ func TestIBDWithPruning(t *testing.T) {
|
|||||||
// iteration to find the highest shared chain
|
// iteration to find the highest shared chain
|
||||||
// block.
|
// block.
|
||||||
const synceeOnlyBlocks = 2
|
const synceeOnlyBlocks = 2
|
||||||
|
rd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
for i := 0; i < synceeOnlyBlocks; i++ {
|
for i := 0; i < synceeOnlyBlocks; i++ {
|
||||||
mineNextBlockWithMockTimestamps(t, syncee1)
|
mineNextBlockWithMockTimestamps(t, syncee1, rd)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < numBlocks-1; i++ {
|
for i := 0; i < numBlocks-1; i++ {
|
||||||
mineNextBlockWithMockTimestamps(t, syncer)
|
mineNextBlockWithMockTimestamps(t, syncer, rd)
|
||||||
}
|
}
|
||||||
|
|
||||||
testSync(syncer, syncee1)
|
testSync(syncer, syncee1)
|
||||||
@ -203,7 +206,7 @@ var currentMockTimestamp int64 = 0
|
|||||||
// mineNextBlockWithMockTimestamps mines blocks with large timestamp differences
|
// mineNextBlockWithMockTimestamps mines blocks with large timestamp differences
|
||||||
// between every two blocks. This is done to avoid the timestamp threshold validation
|
// between every two blocks. This is done to avoid the timestamp threshold validation
|
||||||
// of ibd-with-headers-proof
|
// of ibd-with-headers-proof
|
||||||
func mineNextBlockWithMockTimestamps(t *testing.T, harness *appHarness) *externalapi.DomainBlock {
|
func mineNextBlockWithMockTimestamps(t *testing.T, harness *appHarness, rd *rand.Rand) *externalapi.DomainBlock {
|
||||||
blockTemplate, err := harness.rpcClient.GetBlockTemplate(harness.miningAddress)
|
blockTemplate, err := harness.rpcClient.GetBlockTemplate(harness.miningAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error getting block template: %+v", err)
|
t.Fatalf("Error getting block template: %+v", err)
|
||||||
@ -223,7 +226,7 @@ func mineNextBlockWithMockTimestamps(t *testing.T, harness *appHarness) *externa
|
|||||||
mutableHeader.SetTimeInMilliseconds(currentMockTimestamp)
|
mutableHeader.SetTimeInMilliseconds(currentMockTimestamp)
|
||||||
block.Header = mutableHeader.ToImmutable()
|
block.Header = mutableHeader.ToImmutable()
|
||||||
|
|
||||||
solveBlock(block)
|
mining.SolveBlock(block, rd)
|
||||||
|
|
||||||
_, err = harness.rpcClient.SubmitBlock(block)
|
_, err = harness.rpcClient.SubmitBlock(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3,28 +3,13 @@ package integration
|
|||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/mining"
|
||||||
"github.com/kaspanet/kaspad/util/difficulty"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func solveBlock(block *externalapi.DomainBlock) *externalapi.DomainBlock {
|
|
||||||
targetDifficulty := difficulty.CompactToBig(block.Header.Bits())
|
|
||||||
headerForMining := block.Header.ToMutable()
|
|
||||||
initialNonce := rand.Uint64()
|
|
||||||
for i := initialNonce; i != initialNonce-1; i++ {
|
|
||||||
headerForMining.SetNonce(i)
|
|
||||||
if pow.CheckProofOfWorkWithTarget(headerForMining, targetDifficulty) {
|
|
||||||
block.Header = headerForMining.ToImmutable()
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
panic("Failed to solve block! This should never happen")
|
|
||||||
}
|
|
||||||
|
|
||||||
func mineNextBlock(t *testing.T, harness *appHarness) *externalapi.DomainBlock {
|
func mineNextBlock(t *testing.T, harness *appHarness) *externalapi.DomainBlock {
|
||||||
blockTemplate, err := harness.rpcClient.GetBlockTemplate(harness.miningAddress)
|
blockTemplate, err := harness.rpcClient.GetBlockTemplate(harness.miningAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -36,7 +21,8 @@ func mineNextBlock(t *testing.T, harness *appHarness) *externalapi.DomainBlock {
|
|||||||
t.Fatalf("Error converting block: %s", err)
|
t.Fatalf("Error converting block: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
solveBlock(block)
|
rd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
mining.SolveBlock(block, rd)
|
||||||
|
|
||||||
_, err = harness.rpcClient.SubmitBlock(block)
|
_, err = harness.rpcClient.SubmitBlock(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user