Skip to content
This repository has been archived by the owner on Oct 25, 2024. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'origin/main' into efficient-reverts
Browse files Browse the repository at this point in the history
  • Loading branch information
Wazzymandias committed Aug 3, 2023
2 parents 4317b0a + 4a2b6dc commit 072890f
Show file tree
Hide file tree
Showing 14 changed files with 136 additions and 22 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ $ geth --help
--builder.cancellations (default: false)
Enable cancellations for the builder
--builder.discard_revertible_tx_on_error (default: false)
When enabled, if a transaction submitted as part of a bundle in a send bundle
request has error on commit, and its hash is specified as one that can revert in
the request body, the builder will discard the hash of the failed transaction
from the submitted bundle.For additional details on the structure of the request
body, see
https://docs.flashbots.net/flashbots-mev-share/searchers/understanding-bundles#bundle-definition
[$FLASHBOTS_BUILDER_DISCARD_REVERTIBLE_TX_ON_ERROR]
--builder.dry-run (default: false)
Builder only validates blocks without submission to the relay
Expand Down
3 changes: 3 additions & 0 deletions builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ type Builder struct {
builderPublicKey phase0.BLSPubKey
builderSigningDomain phase0.Domain
builderResubmitInterval time.Duration
discardRevertibleTxOnErr bool

limiter *rate.Limiter
submissionOffsetFromEndOfSlot time.Duration
Expand All @@ -91,6 +92,7 @@ type BuilderArgs struct {
relay IRelay
builderSigningDomain phase0.Domain
builderBlockResubmitInterval time.Duration
discardRevertibleTxOnErr bool
eth IEthereumService
dryRun bool
ignoreLatePayloadAttributes bool
Expand Down Expand Up @@ -136,6 +138,7 @@ func NewBuilder(args BuilderArgs) (*Builder, error) {
builderPublicKey: pk,
builderSigningDomain: args.builderSigningDomain,
builderResubmitInterval: args.builderBlockResubmitInterval,
discardRevertibleTxOnErr: args.discardRevertibleTxOnErr,
submissionOffsetFromEndOfSlot: args.submissionOffsetFromEndOfSlot,

limiter: args.limiter,
Expand Down
2 changes: 2 additions & 0 deletions builder/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Config struct {
BuilderRateLimitMaxBurst int `toml:",omitempty"`
BuilderRateLimitResubmitInterval string `toml:",omitempty"`
BuilderSubmissionOffset time.Duration `toml:",omitempty"`
DiscardRevertibleTxOnErr bool `toml:",omitempty"`
EnableCancellations bool `toml:",omitempty"`
}

Expand All @@ -50,6 +51,7 @@ var DefaultConfig = Config{
ValidationBlocklist: "",
BuilderRateLimitDuration: RateLimitIntervalDefault.String(),
BuilderRateLimitMaxBurst: RateLimitBurstDefault,
DiscardRevertibleTxOnErr: false,
EnableCancellations: false,
}

Expand Down
1 change: 1 addition & 0 deletions builder/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ func Register(stack *node.Node, backend *eth.Ethereum, cfg *Config) error {
builderSigningDomain: builderSigningDomain,
builderBlockResubmitInterval: builderRateLimitInterval,
submissionOffsetFromEndOfSlot: submissionOffset,
discardRevertibleTxOnErr: cfg.DiscardRevertibleTxOnErr,
ignoreLatePayloadAttributes: cfg.IgnoreLatePayloadAttributes,
validator: validator,
beaconClient: beaconClient,
Expand Down
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ var (
utils.BuilderRateLimitMaxBurst,
utils.BuilderBlockResubmitInterval,
utils.BuilderSubmissionOffset,
utils.BuilderDiscardRevertibleTxOnErr,
utils.BuilderEnableCancellations,
}

Expand Down
12 changes: 12 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,16 @@ var (
Category: flags.BuilderCategory,
}

BuilderDiscardRevertibleTxOnErr = &cli.BoolFlag{
Name: "builder.discard_revertible_tx_on_error",
Usage: "When enabled, if a transaction submitted as part of a bundle in a send bundle request has error on commit, " +
"and its hash is specified as one that can revert in the request body, the builder will discard the hash of the failed transaction from the submitted bundle." +
"For additional details on the structure of the request body, see https://docs.flashbots.net/flashbots-mev-share/searchers/understanding-bundles#bundle-definition",
EnvVars: []string{"FLASHBOTS_BUILDER_DISCARD_REVERTIBLE_TX_ON_ERROR"},
Value: builder.DefaultConfig.DiscardRevertibleTxOnErr,
Category: flags.BuilderCategory,
}

BuilderEnableCancellations = &cli.BoolFlag{
Name: "builder.cancellations",
Usage: "Enable cancellations for the builder",
Expand Down Expand Up @@ -1712,6 +1722,7 @@ func SetBuilderConfig(ctx *cli.Context, cfg *builder.Config) {
cfg.BuilderRateLimitDuration = ctx.String(BuilderRateLimitDuration.Name)
cfg.BuilderRateLimitMaxBurst = ctx.Int(BuilderRateLimitMaxBurst.Name)
cfg.BuilderSubmissionOffset = ctx.Duration(BuilderSubmissionOffset.Name)
cfg.DiscardRevertibleTxOnErr = ctx.Bool(BuilderDiscardRevertibleTxOnErr.Name)
cfg.EnableCancellations = ctx.IsSet(BuilderEnableCancellations.Name)
cfg.BuilderRateLimitResubmitInterval = ctx.String(BuilderBlockResubmitInterval.Name)
}
Expand Down Expand Up @@ -1961,6 +1972,7 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) {
}
}

cfg.DiscardRevertibleTxOnErr = ctx.Bool(BuilderDiscardRevertibleTxOnErr.Name)
cfg.EnableMultiTransactionSnapshot = ctx.Bool(BuilderEnableMultiTxSnapshot.Name)
cfg.PriceCutoffPercent = ctx.Int(BuilderPriceCutoffPercentFlag.Name)
}
Expand Down
20 changes: 14 additions & 6 deletions miner/algo_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@ const (
)

const (
// defaultProfitPercentMinimum is to ensure committed transactions, bundles, sbundles don't fall below this threshold
// defaultProfitThresholdPercent is to ensure committed transactions, bundles, sbundles don't fall below this threshold
// when profit is enforced
defaultProfitPercentMinimum = 70
defaultProfitThresholdPercent = 70

// defaultPriceCutoffPercent is for bucketing transactions by price, used for greedy buckets algorithm
defaultPriceCutoffPercent = 50
)

var (
defaultProfitThreshold = big.NewInt(defaultProfitPercentMinimum)
defaultAlgorithmConfig = algorithmConfig{
DropRevertibleTxOnErr: false,
EnforceProfit: false,
ExpectedProfit: common.Big0,
ProfitThresholdPercent: defaultProfitThreshold,
ProfitThresholdPercent: defaultProfitThresholdPercent,
PriceCutoffPercent: defaultPriceCutoffPercent,
EnableMultiTxSnap: false,
}
Expand Down Expand Up @@ -68,13 +68,17 @@ func (e *lowProfitError) Error() string {

type (
algorithmConfig struct {
// DropRevertibleTxOnErr is used when a revertible transaction has error on commit, and we wish to discard
// the transaction and continue processing the rest of a bundle or sbundle.
// Revertible transactions are specified as hashes that can revert in a bundle or sbundle.
DropRevertibleTxOnErr bool
// EnforceProfit is true if we want to enforce a minimum profit threshold
// for committing a transaction based on ProfitThresholdPercent
EnforceProfit bool
// ExpectedProfit should be set on a per-transaction basis when profit is enforced
ExpectedProfit *big.Int
// ProfitThresholdPercent is the minimum profit threshold for committing a transaction
ProfitThresholdPercent *big.Int
ProfitThresholdPercent int // 0-100, e.g. 70 means 70%
// 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
Expand Down Expand Up @@ -122,7 +126,11 @@ func checkInterrupt(i *int32) bool {

// Simulate bundle on top of current state without modifying it
// pending txs used to track if bundle tx is part of the mempool
func applyTransactionWithBlacklist(signer types.Signer, config *params.ChainConfig, bc core.ChainContext, author *common.Address, gp *core.GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config, blacklist map[common.Address]struct{}) (*types.Receipt, *state.StateDB, error) {
func applyTransactionWithBlacklist(
signer types.Signer, config *params.ChainConfig, bc core.ChainContext, author *common.Address, gp *core.GasPool,
statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64,
cfg vm.Config, blacklist map[common.Address]struct{},
) (*types.Receipt, *state.StateDB, error) {
// short circuit if blacklist is empty
if len(blacklist) == 0 {
snap := statedb.Snapshot()
Expand Down
3 changes: 2 additions & 1 deletion miner/algo_common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ func TestTxCommit(t *testing.T) {
}

func TestBundleCommit(t *testing.T) {
algoConf := defaultAlgorithmConfig
statedb, chData, signers := genTestSetup()

env := newEnvironment(chData, statedb, signers.addresses[0], GasLimit, big.NewInt(1))
Expand All @@ -298,7 +299,7 @@ func TestBundleCommit(t *testing.T) {
t.Fatal("Failed to simulate bundle", err)
}

err = envDiff.commitBundle(&simBundle, chData, nil, defaultAlgorithmConfig)
err = envDiff.commitBundle(&simBundle, chData, nil, algoConf)
if err != nil {
t.Fatal("Failed to commit bundle", err)
}
Expand Down
3 changes: 2 additions & 1 deletion miner/algo_greedy_buckets.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,10 @@ func (b *greedyBucketsBuilder) commit(envDiff *environmentDiff,
gasUsedMap map[*types.TxWithMinerFee]uint64, retryMap map[*types.TxWithMinerFee]int, retryLimit int,
) ([]types.SimulatedBundle, []types.UsedSBundle) {
var (
algoConf = b.algoConf

usedBundles []types.SimulatedBundle
usedSbundles []types.UsedSBundle
algoConf = b.algoConf
)

for _, order := range transactions {
Expand Down
74 changes: 71 additions & 3 deletions miner/algo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var algoTests = []*algoTest{
},
WantProfit: big.NewInt(2 * 21_000),
SupportedAlgorithms: []AlgoType{ALGO_GREEDY, ALGO_GREEDY_BUCKETS},
AlgorithmConfig: defaultAlgorithmConfig,
},
{
// Trivial tx pool with 3 txs by two accounts and a block gas limit that only allows two txs
Expand All @@ -65,6 +66,7 @@ var algoTests = []*algoTest{
},
WantProfit: big.NewInt(4 * 21_000),
SupportedAlgorithms: []AlgoType{ALGO_GREEDY, ALGO_GREEDY_BUCKETS},
AlgorithmConfig: defaultAlgorithmConfig,
},
{
// Trivial bundle with one tx that reverts but is not allowed to revert.
Expand All @@ -83,6 +85,7 @@ var algoTests = []*algoTest{
},
WantProfit: big.NewInt(0),
SupportedAlgorithms: []AlgoType{ALGO_GREEDY, ALGO_GREEDY_BUCKETS},
AlgorithmConfig: defaultAlgorithmConfig,
},
{
// Trivial bundle with one tx that reverts and is allowed to revert.
Expand All @@ -104,6 +107,65 @@ var algoTests = []*algoTest{
},
WantProfit: big.NewInt(50_000),
SupportedAlgorithms: []AlgoType{ALGO_GREEDY, ALGO_GREEDY_BUCKETS},
AlgorithmConfig: defaultAlgorithmConfig,
},
{
// Trivial bundle with one tx that has nonce error and fails.
//
// Bundle should NOT be included since DropRevertibleTxOnErr is enabled.
Name: "atomic-bundle-nonce-error-and-discard",
Header: &types.Header{GasLimit: 50_000},
Alloc: []core.GenesisAccount{
{Balance: big.NewInt(50_000)},
{Code: contractRevert},
},
Bundles: func(acc accByIndex, sign signByIndex, txs txByAccIndexAndNonce) []*bundle {
return []*bundle{
{
Txs: types.Transactions{sign(0, &types.LegacyTx{Nonce: 1, Gas: 50_000, To: acc(1), GasPrice: big.NewInt(1)})},
RevertingTxIndices: []int{0},
},
}
},
WantProfit: common.Big0,
SupportedAlgorithms: []AlgoType{ALGO_GREEDY, ALGO_GREEDY_BUCKETS},
AlgorithmConfig: algorithmConfig{
DropRevertibleTxOnErr: true,
EnforceProfit: defaultAlgorithmConfig.EnforceProfit,
ProfitThresholdPercent: defaultAlgorithmConfig.ProfitThresholdPercent,
},
},
{
// Bundle with two transactions - first tx will revert and second has nonce error
//
// Bundle SHOULD be included ONLY with first tx since DropRevertibleTxOnErr is enabled.
Name: "bundle-with-revert-tx-and-invalid-nonce-discard",
Header: &types.Header{
GasLimit: 3 * 21_000,
},
Alloc: []core.GenesisAccount{
{Balance: big.NewInt(3 * 21_000)},
{Code: contractRevert},
},
Bundles: func(acc accByIndex, sign signByIndex, txs txByAccIndexAndNonce) []*bundle {
return []*bundle{
{
Txs: types.Transactions{sign(0, &types.LegacyTx{Nonce: 0, Gas: 21_000, To: acc(1), GasPrice: big.NewInt(1)})},
RevertingTxIndices: []int{0},
},
{
Txs: types.Transactions{sign(0, &types.LegacyTx{Nonce: 2, Gas: 42_000, To: acc(1), GasPrice: big.NewInt(1)})},
RevertingTxIndices: []int{0},
},
}
},
WantProfit: big.NewInt(21_000),
SupportedAlgorithms: []AlgoType{ALGO_GREEDY, ALGO_GREEDY_BUCKETS},
AlgorithmConfig: algorithmConfig{
DropRevertibleTxOnErr: true,
EnforceProfit: defaultAlgorithmConfig.EnforceProfit,
ProfitThresholdPercent: defaultAlgorithmConfig.ProfitThresholdPercent,
},
},
{
// Single failing tx that is included in the tx pool and in a bundle that is not allowed to
Expand All @@ -130,6 +192,7 @@ var algoTests = []*algoTest{
},
WantProfit: big.NewInt(50_000),
SupportedAlgorithms: []AlgoType{ALGO_GREEDY, ALGO_GREEDY_BUCKETS},
AlgorithmConfig: defaultAlgorithmConfig,
},
}

Expand Down Expand Up @@ -216,7 +279,7 @@ func BenchmarkAlgo(b *testing.B) {
}
}()

gotProfit, err := runAlgoTest(algo, defaultAlgorithmConfig, config, alloc, txPoolCopy, simBundles, test.Header, scale)
gotProfit, err := runAlgoTest(algo, test.AlgorithmConfig, config, alloc, txPoolCopy, simBundles, test.Header, scale)
if err != nil {
b.Fatal(err)
}
Expand All @@ -231,8 +294,11 @@ func BenchmarkAlgo(b *testing.B) {
}

// runAlgo executes a single algoTest case and returns the profit.
func runAlgoTest(algo AlgoType, algoConf algorithmConfig, config *params.ChainConfig, alloc core.GenesisAlloc,
txPool map[common.Address]types.Transactions, bundles []types.SimulatedBundle, header *types.Header, scale int) (gotProfit *big.Int, err error) {
func runAlgoTest(
algo AlgoType, algoConf algorithmConfig,
config *params.ChainConfig, alloc core.GenesisAlloc,
txPool map[common.Address]types.Transactions, bundles []types.SimulatedBundle, header *types.Header, scale int,
) (gotProfit *big.Int, err error) {
var (
statedb, chData = genTestSetupWithAlloc(config, alloc)
env = newEnvironment(chData, statedb, header.Coinbase, header.GasLimit*uint64(scale), header.BaseFee)
Expand Down Expand Up @@ -299,6 +365,8 @@ type algoTest struct {
WantProfit *big.Int // Expected block profit

SupportedAlgorithms []AlgoType

AlgorithmConfig algorithmConfig
}

// setDefaults sets default values for the algoTest.
Expand Down
2 changes: 1 addition & 1 deletion miner/env_changes.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ func (c *envChanges) CommitSBundle(sbundle *types.SimSBundle, chData chainData,

// We want to make simulated profit smaller to allow for some leeway in cases where the actual profit is
// lower due to transaction ordering
simulatedProfitMultiple := new(big.Int).Mul(simulatedProfit, algoConf.ProfitThresholdPercent)
simulatedProfitMultiple := common.PercentOf(simulatedProfit, algoConf.ProfitThresholdPercent)
actualProfitMultiple := new(big.Int).Mul(actualProfit, common.Big100)

if simulatedProfitMultiple.Cmp(actualProfitMultiple) > 0 {
Expand Down
4 changes: 2 additions & 2 deletions miner/environment_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func (envDiff *environmentDiff) commitBundle(bundle *types.SimulatedBundle, chDa

// We want to make simulated profit smaller to allow for some leeway in cases where the actual profit is
// lower due to transaction ordering
simulatedProfitMultiple := new(big.Int).Mul(simulatedBundleProfit, algoConf.ProfitThresholdPercent)
simulatedProfitMultiple := common.PercentOf(simulatedBundleProfit, algoConf.ProfitThresholdPercent)
actualProfitMultiple := new(big.Int).Mul(actualBundleProfit, common.Big100)

if simulatedProfitMultiple.Cmp(actualProfitMultiple) > 0 {
Expand Down Expand Up @@ -281,7 +281,7 @@ func (envDiff *environmentDiff) commitSBundle(b *types.SimSBundle, chData chainD

// We want to make simulated profit smaller to allow for some leeway in cases where the actual profit is
// lower due to transaction ordering
simulatedProfitMultiple := new(big.Int).Mul(simulatedSbundleProfit, algoConf.ProfitThresholdPercent)
simulatedProfitMultiple := common.PercentOf(simulatedSbundleProfit, algoConf.ProfitThresholdPercent)
actualProfitMultiple := new(big.Int).Mul(actualSbundleProfit, common.Big100)

if simulatedProfitMultiple.Cmp(actualProfitMultiple) > 0 {
Expand Down
1 change: 1 addition & 0 deletions miner/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ type Config struct {
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)
DiscardRevertibleTxOnErr bool // When enabled, if bundle revertible transaction has error on commit, builder will discard the transaction
EnableMultiTransactionSnapshot bool // Enable block building with multi-transaction snapshots to reduce state copying (note: experimental)
}

Expand Down
Loading

0 comments on commit 072890f

Please sign in to comment.