Skip to content

Commit

Permalink
Implemented the limit per fee currency
Browse files Browse the repository at this point in the history
  • Loading branch information
Valentin Rodygin committed Oct 30, 2023
1 parent a59dd19 commit 4e8b821
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 8 deletions.
2 changes: 2 additions & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ var (
utils.ProxyEnodeURLPairsFlag,
utils.LegacyProxyEnodeURLPairsFlag,
utils.ProxyAllowPrivateIPFlag,
utils.CeloFeeCurrencyDefault,
utils.CeloFeeCurrencyLimits,
}

rpcFlags = []cli.Flag{
Expand Down
2 changes: 2 additions & 0 deletions cmd/geth/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ var AppHelpFlagGroups = []flags.FlagGroup{
utils.MiningEnabledFlag,
utils.MinerValidatorFlag,
utils.MinerExtraDataFlag,
utils.CeloFeeCurrencyDefault,
utils.CeloFeeCurrencyLimits,
},
},
{
Expand Down
35 changes: 35 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,16 @@ var (
Name: "miner.extradata",
Usage: "Block extra data set by the miner (default = client version)",
}
CeloFeeCurrencyDefault = cli.Float64Flag{
Name: "celo.feecurrency.default",
Usage: "Default fraction of block gas limit available for TXs paid with a whitelisted currency",
Value: 0.9,
}
CeloFeeCurrencyLimits = cli.StringFlag{
Name: "celo.feecurrency.limits",
Usage: "Comma separated currency address-to-block percentage mappings (<address>=<fraction>)",
}

// Account settings

UnlockedAccountFlag = cli.StringFlag{
Expand Down Expand Up @@ -1433,6 +1443,31 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) {
if ctx.GlobalIsSet(MinerExtraDataFlag.Name) {
cfg.ExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name))
}

cfg.FeeCurrencyDefault = ctx.GlobalFloat64(CeloFeeCurrencyDefault.Name)

if ctx.GlobalIsSet(CeloFeeCurrencyLimits.Name) {
feeCurrencyLimits := ctx.GlobalString(CeloFeeCurrencyLimits.Name)
cfg.FeeCurrencyLimits = make(map[common.Address]float64)

for _, entry := range strings.Split(feeCurrencyLimits, ",") {
parts := strings.Split(entry, "=")
if len(parts) != 2 {
Fatalf("Invalid fee currency limits entry: %s", entry)
}
var address common.Address
if err := address.UnmarshalText([]byte(parts[0])); err != nil {
Fatalf("Invalid fee currency address hash %s: %v", parts[0], err)
}

fraction, err := strconv.ParseFloat(parts[1], 64)
if err != nil {
Fatalf("Invalid block limit fraction %s: %v", parts[1], err)
}

cfg.FeeCurrencyLimits[address] = fraction
}
}
}

func setWhitelist(ctx *cli.Context, cfg *ethconfig.Config) {
Expand Down
57 changes: 57 additions & 0 deletions core/celo_multi_gaspool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package core

import (
// "fmt"
// "math"

"github.com/celo-org/celo-blockchain/common"
)

type FeeCurrency = common.Address

// MultiGasPool tracks the amount of gas available during execution
// of the transactions in a block per fee currency. The zero value is a pool
// with zero gas available.
type MultiGasPool struct {
pools map[FeeCurrency]*GasPool
defaultPool *GasPool
}

type FeeCurrencyLimitMapping = map[FeeCurrency]float64

func NewMultiGasPool(
block_gas_limit uint64,
whitelist []FeeCurrency,
defaultLimit float64,
limitsMapping FeeCurrencyLimitMapping,
) MultiGasPool {
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(block_gas_limit) * fraction),
)
}

// A special case for CELO which doesn't have a limit
celoPool := new(GasPool).AddGas(block_gas_limit)

return MultiGasPool{
pools: pools,
defaultPool: celoPool,
}
}

func (mgp MultiGasPool) PoolFor(feeCurrency *FeeCurrency) *GasPool {
if feeCurrency == nil || mgp.pools[*feeCurrency] == nil {
return mgp.defaultPool
}

return mgp.pools[*feeCurrency]
}
50 changes: 44 additions & 6 deletions miner/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ import (
type blockState 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
bytesBlock *core.BytesBlock // available bytes used to pack transactions
gasLimit uint64
sysCtx *core.SysContractCallCtx
state *state.StateDB // apply state changes here
tcount int // tx count in cycle
gasPool *core.GasPool // available gas used to pack transactions
bytesBlock *core.BytesBlock // available bytes used to pack transactions
multiGasPool core.MultiGasPool // available gas to pay for with currency
gasLimit uint64
sysCtx *core.SysContractCallCtx

header *types.Header
txs []*types.Transaction
Expand Down Expand Up @@ -112,6 +113,20 @@ func prepareBlock(w *worker) (*blockState, error) {
txFeeRecipient: txFeeRecipient,
}
b.gasPool = new(core.GasPool).AddGas(b.gasLimit)

whitelist, err := currency.CurrencyWhitelist(vmRunner)
if err != nil {
log.Warn("Can't fetch currency whitelist", "error", err, "block", header.Number.Uint64())
whitelist = []common.Address{}
}

b.multiGasPool = core.NewMultiGasPool(
b.gasLimit,
whitelist,
w.config.FeeCurrencyDefault,
w.config.FeeCurrencyLimits,
)

if w.chainConfig.IsGingerbread(header.Number) {
header.GasLimit = b.gasLimit
header.Difficulty = big.NewInt(0)
Expand Down Expand Up @@ -250,6 +265,17 @@ loop:
if tx == nil {
break
}
// Short-circuit if the transaction is using more gas allocated for the
// given fee currency.
if b.multiGasPool.PoolFor(tx.FeeCurrency()).Gas() < tx.Gas() {
log.Trace(
"Skipping transaction which requires more gas than is left in the pool",
"hash", tx.Hash(), "gas", b.multiGasPool.PoolFor(tx.FeeCurrency()).Gas(),
"txgas", tx.Gas(),
)
txs.Pop()
continue
}
// Short-circuit if the transaction requires more gas than we have in the pool.
// If we didn't short-circuit here, we would get core.ErrGasLimitReached below.
// Short-circuiting here saves us the trouble of checking the GPM and so on when the tx can't be included
Expand Down Expand Up @@ -321,6 +347,18 @@ loop:
return err
}
}

err = b.multiGasPool.PoolFor(tx.FeeCurrency()).SubGas(tx.Gas())
// Should never happen as we check it above
if err != nil {
log.Warn(
"Unexpectedly reached limit for fee currency",
"hash", tx.Hash(), "gas", b.multiGasPool.PoolFor(tx.FeeCurrency()).Gas(),
"txgas", tx.Gas(),
)
return err
}

txs.Shift()

default:
Expand Down
6 changes: 4 additions & 2 deletions miner/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ type Backend interface {

// Config is the configuration parameters of mining.
type Config struct {
Validator common.Address `toml:",omitempty"` // Public address for block signing and randomness (default = first account)
ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner
Validator common.Address `toml:",omitempty"` // Public address for block signing and randomness (default = first account)
ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner
FeeCurrencyDefault float64 // Default fraction of block gas limit
FeeCurrencyLimits map[common.Address]float64 // Fee currency-to-limit fraction mapping
}

// Miner creates blocks and searches for proof-of-work values.
Expand Down

0 comments on commit 4e8b821

Please sign in to comment.