Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support eth.sendBundle on geth console #71

Open
wants to merge 20 commits into
base: aws-mainnet
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Go

on:
push:
pull_request:
branches: [ master ]

jobs:

build:
name: Build
runs-on: ubuntu-latest
steps:

- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.13
id: go

- name: Check out code into the Go module directory
uses: actions/checkout@v2

- name: Test
run: go test ./core ./miner/... ./internal/ethapi/... ./les/...

- name: Build
run: make geth

e2e:
name: End to End
runs-on: ubuntu-latest
steps:

- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.13
id: go

- name: Use Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: 12.x

- name: Check out code into the Go module directory
uses: actions/checkout@v2

- name: Build
run: make geth

- name: Check out the e2e code repo
uses: actions/checkout@v2
with:
repository: flashbots/mev-geth-demo
path: e2e

- run: cd e2e && yarn install
- run: |
cd e2e
GETH=`pwd`/../build/bin/geth ./run.sh &
sleep 15
yarn run demo-simple
yarn run demo-contract
404 changes: 98 additions & 306 deletions README.md

Large diffs are not rendered by default.

359 changes: 359 additions & 0 deletions README.original.md

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions core/mev_bundle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2014 The go-ethereum Authors
// 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 core

import (
"math/big"

"github.com/ethereum/go-ethereum/core/types"
)

type mevBundle struct {
txs types.Transactions
blockNumber *big.Int
minTimestamp uint64
maxTimestamp uint64
}
56 changes: 56 additions & 0 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,51 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
return receipt, err
}

func applyTransactionWithResult(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, *ExecutionResult, error) {
// Create a new context to be used in the EVM environment.
txContext := NewEVMTxContext(msg)
evm.Reset(txContext, statedb)

// Apply the transaction to the current state (included in the env).
result, err := ApplyMessage(evm, msg, gp)
if err != nil {
return nil, nil, err
}

// Update the state with pending changes.
var root []byte
if config.IsByzantium(header.Number) {
statedb.Finalise(true)
} else {
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
}
*usedGas += result.UsedGas

// Create a new receipt for the transaction, storing the intermediate root and gas used
// by the tx.
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas}
if result.Failed() {
receipt.Status = types.ReceiptStatusFailed
} else {
receipt.Status = types.ReceiptStatusSuccessful
}
receipt.TxHash = tx.Hash()
receipt.GasUsed = result.UsedGas

// If the transaction created a contract, store the creation address in the receipt.
if msg.To() == nil {
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
}

// Set the receipt logs and create the bloom filter.
receipt.Logs = statedb.GetLogs(tx.Hash())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
receipt.BlockHash = statedb.BlockHash()
receipt.BlockNumber = header.Number
receipt.TransactionIndex = uint(statedb.TxIndex())
return receipt, result, err
}

// ApplyTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed,
Expand All @@ -148,3 +193,14 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
return applyTransaction(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv)
}

func ApplyTransactionWithResult(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, *ExecutionResult, error) {
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
if err != nil {
return nil, nil, err
}
// Create a new context to be used in the EVM environment
blockContext := NewEVMBlockContext(header, bc, author)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
return applyTransactionWithResult(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv)
}
63 changes: 58 additions & 5 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,12 @@ type TxPool struct {
locals *accountSet // Set of local transaction to exempt from eviction rules
journal *txJournal // Journal of local transaction to back up to disk

pending map[common.Address]*txList // All currently processable transactions
queue map[common.Address]*txList // Queued but non-processable transactions
beats map[common.Address]time.Time // Last heartbeat from each known account
all *txLookup // All transactions to allow lookups
priced *txPricedList // All transactions sorted by price
pending map[common.Address]*txList // All currently processable transactions
queue map[common.Address]*txList // Queued but non-processable transactions
beats map[common.Address]time.Time // Last heartbeat from each known account
mevBundles []mevBundle
all *txLookup // All transactions to allow lookups
priced *txPricedList // All transactions sorted by price

chainHeadCh chan ChainHeadEvent
chainHeadSub event.Subscription
Expand Down Expand Up @@ -496,6 +497,58 @@ func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) {
return pending, nil
}

/// AllMevBundles returns all the MEV Bundles currently in the pool
func (pool *TxPool) AllMevBundles() []mevBundle {
return pool.mevBundles
}

// MevBundles returns a list of bundles valid for the given blockNumber/blockTimestamp
// also prunes bundles that are outdated
func (pool *TxPool) MevBundles(blockNumber *big.Int, blockTimestamp uint64) ([]types.Transactions, error) {
pool.mu.Lock()
defer pool.mu.Unlock()

// returned values
var txBundles []types.Transactions
// rolled over values
var bundles []mevBundle

for _, bundle := range pool.mevBundles {
// Prune outdated bundles
if (bundle.maxTimestamp != 0 && blockTimestamp > bundle.maxTimestamp) || blockNumber.Cmp(bundle.blockNumber) > 0 {
continue
}

// Roll over future bundles
if (bundle.minTimestamp != 0 && blockTimestamp < bundle.minTimestamp) || blockNumber.Cmp(bundle.blockNumber) < 0 {
bundles = append(bundles, bundle)
continue
}

// return the ones which are in time
txBundles = append(txBundles, bundle.txs)
// keep the bundles around internally until they need to be pruned
bundles = append(bundles, bundle)
}

pool.mevBundles = bundles
return txBundles, nil
}

// AddMevBundle adds a mev bundle to the pool
func (pool *TxPool) AddMevBundle(txs types.Transactions, blockNumber *big.Int, minTimestamp, maxTimestamp uint64) error {
pool.mu.Lock()
defer pool.mu.Unlock()

pool.mevBundles = append(pool.mevBundles, mevBundle{
txs: txs,
blockNumber: blockNumber,
minTimestamp: minTimestamp,
maxTimestamp: maxTimestamp,
})
return nil
}

// Locals retrieves the accounts currently considered local by the pool.
func (pool *TxPool) Locals() []common.Address {
pool.mu.Lock()
Expand Down
10 changes: 10 additions & 0 deletions core/tx_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2052,3 +2052,13 @@ func BenchmarkInsertRemoteWithAllLocals(b *testing.B) {
pool.Stop()
}
}

func checkBundles(t *testing.T, pool *TxPool, block int64, timestamp uint64, expectedRes int, expectedRemaining int) {
res, _ := pool.MevBundles(big.NewInt(block), timestamp)
if len(res) != expectedRes {
t.Fatalf("expected returned bundles did not match got %d, expected %d", len(res), expectedRes)
}
if len(pool.mevBundles) != expectedRemaining {
t.Fatalf("expected remaining bundles did not match got %d, expected %d", len(pool.mevBundles), expectedRemaining)
}
}
4 changes: 4 additions & 0 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
return b.eth.txPool.AddLocal(signedTx)
}

func (b *EthAPIBackend) SendBundle(ctx context.Context, txs types.Transactions, blockNumber rpc.BlockNumber, minTimestamp uint64, maxTimestamp uint64) error {
return b.eth.txPool.AddMevBundle(txs, big.NewInt(blockNumber.Int64()), minTimestamp, maxTimestamp)
}

func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
pending, err := b.eth.txPool.Pending()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ func makeExtraData(extra []byte) []byte {
// APIs return the collection of RPC services the ethereum package offers.
// NOTE, some of these services probably need to be moved to somewhere else.
func (s *Ethereum) APIs() []rpc.API {
apis := ethapi.GetAPIs(s.APIBackend)
apis := ethapi.GetAPIs(s.APIBackend, s.BlockChain())

// Append any APIs exposed explicitly by the consensus engine
apis = append(apis, s.engine.APIs(s.BlockChain())...)
Expand Down
23 changes: 23 additions & 0 deletions infra/Dockerfile.node
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Build Geth in a stock Go builder container
FROM golang:1.15-alpine as builder

RUN apk add --no-cache make gcc musl-dev linux-headers git

ADD . /go-ethereum
RUN cd /go-ethereum && make geth

# Pull Geth into a second stage deploy alpine container
FROM alpine:latest

ENV PYTHONUNBUFFERED=1
RUN apk add --update --no-cache groff less python3 curl jq ca-certificates && ln -sf python3 /usr/bin/python
RUN python3 -m ensurepip
RUN pip3 install --no-cache --upgrade pip setuptools awscli

COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/

COPY ./infra/start-mev-geth-node.sh /root/start-mev-geth-node.sh
RUN chmod 755 /root/start-mev-geth-node.sh

EXPOSE 8545 8546 30303 30303/udp
ENTRYPOINT ["/root/start-mev-geth-node.sh"]
23 changes: 23 additions & 0 deletions infra/Dockerfile.updater
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Build Geth in a stock Go builder container
FROM golang:1.15-alpine as builder

RUN apk add --no-cache make gcc musl-dev linux-headers git

ADD . /go-ethereum
RUN cd /go-ethereum && make geth

# Pull Geth into a second stage deploy alpine container
FROM alpine:latest

ENV PYTHONUNBUFFERED=1
RUN apk add --update --no-cache groff less python3 curl jq ca-certificates && ln -sf python3 /usr/bin/python
RUN python3 -m ensurepip
RUN pip3 install --no-cache --upgrade pip setuptools awscli

COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/

COPY ./infra/start-mev-geth-updater.sh /root/start-mev-geth-updater.sh
RUN chmod 755 /root/start-mev-geth-updater.sh

EXPOSE 8545 8546 30303 30303/udp
ENTRYPOINT ["/root/start-mev-geth-updater.sh"]
Loading