From fe05688e937d2b6bdcdccf4b2d2da426c927f9d8 Mon Sep 17 00:00:00 2001
From: Jin <lochjin@gmail.com>
Date: Wed, 6 Mar 2024 10:31:11 +0800
Subject: [PATCH 1/5] BUG:cpuworker deadlock

---
 services/miner/cpuworker.go | 82 +++++++++++++++----------------------
 services/miner/miner.go     |  2 +-
 2 files changed, 35 insertions(+), 49 deletions(-)

diff --git a/services/miner/cpuworker.go b/services/miner/cpuworker.go
index dd62cba7..a3bfeed5 100644
--- a/services/miner/cpuworker.go
+++ b/services/miner/cpuworker.go
@@ -7,7 +7,6 @@ import (
 	"github.com/Qitmeer/qng/core/types"
 	"github.com/Qitmeer/qng/core/types/pow"
 	"github.com/Qitmeer/qng/params"
-	"github.com/Qitmeer/qng/services/mining"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -49,8 +48,7 @@ type CPUWorker struct {
 	workWg            sync.WaitGroup
 	updateNumWorks    chan struct{}
 	numWorks          uint32
-	updateWork        chan struct{}
-	hasNewWork        bool
+	hasNewWork        atomic.Bool
 
 	miner *Miner
 
@@ -274,15 +272,7 @@ func (w *CPUWorker) Update() {
 	if atomic.LoadInt32(&w.shutdown) != 0 {
 		return
 	}
-	w.Lock()
-	defer w.Unlock()
-
-	if w.discrete && w.discreteNum <= 0 {
-		return
-	}
-	w.hasNewWork = true
-	w.updateWork <- struct{}{}
-	w.hasNewWork = false
+	w.hasNewWork.Store(true)
 }
 
 func (w *CPUWorker) generateDiscrete(num int, block chan *hash.Hash) bool {
@@ -302,45 +292,49 @@ func (w *CPUWorker) generateDiscrete(num int, block chan *hash.Hash) bool {
 }
 
 func (w *CPUWorker) generateBlocks() {
-	log.Trace(fmt.Sprintf("Starting generate blocks worker:%s", w.GetType()))
+	log.Info(fmt.Sprintf("Starting generate blocks worker:%s", w.GetType()))
 out:
 	for {
 		// Quit when the miner is stopped.
 		select {
-		case <-w.updateWork:
-			if w.discrete && w.discreteNum <= 0 {
+		case <-w.quit:
+			break out
+		default:
+			// Non-blocking select to fall through
+		}
+		if w.discrete && w.discreteNum <= 0 || !w.hasNewWork.Load() {
+			time.Sleep(time.Second)
+			continue
+		}
+		start := time.Now()
+		sb := w.solveBlock()
+		if sb != nil {
+			w.hasNewWork.Store(false)
+			block := types.NewBlock(sb)
+			info, err := w.miner.submitBlock(block)
+			if err != nil {
+				log.Error(fmt.Sprintf("Failed to submit new block:%s ,%v", block.Hash().String(), err))
+				w.cleanDiscrete()
 				continue
 			}
-			sb := w.solveBlock()
-			if sb != nil {
-				block := types.NewBlock(sb)
-				info, err := w.miner.submitBlock(block)
-				if err != nil {
-					log.Error(fmt.Sprintf("Failed to submit new block:%s ,%v", block.Hash().String(), err))
-					w.cleanDiscrete()
-					continue
+			log.Info(fmt.Sprintf("%v", info), "cost", time.Since(start).String())
+
+			if w.discrete && w.discreteNum > 0 {
+				if w.discreteBlock != nil {
+					w.discreteBlock <- block.Hash()
 				}
-				log.Info(fmt.Sprintf("%v", info))
-
-				if w.discrete && w.discreteNum > 0 {
-					if w.discreteBlock != nil {
-						w.discreteBlock <- block.Hash()
-					}
-					w.discreteNum--
-					if w.discreteNum <= 0 {
-						w.cleanDiscrete()
-					}
+				w.discreteNum--
+				if w.discreteNum <= 0 {
+					w.cleanDiscrete()
 				}
-			} else {
-				w.cleanDiscrete()
 			}
-		case <-w.quit:
-			break out
+		} else {
+			w.cleanDiscrete()
 		}
 	}
 
 	w.workWg.Done()
-	log.Trace(fmt.Sprintf("Generate blocks worker done:%s", w.GetType()))
+	log.Info(fmt.Sprintf("Generate blocks worker done:%s", w.GetType()))
 }
 
 func (w *CPUWorker) cleanDiscrete() {
@@ -359,7 +353,7 @@ func (w *CPUWorker) solveBlock() *types.Block {
 	}
 	// Start a ticker which is used to signal checks for stale work and
 	// updates to the speed monitor.
-	ticker := time.NewTicker(333 * time.Millisecond)
+	ticker := time.NewTicker(time.Second)
 	defer ticker.Stop()
 
 	// Create a couple of convenience variables.
@@ -405,16 +399,9 @@ func (w *CPUWorker) solveBlock() *types.Block {
 			// has been updated since the block template was
 			// generated and it has been at least 3 seconds,
 			// or if it's been one minute.
-			if w.hasNewWork || roughtime.Now().After(lastGenerated.Add(gbtRegenerateSeconds*time.Second)) {
-				return nil
-			}
-
-			err := mining.UpdateBlockTime(block, w.miner.BlockChain(), w.miner.timeSource, params.ActiveNetParams.Params)
-			if err != nil {
-				log.Warn(fmt.Sprintf("CPU miner unable to update block template time: %v", err))
+			if roughtime.Now().After(lastGenerated.Add(gbtRegenerateSeconds * time.Second)) {
 				return nil
 			}
-
 		default:
 			// Non-blocking select to fall through
 		}
@@ -443,7 +430,6 @@ func NewCPUWorker(miner *Miner) *CPUWorker {
 		queryHashesPerSec: make(chan float64),
 		updateNumWorks:    make(chan struct{}),
 		numWorks:          defaultNumWorkers,
-		updateWork:        make(chan struct{}),
 	}
 
 	return &w
diff --git a/services/miner/miner.go b/services/miner/miner.go
index 3f8e7825..77eb082a 100644
--- a/services/miner/miner.go
+++ b/services/miner/miner.go
@@ -689,7 +689,7 @@ func (m *Miner) CanMining() error {
 		return nil
 	}
 	if !m.BlockChain().IsNearlySynced() {
-		log.Warn("Client in initial download, qitmeer is downloading blocks...")
+		log.Trace("Client in initial download, qitmeer is downloading blocks...")
 		return rpc.RPCClientInInitialDownloadError("Client in initial download ",
 			"qitmeer is downloading blocks...")
 	}

From 3a284dee4f22592f8e9b0180cf79d2f48c3c4f55 Mon Sep 17 00:00:00 2001
From: Jin <lochjin@gmail.com>
Date: Wed, 6 Mar 2024 11:06:45 +0800
Subject: [PATCH 2/5] Support NoPowCheck for debug

---
 config/config.go            |  1 +
 core/blockchain/process.go  |  3 +++
 core/blockchain/validate.go | 39 +++++++++++++++++++------------------
 services/common/flags.go    |  7 +++++++
 services/miner/cpuworker.go |  6 ++++++
 5 files changed, 37 insertions(+), 19 deletions(-)

diff --git a/config/config.go b/config/config.go
index 6ac5d0d6..feb8c5a8 100644
--- a/config/config.go
+++ b/config/config.go
@@ -63,6 +63,7 @@ type Config struct {
 	GBTNotify         []string `long:"gbtnotify" description:"HTTP URL list to be notified of new block template"`
 	ObsoleteHeight    int      `long:"obsoleteheight" description:"What is the maximum allowable height of block obsolescence for submission"`
 	SubmitNoSynced    bool     `long:"allowsubmitwhennotsynced" description:"Allow the node to accept blocks from RPC while not synced (this flag is mainly used for testing)"`
+	NoPowCheck        bool     `long:"nopowcheck" description:"Enable no pow check for debug node"`
 
 	//WebSocket support
 	RPCMaxWebsockets     int `long:"rpcmaxwebsockets" description:"Max number of RPC websocket connections"`
diff --git a/core/blockchain/process.go b/core/blockchain/process.go
index 0e1b324b..0f3e4381 100644
--- a/core/blockchain/process.go
+++ b/core/blockchain/process.go
@@ -47,6 +47,9 @@ func (b *BlockChain) ProcessBlock(block *types.SerializedBlock, flags BehaviorFl
 		return nil, false, fmt.Errorf("Already exists in the queue:%s", block.Hash().String())
 	}
 	b.processQueueMap.Store(bh, nil)
+	if b.consensus.Config().NoPowCheck {
+		flags |= BFNoPoWCheck
+	}
 	msg := processMsg{block: block, flags: flags, result: make(chan *processResult), source: source}
 	b.msgChan <- &msg
 	result := <-msg.result
diff --git a/core/blockchain/validate.go b/core/blockchain/validate.go
index 5a913c92..af2f58a8 100644
--- a/core/blockchain/validate.go
+++ b/core/blockchain/validate.go
@@ -751,26 +751,27 @@ func (b *BlockChain) checkBlockHeaderContext(block *types.SerializedBlock, prevN
 
 	header := &block.Block().Header
 	if !flags.Has(BFFastAdd) {
-		instance := pow.GetInstance(header.Pow.GetPowType(), 0, []byte{})
-		instance.SetMainHeight(pow.MainHeight(prevNode.GetHeight() + 1))
-		instance.SetParams(b.params.PowConfig)
-		// Ensure the difficulty specified in the block header matches
-		// the calculated difficulty based on the previous block and
-		// difficulty retarget rules.
-
-		expDiff, err := b.calcNextRequiredDifficulty(prevNode,
-			header.Timestamp, instance)
-		if err != nil {
-			return err
-		}
-		blockDifficulty := header.Difficulty
-		if blockDifficulty != expDiff {
-			str := fmt.Sprintf("block difficulty of %d is not the"+
-				" expected value of %d", blockDifficulty,
-				expDiff)
-			return ruleError(ErrUnexpectedDifficulty, str)
+		if flags.Has(BFNoPoWCheck) {
+			instance := pow.GetInstance(header.Pow.GetPowType(), 0, []byte{})
+			instance.SetMainHeight(pow.MainHeight(prevNode.GetHeight() + 1))
+			instance.SetParams(b.params.PowConfig)
+			// Ensure the difficulty specified in the block header matches
+			// the calculated difficulty based on the previous block and
+			// difficulty retarget rules.
+
+			expDiff, err := b.calcNextRequiredDifficulty(prevNode,
+				header.Timestamp, instance)
+			if err != nil {
+				return err
+			}
+			blockDifficulty := header.Difficulty
+			if blockDifficulty != expDiff {
+				str := fmt.Sprintf("block difficulty of %d is not the"+
+					" expected value of %d", blockDifficulty,
+					expDiff)
+				return ruleError(ErrUnexpectedDifficulty, str)
+			}
 		}
-
 		// Ensure the timestamp for the block header is after the
 		// median time of the last several blocks (medianTimeBlocks).
 		medianTime := b.CalcPastMedianTime(prevNode)
diff --git a/services/common/flags.go b/services/common/flags.go
index 4447f23a..812b8e5e 100644
--- a/services/common/flags.go
+++ b/services/common/flags.go
@@ -632,6 +632,12 @@ var (
 			Value:       false,
 			Destination: &cfg.SubmitNoSynced,
 		},
+		&cli.BoolFlag{
+			Name:        "nopowcheck",
+			Usage:       "Enable no pow check for debug node",
+			Value:       false,
+			Destination: &cfg.NoPowCheck,
+		},
 	}
 )
 
@@ -668,6 +674,7 @@ func DefaultConfig(homeDir string) *config.Config {
 		RPCPass:              defaultRPCPass,
 		ObsoleteHeight:       defaultObsoleteHeight,
 		SubmitNoSynced:       false,
+		NoPowCheck:           false,
 	}
 	if len(homeDir) > 0 {
 		hd, err := filepath.Abs(homeDir)
diff --git a/services/miner/cpuworker.go b/services/miner/cpuworker.go
index a3bfeed5..10aebf9c 100644
--- a/services/miner/cpuworker.go
+++ b/services/miner/cpuworker.go
@@ -307,6 +307,9 @@ out:
 			continue
 		}
 		start := time.Now()
+		if w.miner.cfg.NoPowCheck {
+			time.Sleep(params.ActiveNetParams.Params.TargetTimePerBlock)
+		}
 		sb := w.solveBlock()
 		if sb != nil {
 			w.hasNewWork.Store(false)
@@ -411,6 +414,9 @@ func (w *CPUWorker) solveBlock() *types.Block {
 		instance.SetParams(params.ActiveNetParams.Params.PowConfig)
 		hashesCompleted += 2
 		header.Pow = instance
+		if w.miner.cfg.NoPowCheck {
+			return block
+		}
 		if header.Pow.FindSolver(header.BlockData(), header.BlockHash(), header.Difficulty) {
 			w.updateHashes <- hashesCompleted
 			return block

From 1fc1f0dfced00f95d71534dc5ca0ad9c4b7ce944 Mon Sep 17 00:00:00 2001
From: Jin <lochjin@gmail.com>
Date: Wed, 6 Mar 2024 11:10:44 +0800
Subject: [PATCH 3/5] Support NoPowCheck for debug

---
 core/blockchain/validate.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/blockchain/validate.go b/core/blockchain/validate.go
index af2f58a8..17ca0af0 100644
--- a/core/blockchain/validate.go
+++ b/core/blockchain/validate.go
@@ -751,7 +751,7 @@ func (b *BlockChain) checkBlockHeaderContext(block *types.SerializedBlock, prevN
 
 	header := &block.Block().Header
 	if !flags.Has(BFFastAdd) {
-		if flags.Has(BFNoPoWCheck) {
+		if !flags.Has(BFNoPoWCheck) {
 			instance := pow.GetInstance(header.Pow.GetPowType(), 0, []byte{})
 			instance.SetMainHeight(pow.MainHeight(prevNode.GetHeight() + 1))
 			instance.SetParams(b.params.PowConfig)

From d672af7d74dcc47471d5e16b4c7eeebe231828cd Mon Sep 17 00:00:00 2001
From: Jin <lochjin@gmail.com>
Date: Wed, 6 Mar 2024 14:54:58 +0800
Subject: [PATCH 4/5] Support NoPowCheck for debug

---
 core/blockchain/blockchain.go                         | 2 +-
 core/types/pow/difficultymanager/difficultymanager.go | 8 +++++---
 core/types/pow/difficultymanager/kaspad.go            | 3 ++-
 core/types/pow/difficultymanager/meer.go              | 3 ++-
 4 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/core/blockchain/blockchain.go b/core/blockchain/blockchain.go
index 61eaf060..49a06559 100644
--- a/core/blockchain/blockchain.go
+++ b/core/blockchain/blockchain.go
@@ -175,7 +175,7 @@ func (b *BlockChain) Init() error {
 		log.Info(fmt.Sprintf("hash=%s,order=%s,height=%d", v.GetHash(), meerdag.GetOrderLogStr(v.GetOrder()), v.GetHeight()))
 	}
 
-	b.difficultyManager = difficultymanager.NewDiffManager(b.Consensus().BlockChain(), b.params)
+	b.difficultyManager = difficultymanager.NewDiffManager(b.Consensus(), b.params)
 	return nil
 }
 
diff --git a/core/types/pow/difficultymanager/difficultymanager.go b/core/types/pow/difficultymanager/difficultymanager.go
index 4bb7135b..25f8cd92 100644
--- a/core/types/pow/difficultymanager/difficultymanager.go
+++ b/core/types/pow/difficultymanager/difficultymanager.go
@@ -6,11 +6,12 @@ import (
 	"github.com/Qitmeer/qng/params"
 )
 
-func NewDiffManager(b model.BlockChain, cfg *params.Params) model.DifficultyManager {
+func NewDiffManager(con model.Consensus, cfg *params.Params) model.DifficultyManager {
 	switch cfg.PowConfig.DifficultyMode {
 	case pow.DIFFICULTY_MODE_KASPAD:
 		return &kaspadDiff{
-			b:                              b,
+			con:                            con,
+			b:                              con.BlockChain(),
 			powMax:                         cfg.PowConfig.MeerXKeccakV1PowLimit,
 			difficultyAdjustmentWindowSize: int(cfg.WorkDiffWindowSize),
 			disableDifficultyAdjustment:    false,
@@ -20,7 +21,8 @@ func NewDiffManager(b model.BlockChain, cfg *params.Params) model.DifficultyMana
 		}
 	}
 	return &meerDiff{
-		b:   b,
+		con: con,
+		b:   con.BlockChain(),
 		cfg: cfg,
 	}
 }
diff --git a/core/types/pow/difficultymanager/kaspad.go b/core/types/pow/difficultymanager/kaspad.go
index 7727ad4a..321f3ba2 100644
--- a/core/types/pow/difficultymanager/kaspad.go
+++ b/core/types/pow/difficultymanager/kaspad.go
@@ -67,6 +67,7 @@ type kaspadDiff struct {
 	genesisBits                    uint32
 	b                              model.BlockChain
 	cfg                            *params.Params
+	con                            model.Consensus
 }
 
 // CalcEasiestDifficulty calculates the easiest possible difficulty that a block
@@ -114,7 +115,7 @@ func (m *kaspadDiff) RequiredDifficulty(block model.Block, newBlockTime time.Tim
 
 // RequiredDifficultyByWindows returns the difficulty required for some block
 func (dm *kaspadDiff) RequiredDifficultyByWindows(targetsWindow blockWindow) (uint32, error) {
-	if len(targetsWindow) < 1 {
+	if len(targetsWindow) < 1 || dm.con.Config().NoPowCheck {
 		return dm.genesisBits, nil
 	}
 	return dm.requiredDifficultyFromTargetsWindow(targetsWindow)
diff --git a/core/types/pow/difficultymanager/meer.go b/core/types/pow/difficultymanager/meer.go
index 482b08d6..a69aaccd 100644
--- a/core/types/pow/difficultymanager/meer.go
+++ b/core/types/pow/difficultymanager/meer.go
@@ -29,6 +29,7 @@ const maxShift = uint(256)
 type meerDiff struct {
 	b   model.BlockChain
 	cfg *params.Params
+	con model.Consensus
 }
 
 // CalcEasiestDifficulty calculates the easiest possible difficulty that a block
@@ -102,7 +103,7 @@ func (m *meerDiff) RequiredDifficulty(block model.Block, newBlockTime time.Time,
 	baseTarget := powInstance.GetSafeDiff(0)
 	originCurrentBlock := block
 	// Genesis block.
-	if block == nil {
+	if block == nil || m.con.Config().NoPowCheck {
 		return pow.BigToCompact(baseTarget), nil
 	}
 

From ede62db9822b7b9881cb88a864a9a7762623b5f3 Mon Sep 17 00:00:00 2001
From: Jin <lochjin@gmail.com>
Date: Thu, 7 Mar 2024 15:16:17 +0800
Subject: [PATCH 5/5] Support Develop difficulty mode

---
 config/config.go                              |   1 -
 core/blockchain/process.go                    |   3 -
 core/blockchain/validate.go                   |   4 +-
 core/types/pow/diff.go                        |   2 +
 core/types/pow/difficultymanager/develop.go   | 102 ++++++++++++++++++
 .../difficultymanager/difficultymanager.go    |   5 +
 core/types/pow/difficultymanager/kaspad.go    |   2 +-
 core/types/pow/difficultymanager/meer.go      |   2 +-
 params/params.go                              |   4 +
 services/common/flags.go                      |   7 --
 services/miner/cpuworker.go                   |   4 +-
 11 files changed, 119 insertions(+), 17 deletions(-)
 create mode 100644 core/types/pow/difficultymanager/develop.go

diff --git a/config/config.go b/config/config.go
index feb8c5a8..6ac5d0d6 100644
--- a/config/config.go
+++ b/config/config.go
@@ -63,7 +63,6 @@ type Config struct {
 	GBTNotify         []string `long:"gbtnotify" description:"HTTP URL list to be notified of new block template"`
 	ObsoleteHeight    int      `long:"obsoleteheight" description:"What is the maximum allowable height of block obsolescence for submission"`
 	SubmitNoSynced    bool     `long:"allowsubmitwhennotsynced" description:"Allow the node to accept blocks from RPC while not synced (this flag is mainly used for testing)"`
-	NoPowCheck        bool     `long:"nopowcheck" description:"Enable no pow check for debug node"`
 
 	//WebSocket support
 	RPCMaxWebsockets     int `long:"rpcmaxwebsockets" description:"Max number of RPC websocket connections"`
diff --git a/core/blockchain/process.go b/core/blockchain/process.go
index 0f3e4381..0e1b324b 100644
--- a/core/blockchain/process.go
+++ b/core/blockchain/process.go
@@ -47,9 +47,6 @@ func (b *BlockChain) ProcessBlock(block *types.SerializedBlock, flags BehaviorFl
 		return nil, false, fmt.Errorf("Already exists in the queue:%s", block.Hash().String())
 	}
 	b.processQueueMap.Store(bh, nil)
-	if b.consensus.Config().NoPowCheck {
-		flags |= BFNoPoWCheck
-	}
 	msg := processMsg{block: block, flags: flags, result: make(chan *processResult), source: source}
 	b.msgChan <- &msg
 	result := <-msg.result
diff --git a/core/blockchain/validate.go b/core/blockchain/validate.go
index 17ca0af0..350f963c 100644
--- a/core/blockchain/validate.go
+++ b/core/blockchain/validate.go
@@ -289,7 +289,7 @@ func checkProofOfWork(header *types.BlockHeader, powConfig *pow.PowConfig, flags
 
 	// The block hash must be less than the claimed target unless the flag
 	// to avoid proof of work checks is set.
-	if !flags.Has(BFNoPoWCheck) {
+	if !flags.Has(BFNoPoWCheck) && !params.ActiveNetParams.Params.IsDevelopDiff() {
 		header.Pow.SetParams(powConfig)
 		header.Pow.SetMainHeight(pow.MainHeight(mHeight))
 		// The block hash must be less than the claimed target.
@@ -751,7 +751,7 @@ func (b *BlockChain) checkBlockHeaderContext(block *types.SerializedBlock, prevN
 
 	header := &block.Block().Header
 	if !flags.Has(BFFastAdd) {
-		if !flags.Has(BFNoPoWCheck) {
+		if !b.params.IsDevelopDiff() {
 			instance := pow.GetInstance(header.Pow.GetPowType(), 0, []byte{})
 			instance.SetMainHeight(pow.MainHeight(prevNode.GetHeight() + 1))
 			instance.SetParams(b.params.PowConfig)
diff --git a/core/types/pow/diff.go b/core/types/pow/diff.go
index 86892646..e3eb9b0b 100644
--- a/core/types/pow/diff.go
+++ b/core/types/pow/diff.go
@@ -25,6 +25,8 @@ const (
 	DIFFICULTY_MODE_MEER = 0
 	// KASPAD difficulty adjustment
 	DIFFICULTY_MODE_KASPAD = 1
+	// DEVELOP difficulty adjustment
+	DIFFICULTY_MODE_DEVELOP = 2
 )
 
 // HashToBig converts a hash.Hash into a big.Int that can be used to
diff --git a/core/types/pow/difficultymanager/develop.go b/core/types/pow/difficultymanager/develop.go
new file mode 100644
index 00000000..96e2052e
--- /dev/null
+++ b/core/types/pow/difficultymanager/develop.go
@@ -0,0 +1,102 @@
+// Copyright (c) 2017-2018 The qitmeer developers
+// Copyright (c) 2013-2016 The btcsuite developers
+// Copyright (c) 2015-2018 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package difficultymanager
+
+import (
+	"math/big"
+	"time"
+
+	"github.com/Qitmeer/qng/consensus/model"
+	"github.com/Qitmeer/qng/core/types"
+	"github.com/Qitmeer/qng/core/types/pow"
+	"github.com/Qitmeer/qng/params"
+)
+
+type developDiff struct {
+	b   model.BlockChain
+	cfg *params.Params
+}
+
+// CalcEasiestDifficulty calculates the easiest possible difficulty that a block
+// can have given starting difficulty bits and a duration.  It is mainly used to
+// verify that claimed proof of work by a block is sane as compared to a
+// known good checkpoint.
+func (m *developDiff) CalcEasiestDifficulty(bits uint32, duration time.Duration, powInstance pow.IPow) uint32 {
+	// Convert types used in the calculations below.
+	durationVal := int64(duration)
+	adjustmentFactor := big.NewInt(m.cfg.RetargetAdjustmentFactor)
+	maxRetargetTimespan := int64(m.cfg.TargetTimespan) *
+		m.cfg.RetargetAdjustmentFactor
+	target := powInstance.GetSafeDiff(0)
+	// The test network rules allow minimum difficulty blocks once too much
+	// time has elapsed without mining a block.
+	if m.cfg.ReduceMinDifficulty {
+		if durationVal > int64(m.cfg.MinDiffReductionTime) {
+			return pow.BigToCompact(target)
+		}
+	}
+
+	// Since easier difficulty equates to higher numbers, the easiest
+	// difficulty for a given duration is the largest value possible given
+	// the number of retargets for the duration and starting difficulty
+	// multiplied by the max adjustment factor.
+	newTarget := pow.CompactToBig(bits)
+
+	for durationVal > 0 && powInstance.CompareDiff(newTarget, target) {
+		newTarget.Mul(newTarget, adjustmentFactor)
+		newTarget = powInstance.GetNextDiffBig(adjustmentFactor, newTarget, big.NewInt(0))
+		durationVal -= maxRetargetTimespan
+	}
+
+	// Limit new value to the proof of work limit.
+	if !powInstance.CompareDiff(newTarget, target) {
+		newTarget.Set(target)
+	}
+
+	return pow.BigToCompact(newTarget)
+}
+
+// findPrevTestNetDifficulty returns the difficulty of the previous block which
+// did not have the special testnet minimum difficulty rule applied.
+//
+// This function MUST be called with the chain state lock held (for writes).
+func (m *developDiff) findPrevTestNetDifficulty(startBlock model.Block, powInstance pow.IPow) uint32 {
+	// Search backwards through the chain for the last block without
+	// the special rule applied.
+	target := powInstance.GetSafeDiff(0)
+	lastBits := pow.BigToCompact(target)
+	blocksPerRetarget := uint64(m.cfg.WorkDiffWindowSize * m.cfg.WorkDiffWindows)
+	iterBlock := startBlock
+	if iterBlock == nil ||
+		uint64(iterBlock.GetHeight())%blocksPerRetarget == 0 {
+		return lastBits
+	}
+	var iterNode *types.BlockHeader
+	iterNode = m.b.GetBlockHeader(iterBlock)
+	if iterNode.Difficulty != pow.BigToCompact(target) {
+		return lastBits
+	}
+	return iterNode.Difficulty
+}
+
+// RequiredDifficulty calculates the required difficulty for the block
+// after the passed previous block node based on the difficulty retarget rules.
+// This function differs from the exported RequiredDifficulty in that
+// the exported version uses the current best chain as the previous block node
+// while this function accepts any block node.
+func (m *developDiff) RequiredDifficulty(block model.Block, newBlockTime time.Time, powInstance pow.IPow) (uint32, error) {
+	baseTarget := powInstance.GetSafeDiff(0)
+	return pow.BigToCompact(baseTarget), nil
+}
+
+// find block node by pow type
+func (m *developDiff) GetCurrentPowDiff(ib model.Block, powType pow.PowType) *big.Int {
+	instance := pow.GetInstance(powType, 0, []byte{})
+	instance.SetParams(m.cfg.PowConfig)
+	safeBigDiff := instance.GetSafeDiff(0)
+	return safeBigDiff
+}
diff --git a/core/types/pow/difficultymanager/difficultymanager.go b/core/types/pow/difficultymanager/difficultymanager.go
index 25f8cd92..fb7efeb9 100644
--- a/core/types/pow/difficultymanager/difficultymanager.go
+++ b/core/types/pow/difficultymanager/difficultymanager.go
@@ -19,6 +19,11 @@ func NewDiffManager(con model.Consensus, cfg *params.Params) model.DifficultyMan
 			genesisBits:                    cfg.PowConfig.MeerXKeccakV1PowLimitBits,
 			cfg:                            cfg,
 		}
+	case pow.DIFFICULTY_MODE_DEVELOP:
+		return &developDiff{
+			b:   con.BlockChain(),
+			cfg: cfg,
+		}
 	}
 	return &meerDiff{
 		con: con,
diff --git a/core/types/pow/difficultymanager/kaspad.go b/core/types/pow/difficultymanager/kaspad.go
index 321f3ba2..5f353f4c 100644
--- a/core/types/pow/difficultymanager/kaspad.go
+++ b/core/types/pow/difficultymanager/kaspad.go
@@ -115,7 +115,7 @@ func (m *kaspadDiff) RequiredDifficulty(block model.Block, newBlockTime time.Tim
 
 // RequiredDifficultyByWindows returns the difficulty required for some block
 func (dm *kaspadDiff) RequiredDifficultyByWindows(targetsWindow blockWindow) (uint32, error) {
-	if len(targetsWindow) < 1 || dm.con.Config().NoPowCheck {
+	if len(targetsWindow) < 1 {
 		return dm.genesisBits, nil
 	}
 	return dm.requiredDifficultyFromTargetsWindow(targetsWindow)
diff --git a/core/types/pow/difficultymanager/meer.go b/core/types/pow/difficultymanager/meer.go
index a69aaccd..2c3ff904 100644
--- a/core/types/pow/difficultymanager/meer.go
+++ b/core/types/pow/difficultymanager/meer.go
@@ -103,7 +103,7 @@ func (m *meerDiff) RequiredDifficulty(block model.Block, newBlockTime time.Time,
 	baseTarget := powInstance.GetSafeDiff(0)
 	originCurrentBlock := block
 	// Genesis block.
-	if block == nil || m.con.Config().NoPowCheck {
+	if block == nil {
 		return pow.BigToCompact(baseTarget), nil
 	}
 
diff --git a/params/params.go b/params/params.go
index 5829a01c..c7fab280 100644
--- a/params/params.go
+++ b/params/params.go
@@ -294,6 +294,10 @@ func (p *Params) HasTax() bool {
 	return false
 }
 
+func (p *Params) IsDevelopDiff() bool {
+	return p.PowConfig.DifficultyMode == pow.DIFFICULTY_MODE_DEVELOP
+}
+
 var (
 	// ErrDuplicateNet describes an error where the parameters for a network
 	// could not be set due to the network already being a standard
diff --git a/services/common/flags.go b/services/common/flags.go
index 812b8e5e..4447f23a 100644
--- a/services/common/flags.go
+++ b/services/common/flags.go
@@ -632,12 +632,6 @@ var (
 			Value:       false,
 			Destination: &cfg.SubmitNoSynced,
 		},
-		&cli.BoolFlag{
-			Name:        "nopowcheck",
-			Usage:       "Enable no pow check for debug node",
-			Value:       false,
-			Destination: &cfg.NoPowCheck,
-		},
 	}
 )
 
@@ -674,7 +668,6 @@ func DefaultConfig(homeDir string) *config.Config {
 		RPCPass:              defaultRPCPass,
 		ObsoleteHeight:       defaultObsoleteHeight,
 		SubmitNoSynced:       false,
-		NoPowCheck:           false,
 	}
 	if len(homeDir) > 0 {
 		hd, err := filepath.Abs(homeDir)
diff --git a/services/miner/cpuworker.go b/services/miner/cpuworker.go
index 10aebf9c..1b7c219c 100644
--- a/services/miner/cpuworker.go
+++ b/services/miner/cpuworker.go
@@ -307,7 +307,7 @@ out:
 			continue
 		}
 		start := time.Now()
-		if w.miner.cfg.NoPowCheck {
+		if params.ActiveNetParams.Params.IsDevelopDiff() {
 			time.Sleep(params.ActiveNetParams.Params.TargetTimePerBlock)
 		}
 		sb := w.solveBlock()
@@ -414,7 +414,7 @@ func (w *CPUWorker) solveBlock() *types.Block {
 		instance.SetParams(params.ActiveNetParams.Params.PowConfig)
 		hashesCompleted += 2
 		header.Pow = instance
-		if w.miner.cfg.NoPowCheck {
+		if params.ActiveNetParams.Params.IsDevelopDiff() {
 			return block
 		}
 		if header.Pow.FindSolver(header.BlockData(), header.BlockHash(), header.Difficulty) {