From 49b08dc2c7624027e976c422397775194aecd394 Mon Sep 17 00:00:00 2001 From: frankcrypto Date: Thu, 7 Dec 2023 10:15:36 +0800 Subject: [PATCH] restrcut --- consensus/model/block_chain.go | 5 + consensus/model/meer_dag.go | 11 + core/blockchain/validate.go | 8 +- core/types/pow/config.go | 4 +- .../difficultymanager/difficultymanager.go | 77 ------- .../interface_difficultymanager.go | 40 ++++ .../interface_processes_difficultymanager.go | 60 ------ core/types/pow/difficultymanager/kaspad.go | 195 ++++++++++++++++++ .../pow/difficultymanager/meer.go} | 187 +++++++---------- 9 files changed, 331 insertions(+), 256 deletions(-) create mode 100644 consensus/model/meer_dag.go delete mode 100644 core/types/pow/difficultymanager/difficultymanager.go create mode 100644 core/types/pow/difficultymanager/interface_difficultymanager.go delete mode 100644 core/types/pow/difficultymanager/interface_processes_difficultymanager.go create mode 100644 core/types/pow/difficultymanager/kaspad.go rename core/{blockchain/difficulty.go => types/pow/difficultymanager/meer.go} (68%) diff --git a/consensus/model/block_chain.go b/consensus/model/block_chain.go index 418f8d8d..dbb970f1 100644 --- a/consensus/model/block_chain.go +++ b/consensus/model/block_chain.go @@ -3,6 +3,8 @@ package model import ( "github.com/Qitmeer/qng/common/hash" "github.com/Qitmeer/qng/core/types" + "github.com/Qitmeer/qng/meerdag" + "github.com/Qitmeer/qng/params" ) type BlockChain interface { @@ -22,4 +24,7 @@ type BlockChain interface { GetBlockById(id uint) Block FetchBlockByHash(hash *hash.Hash) (*types.SerializedBlock, error) GetBlockOrderByHash(hash *hash.Hash) (uint, error) + GetBlockHeader(ib meerdag.IBlock) *types.BlockHeader + BlockDAG() *meerdag.MeerDAG + ChainParams() *params.Params } diff --git a/consensus/model/meer_dag.go b/consensus/model/meer_dag.go new file mode 100644 index 00000000..a2bf9fa4 --- /dev/null +++ b/consensus/model/meer_dag.go @@ -0,0 +1,11 @@ +package model + +import ( + "github.com/Qitmeer/qng/common/hash" + "github.com/Qitmeer/qng/rpc/api" +) + +type MeerDag interface { + RegisterAPIs(apis []api.API) + GetBlockIDByTxHash(txhash *hash.Hash) uint64 +} diff --git a/core/blockchain/validate.go b/core/blockchain/validate.go index b83c1dbf..5ab110f0 100644 --- a/core/blockchain/validate.go +++ b/core/blockchain/validate.go @@ -10,6 +10,9 @@ import ( "encoding/binary" "encoding/hex" "fmt" + "math" + "time" + "github.com/Qitmeer/qng/common/hash" "github.com/Qitmeer/qng/consensus/forks" "github.com/Qitmeer/qng/consensus/model" @@ -22,11 +25,10 @@ import ( "github.com/Qitmeer/qng/core/state" "github.com/Qitmeer/qng/core/types" "github.com/Qitmeer/qng/core/types/pow" + "github.com/Qitmeer/qng/core/types/pow/difficultymanager" "github.com/Qitmeer/qng/engine/txscript" "github.com/Qitmeer/qng/meerdag" "github.com/Qitmeer/qng/params" - "math" - "time" ) const ( @@ -758,7 +760,7 @@ func (b *BlockChain) checkBlockHeaderContext(block *types.SerializedBlock, prevN // 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, + expDiff, err := difficultymanager.NewDiffManager(b).CalcNextRequiredDifficulty(prevNode, header.Timestamp, instance) if err != nil { return err diff --git a/core/types/pow/config.go b/core/types/pow/config.go index 52e7b0a4..34a1a1a3 100644 --- a/core/types/pow/config.go +++ b/core/types/pow/config.go @@ -48,9 +48,11 @@ type PowConfig struct { //is init init bool + + DifficultyMode int } -//global cache +// global cache func GetPowConfig() *PowConfig { if PowConfigInstance != nil { return PowConfigInstance diff --git a/core/types/pow/difficultymanager/difficultymanager.go b/core/types/pow/difficultymanager/difficultymanager.go deleted file mode 100644 index 84f96149..00000000 --- a/core/types/pow/difficultymanager/difficultymanager.go +++ /dev/null @@ -1,77 +0,0 @@ -package difficultymanager - -import ( - "math/big" - "time" - - "github.com/Qitmeer/qng/common/math" - "github.com/Qitmeer/qng/core/types/pow" - "github.com/Qitmeer/qng/params" -) - -// DifficultyManager provides a method to resolve the -// difficulty value of a block -type difficultyManager struct { - powMax *big.Int - difficultyAdjustmentWindowSize int - disableDifficultyAdjustment bool - targetTimePerBlock time.Duration - genesisBits uint32 -} - -// New instantiates a new DifficultyManager -func New(cfg *params.Params) DifficultyManager { - return &difficultyManager{ - powMax: cfg.PowConfig.MeerXKeccakV1PowLimit, - difficultyAdjustmentWindowSize: int(cfg.WorkDiffWindowSize), - disableDifficultyAdjustment: false, - targetTimePerBlock: cfg.TargetTimePerBlock, - genesisBits: cfg.PowConfig.MeerXKeccakV1PowLimitBits, - } -} - -// RequiredDifficulty returns the difficulty required for some block -func (dm *difficultyManager) RequiredDifficulty(targetsWindow BlockWindow, powInstance pow.IPow) (uint32, error) { - if powInstance.GetPowType() != pow.MEERXKECCAKV1 || len(targetsWindow) < 1 { - return dm.genesisBits, nil - } - return dm.requiredDifficultyFromTargetsWindow(targetsWindow) -} - -func (dm *difficultyManager) requiredDifficultyFromTargetsWindow(targetsWindow BlockWindow) (uint32, error) { - if dm.disableDifficultyAdjustment { - return dm.genesisBits, nil - } - - // in the past this was < 2 as the comment explains, we changed it to under the window size to - // make the hashrate(which is ~1.5GH/s) constant in the first 2641 blocks so that we won't have a lot of tips - - // We need at least 2 blocks to get a timestamp interval - // We could instead clamp the timestamp difference to `targetTimePerBlock`, - // but then everything will cancel out and we'll get the target from the last block, which will be the same as genesis. - // We add 64 as a safety margin - if len(targetsWindow) < 2 || len(targetsWindow) < dm.difficultyAdjustmentWindowSize { - return dm.genesisBits, nil - } - - windowMinTimestamp, windowMaxTimeStamp, windowMinIndex := targetsWindow.MinMaxTimestamps() - // Remove the last block from the window so to calculate the average target of dag.difficultyAdjustmentWindowSize blocks - targetsWindow.Remove(windowMinIndex) - - // Calculate new target difficulty as: - // averageWindowTarget * (windowMinTimestamp / (targetTimePerBlock * windowSize)) - // The result uses integer division which means it will be slightly - // rounded down. - div := new(big.Int) - newTarget := targetsWindow.AverageTarget() - newTarget. - // We need to clamp the timestamp difference to 1 so that we'll never get a 0 target. - Mul(newTarget, div.SetInt64(math.MaxInt64Val(windowMaxTimeStamp-windowMinTimestamp, 1))). - Div(newTarget, div.SetInt64(dm.targetTimePerBlock.Milliseconds())). - Div(newTarget, div.SetUint64(uint64(len(targetsWindow)))) - if newTarget.Cmp(dm.powMax) > 0 { - return pow.BigToCompact(dm.powMax), nil - } - newTargetBits := pow.BigToCompact(newTarget) - return newTargetBits, nil -} diff --git a/core/types/pow/difficultymanager/interface_difficultymanager.go b/core/types/pow/difficultymanager/interface_difficultymanager.go new file mode 100644 index 00000000..2541aec7 --- /dev/null +++ b/core/types/pow/difficultymanager/interface_difficultymanager.go @@ -0,0 +1,40 @@ +package difficultymanager + +import ( + "time" + + "github.com/Qitmeer/qng/consensus/model" + "github.com/Qitmeer/qng/core/types/pow" + "github.com/Qitmeer/qng/meerdag" +) + +const ( + // MEER difficulty adjustment + DIFFICULTY_MODE_MEER = iota + // KASPAD difficulty adjustment + DIFFICULTY_MODE_KASPAD +) + +// DifficultyManager provides a method to resolve the +// difficulty value of a block +type DifficultyManager interface { + CalcNextRequiredDifficulty(timestamp time.Time, powType pow.PowType) (uint32, error) + RequiredDifficulty(block meerdag.IBlock, newBlockTime time.Time, powInstance pow.IPow) (uint32, error) +} + +func NewDiffManager(b model.BlockChain) DifficultyManager { + switch b.ChainParams().PowConfig.DifficultyMode { + case DIFFICULTY_MODE_KASPAD: + return &kaspadDiff{ + b: b, + powMax: b.ChainParams().PowConfig.MeerXKeccakV1PowLimit, + difficultyAdjustmentWindowSize: int(b.ChainParams().WorkDiffWindowSize), + disableDifficultyAdjustment: false, + targetTimePerBlock: b.ChainParams().TargetTimePerBlock, + genesisBits: b.ChainParams().PowConfig.MeerXKeccakV1PowLimitBits, + } + } + return &meerDiff{ + b: b, + } +} diff --git a/core/types/pow/difficultymanager/interface_processes_difficultymanager.go b/core/types/pow/difficultymanager/interface_processes_difficultymanager.go deleted file mode 100644 index 887e43e0..00000000 --- a/core/types/pow/difficultymanager/interface_processes_difficultymanager.go +++ /dev/null @@ -1,60 +0,0 @@ -package difficultymanager - -import ( - "math" - "math/big" - - "github.com/Qitmeer/qng/common/hash" - "github.com/Qitmeer/qng/core/types/pow" -) - -type DifficultyBlock struct { - TimeInMilliseconds int64 - Bits uint32 - Hash hash.Hash - BlueWork bool -} -type BlockWindow []DifficultyBlock - -func ghostdagLess(blockA *DifficultyBlock, blockB *DifficultyBlock) bool { - return blockA.BlueWork == blockB.BlueWork -} - -func (window BlockWindow) MinMaxTimestamps() (min, max int64, minIndex int) { - min = math.MaxInt64 - minIndex = 0 - max = 0 - for i, block := range window { - // If timestamps are equal we ghostdag compare in order to reach consensus on `minIndex` - if block.TimeInMilliseconds < min || - (block.TimeInMilliseconds == min && ghostdagLess(&block, &window[minIndex])) { - min = block.TimeInMilliseconds - minIndex = i - } - if block.TimeInMilliseconds > max { - max = block.TimeInMilliseconds - } - } - return -} - -func (window *BlockWindow) Remove(n int) { - (*window)[n] = (*window)[len(*window)-1] - *window = (*window)[:len(*window)-1] -} - -func (window BlockWindow) AverageTarget() *big.Int { - averageTarget := new(big.Int) - targetTmp := new(big.Int) - for _, block := range window { - pow.CompactToBigWithDestination(block.Bits, targetTmp) - averageTarget.Add(averageTarget, targetTmp) - } - return averageTarget.Div(averageTarget, big.NewInt(int64(len(window)))) -} - -// DifficultyManager provides a method to resolve the -// difficulty value of a block -type DifficultyManager interface { - RequiredDifficulty(blocks BlockWindow, powInstance pow.IPow) (uint32, error) -} diff --git a/core/types/pow/difficultymanager/kaspad.go b/core/types/pow/difficultymanager/kaspad.go new file mode 100644 index 00000000..b836e252 --- /dev/null +++ b/core/types/pow/difficultymanager/kaspad.go @@ -0,0 +1,195 @@ +package difficultymanager + +import ( + "math/big" + "time" + + "github.com/Qitmeer/qng/common/hash" + "github.com/Qitmeer/qng/common/math" + "github.com/Qitmeer/qng/consensus/model" + "github.com/Qitmeer/qng/core/types/pow" + "github.com/Qitmeer/qng/meerdag" +) + +type DifficultyBlock struct { + TimeInMilliseconds int64 + Bits uint32 + Hash hash.Hash + BlueWork bool +} +type blockWindow []DifficultyBlock + +func ghostdagLess(blockA *DifficultyBlock, blockB *DifficultyBlock) bool { + return blockA.BlueWork == blockB.BlueWork +} + +func (window blockWindow) MinMaxTimestamps() (min, max int64, minIndex int) { + min = math.MaxInt64 + minIndex = 0 + max = 0 + for i, block := range window { + // If timestamps are equal we ghostdag compare in order to reach consensus on `minIndex` + if block.TimeInMilliseconds < min || + (block.TimeInMilliseconds == min && ghostdagLess(&block, &window[minIndex])) { + min = block.TimeInMilliseconds + minIndex = i + } + if block.TimeInMilliseconds > max { + max = block.TimeInMilliseconds + } + } + return +} + +func (window *blockWindow) Remove(n int) { + (*window)[n] = (*window)[len(*window)-1] + *window = (*window)[:len(*window)-1] +} + +func (window blockWindow) AverageTarget() *big.Int { + averageTarget := new(big.Int) + targetTmp := new(big.Int) + for _, block := range window { + pow.CompactToBigWithDestination(block.Bits, targetTmp) + averageTarget.Add(averageTarget, targetTmp) + } + return averageTarget.Div(averageTarget, big.NewInt(int64(len(window)))) +} + +// DifficultyManager provides a method to resolve the +// difficulty value of a block +type kaspadDiff struct { + powMax *big.Int + difficultyAdjustmentWindowSize int + disableDifficultyAdjustment bool + targetTimePerBlock time.Duration + genesisBits uint32 + b model.BlockChain +} + +func (m *kaspadDiff) CalcNextRequiredDifficulty(timestamp time.Time, powType pow.PowType) (uint32, error) { + m.b.ChainRLock() + block := m.b.BlockDAG().GetMainChainTip() + instance := pow.GetInstance(powType, 0, []byte{}) + instance.SetParams(m.b.ChainParams().PowConfig) + instance.SetMainHeight(pow.MainHeight(block.GetHeight() + 1)) + difficulty, err := m.RequiredDifficultyByWindows(m.getblockWindows(block, instance.GetPowType(), int(m.b.ChainParams().WorkDiffWindowSize))) + m.b.ChainRUnlock() + return difficulty, err +} + +func (m *kaspadDiff) RequiredDifficulty(block meerdag.IBlock, newBlockTime time.Time, powInstance pow.IPow) (uint32, error) { + return m.RequiredDifficultyByWindows(m.getblockWindows(block, powInstance.GetPowType(), int(m.b.ChainParams().WorkDiffWindowSize))) +} + +// RequiredDifficultyByWindows returns the difficulty required for some block +func (dm *kaspadDiff) RequiredDifficultyByWindows(targetsWindow blockWindow) (uint32, error) { + if len(targetsWindow) < 1 { + return dm.genesisBits, nil + } + return dm.requiredDifficultyFromTargetsWindow(targetsWindow) +} + +func (dm *kaspadDiff) requiredDifficultyFromTargetsWindow(targetsWindow blockWindow) (uint32, error) { + if dm.disableDifficultyAdjustment { + return dm.genesisBits, nil + } + + // in the past this was < 2 as the comment explains, we changed it to under the window size to + // make the hashrate(which is ~1.5GH/s) constant in the first 2641 blocks so that we won't have a lot of tips + + // We need at least 2 blocks to get a timestamp interval + // We could instead clamp the timestamp difference to `targetTimePerBlock`, + // but then everything will cancel out and we'll get the target from the last block, which will be the same as genesis. + // We add 64 as a safety margin + if len(targetsWindow) < 2 || len(targetsWindow) < dm.difficultyAdjustmentWindowSize { + return dm.genesisBits, nil + } + + windowMinTimestamp, windowMaxTimeStamp, windowMinIndex := targetsWindow.MinMaxTimestamps() + // Remove the last block from the window so to calculate the average target of dag.difficultyAdjustmentWindowSize blocks + targetsWindow.Remove(windowMinIndex) + + // Calculate new target difficulty as: + // averageWindowTarget * (windowMinTimestamp / (targetTimePerBlock * windowSize)) + // The result uses integer division which means it will be slightly + // rounded down. + div := new(big.Int) + newTarget := targetsWindow.AverageTarget() + newTarget. + // We need to clamp the timestamp difference to 1 so that we'll never get a 0 target. + Mul(newTarget, div.SetInt64(math.MaxInt64Val(windowMaxTimeStamp-windowMinTimestamp, 1))). + Div(newTarget, div.SetInt64(dm.targetTimePerBlock.Milliseconds())). + Div(newTarget, div.SetUint64(uint64(len(targetsWindow)))) + if newTarget.Cmp(dm.powMax) > 0 { + return pow.BigToCompact(dm.powMax), nil + } + newTargetBits := pow.BigToCompact(newTarget) + return newTargetBits, nil +} + +// blockWindow returns a blockWindow of the given size that contains the +// blocks in the past of startingNode, the sorting is unspecified. +// If the number of blocks in the past of startingNode is less then windowSize, +// the window will be padded by genesis blocks to achieve a size of windowSize. +func (dm *kaspadDiff) getblockWindows(oldBlock meerdag.IBlock, powType pow.PowType, windowSize int) blockWindow { + windows := make(blockWindow, 0, windowSize) + count := 0 + for i := uint64(0); ; i++ { + // Get the previous node while staying at the genesis block as + // needed. + if oldBlock == nil || !oldBlock.HasParents() { + break + } + ids := oldBlock.GetParents().SortList(false) + for i := 0; i < len(ids); i++ { + id := ids[i] + if count >= windowSize { + return windows + } + oldBlock = dm.b.BlockDAG().GetBlockById(id) + if oldBlock == nil { + continue + } + oldBlock = dm.getPowTypeNode(oldBlock, powType) + if oldBlock == nil { + continue + } + + on := dm.b.GetBlockHeader(oldBlock) + if on == nil { + continue + } + windows = append(windows, DifficultyBlock{ + TimeInMilliseconds: on.Timestamp.UnixMilli(), + Bits: on.Difficulty, + Hash: on.BlockHash(), + BlueWork: dm.b.BlockDAG().IsBlue(oldBlock.GetID()), + }) + count++ + } + + } + return windows +} + +// find block node by pow type +func (m *kaspadDiff) getPowTypeNode(block meerdag.IBlock, powType pow.PowType) meerdag.IBlock { + for { + curNode := m.b.GetBlockHeader(block) + if curNode == nil { + return nil + } + if curNode.Pow.GetPowType() == powType { + return block + } + + if !block.HasParents() { + return nil + } + block = m.b.BlockDAG().GetBlockById(block.GetMainParent()) + if block == nil { + return nil + } + } +} diff --git a/core/blockchain/difficulty.go b/core/types/pow/difficultymanager/meer.go similarity index 68% rename from core/blockchain/difficulty.go rename to core/types/pow/difficultymanager/meer.go index 25c243c6..97f06f3a 100644 --- a/core/blockchain/difficulty.go +++ b/core/types/pow/difficultymanager/meer.go @@ -4,7 +4,7 @@ // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package blockchain +package difficultymanager import ( "fmt" @@ -12,10 +12,11 @@ import ( "time" "github.com/Qitmeer/qng/common/hash" + "github.com/Qitmeer/qng/consensus/model" "github.com/Qitmeer/qng/core/types" "github.com/Qitmeer/qng/core/types/pow" + "github.com/Qitmeer/qng/log" - "github.com/Qitmeer/qng/core/types/pow/difficultymanager" "github.com/Qitmeer/qng/meerdag" ) @@ -27,21 +28,25 @@ var bigZero = big.NewInt(0) // testnet difficulty). const maxShift = uint(256) +type meerDiff struct { + b model.BlockChain +} + // 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 (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration, powInstance pow.IPow) uint32 { +func (m meerDiff) calcEasiestDifficulty(bits uint32, duration time.Duration, powInstance pow.IPow) uint32 { // Convert types used in the calculations below. durationVal := int64(duration) - adjustmentFactor := big.NewInt(b.params.RetargetAdjustmentFactor) - maxRetargetTimespan := int64(b.params.TargetTimespan) * - b.params.RetargetAdjustmentFactor + adjustmentFactor := big.NewInt(m.b.ChainParams().RetargetAdjustmentFactor) + maxRetargetTimespan := int64(m.b.ChainParams().TargetTimespan) * + m.b.ChainParams().RetargetAdjustmentFactor target := powInstance.GetSafeDiff(0) // The test network rules allow minimum difficulty blocks once too much // time has elapsed without mining a block. - if b.params.ReduceMinDifficulty { - if durationVal > int64(b.params.MinDiffReductionTime) { + if m.b.ChainParams().ReduceMinDifficulty { + if durationVal > int64(m.b.ChainParams().MinDiffReductionTime) { return pow.BigToCompact(target) } } @@ -70,34 +75,31 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration, // did not have the special testnet minimum difficulty rule applied. // // This function MUST be called with the chain state lock held (for writes). -func (b *BlockChain) findPrevTestNetDifficulty(startBlock meerdag.IBlock, powInstance pow.IPow) uint32 { +func (m meerDiff) findPrevTestNetDifficulty(startBlock meerdag.IBlock, 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(b.params.WorkDiffWindowSize * b.params.WorkDiffWindows) + blocksPerRetarget := uint64(m.b.ChainParams().WorkDiffWindowSize * m.b.ChainParams().WorkDiffWindows) iterBlock := startBlock if iterBlock == nil || uint64(iterBlock.GetHeight())%blocksPerRetarget == 0 { return lastBits } var iterNode *types.BlockHeader - iterNode = b.GetBlockHeader(iterBlock) + iterNode = m.b.GetBlockHeader(iterBlock) if iterNode.Difficulty != pow.BigToCompact(target) { return lastBits } return iterNode.Difficulty } -// calcNextRequiredDifficulty calculates the required difficulty for the block +// 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 CalcNextRequiredDifficulty in that +// 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 (b *BlockChain) calcNextRequiredDifficulty(block meerdag.IBlock, newBlockTime time.Time, powInstance pow.IPow) (uint32, error) { - if powInstance.GetPowType() == pow.MEERXKECCAKV1 { - return difficultymanager.New(b.params).RequiredDifficulty(b.getBlockWindows(block, powInstance.GetPowType(), int(b.params.WorkDiffWindowSize)), powInstance) - } +func (m meerDiff) RequiredDifficulty(block meerdag.IBlock, newBlockTime time.Time, powInstance pow.IPow) (uint32, error) { baseTarget := powInstance.GetSafeDiff(0) originCurrentBlock := block // Genesis block. @@ -105,11 +107,11 @@ func (b *BlockChain) calcNextRequiredDifficulty(block meerdag.IBlock, newBlockTi return pow.BigToCompact(baseTarget), nil } - block = b.getPowTypeNode(block, powInstance.GetPowType()) + block = m.getPowTypeNode(block, powInstance.GetPowType()) if block == nil { return pow.BigToCompact(baseTarget), nil } - curNode := b.GetBlockHeader(block) + curNode := m.b.GetBlockHeader(block) if curNode == nil { return pow.BigToCompact(baseTarget), nil } @@ -117,21 +119,21 @@ func (b *BlockChain) calcNextRequiredDifficulty(block meerdag.IBlock, newBlockTi // just return this. oldDiff := curNode.Difficulty oldDiffBig := pow.CompactToBig(curNode.Difficulty) - windowsSizeBig := big.NewInt(b.params.WorkDiffWindowSize) + windowsSizeBig := big.NewInt(m.b.ChainParams().WorkDiffWindowSize) // percent is *100 * 2^32 windowsSizeBig.Mul(windowsSizeBig, powInstance.PowPercent()) windowsSizeBig.Div(windowsSizeBig, big.NewInt(100)) windowsSizeBig.Rsh(windowsSizeBig, 32) needAjustCount := int64(windowsSizeBig.Uint64()) // We're not at a retarget point, return the oldDiff. - if !b.needAjustPowDifficulty(block, powInstance.GetPowType(), needAjustCount) { + if !m.needAjustPowDifficulty(block, powInstance.GetPowType(), needAjustCount) { // For networks that support it, allow special reduction of the // required difficulty once too much time has elapsed without // mining a block. - if b.params.ReduceMinDifficulty { + if m.b.ChainParams().ReduceMinDifficulty { // Return minimum difficulty when more than the desired // amount of time has elapsed without mining a block. - reductionTime := int64(b.params.MinDiffReductionTime / + reductionTime := int64(m.b.ChainParams().MinDiffReductionTime / time.Second) allowMinTime := curNode.Timestamp.Unix() + reductionTime @@ -140,7 +142,7 @@ func (b *BlockChain) calcNextRequiredDifficulty(block meerdag.IBlock, newBlockTi if newBlockTime.Unix() > allowMinTime { timePassed := newBlockTime.Unix() - curNode.Timestamp.Unix() timePassed -= reductionTime - shifts := uint((timePassed / int64(b.params.TargetTimePerBlock/ + shifts := uint((timePassed / int64(m.b.ChainParams().TargetTimePerBlock/ time.Second)) + 1) // Scale the difficulty with time passed. @@ -163,29 +165,29 @@ func (b *BlockChain) calcNextRequiredDifficulty(block meerdag.IBlock, newBlockTi // The block was mined within the desired timeframe, so // return the difficulty for the last block which did // not have the special minimum difficulty rule applied. - return b.findPrevTestNetDifficulty(block, powInstance), nil + return m.findPrevTestNetDifficulty(block, powInstance), nil } return oldDiff, nil } // Declare some useful variables. - RAFBig := big.NewInt(b.params.RetargetAdjustmentFactor) + RAFBig := big.NewInt(m.b.ChainParams().RetargetAdjustmentFactor) nextDiffBigMin := pow.CompactToBig(curNode.Difficulty) nextDiffBigMin.Div(nextDiffBigMin, RAFBig) nextDiffBigMax := pow.CompactToBig(curNode.Difficulty) nextDiffBigMax.Mul(nextDiffBigMax, RAFBig) - alpha := b.params.WorkDiffAlpha + alpha := m.b.ChainParams().WorkDiffAlpha // Number of nodes to traverse while calculating difficulty. - nodesToTraverse := needAjustCount * b.params.WorkDiffWindows - percentStatsRecentCount := b.params.WorkDiffWindowSize * b.params.WorkDiffWindows + nodesToTraverse := needAjustCount * m.b.ChainParams().WorkDiffWindows + percentStatsRecentCount := m.b.ChainParams().WorkDiffWindowSize * m.b.ChainParams().WorkDiffWindows //calc pow block count in last nodesToTraverse blocks - currentPowBlockCount := b.calcCurrentPowCount(originCurrentBlock, percentStatsRecentCount, powInstance.GetPowType()) + currentPowBlockCount := m.calcCurrentPowCount(originCurrentBlock, percentStatsRecentCount, powInstance.GetPowType()) // Initialize bigInt slice for the percentage changes for each window period // above or below the target. - windowChanges := make([]*big.Int, b.params.WorkDiffWindows) + windowChanges := make([]*big.Int, m.b.ChainParams().WorkDiffWindows) // Regress through all of the previous blocks and store the percent changes // per window period; use bigInts to emulate 64.32 bit fixed point. @@ -205,22 +207,22 @@ func (b *BlockChain) calcNextRequiredDifficulty(block meerdag.IBlock, newBlockTi // Just assume we're at the target (no change) if we've // gone all the way back to the genesis block. if oldBlockOrder == 0 { - timeDifference = int64(b.params.TargetTimespan / + timeDifference = int64(m.b.ChainParams().TargetTimespan / time.Second) } timeDifBig := big.NewInt(timeDifference) timeDifBig.Lsh(timeDifBig, 32) // Add padding - targetTemp := big.NewInt(int64(b.params.TargetTimespan / + targetTemp := big.NewInt(int64(m.b.ChainParams().TargetTimespan / time.Second)) windowAdjusted := targetTemp.Div(timeDifBig, targetTemp) // Weight it exponentially. Be aware that this could at some point // overflow if alpha or the number of blocks used is really large. windowAdjusted = windowAdjusted.Lsh(windowAdjusted, - uint((b.params.WorkDiffWindows-windowPeriod)*alpha)) + uint((m.b.ChainParams().WorkDiffWindows-windowPeriod)*alpha)) // Sum up all the different weights incrementally. - weights += 1 << uint64((b.params.WorkDiffWindows-windowPeriod)* + weights += 1 << uint64((m.b.ChainParams().WorkDiffWindows-windowPeriod)* alpha) // Store it in the slice. @@ -237,17 +239,17 @@ func (b *BlockChain) calcNextRequiredDifficulty(block meerdag.IBlock, newBlockTi // Get the previous node while staying at the genesis block as // needed. if oldBlock != nil && oldBlock.HasParents() { - oldBlock = b.bd.GetBlockById(oldBlock.GetMainParent()) + oldBlock = m.b.BlockDAG().GetBlockById(oldBlock.GetMainParent()) if oldBlock == nil { continue } - oldBlock = b.getPowTypeNode(oldBlock, powInstance.GetPowType()) + oldBlock = m.getPowTypeNode(oldBlock, powInstance.GetPowType()) if oldBlock == nil { oldNodeTimestamp = 0 oldBlockOrder = 0 continue } - on := b.GetBlockHeader(oldBlock) + on := m.b.GetBlockHeader(oldBlock) if on == nil { continue } @@ -257,7 +259,7 @@ func (b *BlockChain) calcNextRequiredDifficulty(block meerdag.IBlock, newBlockTi } // Sum up the weighted window periods. weightedSum := big.NewInt(0) - for i := int64(0); i < b.params.WorkDiffWindows; i++ { + for i := int64(0); i < m.b.ChainParams().WorkDiffWindows; i++ { weightedSum.Add(weightedSum, windowChanges[i]) } @@ -308,53 +310,8 @@ func (b *BlockChain) calcNextRequiredDifficulty(block meerdag.IBlock, newBlockTi return nextDiffBits, nil } -// blockWindow returns a blockWindow of the given size that contains the -// blocks in the past of startingNode, the sorting is unspecified. -// If the number of blocks in the past of startingNode is less then windowSize, -// the window will be padded by genesis blocks to achieve a size of windowSize. -func (b *BlockChain) getBlockWindows(oldBlock meerdag.IBlock, powType pow.PowType, windowSize int) difficultymanager.BlockWindow { - windows := make(difficultymanager.BlockWindow, 0, windowSize) - count := 0 - for i := uint64(0); ; i++ { - // Get the previous node while staying at the genesis block as - // needed. - if oldBlock == nil || !oldBlock.HasParents() { - break - } - ids := oldBlock.GetParents().SortList(false) - for i := 0; i < len(ids); i++ { - id := ids[i] - if count >= windowSize { - return windows - } - oldBlock = b.bd.GetBlockById(id) - if oldBlock == nil { - continue - } - oldBlock = b.getPowTypeNode(oldBlock, powType) - if oldBlock == nil { - continue - } - - on := b.GetBlockHeader(oldBlock) - if on == nil { - continue - } - windows = append(windows, difficultymanager.DifficultyBlock{ - TimeInMilliseconds: on.Timestamp.UnixMilli(), - Bits: on.Difficulty, - Hash: on.BlockHash(), - BlueWork: b.BlockDAG().IsBlue(oldBlock.GetID()), - }) - count++ - } - - } - return windows -} - // stats current pow count in nodesToTraverse -func (b *BlockChain) calcCurrentPowCount(block meerdag.IBlock, nodesToTraverse int64, powType pow.PowType) int64 { +func (m meerDiff) calcCurrentPowCount(block meerdag.IBlock, nodesToTraverse int64, powType pow.PowType) int64 { // Genesis block. if block == nil { return 0 @@ -370,9 +327,9 @@ func (b *BlockChain) calcCurrentPowCount(block meerdag.IBlock, nodesToTraverse i currentPowBlockCount-- } if oldBlock.HasParents() { - ob := b.bd.GetBlockById(oldBlock.GetMainParent()) + ob := m.b.BlockDAG().GetBlockById(oldBlock.GetMainParent()) if ob != nil { - oldNode := b.GetBlockHeader(ob) + oldNode := m.b.GetBlockHeader(ob) if oldNode == nil { continue } @@ -388,21 +345,21 @@ func (b *BlockChain) calcCurrentPowCount(block meerdag.IBlock, nodesToTraverse i } // whether need ajust Pow Difficulty -// recent b.params.WorkDiffWindowSize blocks +// recent m.b.ChainParams().WorkDiffWindowSize blocks // if current count arrived target block count . need ajustment difficulty -func (b *BlockChain) needAjustPowDifficulty(block meerdag.IBlock, powType pow.PowType, needAjustCount int64) bool { - countFromLastAdjustment := b.getDistanceFromLastAdjustment(block, powType, needAjustCount) - // countFromLastAdjustment stats b.params.WorkDiffWindows Multiple count - countFromLastAdjustment /= b.params.WorkDiffWindows +func (m meerDiff) needAjustPowDifficulty(block meerdag.IBlock, powType pow.PowType, needAjustCount int64) bool { + countFromLastAdjustment := m.getDistanceFromLastAdjustment(block, powType, needAjustCount) + // countFromLastAdjustment stats m.b.params.WorkDiffWindows Multiple count + countFromLastAdjustment /= m.b.ChainParams().WorkDiffWindows return countFromLastAdjustment > 0 && countFromLastAdjustment%needAjustCount == 0 } // Distance block count from last adjustment -func (b *BlockChain) getDistanceFromLastAdjustment(block meerdag.IBlock, powType pow.PowType, needAjustCount int64) int64 { +func (m meerDiff) getDistanceFromLastAdjustment(block meerdag.IBlock, powType pow.PowType, needAjustCount int64) int64 { if block == nil { return 0 } - curNode := b.GetBlockHeader(block) + curNode := m.b.GetBlockHeader(block) if curNode == nil { return 0 } @@ -423,17 +380,17 @@ func (b *BlockChain) getDistanceFromLastAdjustment(block meerdag.IBlock, powType } // if TargetTimespan have only one pow block need ajustment difficulty // or count >= needAjustCount - if (count > 1 && currentTime-curNode.Timestamp.Unix() > (count-1)*int64(b.params.TargetTimespan/time.Second)) || + if (count > 1 && currentTime-curNode.Timestamp.Unix() > (count-1)*int64(m.b.ChainParams().TargetTimespan/time.Second)) || count >= needAjustCount { - return needAjustCount * b.params.WorkDiffWindows + return needAjustCount * m.b.ChainParams().WorkDiffWindows } if !block.HasParents() { return count } - block = b.bd.GetBlockById(block.GetMainParent()) + block = m.b.BlockDAG().GetBlockById(block.GetMainParent()) if block != nil { - curNode = b.GetBlockHeader(block) + curNode = m.b.GetBlockHeader(block) } else { return count } @@ -444,16 +401,16 @@ func (b *BlockChain) getDistanceFromLastAdjustment(block meerdag.IBlock, powType // given with the passed hash along with the given timestamp. // // This function is NOT safe for concurrent access. -func (b *BlockChain) CalcNextRequiredDiffFromNode(hash *hash.Hash, timestamp time.Time, powType pow.PowType) (uint32, error) { - ib := b.bd.GetBlock(hash) +func (m meerDiff) CalcNextRequiredDiffFromNode(hash *hash.Hash, timestamp time.Time, powType pow.PowType) (uint32, error) { + ib := m.b.BlockDAG().GetBlock(hash) if ib == nil { return 0, fmt.Errorf("block %s is not known", hash) } instance := pow.GetInstance(powType, 0, []byte{}) - instance.SetParams(b.params.PowConfig) + instance.SetParams(m.b.ChainParams().PowConfig) instance.SetMainHeight(pow.MainHeight(ib.GetHeight() + 1)) - return b.calcNextRequiredDifficulty(ib, timestamp, instance) + return m.RequiredDifficulty(ib, timestamp, instance) } // CalcNextRequiredDifficulty calculates the required difficulty for the block @@ -461,21 +418,21 @@ func (b *BlockChain) CalcNextRequiredDiffFromNode(hash *hash.Hash, timestamp tim // rules. // // This function is safe for concurrent access. -func (b *BlockChain) CalcNextRequiredDifficulty(timestamp time.Time, powType pow.PowType) (uint32, error) { - b.ChainRLock() - block := b.bd.GetMainChainTip() +func (m meerDiff) CalcNextRequiredDifficulty(timestamp time.Time, powType pow.PowType) (uint32, error) { + m.b.ChainRLock() + block := m.b.BlockDAG().GetMainChainTip() instance := pow.GetInstance(powType, 0, []byte{}) - instance.SetParams(b.params.PowConfig) + instance.SetParams(m.b.ChainParams().PowConfig) instance.SetMainHeight(pow.MainHeight(block.GetHeight() + 1)) - difficulty, err := b.calcNextRequiredDifficulty(block, timestamp, instance) - b.ChainRUnlock() + difficulty, err := m.RequiredDifficulty(block, timestamp, instance) + m.b.ChainRUnlock() return difficulty, err } // find block node by pow type -func (b *BlockChain) getPowTypeNode(block meerdag.IBlock, powType pow.PowType) meerdag.IBlock { +func (m meerDiff) getPowTypeNode(block meerdag.IBlock, powType pow.PowType) meerdag.IBlock { for { - curNode := b.GetBlockHeader(block) + curNode := m.b.GetBlockHeader(block) if curNode == nil { return nil } @@ -486,7 +443,7 @@ func (b *BlockChain) getPowTypeNode(block meerdag.IBlock, powType pow.PowType) m if !block.HasParents() { return nil } - block = b.bd.GetBlockById(block.GetMainParent()) + block = m.b.BlockDAG().GetBlockById(block.GetMainParent()) if block == nil { return nil } @@ -494,12 +451,12 @@ func (b *BlockChain) getPowTypeNode(block meerdag.IBlock, powType pow.PowType) m } // find block node by pow type -func (b *BlockChain) GetCurrentPowDiff(ib meerdag.IBlock, powType pow.PowType) *big.Int { +func (m meerDiff) GetCurrentPowDiff(ib meerdag.IBlock, powType pow.PowType) *big.Int { instance := pow.GetInstance(powType, 0, []byte{}) - instance.SetParams(b.params.PowConfig) + instance.SetParams(m.b.ChainParams().PowConfig) safeBigDiff := instance.GetSafeDiff(0) for { - curNode := b.GetBlockHeader(ib) + curNode := m.b.GetBlockHeader(ib) if curNode == nil { return safeBigDiff } @@ -511,7 +468,7 @@ func (b *BlockChain) GetCurrentPowDiff(ib meerdag.IBlock, powType pow.PowType) * return safeBigDiff } - ib = b.bd.GetBlockById(ib.GetMainParent()) + ib = m.b.BlockDAG().GetBlockById(ib.GetMainParent()) if ib == nil { return safeBigDiff }