Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Poem upgrade #1071

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions common/big.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@

package common

import "math/big"
import (
"math/big"
"modernc.org/mathutil"
)

// Common big integers often used
var (
Big0 = big.NewInt(0)
Big1 = big.NewInt(1)
Big2 = big.NewInt(2)
Big3 = big.NewInt(3)
Big4 = big.NewInt(4)
Big32 = big.NewInt(32)
Big256 = big.NewInt(256)
Big257 = big.NewInt(257)
Expand All @@ -36,6 +38,13 @@ func BigBitsToBits(original *big.Int) *big.Int {
return big.NewInt(0).Div(original, e2e64)
}

func BitsToBigBits(original *big.Int) *big.Int {
c, m := mathutil.BinaryLog(original, 64)
bigBits := new(big.Int).Mul(big.NewInt(int64(c)), new(big.Int).Exp(big.NewInt(2), big.NewInt(64), nil))
bigBits = new(big.Int).Add(bigBits, m)
return bigBits
}

func BigBitsArrayToBitsArray(original []*big.Int) []*big.Int {
e2e64 := big.NewInt(0).Exp(big.NewInt(2), big.NewInt(64), nil)
bitsArray := make([]*big.Int, len(original))
Expand All @@ -45,10 +54,3 @@ 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
}
76 changes: 0 additions & 76 deletions consensus/blake3pow/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ 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 @@ -281,35 +280,11 @@ 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 prime difficulty
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.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 @@ -401,57 +376,6 @@ func (blake3pow *Blake3pow) CalcDifficulty(chain consensus.ChainHeaderReader, pa
return x
}

// CalcPrimeDifficultyThreshold calculates the difficulty that a block must meet
// to become a region block. This function needs to have a controller so that the
// liveliness of the slices can balance even if the hash rate of the slice varies.
// This will also cause the production of the prime blocks to naturally diverge
// with time reducing the uncle rate. The controller is built to adjust the
// number of zone blocks it takes to produce a prime block. This is done based on
// the prior number of blocks to reach threshold which is than multiplied by the
// current difficulty to establish the threshold. The controller adjust the block
// threshold value and is a simple form of a bang-bang controller which is all
// that is needed to ensure liveliness of the slices in prime overtime. If the
// slice is not sufficiently lively 20 zone blocks are subtracted from the
// threshold. If it is too lively 20 blocks are added to the threshold.
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) IsDomCoincident(chain consensus.ChainHeaderReader, header *types.Header) bool {
_, order, err := blake3pow.CalcOrder(header)
if err != nil {
Expand Down
20 changes: 7 additions & 13 deletions consensus/blake3pow/poem.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,25 @@ func (blake3pow *Blake3pow) CalcOrder(header *types.Header) (*big.Int, int, erro

// Get entropy reduction of this header
intrinsicS := blake3pow.IntrinsicLogS(header.Hash())
target := new(big.Int).Div(common.Big2e256, header.Difficulty()).Bytes()
zoneThresholdS := blake3pow.IntrinsicLogS(common.BytesToHash(target))
target := new(big.Int).Div(common.Big2e256, header.Difficulty())
zoneThresholdS := blake3pow.IntrinsicLogS(common.BytesToHash(target.Bytes()))

// 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)

// PrimeEntropyThreshold number of zone blocks times the intrinsic logs of
// the given header determines the prime block
primeEntropyThreshold := new(big.Int).Mul(zoneThresholdS, header.PrimeEntropyThreshold(header.Location().Zone()))
if totalDeltaSPrime.Cmp(primeEntropyThreshold) > 0 {
primeBlockEntropyThreshold := new(big.Int).Add(zoneThresholdS, common.BitsToBigBits(params.PrimeEntropyTarget))
if intrinsicS.Cmp(primeBlockEntropyThreshold) > 0 {
gameofpointers marked this conversation as resolved.
Show resolved Hide resolved
return intrinsicS, common.PRIME_CTX, nil
}

// 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, params.TimeFactor)
regionEntropyThreshold = new(big.Int).Mul(regionEntropyThreshold, big.NewInt(common.NumZonesInRegion))
if totalDeltaSRegion.Cmp(regionEntropyThreshold) > 0 {
regionBlockEntropyThreshold := new(big.Int).Add(zoneThresholdS, common.BitsToBigBits(params.RegionEntropyTarget))
if intrinsicS.Cmp(regionBlockEntropyThreshold) > 0 {
gameofpointers marked this conversation as resolved.
Show resolved Hide resolved
return intrinsicS, common.REGION_CTX, nil
}

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

Expand Down
3 changes: 0 additions & 3 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,6 @@ type Engine interface {
// that a new block should have.
CalcDifficulty(chain ChainHeaderReader, parent *types.Header) *big.Int

// 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
78 changes: 0 additions & 78 deletions consensus/progpow/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ var (
big8 = big.NewInt(8)
big9 = big.NewInt(9)
big10 = big.NewInt(10)
big20 = big.NewInt(20)
big32 = big.NewInt(32)
big100 = big.NewInt(100)
bigMinus99 = big.NewInt(-99)
big2e256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) // 2^256
)
Expand Down Expand Up @@ -282,36 +280,11 @@ func (progpow *Progpow) verifyHeader(chain consensus.ChainHeaderReader, header,
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 prime difficulty
if nodeCtx == common.REGION_CTX {
primeEntropyThreshold, err := progpow.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 := progpow.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.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())
}
}

}
}
if nodeCtx == common.ZONE_CTX {
Expand Down Expand Up @@ -347,57 +320,6 @@ func (progpow *Progpow) verifyHeader(chain consensus.ChainHeaderReader, header,
return nil
}

// CalcPrimeDifficultyThreshold calculates the difficulty that a block must meet
// to become a region block. This function needs to have a controller so that the
// liveliness of the slices can balance even if the hash rate of the slice varies.
// This will also cause the production of the prime blocks to naturally diverge
// with time reducing the uncle rate. The controller is built to adjust the
// number of zone blocks it takes to produce a prime block. This is done based on
// the prior number of blocks to reach threshold which is than multiplied by the
// current difficulty to establish the threshold. The controller adjust the block
// threshold value and is a simple form of a bang-bang controller which is all
// that is needed to ensure liveliness of the slices in prime overtime. If the
// slice is not sufficiently lively 20 zone blocks are subtracted from the
// threshold. If it is too lively 20 blocks are added to the threshold.
func (progpow *Progpow) 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
}

// CalcDifficulty is the difficulty adjustment algorithm. It returns
// the difficulty that a new block should have when created at time
// given the parent block's time and difficulty.
Expand Down
21 changes: 7 additions & 14 deletions consensus/progpow/poem.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,23 @@ func (progpow *Progpow) CalcOrder(header *types.Header) (*big.Int, int, error) {

// Get entropy reduction of this header
intrinsicS := progpow.IntrinsicLogS(powHash)
target := new(big.Int).Div(common.Big2e256, header.Difficulty()).Bytes()
zoneThresholdS := progpow.IntrinsicLogS(common.BytesToHash(target))

// 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)
target := new(big.Int).Div(common.Big2e256, header.Difficulty())
zoneThresholdS := progpow.IntrinsicLogS(common.BytesToHash(target.Bytes()))

// Prime case
// PrimeEntropyThreshold number of zone blocks times the intrinsic logs of the given header determines the prime block
primeEntropyThreshold := new(big.Int).Mul(zoneThresholdS, header.PrimeEntropyThreshold(header.Location().Zone()))
if totalDeltaSPrime.Cmp(primeEntropyThreshold) > 0 {
primeBlockEntropyThreshold := new(big.Int).Add(zoneThresholdS, common.BitsToBigBits(params.PrimeEntropyTarget))
if intrinsicS.Cmp(primeBlockEntropyThreshold) > 0 {
gameofpointers marked this conversation as resolved.
Show resolved Hide resolved
return intrinsicS, common.PRIME_CTX, nil
}

// 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, params.TimeFactor)
regionEntropyThreshold = new(big.Int).Mul(regionEntropyThreshold, big.NewInt(common.NumZonesInRegion))
if totalDeltaSRegion.Cmp(regionEntropyThreshold) > 0 {
regionBlockEntropyThreshold := new(big.Int).Add(zoneThresholdS, common.BitsToBigBits(params.RegionEntropyTarget))
if intrinsicS.Cmp(regionBlockEntropyThreshold) > 0 {
return intrinsicS, common.REGION_CTX, nil
}

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

Expand Down
8 changes: 4 additions & 4 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,12 @@ func (c *Core) ConstructLocalMinedBlock(header *types.Header) (*types.Block, err
return c.sl.ConstructLocalMinedBlock(header)
}

func (c *Core) SubRelayPendingHeader(slPendingHeader types.PendingHeader, location common.Location, subReorg bool) {
c.sl.SubRelayPendingHeader(slPendingHeader, location, subReorg)
func (c *Core) SubRelayPendingHeader(slPendingHeader types.PendingHeader, newEntropy *big.Int, location common.Location, subReorg bool) {
c.sl.SubRelayPendingHeader(slPendingHeader, newEntropy, location, subReorg)
}

func (c *Core) UpdateDom(oldTerminus common.Hash, newTerminus common.Hash, location common.Location) {
c.sl.UpdateDom(oldTerminus, newTerminus, location)
func (c *Core) UpdateDom(oldTerminus common.Hash, newTerminus common.Hash, newEntropy *big.Int, location common.Location) {
c.sl.UpdateDom(oldTerminus, newTerminus, newEntropy, location)
}

func (c *Core) NewGenesisPendigHeader(pendingHeader *types.Header) {
Expand Down
Loading
Loading