From 590806fced3a39fce08b78a09243741249c79c85 Mon Sep 17 00:00:00 2001 From: Valentin Rodygin Date: Mon, 30 Oct 2023 16:30:12 +0100 Subject: [PATCH] Implemented the limit per fee currency --- cmd/geth/main.go | 2 ++ cmd/geth/usage.go | 2 ++ cmd/utils/flags.go | 35 ++++++++++++++++++++++++++++++++ miner/block.go | 50 ++++++++++++++++++++++++++++++++++++++++------ miner/miner.go | 6 ++++-- 5 files changed, 87 insertions(+), 8 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 0e2c964717..d662b96f40 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -162,6 +162,8 @@ var ( utils.ProxyEnodeURLPairsFlag, utils.LegacyProxyEnodeURLPairsFlag, utils.ProxyAllowPrivateIPFlag, + utils.CeloFeeCurrencyDefault, + utils.CeloFeeCurrencyLimits, } rpcFlags = []cli.Flag{ diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 8aab205a15..ef8f979e49 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -171,6 +171,8 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.MiningEnabledFlag, utils.MinerValidatorFlag, utils.MinerExtraDataFlag, + utils.CeloFeeCurrencyDefault, + utils.CeloFeeCurrencyLimits, }, }, { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 549f5e10bc..17a7ac193e 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -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 (
=)", + } + // Account settings UnlockedAccountFlag = cli.StringFlag{ @@ -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) { diff --git a/miner/block.go b/miner/block.go index 8efed03943..3aefde0890 100644 --- a/miner/block.go +++ b/miner/block.go @@ -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 @@ -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) @@ -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 @@ -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: diff --git a/miner/miner.go b/miner/miner.go index 6e22cdf230..a87faf0aa5 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -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.