Skip to content

Commit

Permalink
Initialize MultiGasPool with currency whitelist
Browse files Browse the repository at this point in the history
  • Loading branch information
ezdac committed Jun 3, 2024
1 parent 8b31509 commit f437ea2
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 62 deletions.
10 changes: 10 additions & 0 deletions common/celo_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ var (

type ExchangeRates = map[Address]*big.Rat

func CurrencyWhitelist(exchangeRates ExchangeRates) []Address {
addrs := make([]Address, len(exchangeRates))
i := 0
for k := range exchangeRates {
addrs[i] = k
i++
}
return addrs
}

func IsCurrencyWhitelisted(exchangeRates ExchangeRates, feeCurrency *Address) bool {
if feeCurrency == nil {
return true
Expand Down
68 changes: 30 additions & 38 deletions core/celo_multi_gaspool.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package core

import "github.com/ethereum/go-ethereum/common"
import (
"github.com/ethereum/go-ethereum/common"
)

type FeeCurrency = common.Address

Expand All @@ -10,9 +12,6 @@ type FeeCurrency = common.Address
type MultiGasPool struct {
pools map[FeeCurrency]*GasPool
defaultPool *GasPool

blockGasLimit uint64
defaultLimit float64
}

type FeeCurrencyLimitMapping = map[FeeCurrency]float64
Expand All @@ -21,48 +20,41 @@ type FeeCurrencyLimitMapping = map[FeeCurrency]float64
// pool for CELO
func NewMultiGasPool(
blockGasLimit uint64,
whitelist []FeeCurrency,
defaultLimit float64,
limitsMapping FeeCurrencyLimitMapping,
) *MultiGasPool {
pools := make(map[FeeCurrency]*GasPool, len(limitsMapping))
pools := make(map[FeeCurrency]*GasPool, len(whitelist))

for i := range whitelist {
currency := whitelist[i]
fraction, ok := limitsMapping[currency]
if !ok {
fraction = defaultLimit
}

pools[currency] = new(GasPool).AddGas(
uint64(float64(blockGasLimit) * fraction),
)
}

// A special case for CELO which doesn't have a limit
celoPool := new(GasPool).AddGas(blockGasLimit)
mgp := &MultiGasPool{
pools: pools,
defaultPool: celoPool,
blockGasLimit: blockGasLimit,
defaultLimit: defaultLimit,
}
for feeCurrency, fraction := range limitsMapping {
mgp.getOrInitPool(feeCurrency, &fraction)
}
return mgp
}

func (mgp MultiGasPool) getOrInitPool(c FeeCurrency, fraction *float64) *GasPool {
if gp, ok := mgp.pools[c]; ok {
return gp
}
if fraction == nil {
fraction = &mgp.defaultLimit
return &MultiGasPool{
pools: pools,
defaultPool: celoPool,
}
gp := new(GasPool).AddGas(
uint64(float64(mgp.blockGasLimit) * *fraction),
)
mgp.pools[c] = gp
return gp
}

// GetPool returns an initialised pool for the given fee currency or
// initialises and returns a new pool with a default limit.
// For a `nil` FeeCurrency value, it returns the default pool.
func (mgp MultiGasPool) GetPool(c *FeeCurrency) *GasPool {
if c == nil {
// PoolFor returns a configured pool for the given fee currency or the default
// one otherwise
func (mgp MultiGasPool) PoolFor(feeCurrency *FeeCurrency) *GasPool {
if feeCurrency == nil || mgp.pools[*feeCurrency] == nil {
return mgp.defaultPool
}
// Use the default fraction here because the configured limits'
// pools have been created already in the constructor.
return mgp.getOrInitPool(*c, nil)

return mgp.pools[*feeCurrency]
}

func (mgp MultiGasPool) Copy() *MultiGasPool {
Expand All @@ -71,9 +63,9 @@ func (mgp MultiGasPool) Copy() *MultiGasPool {
gpCpy := *gp
pools[fc] = &gpCpy
}
gpCpy := *mgp.defaultPool
return &MultiGasPool{
pools: pools,
blockGasLimit: mgp.blockGasLimit,
defaultLimit: mgp.defaultLimit,
pools: pools,
defaultPool: &gpCpy,
}
}
64 changes: 51 additions & 13 deletions core/celo_multi_gaspool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,27 @@ func TestMultiCurrencyGasPool(t *testing.T) {
testCases := []struct {
name string
feeCurrency *FeeCurrency
whitelist []FeeCurrency
defaultLimit float64
limits FeeCurrencyLimitMapping
defaultPoolExpected bool
expectedValue uint64
}{
{
name: "Empty mapping, CELO uses default pool",
name: "Empty whitelist, empty mapping, CELO uses default pool",
feeCurrency: nil,
whitelist: []FeeCurrency{},
defaultLimit: 0.9,
limits: map[FeeCurrency]float64{},
defaultPoolExpected: true,
expectedValue: 900, // blockGasLimit - subGasAmount
},
{
name: "Non-empty mapping, CELO uses default pool",
feeCurrency: nil,
name: "Non-empty whitelist, non-empty mapping, CELO uses default pool",
feeCurrency: nil,
whitelist: []FeeCurrency{
cUSDToken,
},
defaultLimit: 0.9,
limits: map[FeeCurrency]float64{
cUSDToken: 0.5,
Expand All @@ -40,53 +45,86 @@ func TestMultiCurrencyGasPool(t *testing.T) {
expectedValue: 900, // blockGasLimit - subGasAmount
},
{
name: "Empty mapping, currency fallbacks to the default limit",
name: "Empty whitelist, empty mapping, non-whitelisted currency fallbacks to the default pool",
feeCurrency: &cUSDToken,
whitelist: []FeeCurrency{},
defaultLimit: 0.9,
limits: map[FeeCurrency]float64{},
defaultPoolExpected: false,
expectedValue: 800, // blockGasLimit * defaultLimit- subGasAmount
defaultPoolExpected: true,
expectedValue: 900, // blockGasLimit - subGasAmount
},
{
name: "Non-empty mapping, currency uses default limit",
feeCurrency: &cEURToken,
name: "Non-empty whitelist, non-empty mapping, non-whitelisted currency uses default pool",
feeCurrency: &cEURToken,
whitelist: []FeeCurrency{
cUSDToken,
},
defaultLimit: 0.9,
limits: map[FeeCurrency]float64{
cUSDToken: 0.5,
},
defaultPoolExpected: true,
expectedValue: 900, // blockGasLimit - subGasAmount
},
{
name: "Non-empty whitelist, empty mapping, whitelisted currency uses default limit",
feeCurrency: &cUSDToken,
whitelist: []FeeCurrency{
cUSDToken,
},
defaultLimit: 0.9,
limits: map[FeeCurrency]float64{},
defaultPoolExpected: false,
expectedValue: 800, // blockGasLimit * defaultLimit - subGasAmount
},
{
name: "Non-empty mapping, configured currency uses configured limits",
feeCurrency: &cUSDToken,
name: "Non-empty whitelist, non-empty mapping, configured whitelisted currency uses configured limits",
feeCurrency: &cUSDToken,
whitelist: []FeeCurrency{
cUSDToken,
},
defaultLimit: 0.9,
limits: map[FeeCurrency]float64{
cUSDToken: 0.5,
},
defaultPoolExpected: false,
expectedValue: 400, // blockGasLimit * 0.5 - subGasAmount
},
{
name: "Non-empty whitelist, non-empty mapping, unconfigured whitelisted currency uses default limit",
feeCurrency: &cEURToken,
whitelist: []FeeCurrency{
cUSDToken,
cEURToken,
},
defaultLimit: 0.9,
limits: map[FeeCurrency]float64{
cUSDToken: 0.5,
},
defaultPoolExpected: false,
expectedValue: 800, // blockGasLimit * 0.5 - subGasAmount
},
}

for _, c := range testCases {
t.Run(c.name, func(t *testing.T) {
mgp := NewMultiGasPool(
blockGasLimit,
c.whitelist,
c.defaultLimit,
c.limits,
)

pool := mgp.GetPool(c.feeCurrency)
pool := mgp.PoolFor(c.feeCurrency)
pool.SubGas(uint64(subGasAmount))

if c.defaultPoolExpected {
result := mgp.GetPool(nil).Gas()
result := mgp.PoolFor(nil).Gas()
if result != c.expectedValue {
t.Error("Default pool expected", c.expectedValue, "got", result)
}
} else {
result := mgp.GetPool(c.feeCurrency).Gas()
result := mgp.PoolFor(c.feeCurrency).Gas()

if result != c.expectedValue {
t.Error(
Expand Down
27 changes: 16 additions & 11 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,13 @@ var (
// environment is the worker's current environment and holds all
// information of the sealing block generation.
type environment struct {
signer types.Signer
state *state.StateDB // apply state changes here
tcount int // tx count in cycle
gasPool *core.GasPool // available gas used to pack transactions
multiGasPool *core.MultiGasPool // available per-fee-currency gas used to pack transactions
coinbase common.Address
signer types.Signer
state *state.StateDB // apply state changes here
tcount int // tx count in cycle
gasPool *core.GasPool // available gas used to pack transactions
multiGasPool *core.MultiGasPool // available per-fee-currency gas used to pack transactions
exchangeRates common.ExchangeRates
coinbase common.Address

header *types.Header
txs []*types.Transaction
Expand Down Expand Up @@ -858,6 +859,7 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac
if env.multiGasPool == nil {
env.multiGasPool = core.NewMultiGasPool(
env.header.GasLimit,
common.CurrencyWhitelist(env.exchangeRates),
w.config.FeeCurrencyDefault,
w.config.FeeCurrencyLimits,
)
Expand Down Expand Up @@ -917,7 +919,7 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac
txs.Pop()
continue
}
if left := env.multiGasPool.GetPool(ltx.FeeCurrency).Gas(); left < ltx.Gas {
if left := env.multiGasPool.PoolFor(ltx.FeeCurrency).Gas(); left < ltx.Gas {
log.Trace(
"Not enough specific fee-currency gas left for transaction",
"currency", ltx.FeeCurrency, "hash", ltx.Hash,
Expand Down Expand Up @@ -957,12 +959,12 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac
txs.Shift()

case errors.Is(err, nil):
err := env.multiGasPool.GetPool(tx.FeeCurrency()).SubGas(gasUsed)
err := env.multiGasPool.PoolFor(tx.FeeCurrency()).SubGas(gasUsed)
if err != nil {
// Should never happen as we check it above
log.Warn(
"Unexpectedly reached limit for fee currency, but tx will not be skipped",
"hash", tx.Hash(), "gas", env.multiGasPool.GetPool(tx.FeeCurrency()).Gas(),
"hash", tx.Hash(), "gas", env.multiGasPool.PoolFor(tx.FeeCurrency()).Gas(),
"tx gas used", gasUsed,
)
// If we reach this codepath, we want to still include the transaction,
Expand Down Expand Up @@ -1134,8 +1136,10 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
log.Error("Failed to create sealing context", "err", err)
return nil, err
}
context := core.NewEVMBlockContext(header, w.chain, nil, w.chainConfig, env.state)
//FIXME: can be nil when not Cel2
env.exchangeRates = context.ExchangeRates
if header.ParentBeaconRoot != nil {
context := core.NewEVMBlockContext(header, w.chain, nil, w.chainConfig, env.state)
vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, w.chainConfig, vm.Config{})
core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state)
}
Expand Down Expand Up @@ -1217,6 +1221,7 @@ func (w *worker) generateWork(genParams *generateParams) *newPayloadResult {
if work.multiGasPool == nil {
work.multiGasPool = core.NewMultiGasPool(
work.header.GasLimit,
common.CurrencyWhitelist(work.exchangeRates),
w.config.FeeCurrencyDefault,
w.config.FeeCurrencyLimits,
)
Expand All @@ -1234,7 +1239,7 @@ func (w *worker) generateWork(genParams *generateParams) *newPayloadResult {
// the non-fee currency pool in the multipool is not used, but for consistency
// subtract the gas. Don't check the error either, this has been checked already
// with the work.gasPool.
work.multiGasPool.GetPool(nil).SubGas(tx.Gas())
work.multiGasPool.PoolFor(nil).SubGas(tx.Gas())
work.tcount++
}

Expand Down

0 comments on commit f437ea2

Please sign in to comment.