diff --git a/consensus/blake3pow/consensus.go b/consensus/blake3pow/consensus.go index d516881f66..668d8c3f7f 100644 --- a/consensus/blake3pow/consensus.go +++ b/consensus/blake3pow/consensus.go @@ -1,7 +1,6 @@ package blake3pow import ( - "errors" "fmt" "math/big" "runtime" @@ -47,22 +46,6 @@ var ( big2e256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) // 2^256 ) -// Various error messages to mark blocks invalid. These should be private to -// prevent engine specific errors from being referenced in the remainder of the -// codebase, inherently breaking if the engine is swapped out. Please put common -// error types into the consensus package. -var ( - errOlderBlockTime = errors.New("timestamp older than parent") - errTooManyUncles = errors.New("too many uncles") - errDuplicateUncle = errors.New("duplicate uncle") - errUncleIsAncestor = errors.New("uncle is ancestor") - errDanglingUncle = errors.New("uncle's parent is not ancestor") - errInvalidDifficulty = errors.New("non-positive difficulty") - errDifficultyCrossover = errors.New("sub's difficulty exceeds dom's") - errInvalidPoW = errors.New("invalid proof-of-work") - errInvalidOrder = errors.New("invalid order") -) - // Author implements consensus.Engine, returning the header's coinbase as the // proof-of-work verified author of the block. func (blake3pow *Blake3pow) Author(header *types.WorkObject) (common.Address, error) { @@ -194,7 +177,7 @@ func (blake3pow *Blake3pow) VerifyUncles(chain consensus.ChainReader, block *typ } // Verify that there are at most params.MaxWorkShareCount uncles included in this block if len(block.Uncles()) > params.MaxWorkShareCount { - return errTooManyUncles + return consensus.ErrTooManyUncles } if len(block.Uncles()) == 0 { return nil @@ -230,13 +213,13 @@ func (blake3pow *Blake3pow) VerifyUncles(chain consensus.ChainReader, block *typ // Make sure every uncle is rewarded only once hash := uncle.Hash() if uncles.Contains(hash) { - return errDuplicateUncle + return consensus.ErrDuplicateUncle } uncles.Add(hash) // Make sure the uncle has a valid ancestry if ancestors[hash] != nil { - return errUncleIsAncestor + return consensus.ErrUncleIsAncestor } // Siblings are not allowed to be included in the workshares list if its an // uncle but can be if its a workshare @@ -246,7 +229,7 @@ func (blake3pow *Blake3pow) VerifyUncles(chain consensus.ChainReader, block *typ workShare = true } if ancestors[uncle.ParentHash()] == nil || (!workShare && (uncle.ParentHash() == block.ParentHash(nodeCtx))) { - return errDanglingUncle + return consensus.ErrDanglingUncle } // make sure that the work can be computed @@ -300,7 +283,7 @@ func (blake3pow *Blake3pow) verifyHeader(chain consensus.ChainHeaderReader, head } } if header.Time() < parent.Time() { - return errOlderBlockTime + return consensus.ErrOlderBlockTime } // Verify the block's difficulty based on its timestamp and parent's difficulty // difficulty adjustment can only be checked in zone @@ -583,18 +566,18 @@ func (blake3pow *Blake3pow) verifySeal(header *types.WorkObjectHeader) error { if blake3pow.config.PowMode == ModeFake || blake3pow.config.PowMode == ModeFullFake { time.Sleep(blake3pow.fakeDelay) if blake3pow.fakeFail == header.NumberU64() { - return errInvalidPoW + return consensus.ErrInvalidPoW } return nil } // Ensure that we have a valid difficulty for the block if header.Difficulty().Sign() <= 0 { - return errInvalidDifficulty + return consensus.ErrInvalidDifficulty } target := new(big.Int).Div(big2e256, header.Difficulty()) if new(big.Int).SetBytes(header.Hash().Bytes()).Cmp(target) > 0 { - return errInvalidPoW + return consensus.ErrInvalidPoW } return nil } diff --git a/consensus/blake3pow/poem.go b/consensus/blake3pow/poem.go index 0dea95f5ee..e615d8dc83 100644 --- a/consensus/blake3pow/poem.go +++ b/consensus/blake3pow/poem.go @@ -68,8 +68,8 @@ func (blake3pow *Blake3pow) CalcOrder(chain consensus.BlockReader, header *types func (blake3pow *Blake3pow) IntrinsicLogS(powHash common.Hash) *big.Int { x := new(big.Int).SetBytes(powHash.Bytes()) d := new(big.Int).Div(big2e256, x) - c, m := mathutil.BinaryLog(d, mantBits) - bigBits := new(big.Int).Mul(big.NewInt(int64(c)), new(big.Int).Exp(big.NewInt(2), big.NewInt(mantBits), nil)) + c, m := mathutil.BinaryLog(d, consensus.MantBits) + bigBits := new(big.Int).Mul(big.NewInt(int64(c)), new(big.Int).Exp(big.NewInt(2), big.NewInt(consensus.MantBits), nil)) bigBits = new(big.Int).Add(bigBits, m) return bigBits } @@ -269,18 +269,14 @@ func (blake3pow *Blake3pow) CalcRank(chain consensus.ChainHeaderReader, header * } func (blake3pow *Blake3pow) CheckIfValidWorkShare(workShare *types.WorkObjectHeader) bool { - // Extract some data from the header - diff := new(big.Int).Set(workShare.Difficulty()) - c, _ := mathutil.BinaryLog(diff, mantBits) - if c <= params.WorkSharesThresholdDiff { + workShareMinTarget, err := consensus.CalcWorkShareThreshold(workShare) + if err != nil { + blake3pow.logger.Error(err) return false } - workShareThreshold := c - params.WorkSharesThresholdDiff - workShareDiff := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(workShareThreshold)), nil) - workShareMintarget := new(big.Int).Div(big2e256, workShareDiff) powHash, err := blake3pow.ComputePowHash(workShare) if err != nil { return false } - return new(big.Int).SetBytes(powHash.Bytes()).Cmp(workShareMintarget) <= 0 + return new(big.Int).SetBytes(powHash.Bytes()).Cmp(workShareMinTarget) <= 0 } diff --git a/consensus/blake3pow/sealer.go b/consensus/blake3pow/sealer.go index e30efb0f74..85b797de30 100644 --- a/consensus/blake3pow/sealer.go +++ b/consensus/blake3pow/sealer.go @@ -10,18 +10,13 @@ import ( "runtime/debug" "sync" + "github.com/dominant-strategies/go-quai/consensus" "github.com/dominant-strategies/go-quai/core/types" "github.com/dominant-strategies/go-quai/log" "github.com/dominant-strategies/go-quai/params" "modernc.org/mathutil" ) -const ( - // staleThreshold is the maximum depth of the acceptable stale but valid blake3pow solution. - staleThreshold = 7 - mantBits = 64 -) - var ( errNoMiningWork = errors.New("no mining work available yet") errInvalidSealResult = errors.New("invalid or stale proof-of-work solution") @@ -130,7 +125,7 @@ func (blake3pow *Blake3pow) Seal(header *types.WorkObject, results chan<- *types func (blake3pow *Blake3pow) mine(header *types.WorkObject, id int, seed uint64, abort chan struct{}, found chan *types.WorkObject) { // Extract some data from the header diff := new(big.Int).Set(header.Difficulty()) - c, _ := mathutil.BinaryLog(diff, mantBits) + c, _ := mathutil.BinaryLog(diff, consensus.MantBits) if c <= params.WorkSharesThresholdDiff { return } diff --git a/consensus/consensus.go b/consensus/consensus.go index 1c7aff72fc..2816a8f804 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -18,12 +18,52 @@ package consensus import ( + "errors" "math/big" "github.com/dominant-strategies/go-quai/common" "github.com/dominant-strategies/go-quai/core/state" "github.com/dominant-strategies/go-quai/core/types" "github.com/dominant-strategies/go-quai/params" + "modernc.org/mathutil" +) + +const ( + // staleThreshold is the maximum depth of the acceptable stale but valid solution. + StaleThreshold = 7 + MantBits = 64 +) + +// Some useful constants to avoid constant memory allocs for them. +var ( + ExpDiffPeriod = big.NewInt(100000) + Big0 = big.NewInt(0) + Big1 = big.NewInt(1) + Big2 = big.NewInt(2) + Big3 = big.NewInt(3) + Big8 = big.NewInt(8) + Big9 = big.NewInt(9) + Big10 = big.NewInt(10) + Big32 = big.NewInt(32) + BigMinus99 = big.NewInt(-99) + Big2e256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) // 2^256 +) + +// Various error messages to mark blocks invalid. These should be private to +// prevent engine specific errors from being referenced in the remainder of the +// codebase, inherently breaking if the engine is swapped out. Please put common +// error types into the consensus package. +var ( + ErrOlderBlockTime = errors.New("timestamp older than parent") + ErrTooManyUncles = errors.New("too many uncles") + ErrDuplicateUncle = errors.New("duplicate uncle") + ErrUncleIsAncestor = errors.New("uncle is ancestor") + ErrDanglingUncle = errors.New("uncle's parent is not ancestor") + ErrInvalidDifficulty = errors.New("difficulty too low") + ErrDifficultyCrossover = errors.New("sub's difficulty exceeds dom's") + ErrInvalidMixHash = errors.New("invalid mixHash") + ErrInvalidPoW = errors.New("invalid proof-of-work") + ErrInvalidOrder = errors.New("invalid order") ) // ChainHeaderReader defines a small collection of methods needed to access the local @@ -191,6 +231,19 @@ func DifficultyToTarget(difficulty *big.Int) *big.Int { return TargetToDifficulty(difficulty) } +func CalcWorkShareThreshold(workShare *types.WorkObjectHeader) (*big.Int, error) { + // Extract some data from the header + diff := new(big.Int).Set(workShare.Difficulty()) + c, _ := mathutil.BinaryLog(diff, MantBits) + if c <= params.WorkSharesThresholdDiff { + return nil, ErrInvalidDifficulty + } + workShareThreshold := c - params.WorkSharesThresholdDiff + workShareDiff := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(workShareThreshold)), nil) + workShareMinTarget := new(big.Int).Div(Big2e256, workShareDiff) + return workShareMinTarget, nil +} + // PoW is a consensus engine based on proof-of-work. type PoW interface { Engine diff --git a/consensus/progpow/consensus.go b/consensus/progpow/consensus.go index b891a3bf4e..8d6d449dfc 100644 --- a/consensus/progpow/consensus.go +++ b/consensus/progpow/consensus.go @@ -2,7 +2,6 @@ package progpow import ( "bytes" - "errors" "fmt" "math/big" "runtime" @@ -48,23 +47,6 @@ var ( big2e256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) // 2^256 ) -// Various error messages to mark blocks invalid. These should be private to -// prevent engine specific errors from being referenced in the remainder of the -// codebase, inherently breaking if the engine is swapped out. Please put common -// error types into the consensus package. -var ( - errOlderBlockTime = errors.New("timestamp older than parent") - errTooManyUncles = errors.New("too many uncles") - errDuplicateUncle = errors.New("duplicate uncle") - errUncleIsAncestor = errors.New("uncle is ancestor") - errDanglingUncle = errors.New("uncle's parent is not ancestor") - errInvalidDifficulty = errors.New("non-positive difficulty") - errDifficultyCrossover = errors.New("sub's difficulty exceeds dom's") - errInvalidMixHash = errors.New("invalid mixHash") - errInvalidPoW = errors.New("invalid proof-of-work") - errInvalidOrder = errors.New("invalid order") -) - // Author implements consensus.Engine, returning the header's coinbase as the // proof-of-work verified author of the block. func (progpow *Progpow) Author(header *types.WorkObject) (common.Address, error) { @@ -197,7 +179,7 @@ func (progpow *Progpow) VerifyUncles(chain consensus.ChainReader, block *types.W } // Verify that there are at most params.MaxWorkShareCount uncles included in this block if len(block.Uncles()) > params.MaxWorkShareCount { - return errTooManyUncles + return consensus.ErrTooManyUncles } if len(block.Uncles()) == 0 { return nil @@ -233,13 +215,13 @@ func (progpow *Progpow) VerifyUncles(chain consensus.ChainReader, block *types.W // Make sure every uncle is rewarded only once hash := uncle.Hash() if uncles.Contains(hash) { - return errDuplicateUncle + return consensus.ErrDuplicateUncle } uncles.Add(hash) // Make sure the uncle has a valid ancestry if ancestors[hash] != nil { - return errUncleIsAncestor + return consensus.ErrUncleIsAncestor } // Siblings are not allowed to be included in the workshares list if its an // uncle but can be if its a workshare @@ -249,7 +231,7 @@ func (progpow *Progpow) VerifyUncles(chain consensus.ChainReader, block *types.W workShare = true } if ancestors[uncle.ParentHash()] == nil || (!workShare && (uncle.ParentHash() == block.ParentHash(nodeCtx))) { - return errDanglingUncle + return consensus.ErrDanglingUncle } _, err = progpow.ComputePowHash(uncle) if err != nil { @@ -302,7 +284,7 @@ func (progpow *Progpow) verifyHeader(chain consensus.ChainHeaderReader, header, } } if header.Time() < parent.Time() { - return errOlderBlockTime + return consensus.ErrOlderBlockTime } // Verify the block's difficulty based on its timestamp and parent's difficulty // difficulty adjustment can only be checked in zone @@ -613,7 +595,7 @@ func (progpow *Progpow) verifySeal(header *types.WorkObjectHeader) (common.Hash, if progpow.config.PowMode == ModeFake || progpow.config.PowMode == ModeFullFake { time.Sleep(progpow.fakeDelay) if progpow.fakeFail == header.NumberU64() { - return common.Hash{}, errInvalidPoW + return common.Hash{}, consensus.ErrInvalidPoW } return common.Hash{}, nil } @@ -623,7 +605,7 @@ func (progpow *Progpow) verifySeal(header *types.WorkObjectHeader) (common.Hash, } // Ensure that we have a valid difficulty for the block if header.Difficulty().Sign() <= 0 { - return common.Hash{}, errInvalidDifficulty + return common.Hash{}, consensus.ErrInvalidDifficulty } // Check progpow mixHash := header.PowDigest.Load() @@ -633,11 +615,11 @@ func (progpow *Progpow) verifySeal(header *types.WorkObjectHeader) (common.Hash, } // Verify the calculated values against the ones provided in the header if !bytes.Equal(header.MixHash().Bytes(), mixHash.(common.Hash).Bytes()) { - return common.Hash{}, errInvalidMixHash + return common.Hash{}, consensus.ErrInvalidMixHash } target := new(big.Int).Div(big2e256, header.Difficulty()) if new(big.Int).SetBytes(powHash.(common.Hash).Bytes()).Cmp(target) > 0 { - return powHash.(common.Hash), errInvalidPoW + return powHash.(common.Hash), consensus.ErrInvalidPoW } return powHash.(common.Hash), nil } @@ -651,7 +633,7 @@ func (progpow *Progpow) ComputePowHash(header *types.WorkObjectHeader) (common.H } // Verify the calculated values against the ones provided in the header if !bytes.Equal(header.MixHash().Bytes(), mixHash.(common.Hash).Bytes()) { - return common.Hash{}, errInvalidMixHash + return common.Hash{}, consensus.ErrInvalidMixHash } return powHash.(common.Hash), nil } diff --git a/consensus/progpow/poem.go b/consensus/progpow/poem.go index 0b06cca8a9..4f396e8015 100644 --- a/consensus/progpow/poem.go +++ b/consensus/progpow/poem.go @@ -69,8 +69,8 @@ func (progpow *Progpow) CalcOrder(chain consensus.BlockReader, header *types.Wor func (progpow *Progpow) IntrinsicLogS(powHash common.Hash) *big.Int { x := new(big.Int).SetBytes(powHash.Bytes()) d := new(big.Int).Div(big2e256, x) - c, m := mathutil.BinaryLog(d, mantBits) - bigBits := new(big.Int).Mul(big.NewInt(int64(c)), new(big.Int).Exp(big.NewInt(2), big.NewInt(mantBits), nil)) + c, m := mathutil.BinaryLog(d, consensus.MantBits) + bigBits := new(big.Int).Mul(big.NewInt(int64(c)), new(big.Int).Exp(big.NewInt(2), big.NewInt(consensus.MantBits), nil)) bigBits = new(big.Int).Add(bigBits, m) return bigBits } @@ -270,18 +270,14 @@ func (progpow *Progpow) CalcRank(chain consensus.ChainHeaderReader, header *type } func (progpow *Progpow) CheckIfValidWorkShare(workShare *types.WorkObjectHeader) bool { - // Extract some data from the header - diff := new(big.Int).Set(workShare.Difficulty()) - c, _ := mathutil.BinaryLog(diff, mantBits) - if c <= params.WorkSharesThresholdDiff { + workShareMinTarget, err := consensus.CalcWorkShareThreshold(workShare) + if err != nil { + progpow.logger.Error(err) return false } - workShareThreshold := c - params.WorkSharesThresholdDiff - workShareDiff := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(workShareThreshold)), nil) - workShareMintarget := new(big.Int).Div(big2e256, workShareDiff) powHash, err := progpow.ComputePowHash(workShare) if err != nil { return false } - return new(big.Int).SetBytes(powHash.Bytes()).Cmp(workShareMintarget) <= 0 + return new(big.Int).SetBytes(powHash.Bytes()).Cmp(workShareMinTarget) <= 0 } diff --git a/consensus/progpow/sealer.go b/consensus/progpow/sealer.go index 84bc4cc79f..82a25dac3c 100644 --- a/consensus/progpow/sealer.go +++ b/consensus/progpow/sealer.go @@ -11,18 +11,13 @@ import ( "sync" "github.com/dominant-strategies/go-quai/common" + "github.com/dominant-strategies/go-quai/consensus" "github.com/dominant-strategies/go-quai/core/types" "github.com/dominant-strategies/go-quai/log" "github.com/dominant-strategies/go-quai/params" "modernc.org/mathutil" ) -const ( - // staleThreshold is the maximum depth of the acceptable stale but valid progpow solution. - staleThreshold = 7 - mantBits = 64 -) - var ( errNoMiningWork = errors.New("no mining work available yet") errInvalidSealResult = errors.New("invalid or stale proof-of-work solution") @@ -131,7 +126,7 @@ func (progpow *Progpow) Seal(header *types.WorkObject, results chan<- *types.Wor func (progpow *Progpow) mine(workObject *types.WorkObject, id int, seed uint64, abort chan struct{}, found chan *types.WorkObject) { // Extract some data from the header diff := new(big.Int).Set(workObject.Difficulty()) - c, _ := mathutil.BinaryLog(diff, mantBits) + c, _ := mathutil.BinaryLog(diff, consensus.MantBits) if c <= params.WorkSharesThresholdDiff { return } diff --git a/core/worker.go b/core/worker.go index 035f9a744d..a55f736b4b 100644 --- a/core/worker.go +++ b/core/worker.go @@ -43,9 +43,6 @@ const ( // any newly arrived transactions. minRecommitInterval = 1 * time.Second - // staleThreshold is the maximum depth of the acceptable stale block. - staleThreshold = 7 - // pendingBlockBodyLimit is maximum number of pending block bodies to be kept in cache. pendingBlockBodyLimit = 100