Skip to content

Commit

Permalink
Added Dom difficulty controller using the Prime and Region difficullt…
Browse files Browse the repository at this point in the history
…y values
  • Loading branch information
kiltsonfire authored and gameofpointers committed Aug 18, 2023
1 parent da55e5d commit d51aa4f
Show file tree
Hide file tree
Showing 11 changed files with 364 additions and 67 deletions.
23 changes: 16 additions & 7 deletions common/big.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ import "math/big"

// Common big integers often used
var (
Big1 = big.NewInt(1)
Big2 = big.NewInt(2)
Big3 = big.NewInt(3)
Big0 = big.NewInt(0)
Big32 = big.NewInt(32)
Big256 = big.NewInt(256)
Big257 = big.NewInt(257)
Big1 = big.NewInt(1)
Big2 = big.NewInt(2)
Big3 = big.NewInt(3)
Big4 = big.NewInt(4)
Big0 = big.NewInt(0)
Big32 = big.NewInt(32)
Big256 = big.NewInt(256)
Big257 = big.NewInt(257)
Big2e256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
)

func BigBitsToBits(original *big.Int) *big.Int {
Expand All @@ -43,3 +45,10 @@ func BigBitsArrayToBitsArray(original []*big.Int) []*big.Int {

return bitsArray
}

func MaxBigInt(x, y *big.Int) *big.Int {
if x.Cmp(y) > 0 {
return x
}
return y
}
113 changes: 113 additions & 0 deletions consensus/blake3pow/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ var (
big8 = big.NewInt(8)
big9 = big.NewInt(9)
big10 = big.NewInt(10)
big20 = big.NewInt(20)
big32 = big.NewInt(32)
bigMinus99 = big.NewInt(-99)
big2e256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) // 2^256
Expand Down Expand Up @@ -280,11 +281,47 @@ func (blake3pow *Blake3pow) verifyHeader(chain consensus.ChainHeaderReader, head
if common.Big0.Cmp(header.ParentDeltaS()) != 0 {
return fmt.Errorf("invalid parent delta s: have %v, want %v", header.ParentDeltaS(), common.Big0)
}
// If parent block is dom, validate the region and prime difficulty
if nodeCtx == common.ZONE_CTX {
regionDifficulty, err := blake3pow.CalcRegionEntropyThreshold(chain, parent)
if err != nil {
return err
}
if header.RegionEntropyThreshold().Cmp(regionDifficulty) != 0 {
return fmt.Errorf("invalid region difficulty dom block rd: have %v, want %v", header.RegionEntropyThreshold(), regionDifficulty)
}
}
if nodeCtx == common.REGION_CTX {
primeEntropyThreshold, err := blake3pow.CalcPrimeEntropyThreshold(chain, parent)
if err != nil {
return err
}
if header.PrimeEntropyThreshold(parent.Location().SubIndex()).Cmp(primeEntropyThreshold) != 0 {
return fmt.Errorf("invalid prime difficulty pd: have %v, want %v", header.PrimeEntropyThreshold(parent.Location().SubIndex()), primeEntropyThreshold)
}
}
} else {
parentDeltaS := blake3pow.DeltaLogS(parent)
if parentDeltaS.Cmp(header.ParentDeltaS()) != 0 {
return fmt.Errorf("invalid parent delta s: have %v, want %v", header.ParentDeltaS(), parentDeltaS)
}
if nodeCtx == common.REGION_CTX {
// if parent is not a dom block, no adjustment to the prime or region difficulty will be made
for i := 0; i < common.NumZonesInRegion; i++ {
if header.PrimeEntropyThreshold(i).Cmp(parent.PrimeEntropyThreshold(i)) != 0 {
return fmt.Errorf("invalid prime difficulty pd: have %v, want %v at index %v", header.PrimeEntropyThreshold(i), parent.PrimeEntropyThreshold(i), i)
}
}
}
if nodeCtx == common.ZONE_CTX {
if header.RegionEntropyThreshold().Cmp(parent.RegionEntropyThreshold()) != 0 {
return fmt.Errorf("invalid region difficulty rd: have %v, want %v", header.RegionEntropyThreshold(), parent.RegionEntropyThreshold())
}
if header.PrimeEntropyThreshold(common.NodeLocation.Zone()).Cmp(parent.PrimeEntropyThreshold(common.NodeLocation.Zone())) != 0 {
return fmt.Errorf("invalid prime difficulty pd: have %v, want %v at index %v", header.PrimeEntropyThreshold(common.NodeLocation.Zone()), parent.PrimeEntropyThreshold(common.NodeLocation.Zone()), common.NodeLocation.Zone())
}
}

}
}

Expand Down Expand Up @@ -376,6 +413,82 @@ func (blake3pow *Blake3pow) CalcDifficulty(chain consensus.ChainHeaderReader, pa
return x
}

func (blake3pow *Blake3pow) CalcPrimeEntropyThreshold(chain consensus.ChainHeaderReader, parent *types.Header) (*big.Int, error) {
nodeCtx := common.NodeLocation.Context()

if nodeCtx != common.REGION_CTX {
log.Error("Cannot CalcPrimeEntropyThreshold for", "context", nodeCtx)
return nil, errors.New("cannot CalcPrimeEntropyThreshold for non-region context")
}

if parent.Hash() == chain.Config().GenesisHash {
return parent.PrimeEntropyThreshold(parent.Location().SubIndex()), nil
}

// Get the primeTerminus
termini := chain.GetTerminiByHash(parent.ParentHash())
if termini == nil {
return nil, errors.New("termini not found in CalcPrimeEntropyThreshold")
}
primeTerminusHeader := chain.GetHeaderByHash(termini.PrimeTerminiAtIndex(parent.Location().SubIndex()))

log.Info("CalcPrimeEntropyThreshold", "primeTerminusHeader:", primeTerminusHeader.NumberArray(), "Hash", primeTerminusHeader.Hash())
deltaNumber := new(big.Int).Sub(parent.Number(), primeTerminusHeader.Number())
log.Info("CalcPrimeEntropyThreshold", "deltaNumber:", deltaNumber)
target := new(big.Int).Mul(big.NewInt(common.NumRegionsInPrime), params.TimeFactor)
target = new(big.Int).Mul(big.NewInt(common.NumZonesInRegion), target)
log.Info("CalcPrimeEntropyThreshold", "target:", target)

var newThreshold *big.Int
if target.Cmp(deltaNumber) > 0 {
newThreshold = new(big.Int).Add(parent.PrimeEntropyThreshold(parent.Location().Zone()), big20)
} else {
newThreshold = new(big.Int).Sub(parent.PrimeEntropyThreshold(parent.Location().Zone()), big20)
}
newMinThreshold := new(big.Int).Div(target, big2)
newThreshold = new(big.Int).Set(common.MaxBigInt(newThreshold, newMinThreshold))
log.Info("CalcPrimeEntropyThreshold", "newThreshold:", newThreshold)

return newThreshold, nil
}

func (blake3pow *Blake3pow) CalcRegionEntropyThreshold(chain consensus.ChainHeaderReader, parent *types.Header) (*big.Int, error) {
nodeCtx := common.NodeLocation.Context()

if nodeCtx != common.ZONE_CTX {
log.Error("Cannot CalcRegionEntropyThreshold for", "context", nodeCtx)
return nil, errors.New("cannot CalcRegionEntropyThreshold for non-zone context")
}

if parent.Hash() == chain.Config().GenesisHash {
return parent.RegionEntropyThreshold(), nil
}

// Get the primeTerminus
termini := chain.GetTerminiByHash(parent.ParentHash())
if termini == nil {
return nil, errors.New("termini not found in CalcRegionEntropyThreshold")
}
regionTerminusHeader := chain.GetHeaderByHash(termini.DomTerminus())

deltaNumber := new(big.Int).Sub(parent.Number(), regionTerminusHeader.Number())
target := new(big.Int).Mul(big.NewInt(common.NumZonesInRegion), params.TimeFactor)

var newThreshold *big.Int
if target.Cmp(deltaNumber) > 0 {
newThreshold = new(big.Int).Add(parent.RegionEntropyThreshold(), big2)
} else {
newThreshold = new(big.Int).Sub(parent.RegionEntropyThreshold(), big2)
}
log.Info("CalcRegionEntropyThreshold", "newThreshold:", newThreshold)

newMinThreshold := new(big.Int).Div(target, big2)
newThreshold = new(big.Int).Set(common.MaxBigInt(newThreshold, newMinThreshold))
log.Info("CalcRegionEntropyThreshold", "newThreshold:", newThreshold)

return newThreshold, nil
}

func (blake3pow *Blake3pow) IsDomCoincident(chain consensus.ChainHeaderReader, header *types.Header) bool {
_, order, err := blake3pow.CalcOrder(header)
if err != nil {
Expand Down
44 changes: 17 additions & 27 deletions consensus/blake3pow/poem.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package blake3pow

import (
"fmt"
"math/big"

"github.com/dominant-strategies/go-quai/common"
"github.com/dominant-strategies/go-quai/core/types"
"github.com/dominant-strategies/go-quai/params"
"modernc.org/mathutil"
)

// CalcOrder returns the order of the block within the hierarchy of chains
func (blake3pow *Blake3pow) CalcOrder(header *types.Header) (*big.Int, int, error) {
if header.NumberU64() == 0 {
fmt.Println("Header number is zero, so its a zone block")
return common.Big0, common.PRIME_CTX, nil
}

Expand All @@ -23,41 +24,30 @@ func (blake3pow *Blake3pow) CalcOrder(header *types.Header) (*big.Int, int, erro

// Get entropy reduction of this header
intrinsicS := blake3pow.IntrinsicLogS(header.Hash())

// This is the updated the threshold calculation based on the zone difficulty threshold
target := new(big.Int).Div(big2e256, header.Difficulty()).Bytes()
target := new(big.Int).Div(common.Big2e256, header.Difficulty()).Bytes()
zoneThresholdS := blake3pow.IntrinsicLogS(common.BytesToHash(target))
timeFactorHierarchyDepthMultiple := new(big.Int).Mul(params.TimeFactor, big.NewInt(common.HierarchyDepth))

// Prime case
primeEntropyThreshold := new(big.Int).Mul(timeFactorHierarchyDepthMultiple, timeFactorHierarchyDepthMultiple)
primeEntropyThreshold = new(big.Int).Mul(primeEntropyThreshold, zoneThresholdS)
primeBlockThreshold := new(big.Int).Quo(primeEntropyThreshold, big.NewInt(2))
primeEntropyThreshold = new(big.Int).Sub(primeEntropyThreshold, primeBlockThreshold)

primeBlockEntropyThresholdAdder, _ := mathutil.BinaryLog(primeBlockThreshold, 8)
primeBlockEntropyThreshold := new(big.Int).Add(zoneThresholdS, big.NewInt(int64(primeBlockEntropyThresholdAdder)))
// PRIME
// Compute the total accumulated entropy since the last prime block
totalDeltaSPrime := new(big.Int).Add(header.ParentDeltaS(common.REGION_CTX), header.ParentDeltaS(common.ZONE_CTX))
totalDeltaSPrime.Add(totalDeltaSPrime, intrinsicS)

totalDeltaS := new(big.Int).Add(header.ParentDeltaS(common.REGION_CTX), header.ParentDeltaS(common.ZONE_CTX))
totalDeltaS.Add(totalDeltaS, intrinsicS)
if intrinsicS.Cmp(primeBlockEntropyThreshold) > 0 && totalDeltaS.Cmp(primeEntropyThreshold) > 0 {
primeEntropyThreshold := new(big.Int).Mul(zoneThresholdS, header.PrimeEntropyThreshold(header.Location().Zone()))
if totalDeltaSPrime.Cmp(primeEntropyThreshold) > 0 {
fmt.Println("prime block because", common.BigBitsToBits(totalDeltaSPrime), ">", common.BigBitsToBits(primeEntropyThreshold))
return intrinsicS, common.PRIME_CTX, nil
}

// Region case
regionEntropyThreshold := new(big.Int).Mul(timeFactorHierarchyDepthMultiple, zoneThresholdS)
regionBlockThreshold := new(big.Int).Quo(regionEntropyThreshold, big.NewInt(2))
regionEntropyThreshold = new(big.Int).Sub(regionEntropyThreshold, regionBlockThreshold)

regionBlockEntropyThresholdAdder, _ := mathutil.BinaryLog(regionBlockThreshold, 8)
regionBlockEntropyThreshold := new(big.Int).Add(zoneThresholdS, big.NewInt(int64(regionBlockEntropyThresholdAdder)))

totalDeltaS = new(big.Int).Add(header.ParentDeltaS(common.ZONE_CTX), intrinsicS)
if intrinsicS.Cmp(regionBlockEntropyThreshold) > 0 && totalDeltaS.Cmp(regionEntropyThreshold) > 0 {
// REGION
// Compute the total accumulated entropy since the last region block
totalDeltaSRegion := new(big.Int).Add(header.ParentDeltaS(common.ZONE_CTX), intrinsicS)
regionEntropyThreshold := new(big.Int).Mul(zoneThresholdS, header.RegionEntropyThreshold())
if totalDeltaSRegion.Cmp(regionEntropyThreshold) > 0 {
fmt.Println("region block because", common.BigBitsToBits(totalDeltaSRegion), ">", common.BigBitsToBits(regionEntropyThreshold))
return intrinsicS, common.REGION_CTX, nil
}

// Zone case
// ZONE
return intrinsicS, common.ZONE_CTX, nil
}

Expand Down
9 changes: 9 additions & 0 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ type ChainHeaderReader interface {

// GetHeaderByHash retrieves a block header from the database by its hash.
GetHeaderByHash(hash common.Hash) *types.Header

// GetTerminiByHash retrieves the termini for a given header hash
GetTerminiByHash(hash common.Hash) *types.Termini
}

// ChainReader defines a small collection of methods needed to access the local
Expand Down Expand Up @@ -128,6 +131,12 @@ type Engine interface {
// that a new block should have.
CalcDifficulty(chain ChainHeaderReader, parent *types.Header) *big.Int

// CalcRegionEntropyThreshold is the threshold adjustment algorithm for Region blocks per slice
CalcRegionEntropyThreshold(chain ChainHeaderReader, parent *types.Header) (*big.Int, error)

// CalcPrimeEntropyThreshold is the threshold adjustment algorithm for prime blocks per slice
CalcPrimeEntropyThreshold(chain ChainHeaderReader, parent *types.Header) (*big.Int, error)

// IsDomCoincident returns true if this block satisfies the difficulty order
// of a dominant chain. If this node does not have a dominant chain (i.e.
// if this is a prime node), then the function will always return false.
Expand Down
Loading

0 comments on commit d51aa4f

Please sign in to comment.