Skip to content

Commit

Permalink
add miner blocklist (ethereum#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
dvush authored and avalonche committed Mar 9, 2023
1 parent 10fa312 commit bf900e9
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 8 deletions.
17 changes: 17 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,12 @@ var (
Value: "0x870e2734DdBe2Fba9864f33f3420d59Bc641f2be",
Category: flags.MinerCategory,
}
MinerBlocklistFileFlag = &cli.StringFlag{
Name: "miner.blocklist",
Usage: "flashbots - Path to JSON file with list of blocked addresses. Miner will ignore txs that touch mentioned addresses.",
Value: "",
Category: flags.MinerCategory,
}

// Account settings
UnlockedAccountFlag = &cli.StringFlag{
Expand Down Expand Up @@ -1759,6 +1765,17 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) {
}
}
log.Info("Trusted relays set as", "addresses", cfg.TrustedRelays)

if ctx.IsSet(MinerBlocklistFileFlag.Name) {
bytes, err := os.ReadFile(ctx.String(MinerBlocklistFileFlag.Name))
if err != nil {
Fatalf("Failed to read blocklist file: %s", err)
}

if err := json.Unmarshal(bytes, &cfg.Blocklist); err != nil {
Fatalf("Failed to parse blocklist: %s", err)
}
}
}

func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) {
Expand Down
69 changes: 69 additions & 0 deletions eth/tracers/logger/account_touch_tracer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2022 flashbots
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package logger

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"math/big"
"time"
)

type AccountTouchTracer struct {
touched map[common.Address]struct{}
}

// NewAccountTouchTracer creates new AccountTouchTracer
// that collect all addresses touched in the given tx
// including tx sender and tx.to from the top level call
func NewAccountTouchTracer() *AccountTouchTracer {
return &AccountTouchTracer{
touched: map[common.Address]struct{}{},
}
}

func (t *AccountTouchTracer) TouchedAddresses() []common.Address {
result := make([]common.Address, 0, len(t.touched))

for address := range t.touched {
result = append(result, address)
}
return result
}

func (t *AccountTouchTracer) CaptureTxStart(uint64) {}

func (t *AccountTouchTracer) CaptureTxEnd(uint64) {}

func (t *AccountTouchTracer) CaptureStart(_ *vm.EVM, from common.Address, to common.Address, _ bool, _ []byte, _ uint64, _ *big.Int) {
t.touched[from] = struct{}{}
t.touched[to] = struct{}{}
}

func (t *AccountTouchTracer) CaptureEnd([]byte, uint64, time.Duration, error) {}

func (t *AccountTouchTracer) CaptureEnter(_ vm.OpCode, _ common.Address, to common.Address, _ []byte, _ uint64, _ *big.Int) {
t.touched[to] = struct{}{}
}

func (t *AccountTouchTracer) CaptureExit([]byte, uint64, error) {}

func (t *AccountTouchTracer) CaptureState(uint64, vm.OpCode, uint64, uint64, *vm.ScopeContext, []byte, int, error) {
}

func (t *AccountTouchTracer) CaptureFault(uint64, vm.OpCode, uint64, uint64, *vm.ScopeContext, int, error) {
}
63 changes: 55 additions & 8 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
Expand Down Expand Up @@ -210,6 +211,7 @@ type worker struct {
engine consensus.Engine
eth Backend
chain *core.BlockChain
blockList map[common.Address]struct{}

// Feeds
pendingLogsFeed event.Feed
Expand Down Expand Up @@ -330,6 +332,11 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
}()
}

blockList := make(map[common.Address]struct{})
for _, address := range config.Blocklist {
blockList[address] = struct{}{}
}

worker := &worker{
config: config,
chainConfig: chainConfig,
Expand Down Expand Up @@ -957,22 +964,47 @@ func (w *worker) updateSnapshot(env *environment) {
}

func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]*types.Log, error) {
var (
snap = env.state.Snapshot()
gp = env.gasPool.Gas()
)
gasPool := *env.gasPool
envGasUsed := env.header.GasUsed
var stateDB *state.StateDB
if len(w.blockList) != 0 {
stateDB = env.state.Copy()
} else {
stateDB = env.state
}

snapshot := stateDB.Snapshot()

gasPrice, err := tx.EffectiveGasTip(env.header.BaseFee)
if err != nil {
return nil, err
}

receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, *w.chain.GetVMConfig())
var tracer *logger.AccountTouchTracer
config := *w.chain.GetVMConfig()
if len(w.blockList) != 0 {
tracer = logger.NewAccountTouchTracer()
config.Tracer = tracer
config.Debug = true
}

receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, &gasPool, stateDB, env.header, tx, &envGasUsed, config)
if err != nil {
env.state.RevertToSnapshot(snap)
env.gasPool.SetGas(gp)
stateDB.RevertToSnapshot(snapshot)
return nil, err
}
if len(w.blockList) != 0 {
for _, address := range tracer.TouchedAddresses() {
if _, in := w.blockList[address]; in {
return nil, errBlocklistViolation
}
}
}

*env.gasPool = gasPool
env.header.GasUsed = envGasUsed
env.state = stateDB

env.txs = append(env.txs, tx)
env.receipts = append(env.receipts, receipt)

Expand Down Expand Up @@ -1395,6 +1427,7 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, *big.Int, e
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(w.newpayloadTimeout))
}
blockBundles = mergedBundles
log.Info("Filled block with transactions", "time", time.Since(start), "gas used", work.header.GasUsed)
}
block, err := w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts, params.withdrawals)
if err != nil {
Expand Down Expand Up @@ -1674,13 +1707,27 @@ func (w *worker) computeBundleGas(env *environment, bundle types.MevBundle, stat
state.Prepare(tx.Hash(), i+currentTxCount)
coinbaseBalanceBefore := state.GetBalance(env.coinbase)

receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, gasPool, state, env.header, tx, &tempGasUsed, *w.chain.GetVMConfig())
config := *w.chain.GetVMConfig()
var tracer *logger.AccountTouchTracer
if len(w.blockList) != 0 {
tracer = logger.NewAccountTouchTracer()
config.Tracer = tracer
config.Debug = true
}
receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, gasPool, state, env.header, tx, &tempGasUsed, config)
if err != nil {
return simulatedBundle{}, err
}
if receipt.Status == types.ReceiptStatusFailed && !containsHash(bundle.RevertingTxHashes, receipt.TxHash) {
return simulatedBundle{}, errors.New("failed tx")
}
if len(w.blockList) != 0 {
for _, address := range tracer.TouchedAddresses() {
if _, in := w.blockList[address]; in {
return simulatedBundle{}, errBlocklistViolation
}
}
}

totalGasUsed += receipt.GasUsed

Expand Down

0 comments on commit bf900e9

Please sign in to comment.