From 78f8351baa1b3ede50a1ac7cd5334922968d6dcd Mon Sep 17 00:00:00 2001 From: kiltsonfire Date: Wed, 26 Jul 2023 14:27:57 -0500 Subject: [PATCH] Added Dom difficulty controller using the Prime difficullty values --- common/big.go | 23 +++++++--- consensus/blake3pow/consensus.go | 76 +++++++++++++++++++++++++++++++ consensus/blake3pow/poem.go | 42 +++++++---------- consensus/consensus.go | 6 +++ consensus/progpow/consensus.go | 78 ++++++++++++++++++++++++++++++++ consensus/progpow/poem.go | 40 ++++++---------- core/chain_makers.go | 1 + core/genesis.go | 25 +++++++++- core/headerchain.go | 2 +- core/slice.go | 26 +++++++++-- core/worker.go | 14 ++++++ 11 files changed, 268 insertions(+), 65 deletions(-) diff --git a/common/big.go b/common/big.go index 5be6b019d6..52d5cdde59 100644 --- a/common/big.go +++ b/common/big.go @@ -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) + 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) + Big2e256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) ) func BigBitsToBits(original *big.Int) *big.Int { @@ -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 +} diff --git a/consensus/blake3pow/consensus.go b/consensus/blake3pow/consensus.go index 10de5f466f..580de2e0d9 100644 --- a/consensus/blake3pow/consensus.go +++ b/consensus/blake3pow/consensus.go @@ -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 @@ -280,11 +281,35 @@ 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()) + } + } + } } @@ -376,6 +401,57 @@ 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 { diff --git a/consensus/blake3pow/poem.go b/consensus/blake3pow/poem.go index 46203a819c..f2688c226e 100644 --- a/consensus/blake3pow/poem.go +++ b/consensus/blake3pow/poem.go @@ -23,41 +23,31 @@ 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 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 { 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, params.TimeFactor) + regionEntropyThreshold = new(big.Int).Mul(regionEntropyThreshold, big.NewInt(common.NumZonesInRegion)) + if totalDeltaSRegion.Cmp(regionEntropyThreshold) > 0 { return intrinsicS, common.REGION_CTX, nil } - // Zone case + // ZONE return intrinsicS, common.ZONE_CTX, nil } diff --git a/consensus/consensus.go b/consensus/consensus.go index adb731c2b2..9eed397a46 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -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 @@ -128,6 +131,9 @@ 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. diff --git a/consensus/progpow/consensus.go b/consensus/progpow/consensus.go index 3c3d95c118..04d9b4aa4b 100644 --- a/consensus/progpow/consensus.go +++ b/consensus/progpow/consensus.go @@ -41,7 +41,9 @@ 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 ) @@ -280,11 +282,36 @@ 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 { @@ -320,6 +347,57 @@ 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. diff --git a/consensus/progpow/poem.go b/consensus/progpow/poem.go index 0cafffff79..7ab1cdbea9 100644 --- a/consensus/progpow/poem.go +++ b/consensus/progpow/poem.go @@ -23,40 +23,30 @@ func (progpow *Progpow) CalcOrder(header *types.Header) (*big.Int, int, error) { // Get entropy reduction of this header intrinsicS := progpow.IntrinsicLogS(powHash) - - // 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 := progpow.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 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 { 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, params.TimeFactor) + regionEntropyThreshold = new(big.Int).Mul(regionEntropyThreshold, big.NewInt(common.NumZonesInRegion)) + if totalDeltaSRegion.Cmp(regionEntropyThreshold) > 0 { return intrinsicS, common.REGION_CTX, nil } + // ZONE return intrinsicS, common.ZONE_CTX, nil } diff --git a/core/chain_makers.go b/core/chain_makers.go index 5429487d9e..868746985a 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -310,3 +310,4 @@ func (cr *fakeChainReader) GetHeaderByNumber(number uint64) *types.Header func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header { return nil } func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *types.Header { return nil } func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block { return nil } +func (cr *fakeChainReader) GetTerminiByHash(hash common.Hash) *types.Termini { return nil } diff --git a/core/genesis.go b/core/genesis.go index 96b228d173..7663996a92 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -37,12 +37,19 @@ import ( "github.com/dominant-strategies/go-quai/log" "github.com/dominant-strategies/go-quai/params" "github.com/dominant-strategies/go-quai/trie" + "modernc.org/mathutil" ) //go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go //go:generate gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go -var errGenesisNoConfig = errors.New("genesis has no chain configuration") +var ( + errGenesisNoConfig = errors.New("genesis has no chain configuration") +) + +const ( + mantBits = 64 +) // Genesis specifies the header fields, state of a genesis block. It also defines hard // fork switch-over blocks through the chain configuration. @@ -278,9 +285,25 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { head.SetParentHash(common.Hash{}, i) } + initPrimeThreshold := new(big.Int).Mul(params.TimeFactor, big.NewInt(common.NumRegionsInPrime)) + initPrimeThreshold = new(big.Int).Mul(initPrimeThreshold, big.NewInt(common.NumZonesInRegion)) + initPrimeThreshold = new(big.Int).Mul(initPrimeThreshold, params.TimeFactor) + for i := 0; i < common.NumZonesInRegion; i++ { + head.SetPrimeEntropyThreshold(initPrimeThreshold, i) + } return types.NewBlock(head, nil, nil, nil, nil, nil, trie.NewStackTrie(nil)) } +// IntrinsicLogS returns the logarithm of the intrinsic entropy reduction of a PoW hash +func (g *Genesis) IntrinsicLogS(powHash common.Hash) *big.Int { + x := new(big.Int).SetBytes(powHash.Bytes()) + d := new(big.Int).Div(common.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)) + bigBits = new(big.Int).Add(bigBits, m) + return bigBits +} + // Commit writes the block and state of a genesis specification to the database. // The block is committed as the canonical head block. func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { diff --git a/core/headerchain.go b/core/headerchain.go index cd99511255..cedea6d0ee 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -278,7 +278,7 @@ func (hc *HeaderChain) collectInclusiveEtxRollup(b *types.Block) (types.Transact // Append func (hc *HeaderChain) Append(batch ethdb.Batch, block *types.Block, newInboundEtxs types.Transactions) error { nodeCtx := common.NodeLocation.Context() - log.Debug("HeaderChain Append:", "Block information: Hash:", block.Hash(), "block header hash:", block.Header().Hash(), "Number:", block.NumberU64(), "Location:", block.Header().Location, "Parent:", block.ParentHash()) + log.Debug("HeaderChain Append:", "Block information: Hash:", block.Hash(), "block header hash:", block.Header().Hash(), "Number:", block.NumberU64(), "Location:", block.Header().Location(), "Parent:", block.ParentHash()) err := hc.engine.VerifyHeader(hc, block.Header()) if err != nil { diff --git a/core/slice.go b/core/slice.go index c9e05097e1..e65667ced3 100644 --- a/core/slice.go +++ b/core/slice.go @@ -434,7 +434,7 @@ func (sl *Slice) pcrc(batch ethdb.Batch, header *types.Header, domTerminus commo nodeCtx := common.NodeLocation.Context() location := header.Location() - log.Debug("PCRC:", "Parent Hash:", header.ParentHash(), "Number", header.Number, "Location:", header.Location()) + log.Debug("PCRC:", "Parent Hash:", header.ParentHash(), "Number", header.Number(), "Location:", header.Location()) termini := sl.hc.GetTerminiByHash(header.ParentHash()) if !termini.IsValid() { @@ -450,8 +450,11 @@ func (sl *Slice) pcrc(batch ethdb.Batch, header *types.Header, domTerminus commo // Set the terminus if nodeCtx == common.PRIME_CTX || domOrigin { newTermini.SetDomTerminus(header.Hash()) - } else { - newTermini.SetDomTerminus(termini.DomTerminus()) + } + + // Set the prime termini + if nodeCtx == common.REGION_CTX && domOrigin { + newTermini.SetPrimeTerminiAtIndex(header.Hash(), location.SubIndex()) } // Check for a graph cyclic reference @@ -558,19 +561,27 @@ func (sl *Slice) computePendingHeader(localPendingHeaderWithTermini types.Pendin var cachedPendingHeaderWithTermini types.PendingHeader hash := localPendingHeaderWithTermini.Termini().DomTerminus() cachedPendingHeaderWithTermini, exists := sl.readPhCache(hash) - log.Debug("computePendingHeader:", "hash:", hash, "pendingHeader:", cachedPendingHeaderWithTermini, "termini:", cachedPendingHeaderWithTermini.Termini) var newPh *types.Header + log.Info("computePendingHeader:", "primeEntropyThreshold:", localPendingHeaderWithTermini.Header().PrimeEntropyThresholdArray()) if exists { + log.Info("computePendingHeader:", "primeEntropyThreshold:", cachedPendingHeaderWithTermini.Header().PrimeEntropyThresholdArray()) + newPh = sl.combinePendingHeader(localPendingHeaderWithTermini.Header(), cachedPendingHeaderWithTermini.Header(), nodeCtx, true) + + log.Info("computePendingHeader:", "primeEntropyThreshold:", newPh.PrimeEntropyThresholdArray()) return types.NewPendingHeader(newPh, localPendingHeaderWithTermini.Termini()) } else { + log.Info("computePendingHeader:", "primeEntropyThreshold:", domPendingHeader.PrimeEntropyThresholdArray()) + if domOrigin { newPh = sl.combinePendingHeader(localPendingHeaderWithTermini.Header(), domPendingHeader, nodeCtx, true) + log.Info("computePendingHeader:", "primeEntropyThreshold:", newPh.PrimeEntropyThresholdArray()) return types.NewPendingHeader(newPh, localPendingHeaderWithTermini.Termini()) } return localPendingHeaderWithTermini } + } // updatePhCacheFromDom combines the recieved pending header with the pending header stored locally at a given terminus for specified context @@ -676,6 +687,9 @@ func (sl *Slice) init(genesis *Genesis) error { for i := 0; i < len(genesisTermini.SubTermini()); i++ { genesisTermini.SetSubTerminiAtIndex(genesisHash, i) } + for i := 0; i < len(genesisTermini.PrimeTermini()); i++ { + genesisTermini.SetPrimeTerminiAtIndex(genesisHash, i) + } rawdb.WriteTermini(sl.sliceDb, genesisHash, genesisTermini) rawdb.WriteManifest(sl.sliceDb, genesisHash, types.BlockManifest{genesisHash}) @@ -848,7 +862,6 @@ func (sl *Slice) NewGenesisPendingHeader(domPendingHeader *types.Header) { domPendingHeader = sl.combinePendingHeader(localPendingHeader, domPendingHeader, nodeCtx, true) domPendingHeader.SetLocation(common.NodeLocation) } - if nodeCtx != common.ZONE_CTX { for _, client := range sl.subClients { if client != nil { @@ -864,6 +877,9 @@ func (sl *Slice) NewGenesisPendingHeader(domPendingHeader *types.Header) { for i := 0; i < len(genesisTermini.SubTermini()); i++ { genesisTermini.SetSubTerminiAtIndex(genesisHash, i) } + for i := 0; i < len(genesisTermini.PrimeTermini()); i++ { + genesisTermini.SetPrimeTerminiAtIndex(genesisHash, i) + } if sl.hc.Empty() { sl.phCache.Add(sl.config.GenesisHash, types.NewPendingHeader(domPendingHeader, genesisTermini)) } diff --git a/core/worker.go b/core/worker.go index 536b91524c..47e8785cfd 100644 --- a/core/worker.go +++ b/core/worker.go @@ -764,6 +764,20 @@ func (w *worker) prepareWork(genParams *generateParams, block *types.Block) (*en header.SetParentDeltaS(w.engine.DeltaLogS(parent.Header()), nodeCtx) } } + + if nodeCtx == common.REGION_CTX { + for i := 0; i < common.NumZonesInRegion; i++ { + header.SetPrimeEntropyThreshold(parent.Header().PrimeEntropyThreshold(i), i) + } + } + + if nodeCtx == common.REGION_CTX && order == common.PRIME_CTX { + primeEntropyThreshold, err := w.engine.CalcPrimeEntropyThreshold(w.hc, parent.Header()) + if err != nil { + return nil, err + } + header.SetPrimeEntropyThreshold(primeEntropyThreshold, parent.Header().Location().SubIndex()) + } header.SetParentEntropy(w.engine.TotalLogS(parent.Header())) } else { for i := 0; i < common.NumZonesInRegion; i++ {