Skip to content

Commit

Permalink
Merge branch 'jacklevin74-patch-1' into x1-txtracing-jacklevin74-patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
nibty committed Jan 28, 2024
2 parents ed0c869 + 4f24613 commit 3970622
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 108 deletions.
70 changes: 41 additions & 29 deletions eventcheck/gaspowercheck/gas_power_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"math/big"
"time"
//"fmt"

"github.com/Fantom-foundation/lachesis-base/eventcheck/epochcheck"
"github.com/Fantom-foundation/lachesis-base/hash"
Expand Down Expand Up @@ -127,46 +128,57 @@ func CalcValidatorGasPower(e inter.EventI, eTime, prevTime inter.Timestamp, prev
if gasPower > maxGasPower {
gasPower = maxGasPower
}
//fmt.Printf("e.Creator: %v, gasPower %v gasPowerAllocatedBn: %v\n", e.Creator(), gasPower, gasPowerAllocatedBn)

return gasPower
}

func CalcValidatorGasPowerPerSec(
validator idx.ValidatorID,
validators *pos.Validators,
config Config,
validator idx.ValidatorID,
validators *pos.Validators,
config Config,
) (
perSec uint64,
maxGasPower uint64,
startup uint64,
perSec uint64,
maxGasPower uint64,
startup uint64,
) {
stake := validators.Get(validator)
if stake == 0 {
return 0, 0, 0
}

gas := config

validatorGasPowerPerSecBn := new(big.Int).SetUint64(gas.AllocPerSec)
mul(validatorGasPowerPerSecBn, uint64(stake))
div(validatorGasPowerPerSecBn, uint64(validators.TotalWeight()))
perSec = validatorGasPowerPerSecBn.Uint64()

maxGasPower = perSec * (uint64(gas.MaxAllocPeriod) / uint64(time.Second))
if maxGasPower < gas.MinEnsuredAlloc {
maxGasPower = gas.MinEnsuredAlloc
}

startup = perSec * (uint64(gas.StartupAllocPeriod) / uint64(time.Second))
if startup < gas.MinStartupGas {
startup = gas.MinStartupGas
}

return
stake := validators.Get(validator)
if stake == 0 {
return 0, 0, 0
}

// don't calculate, keep the same for all
//maxGasPower = 1000 * 28000 * 60
//startup = 100 * 28000
//return

gas := config

validatorGasPowerPerSecBn := new(big.Int).SetUint64(gas.AllocPerSec)
mul(validatorGasPowerPerSecBn, uint64(stake))
div(validatorGasPowerPerSecBn, uint64(validators.TotalWeight()))
perSec = validatorGasPowerPerSecBn.Uint64()
//if validator == 7 {
perSec = 1000 * 28000
//}

maxGasPower = perSec * (uint64(gas.MaxAllocPeriod) / uint64(time.Second))
if maxGasPower < gas.MinEnsuredAlloc {
maxGasPower = gas.MinEnsuredAlloc
}

startup = perSec * (uint64(gas.StartupAllocPeriod) / uint64(time.Second))
if startup < gas.MinStartupGas {
startup = gas.MinStartupGas
}
//fmt.Printf("validator:%v , GasPowerPerSec: Persec: %v, maxGasPower: %v, startup: %v gas.AllocPerSec %v stake %v validators.TotalWeight() %v\n",validator, perSec, maxGasPower, startup, gas.AllocPerSec, stake, validators.TotalWeight())

return
}

// Validate event
func (v *Checker) Validate(e inter.EventI, selfParent inter.EventI) error {
return nil
gasPowers, err := v.CalcGasPower(e, selfParent)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion gossip/emitter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func DefaultConfig() Config {
Min: 150 * time.Millisecond,
Max: 10 * time.Minute,
Confirming: 170 * time.Millisecond,
DoublesignProtection: 11 * time.Minute, // should be greater than MaxEmitInterval
DoublesignProtection: 30 * time.Second, // should be greater than MaxEmitInterval
ParallelInstanceProtection: 1 * time.Minute,
},

Expand Down
51 changes: 45 additions & 6 deletions gossip/emitter/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package emitter

import (
"time"

"github.com/Fantom-foundation/lachesis-base/emitter/ancestor"
"github.com/Fantom-foundation/lachesis-base/inter/idx"
"github.com/Fantom-foundation/lachesis-base/inter/pos"
Expand Down Expand Up @@ -41,7 +41,28 @@ func eventMetric(orig ancestor.Metric, seq idx.Event) ancestor.Metric {
return kickStartMetric(ancestor.Metric(eventMetricF(uint64(orig))), seq)
}

// Function to get the top 50 elements from a slice
func top50(slice []idx.ValidatorID) []idx.ValidatorID {
if len(slice) > 50 {
return slice[:50] // Return the first 100 elements
}
return slice // Return the slice as is if it has less than or equal to 100 elements
}

// Function to check if a number is in the top 50 elements of a slice
func isInTop50(number idx.ValidatorID, slice []idx.ValidatorID) bool {
var v idx.ValidatorID
top50Slice := top50(slice)
for _, v = range top50Slice {
if v == number {
return true
}
}
return false
}

func (em *Emitter) isAllowedToEmit(e inter.EventI, eTxs bool, metric ancestor.Metric, selfParent *inter.Event) bool {
// for now allow only vals up to ID 30 to emit:
passedTime := e.CreationTime().Time().Sub(em.prevEmittedAtTime)
if passedTime < 0 {
passedTime = 0
Expand All @@ -50,6 +71,21 @@ func (em *Emitter) isAllowedToEmit(e inter.EventI, eTxs bool, metric ancestor.Me
if passedTimeIdle < 0 {
passedTimeIdle = 0
}
// metric is a decimal (0.0, 1.0], being an estimation of how much the event will advance the consensus
adjustedPassedTime := time.Duration(ancestor.Metric(passedTime/piecefunc.DecimalUnit) * metric)
adjustedPassedIdleTime := time.Duration(ancestor.Metric(passedTimeIdle/piecefunc.DecimalUnit) * metric)
passedBlocks := em.world.GetLatestBlockIndex() - em.prevEmittedAtBlock

supermajority := true
// Filter this node's events if not in top50 supermajority of stakers
if e.Creator() == em.config.Validator.ID && !isInTop50(e.Creator(), em.validators.SortedIDs()) {
//fmt.Println("This node is not in supermajority")
//supermajority = false
// disable check
supermajority = true
}

if (supermajority) {
if em.stakeRatio[e.Creator()] < 0.35*piecefunc.DecimalUnit {
// top validators emit event right after transaction is originated
passedTimeIdle = passedTime
Expand All @@ -60,10 +96,6 @@ func (em *Emitter) isAllowedToEmit(e inter.EventI, eTxs bool, metric ancestor.Me
if passedTimeIdle > passedTime {
passedTimeIdle = passedTime
}
// metric is a decimal (0.0, 1.0], being an estimation of how much the event will advance the consensus
adjustedPassedTime := time.Duration(ancestor.Metric(passedTime/piecefunc.DecimalUnit) * metric)
adjustedPassedIdleTime := time.Duration(ancestor.Metric(passedTimeIdle/piecefunc.DecimalUnit) * metric)
passedBlocks := em.world.GetLatestBlockIndex() - em.prevEmittedAtBlock
// Forbid emitting if not enough power and power is decreasing
{
threshold := em.config.EmergencyThreshold
Expand Down Expand Up @@ -127,8 +159,15 @@ func (em *Emitter) isAllowedToEmit(e inter.EventI, eTxs bool, metric ancestor.Me
return false
}
}

// only allow top validators
return true
} else {
// Enforce emitting if passed Max time (10 mins)
if passedTime >= em.intervals.Max {
return true
}
}
return false
}

func (em *Emitter) recheckIdleTime() {
Expand Down
105 changes: 34 additions & 71 deletions gossip/emitter/txs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package emitter
import (
"time"
"fmt"
"math/rand"
"github.com/Fantom-foundation/lachesis-base/common/bigendian"
"github.com/Fantom-foundation/lachesis-base/hash"
"github.com/Fantom-foundation/lachesis-base/inter/idx"
Expand Down Expand Up @@ -34,31 +33,28 @@ func max64(a, b uint64) uint64 {

func (em *Emitter) maxGasPowerToUse(e *inter.MutableEventPayload) uint64 {
rules := em.world.GetRules()
maxGasToUse := rules.Economy.Gas.MaxEventGas
//fmt.Println("maxGasToUse in maxGasPowertoUse, GasPowerLeft ", maxGasToUse, e.GasPowerLeft().Min())
maxGasToUse := rules.Economy.Gas.MaxEventGas
if maxGasToUse > e.GasPowerLeft().Min() {
maxGasToUse = e.GasPowerLeft().Min()
}
//fmt.Println("maxGasToUse in maxGasPowertoUsem after control: ", maxGasToUse)
// Smooth TPS if power isn't big
if em.config.LimitedTpsThreshold > em.config.NoTxsThreshold {
upperThreshold := em.config.LimitedTpsThreshold
downThreshold := em.config.NoTxsThreshold

estimatedAlloc := gaspowercheck.CalcValidatorGasPower(e, e.CreationTime(), e.MedianTime(), 0, em.validators, gaspowercheck.Config{
Idx: inter.LongTermGas,
AllocPerSec: rules.Economy.LongGasPower.AllocPerSec * 2,
MaxAllocPeriod: inter.Timestamp(time.Minute) * 2,
AllocPerSec: rules.Economy.LongGasPower.AllocPerSec * 4 / 5,
MaxAllocPeriod: inter.Timestamp(time.Minute),
MinEnsuredAlloc: 0,
StartupAllocPeriod: 0,
MinStartupGas: 0,
})

//fmt.Println("EstimatedAlloc: ", estimatedAlloc)
gasPowerLeft := e.GasPowerLeft().Min() + estimatedAlloc
//if gasPowerLeft < downThreshold {
// return 0
//}
if gasPowerLeft < downThreshold {
return 0
}
newGasPowerLeft := uint64(0)
if gasPowerLeft > maxGasToUse {
newGasPowerLeft = gasPowerLeft - maxGasToUse
Expand All @@ -84,131 +80,98 @@ func (em *Emitter) maxGasPowerToUse(e *inter.MutableEventPayload) uint64 {
if maxGasToUse > smoothGasToUse {
maxGasToUse = smoothGasToUse
}
//override
//maxGasToUse = estimatedAlloc
}
// pendingGas should be below MaxBlockGas
//{
// maxPendingGas := max64(max64(rules.Blocks.MaxBlockGas/3, rules.Economy.Gas.MaxEventGas), 15000000)
// if maxPendingGas <= em.pendingGas {
// return 0
// }
// this is likely a bug, there is no pendingGas
//if maxPendingGas < em.pendingGas+maxGasToUse {
// maxGasToUse = maxPendingGas - em.pendingGas
//}
//}
{
maxPendingGas := max64(max64(rules.Blocks.MaxBlockGas/3, rules.Economy.Gas.MaxEventGas), 15000000)
if maxPendingGas <= em.pendingGas {
return 0
}
if maxPendingGas < em.pendingGas+maxGasToUse {
maxGasToUse = maxPendingGas - em.pendingGas
}
}
// No txs if power is low
//{
// threshold := em.config.NoTxsThreshold
// if e.GasPowerLeft().Min() <= threshold {
// return 0
// } else if e.GasPowerLeft().Min() < threshold+maxGasToUse {
// maxGasToUse = e.GasPowerLeft().Min() - threshold
// fmt.Println("Show me maxGasToUse = e.GasPowerLeft().Min() - threshold ", maxGasToUse , e.GasPowerLeft().Min(), threshold)
// }
//}
{
threshold := em.config.NoTxsThreshold
if e.GasPowerLeft().Min() <= threshold {
return 0
} else if e.GasPowerLeft().Min() < threshold+maxGasToUse {
maxGasToUse = e.GasPowerLeft().Min() - threshold
}
}
return maxGasToUse
}

// randomWithWeight returns a random number between 1 and 50,
// with the first 21 numbers having a 70% chance of being chosen.
func randomWithWeight() int {
rand.Seed(time.Now().UnixNano()) // Initialize the random number generator.

if rand.Float64() < 0.7 {
// 70% chance to choose a number between 1 and 21.
return rand.Intn(21) + 1
} else {
// 30% chance to choose a number between 22 and 50.
return rand.Intn(29) + 22
}
}


func getTxRoundIndex(now, txTime time.Time, validatorsNum idx.Validator) int {
passed := now.Sub(txTime)
if passed < 0 {
passed = 0
}
return int((passed / TxTurnPeriod) % time.Duration(validatorsNum))
}
passed := now.Sub(txTime)
if passed < 0 {
passed = 0
}
return int((passed / TxTurnPeriod) % time.Duration(validatorsNum))
}

// safe for concurrent use
func (em *Emitter) isMyTxTurn(txHash common.Hash, sender common.Address, accountNonce uint64, now time.Time, validators *pos.Validators, me idx.ValidatorID, epoch idx.Epoch) bool {
txTime := txtime.Of(txHash)

//roundIndex := getTxRoundIndex(now, txTime, validators.Len())
roundIndex := getTxRoundIndex(now, txTime, 50)
roundIndex := getTxRoundIndex(now, txTime, validators.Len())
if roundIndex != getTxRoundIndex(now.Add(TxTurnPeriodLatency), txTime, validators.Len()) {
// round is about to change, avoid originating the transaction to avoid racing with another validator
return false
//return true
}

roundsHash := hash.Of(sender.Bytes(), bigendian.Uint64ToBytes(accountNonce/TxTurnNonces), epoch.Bytes())
rounds := utils.WeightedPermutation(roundIndex+1, validators.SortedWeights(), roundsHash)
fmt.Println ("Validator turn id: ", rounds, validators.GetID(idx.Validator(rounds[roundIndex])))
chosenVal := randomWithWeight()
fmt.Println ("Validator new turn id: ", chosenVal, chosenVal == int(me))
return true
//return validators.GetID(idx.Validator(rounds[roundIndex])) == me
return validators.GetID(idx.Validator(rounds[roundIndex])) == me
}

func (em *Emitter) addTxs(e *inter.MutableEventPayload, sorted *types.TransactionsByPriceAndNonce) {
maxGasUsed := em.maxGasPowerToUse(e)
//fmt.Println ("Old maxGasused: ", maxGasUsed)
oldMaxGasUsed := maxGasUsed
if maxGasUsed <= e.GasPowerUsed() {
fmt.Println ("Too much gas already trying to process: ", maxGasUsed, e.GasPowerUsed())
return
}

// sort transactions by price and nonce
rules := em.world.GetRules()
for tx := sorted.Peek(); tx != nil; tx = sorted.Peek() {
sender, _ := types.Sender(em.world.TxSigner, tx)
//fmt.Println("Considering TX from sender: ", sender, tx.Hash(), tx.Nonce(), time.Now(), e.Creator())
// check transaction epoch rules
if epochcheck.CheckTxs(types.Transactions{tx}, rules) != nil {
fmt.Println("Failing rules TX from sender: ", sender, tx.Hash(), tx.Nonce(), time.Now(), e.Creator())
sorted.Pop()
continue
}
// check there's enough gas power to originate the transaction
if tx.Gas() >= e.GasPowerLeft().Min() || e.GasPowerUsed()+tx.Gas() >= maxGasUsed {
if params.TxGas >= e.GasPowerLeft().Min() || e.GasPowerUsed()+params.TxGas >= maxGasUsed {

// stop if cannot originate even an empty transaction
break
}
fmt.Println("Gas Issues TX from sender: ", sender, tx.Hash(), tx.Nonce(), time.Now(), e.Creator() , tx.Gas() , e.GasPowerLeft().Min(), e.GasPowerUsed()+tx.Gas(), maxGasUsed)
sorted.Pop()
continue
}
// check not conflicted with already originated txs (in any connected event)
if em.originatedTxs.TotalOf(sender) != 0 {
sorted.Pop()
fmt.Println("Already Originated TX from sender: ", sender, tx.Hash(), tx.Nonce(), time.Now(),e.Creator())
continue
}
// my turn, i.e. try to not include the same tx simultaneously by different validators
if !em.isMyTxTurn(tx.Hash(), sender, tx.Nonce(), time.Now(), em.validators, e.Creator(), em.epoch) {
fmt.Println("Not my turn TX from sender: ", sender, tx.Hash(), tx.Nonce(), time.Now(), e.Creator())
sorted.Pop()
continue
}
// check transaction is not outdated
if !em.world.TxPool.Has(tx.Hash()) {
fmt.Println("Outdated TX from sender: ", sender, tx.Hash(), tx.Nonce(), time.Now(), e.Creator())
sorted.Pop()
continue
}
// add
fmt.Println("My Turn to Execute e.GasPowerUsed()+tx.Gas() >= maxGasUsed: ", e.GasPowerUsed()+tx.Gas(), maxGasUsed, oldMaxGasUsed)
fmt.Println("My Turn to Execute e.GasPowerUsed()+tx.Gas() >= maxGasUsed: ", e.GasPowerUsed()+tx.Gas(), maxGasUsed)
e.SetGasPowerUsed(e.GasPowerUsed() + tx.Gas())
e.SetGasPowerLeft(e.GasPowerLeft().Sub(tx.Gas()))
e.SetTxs(append(e.Txs(), tx))
sorted.Shift()
}
}


Loading

0 comments on commit 3970622

Please sign in to comment.