diff --git a/README.md b/README.md index 86dfd72537..17a179964f 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,15 @@ $ geth --help --miner.extradata value Block extra data set by the miner (default = client version) + --miner.price_cutoff_percent value (default: 50) + flashbots - The minimum effective gas price threshold used for bucketing + transactions by price. For example if the top transaction in a list has an + effective gas price of 1000 wei and price_cutoff_percent is 10 (i.e. 10%), then + the minimum effective gas price included in the same bucket as the top + transaction is (1000 * 10%) = 100 wei. + NOTE: This flag is only used when + miner.algotype=greedy-buckets + METRICS --metrics.builder value (default: false) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index b5d3dd3553..cd4a004680 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -133,6 +133,7 @@ var ( utils.MinerMaxMergedBundlesFlag, utils.MinerBlocklistFileFlag, utils.MinerNewPayloadTimeout, + utils.MinerPriceCutoffPercentFlag, utils.NATFlag, utils.NoDiscoverFlag, utils.DiscoveryV5Flag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 66f3da7618..e784e22d1a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -548,7 +548,7 @@ var ( } MinerAlgoTypeFlag = &cli.StringFlag{ Name: "miner.algotype", - Usage: "Block building algorithm to use [=mev-geth] (mev-geth, greedy)", + Usage: "Block building algorithm to use [=mev-geth] (mev-geth, greedy, greedy-buckets)", Value: "mev-geth", Category: flags.MinerCategory, } @@ -591,6 +591,17 @@ var ( Value: ethconfig.Defaults.Miner.NewPayloadTimeout, Category: flags.MinerCategory, } + MinerPriceCutoffPercentFlag = &cli.IntFlag{ + Name: "miner.price_cutoff_percent", + Usage: "flashbots - The minimum effective gas price threshold used for bucketing transactions by price. " + + "For example if the top transaction in a list has an effective gas price of 1000 wei and price_cutoff_percent " + + "is 10 (i.e. 10%), then the minimum effective gas price included in the same bucket as the top transaction " + + "is (1000 * 10%) = 100 wei.\n" + + "NOTE: This flag is only used when miner.algotype=greedy-buckets", + Value: ethconfig.Defaults.Miner.PriceCutoffPercent, + Category: flags.MinerCategory, + EnvVars: []string{"FLASHBOTS_MINER_PRICE_CUTOFF_PERCENT"}, + } // Account settings UnlockedAccountFlag = &cli.StringFlag{ @@ -1893,6 +1904,8 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) { Fatalf("Failed to parse blocklist: %s", err) } } + + cfg.PriceCutoffPercent = ctx.Int(MinerPriceCutoffPercentFlag.Name) } func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) { diff --git a/core/types/transaction.go b/core/types/transaction.go index 503e8fbe18..03eb018326 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -535,7 +535,7 @@ func (t *TxWithMinerFee) Profit(baseFee *big.Int, gasUsed uint64) *big.Int { } return profit } else if bundle := t.Bundle(); bundle != nil { - return bundle.TotalEth + return bundle.EthSentToCoinbase } else if sbundle := t.SBundle(); sbundle != nil { return sbundle.Profit } else { diff --git a/miner/algo_common.go b/miner/algo_common.go index ad82c8dd94..ee036e5e1d 100644 --- a/miner/algo_common.go +++ b/miner/algo_common.go @@ -22,9 +22,14 @@ const ( popTx = 2 ) -// defaultProfitPercentMinimum is to ensure committed transactions, bundles, sbundles don't fall below this threshold -// when profit is enforced -const defaultProfitPercentMinimum = 70 +const ( + // defaultProfitPercentMinimum is to ensure committed transactions, bundles, sbundles don't fall below this threshold + // when profit is enforced + defaultProfitPercentMinimum = 70 + + // defaultPriceCutoffPercent is for bucketing transactions by price, used for greedy buckets algorithm + defaultPriceCutoffPercent = 50 +) var ( defaultProfitThreshold = big.NewInt(defaultProfitPercentMinimum) @@ -63,6 +68,11 @@ type algorithmConfig struct { ExpectedProfit *big.Int // ProfitThresholdPercent is the minimum profit threshold for committing a transaction ProfitThresholdPercent *big.Int + // PriceCutoffPercent is the minimum effective gas price threshold used for bucketing transactions by price. + // For example if the top transaction in a list has an effective gas price of 1000 wei and PriceCutoffPercent + // is 10 (i.e. 10%), then the minimum effective gas price included in the same bucket as the top transaction + // is (1000 * 10%) = 100 wei. + PriceCutoffPercent int } type chainData struct { diff --git a/miner/algo_greedy_buckets.go b/miner/algo_greedy_buckets.go index 6cac40db7f..c1d8f48689 100644 --- a/miner/algo_greedy_buckets.go +++ b/miner/algo_greedy_buckets.go @@ -49,15 +49,9 @@ func newGreedyBucketsBuilder( } // CutoffPriceFromOrder returns the cutoff price for a given order based on the cutoff percent. -// For example, if the cutoff percent is 0.9, the cutoff price will be 90% of the order price, rounded down to the nearest integer. -func CutoffPriceFromOrder(order *types.TxWithMinerFee, cutoffPercent *big.Float) *big.Int { - floorPrice := new(big.Float). - Mul( - new(big.Float).SetInt(order.Price()), - cutoffPercent, - ) - round, _ := floorPrice.Int64() - return big.NewInt(round) +// For example, if the cutoff percent is 90, the cutoff price will be 90% of the order price, rounded down to the nearest integer. +func CutoffPriceFromOrder(order *types.TxWithMinerFee, cutoffPercent int) *big.Int { + return common.PercentOf(order.Price(), cutoffPercent) } // IsOrderInPriceRange returns true if the order price is greater than or equal to the minPrice. @@ -196,15 +190,12 @@ func (b *greedyBucketsBuilder) mergeOrdersIntoEnvDiff( const retryLimit = 1 var ( - baseFee = envDiff.baseEnvironment.header.BaseFee - retryMap = make(map[*types.TxWithMinerFee]int) - usedBundles []types.SimulatedBundle - usedSbundles []types.UsedSBundle - transactions []*types.TxWithMinerFee - percent = new(big.Float).Quo( - new(big.Float).SetInt(b.algoConf.ProfitThresholdPercent), - new(big.Float).SetInt(common.Big100), - ) + baseFee = envDiff.baseEnvironment.header.BaseFee + retryMap = make(map[*types.TxWithMinerFee]int) + usedBundles []types.SimulatedBundle + usedSbundles []types.UsedSBundle + transactions []*types.TxWithMinerFee + priceCutoffPercent = b.algoConf.PriceCutoffPercent SortInPlaceByProfit = func(baseFee *big.Int, transactions []*types.TxWithMinerFee, gasUsedMap map[*types.TxWithMinerFee]uint64) { sort.SliceStable(transactions, func(i, j int) bool { @@ -213,7 +204,7 @@ func (b *greedyBucketsBuilder) mergeOrdersIntoEnvDiff( } ) - minPrice := CutoffPriceFromOrder(orders.Peek(), percent) + minPrice := CutoffPriceFromOrder(orders.Peek(), priceCutoffPercent) for { order := orders.Peek() if order == nil { @@ -241,7 +232,7 @@ func (b *greedyBucketsBuilder) mergeOrdersIntoEnvDiff( usedSbundles = append(usedSbundles, sbundles...) transactions = nil } - minPrice = CutoffPriceFromOrder(order, percent) + minPrice = CutoffPriceFromOrder(order, priceCutoffPercent) } } diff --git a/miner/miner.go b/miner/miner.go index 4c8e908fd6..b4f2f8c709 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -98,6 +98,7 @@ type Config struct { MaxMergedBundles int Blocklist []common.Address `toml:",omitempty"` NewPayloadTimeout time.Duration // The maximum time allowance for creating a new payload + PriceCutoffPercent int // Effective gas price cutoff % used for bucketing transactions by price (only useful in greedy-buckets AlgoType) } // DefaultConfig contains default settings for miner. @@ -109,8 +110,9 @@ var DefaultConfig = Config{ // consensus-layer usually will wait a half slot of time(6s) // for payload generation. It should be enough for Geth to // run 3 rounds. - Recommit: 2 * time.Second, - NewPayloadTimeout: 2 * time.Second, + Recommit: 2 * time.Second, + NewPayloadTimeout: 2 * time.Second, + PriceCutoffPercent: defaultPriceCutoffPercent, } // Miner creates blocks and searches for proof-of-work values. diff --git a/miner/worker.go b/miner/worker.go index 56021b7b49..d175850409 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1405,13 +1405,19 @@ func (w *worker) fillTransactionsAlgoWorker(interrupt *int32, env *environment) switch w.flashbots.algoType { case ALGO_GREEDY_BUCKETS: - validationConf := &algorithmConfig{ + priceCutoffPercent := w.config.PriceCutoffPercent + if !(priceCutoffPercent >= 0 && priceCutoffPercent <= 100) { + return nil, nil, nil, errors.New("invalid price cutoff percent - must be between 0 and 100") + } + + algoConf := &algorithmConfig{ EnforceProfit: true, ExpectedProfit: nil, ProfitThresholdPercent: defaultProfitThreshold, + PriceCutoffPercent: priceCutoffPercent, } builder := newGreedyBucketsBuilder( - w.chain, w.chainConfig, validationConf, w.blockList, env, + w.chain, w.chainConfig, algoConf, w.blockList, env, w.config.BuilderTxSigningKey, interrupt, )