Skip to content

Commit fade660

Browse files
authored
Merge pull request #624 from lochjin/dev1.2
Optimize mining
2 parents 79f5219 + ede62db commit fade660

File tree

10 files changed

+183
-73
lines changed

10 files changed

+183
-73
lines changed

core/blockchain/blockchain.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func (b *BlockChain) Init() error {
175175
log.Info(fmt.Sprintf("hash=%s,order=%s,height=%d", v.GetHash(), meerdag.GetOrderLogStr(v.GetOrder()), v.GetHeight()))
176176
}
177177

178-
b.difficultyManager = difficultymanager.NewDiffManager(b.Consensus().BlockChain(), b.params)
178+
b.difficultyManager = difficultymanager.NewDiffManager(b.Consensus(), b.params)
179179
return nil
180180
}
181181

core/blockchain/validate.go

+21-20
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ func checkProofOfWork(header *types.BlockHeader, powConfig *pow.PowConfig, flags
289289

290290
// The block hash must be less than the claimed target unless the flag
291291
// to avoid proof of work checks is set.
292-
if !flags.Has(BFNoPoWCheck) {
292+
if !flags.Has(BFNoPoWCheck) && !params.ActiveNetParams.Params.IsDevelopDiff() {
293293
header.Pow.SetParams(powConfig)
294294
header.Pow.SetMainHeight(pow.MainHeight(mHeight))
295295
// The block hash must be less than the claimed target.
@@ -751,26 +751,27 @@ func (b *BlockChain) checkBlockHeaderContext(block *types.SerializedBlock, prevN
751751

752752
header := &block.Block().Header
753753
if !flags.Has(BFFastAdd) {
754-
instance := pow.GetInstance(header.Pow.GetPowType(), 0, []byte{})
755-
instance.SetMainHeight(pow.MainHeight(prevNode.GetHeight() + 1))
756-
instance.SetParams(b.params.PowConfig)
757-
// Ensure the difficulty specified in the block header matches
758-
// the calculated difficulty based on the previous block and
759-
// difficulty retarget rules.
760-
761-
expDiff, err := b.calcNextRequiredDifficulty(prevNode,
762-
header.Timestamp, instance)
763-
if err != nil {
764-
return err
765-
}
766-
blockDifficulty := header.Difficulty
767-
if blockDifficulty != expDiff {
768-
str := fmt.Sprintf("block difficulty of %d is not the"+
769-
" expected value of %d", blockDifficulty,
770-
expDiff)
771-
return ruleError(ErrUnexpectedDifficulty, str)
754+
if !b.params.IsDevelopDiff() {
755+
instance := pow.GetInstance(header.Pow.GetPowType(), 0, []byte{})
756+
instance.SetMainHeight(pow.MainHeight(prevNode.GetHeight() + 1))
757+
instance.SetParams(b.params.PowConfig)
758+
// Ensure the difficulty specified in the block header matches
759+
// the calculated difficulty based on the previous block and
760+
// difficulty retarget rules.
761+
762+
expDiff, err := b.calcNextRequiredDifficulty(prevNode,
763+
header.Timestamp, instance)
764+
if err != nil {
765+
return err
766+
}
767+
blockDifficulty := header.Difficulty
768+
if blockDifficulty != expDiff {
769+
str := fmt.Sprintf("block difficulty of %d is not the"+
770+
" expected value of %d", blockDifficulty,
771+
expDiff)
772+
return ruleError(ErrUnexpectedDifficulty, str)
773+
}
772774
}
773-
774775
// Ensure the timestamp for the block header is after the
775776
// median time of the last several blocks (medianTimeBlocks).
776777
medianTime := b.CalcPastMedianTime(prevNode)

core/types/pow/diff.go

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const (
2525
DIFFICULTY_MODE_MEER = 0
2626
// KASPAD difficulty adjustment
2727
DIFFICULTY_MODE_KASPAD = 1
28+
// DEVELOP difficulty adjustment
29+
DIFFICULTY_MODE_DEVELOP = 2
2830
)
2931

3032
// HashToBig converts a hash.Hash into a big.Int that can be used to
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright (c) 2017-2018 The qitmeer developers
2+
// Copyright (c) 2013-2016 The btcsuite developers
3+
// Copyright (c) 2015-2018 The Decred developers
4+
// Use of this source code is governed by an ISC
5+
// license that can be found in the LICENSE file.
6+
7+
package difficultymanager
8+
9+
import (
10+
"math/big"
11+
"time"
12+
13+
"github.com/Qitmeer/qng/consensus/model"
14+
"github.com/Qitmeer/qng/core/types"
15+
"github.com/Qitmeer/qng/core/types/pow"
16+
"github.com/Qitmeer/qng/params"
17+
)
18+
19+
type developDiff struct {
20+
b model.BlockChain
21+
cfg *params.Params
22+
}
23+
24+
// CalcEasiestDifficulty calculates the easiest possible difficulty that a block
25+
// can have given starting difficulty bits and a duration. It is mainly used to
26+
// verify that claimed proof of work by a block is sane as compared to a
27+
// known good checkpoint.
28+
func (m *developDiff) CalcEasiestDifficulty(bits uint32, duration time.Duration, powInstance pow.IPow) uint32 {
29+
// Convert types used in the calculations below.
30+
durationVal := int64(duration)
31+
adjustmentFactor := big.NewInt(m.cfg.RetargetAdjustmentFactor)
32+
maxRetargetTimespan := int64(m.cfg.TargetTimespan) *
33+
m.cfg.RetargetAdjustmentFactor
34+
target := powInstance.GetSafeDiff(0)
35+
// The test network rules allow minimum difficulty blocks once too much
36+
// time has elapsed without mining a block.
37+
if m.cfg.ReduceMinDifficulty {
38+
if durationVal > int64(m.cfg.MinDiffReductionTime) {
39+
return pow.BigToCompact(target)
40+
}
41+
}
42+
43+
// Since easier difficulty equates to higher numbers, the easiest
44+
// difficulty for a given duration is the largest value possible given
45+
// the number of retargets for the duration and starting difficulty
46+
// multiplied by the max adjustment factor.
47+
newTarget := pow.CompactToBig(bits)
48+
49+
for durationVal > 0 && powInstance.CompareDiff(newTarget, target) {
50+
newTarget.Mul(newTarget, adjustmentFactor)
51+
newTarget = powInstance.GetNextDiffBig(adjustmentFactor, newTarget, big.NewInt(0))
52+
durationVal -= maxRetargetTimespan
53+
}
54+
55+
// Limit new value to the proof of work limit.
56+
if !powInstance.CompareDiff(newTarget, target) {
57+
newTarget.Set(target)
58+
}
59+
60+
return pow.BigToCompact(newTarget)
61+
}
62+
63+
// findPrevTestNetDifficulty returns the difficulty of the previous block which
64+
// did not have the special testnet minimum difficulty rule applied.
65+
//
66+
// This function MUST be called with the chain state lock held (for writes).
67+
func (m *developDiff) findPrevTestNetDifficulty(startBlock model.Block, powInstance pow.IPow) uint32 {
68+
// Search backwards through the chain for the last block without
69+
// the special rule applied.
70+
target := powInstance.GetSafeDiff(0)
71+
lastBits := pow.BigToCompact(target)
72+
blocksPerRetarget := uint64(m.cfg.WorkDiffWindowSize * m.cfg.WorkDiffWindows)
73+
iterBlock := startBlock
74+
if iterBlock == nil ||
75+
uint64(iterBlock.GetHeight())%blocksPerRetarget == 0 {
76+
return lastBits
77+
}
78+
var iterNode *types.BlockHeader
79+
iterNode = m.b.GetBlockHeader(iterBlock)
80+
if iterNode.Difficulty != pow.BigToCompact(target) {
81+
return lastBits
82+
}
83+
return iterNode.Difficulty
84+
}
85+
86+
// RequiredDifficulty calculates the required difficulty for the block
87+
// after the passed previous block node based on the difficulty retarget rules.
88+
// This function differs from the exported RequiredDifficulty in that
89+
// the exported version uses the current best chain as the previous block node
90+
// while this function accepts any block node.
91+
func (m *developDiff) RequiredDifficulty(block model.Block, newBlockTime time.Time, powInstance pow.IPow) (uint32, error) {
92+
baseTarget := powInstance.GetSafeDiff(0)
93+
return pow.BigToCompact(baseTarget), nil
94+
}
95+
96+
// find block node by pow type
97+
func (m *developDiff) GetCurrentPowDiff(ib model.Block, powType pow.PowType) *big.Int {
98+
instance := pow.GetInstance(powType, 0, []byte{})
99+
instance.SetParams(m.cfg.PowConfig)
100+
safeBigDiff := instance.GetSafeDiff(0)
101+
return safeBigDiff
102+
}

core/types/pow/difficultymanager/difficultymanager.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,28 @@ import (
66
"github.com/Qitmeer/qng/params"
77
)
88

9-
func NewDiffManager(b model.BlockChain, cfg *params.Params) model.DifficultyManager {
9+
func NewDiffManager(con model.Consensus, cfg *params.Params) model.DifficultyManager {
1010
switch cfg.PowConfig.DifficultyMode {
1111
case pow.DIFFICULTY_MODE_KASPAD:
1212
return &kaspadDiff{
13-
b: b,
13+
con: con,
14+
b: con.BlockChain(),
1415
powMax: cfg.PowConfig.MeerXKeccakV1PowLimit,
1516
difficultyAdjustmentWindowSize: int(cfg.WorkDiffWindowSize),
1617
disableDifficultyAdjustment: false,
1718
targetTimePerBlock: cfg.TargetTimePerBlock,
1819
genesisBits: cfg.PowConfig.MeerXKeccakV1PowLimitBits,
1920
cfg: cfg,
2021
}
22+
case pow.DIFFICULTY_MODE_DEVELOP:
23+
return &developDiff{
24+
b: con.BlockChain(),
25+
cfg: cfg,
26+
}
2127
}
2228
return &meerDiff{
23-
b: b,
29+
con: con,
30+
b: con.BlockChain(),
2431
cfg: cfg,
2532
}
2633
}

core/types/pow/difficultymanager/kaspad.go

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ type kaspadDiff struct {
6767
genesisBits uint32
6868
b model.BlockChain
6969
cfg *params.Params
70+
con model.Consensus
7071
}
7172

7273
// CalcEasiestDifficulty calculates the easiest possible difficulty that a block

core/types/pow/difficultymanager/meer.go

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const maxShift = uint(256)
2929
type meerDiff struct {
3030
b model.BlockChain
3131
cfg *params.Params
32+
con model.Consensus
3233
}
3334

3435
// CalcEasiestDifficulty calculates the easiest possible difficulty that a block

params/params.go

+4
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ func (p *Params) HasTax() bool {
294294
return false
295295
}
296296

297+
func (p *Params) IsDevelopDiff() bool {
298+
return p.PowConfig.DifficultyMode == pow.DIFFICULTY_MODE_DEVELOP
299+
}
300+
297301
var (
298302
// ErrDuplicateNet describes an error where the parameters for a network
299303
// could not be set due to the network already being a standard

services/miner/cpuworker.go

+40-48
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"github.com/Qitmeer/qng/core/types"
88
"github.com/Qitmeer/qng/core/types/pow"
99
"github.com/Qitmeer/qng/params"
10-
"github.com/Qitmeer/qng/services/mining"
1110
"sync"
1211
"sync/atomic"
1312
"time"
@@ -49,8 +48,7 @@ type CPUWorker struct {
4948
workWg sync.WaitGroup
5049
updateNumWorks chan struct{}
5150
numWorks uint32
52-
updateWork chan struct{}
53-
hasNewWork bool
51+
hasNewWork atomic.Bool
5452

5553
miner *Miner
5654

@@ -274,15 +272,7 @@ func (w *CPUWorker) Update() {
274272
if atomic.LoadInt32(&w.shutdown) != 0 {
275273
return
276274
}
277-
w.Lock()
278-
defer w.Unlock()
279-
280-
if w.discrete && w.discreteNum <= 0 {
281-
return
282-
}
283-
w.hasNewWork = true
284-
w.updateWork <- struct{}{}
285-
w.hasNewWork = false
275+
w.hasNewWork.Store(true)
286276
}
287277

288278
func (w *CPUWorker) generateDiscrete(num int, block chan *hash.Hash) bool {
@@ -302,45 +292,52 @@ func (w *CPUWorker) generateDiscrete(num int, block chan *hash.Hash) bool {
302292
}
303293

304294
func (w *CPUWorker) generateBlocks() {
305-
log.Trace(fmt.Sprintf("Starting generate blocks worker:%s", w.GetType()))
295+
log.Info(fmt.Sprintf("Starting generate blocks worker:%s", w.GetType()))
306296
out:
307297
for {
308298
// Quit when the miner is stopped.
309299
select {
310-
case <-w.updateWork:
311-
if w.discrete && w.discreteNum <= 0 {
300+
case <-w.quit:
301+
break out
302+
default:
303+
// Non-blocking select to fall through
304+
}
305+
if w.discrete && w.discreteNum <= 0 || !w.hasNewWork.Load() {
306+
time.Sleep(time.Second)
307+
continue
308+
}
309+
start := time.Now()
310+
if params.ActiveNetParams.Params.IsDevelopDiff() {
311+
time.Sleep(params.ActiveNetParams.Params.TargetTimePerBlock)
312+
}
313+
sb := w.solveBlock()
314+
if sb != nil {
315+
w.hasNewWork.Store(false)
316+
block := types.NewBlock(sb)
317+
info, err := w.miner.submitBlock(block)
318+
if err != nil {
319+
log.Error(fmt.Sprintf("Failed to submit new block:%s ,%v", block.Hash().String(), err))
320+
w.cleanDiscrete()
312321
continue
313322
}
314-
sb := w.solveBlock()
315-
if sb != nil {
316-
block := types.NewBlock(sb)
317-
info, err := w.miner.submitBlock(block)
318-
if err != nil {
319-
log.Error(fmt.Sprintf("Failed to submit new block:%s ,%v", block.Hash().String(), err))
320-
w.cleanDiscrete()
321-
continue
323+
log.Info(fmt.Sprintf("%v", info), "cost", time.Since(start).String())
324+
325+
if w.discrete && w.discreteNum > 0 {
326+
if w.discreteBlock != nil {
327+
w.discreteBlock <- block.Hash()
322328
}
323-
log.Info(fmt.Sprintf("%v", info))
324-
325-
if w.discrete && w.discreteNum > 0 {
326-
if w.discreteBlock != nil {
327-
w.discreteBlock <- block.Hash()
328-
}
329-
w.discreteNum--
330-
if w.discreteNum <= 0 {
331-
w.cleanDiscrete()
332-
}
329+
w.discreteNum--
330+
if w.discreteNum <= 0 {
331+
w.cleanDiscrete()
333332
}
334-
} else {
335-
w.cleanDiscrete()
336333
}
337-
case <-w.quit:
338-
break out
334+
} else {
335+
w.cleanDiscrete()
339336
}
340337
}
341338

342339
w.workWg.Done()
343-
log.Trace(fmt.Sprintf("Generate blocks worker done:%s", w.GetType()))
340+
log.Info(fmt.Sprintf("Generate blocks worker done:%s", w.GetType()))
344341
}
345342

346343
func (w *CPUWorker) cleanDiscrete() {
@@ -359,7 +356,7 @@ func (w *CPUWorker) solveBlock() *types.Block {
359356
}
360357
// Start a ticker which is used to signal checks for stale work and
361358
// updates to the speed monitor.
362-
ticker := time.NewTicker(333 * time.Millisecond)
359+
ticker := time.NewTicker(time.Second)
363360
defer ticker.Stop()
364361

365362
// Create a couple of convenience variables.
@@ -405,16 +402,9 @@ func (w *CPUWorker) solveBlock() *types.Block {
405402
// has been updated since the block template was
406403
// generated and it has been at least 3 seconds,
407404
// or if it's been one minute.
408-
if w.hasNewWork || roughtime.Now().After(lastGenerated.Add(gbtRegenerateSeconds*time.Second)) {
405+
if roughtime.Now().After(lastGenerated.Add(gbtRegenerateSeconds * time.Second)) {
409406
return nil
410407
}
411-
412-
err := mining.UpdateBlockTime(block, w.miner.BlockChain(), w.miner.timeSource, params.ActiveNetParams.Params)
413-
if err != nil {
414-
log.Warn(fmt.Sprintf("CPU miner unable to update block template time: %v", err))
415-
return nil
416-
}
417-
418408
default:
419409
// Non-blocking select to fall through
420410
}
@@ -424,6 +414,9 @@ func (w *CPUWorker) solveBlock() *types.Block {
424414
instance.SetParams(params.ActiveNetParams.Params.PowConfig)
425415
hashesCompleted += 2
426416
header.Pow = instance
417+
if params.ActiveNetParams.Params.IsDevelopDiff() {
418+
return block
419+
}
427420
if header.Pow.FindSolver(header.BlockData(), header.BlockHash(), header.Difficulty) {
428421
w.updateHashes <- hashesCompleted
429422
return block
@@ -443,7 +436,6 @@ func NewCPUWorker(miner *Miner) *CPUWorker {
443436
queryHashesPerSec: make(chan float64),
444437
updateNumWorks: make(chan struct{}),
445438
numWorks: defaultNumWorkers,
446-
updateWork: make(chan struct{}),
447439
}
448440

449441
return &w

0 commit comments

Comments
 (0)