Skip to content

Commit

Permalink
Use object in eth_sendBundle params and add revertingTxHashes param
Browse files Browse the repository at this point in the history
  • Loading branch information
jparyani committed Jul 22, 2021
1 parent 82b60ce commit 6f768de
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 77 deletions.
30 changes: 0 additions & 30 deletions core/mev_bundle.go

This file was deleted.

31 changes: 16 additions & 15 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ type TxPool struct {
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
mevBundles []types.MevBundle
all *txLookup // All transactions to allow lookups
priced *txPricedList // All transactions sorted by price

Expand Down Expand Up @@ -544,53 +544,54 @@ func (pool *TxPool) Pending(enforceTips bool) (map[common.Address]types.Transact
}

/// AllMevBundles returns all the MEV Bundles currently in the pool
func (pool *TxPool) AllMevBundles() []mevBundle {
func (pool *TxPool) AllMevBundles() []types.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) {
func (pool *TxPool) MevBundles(blockNumber *big.Int, blockTimestamp uint64) ([]types.MevBundle, error) {
pool.mu.Lock()
defer pool.mu.Unlock()

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

for _, bundle := range pool.mevBundles {
// Prune outdated bundles
if (bundle.maxTimestamp != 0 && blockTimestamp > bundle.maxTimestamp) || blockNumber.Cmp(bundle.blockNumber) > 0 {
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 {
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)
ret = append(ret, bundle)
// keep the bundles around internally until they need to be pruned
bundles = append(bundles, bundle)
}

pool.mevBundles = bundles
return txBundles, nil
return ret, nil
}

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

pool.mevBundles = append(pool.mevBundles, mevBundle{
txs: txs,
blockNumber: blockNumber,
minTimestamp: minTimestamp,
maxTimestamp: maxTimestamp,
pool.mevBundles = append(pool.mevBundles, types.MevBundle{
Txs: txs,
BlockNumber: blockNumber,
MinTimestamp: minTimestamp,
MaxTimestamp: maxTimestamp,
RevertingTxHashes: revertingTxHashes,
})
return nil
}
Expand Down
8 changes: 8 additions & 0 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,3 +632,11 @@ func (m Message) Nonce() uint64 { return m.nonce }
func (m Message) Data() []byte { return m.data }
func (m Message) AccessList() AccessList { return m.accessList }
func (m Message) CheckNonce() bool { return m.checkNonce }

type MevBundle struct {
Txs Transactions
BlockNumber *big.Int
MinTimestamp uint64
MaxTimestamp uint64
RevertingTxHashes []common.Hash
}
4 changes: 2 additions & 2 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ 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) SendBundle(ctx context.Context, txs types.Transactions, blockNumber rpc.BlockNumber, minTimestamp uint64, maxTimestamp uint64, revertingTxHashes []common.Hash) error {
return b.eth.txPool.AddMevBundle(txs, big.NewInt(blockNumber.Int64()), minTimestamp, maxTimestamp, revertingTxHashes)
}

func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
Expand Down
29 changes: 22 additions & 7 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2071,12 +2071,27 @@ func NewPrivateTxBundleAPI(b Backend) *PrivateTxBundleAPI {
return &PrivateTxBundleAPI{b}
}

// SendBundleArgs represents the arguments for a call.
type SendBundleArgs struct {
Txs []hexutil.Bytes `json:"txs"`
BlockNumber rpc.BlockNumber `json:"blockNumber"`
MinTimestamp *uint64 `json:"minTimestamp"`
MaxTimestamp *uint64 `json:"maxTimestamp"`
RevertingTxHashes []common.Hash `json:"revertingTxHashes"`
}

// SendBundle will add the signed transaction to the transaction pool.
// The sender is responsible for signing the transaction and using the correct nonce and ensuring validity
func (s *PrivateTxBundleAPI) SendBundle(ctx context.Context, encodedTxs []hexutil.Bytes, blockNumber rpc.BlockNumber, minTimestampPtr, maxTimestampPtr *uint64) error {
func (s *PrivateTxBundleAPI) SendBundle(ctx context.Context, args SendBundleArgs) error {
var txs types.Transactions
if len(args.Txs) == 0 {
return errors.New("bundle missing txs")
}
if args.BlockNumber == 0 {
return errors.New("bundle missing blockNumber")
}

for _, encodedTx := range encodedTxs {
for _, encodedTx := range args.Txs {
tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return err
Expand All @@ -2085,12 +2100,12 @@ func (s *PrivateTxBundleAPI) SendBundle(ctx context.Context, encodedTxs []hexuti
}

var minTimestamp, maxTimestamp uint64
if minTimestampPtr != nil {
minTimestamp = *minTimestampPtr
if args.MinTimestamp != nil {
minTimestamp = *args.MinTimestamp
}
if maxTimestampPtr != nil {
maxTimestamp = *maxTimestampPtr
if args.MaxTimestamp != nil {
maxTimestamp = *args.MaxTimestamp
}

return s.b.SendBundle(ctx, txs, blockNumber, minTimestamp, maxTimestamp)
return s.b.SendBundle(ctx, txs, args.BlockNumber, minTimestamp, maxTimestamp, args.RevertingTxHashes)
}
2 changes: 1 addition & 1 deletion internal/ethapi/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ type Backend interface {

// Transaction pool API
SendTx(ctx context.Context, signedTx *types.Transaction) error
SendBundle(ctx context.Context, txs types.Transactions, blockNumber rpc.BlockNumber, minTimestamp uint64, maxTimestamp uint64) error
SendBundle(ctx context.Context, txs types.Transactions, blockNumber rpc.BlockNumber, minTimestamp uint64, maxTimestamp uint64, revertingTxHashes []common.Hash) error
GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
GetPoolTransactions() (types.Transactions, error)
GetPoolTransaction(txHash common.Hash) *types.Transaction
Expand Down
2 changes: 1 addition & 1 deletion internal/web3ext/web3ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ web3._extend({
new web3._extend.Method({
name: 'sendBundle',
call: 'eth_sendBundle',
params: 4
params: 1
}),
],
properties: [
Expand Down
4 changes: 2 additions & 2 deletions les/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@ func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
func (b *LesApiBackend) RemoveTx(txHash common.Hash) {
b.eth.txPool.RemoveTx(txHash)
}
func (b *LesApiBackend) 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 *LesApiBackend) SendBundle(ctx context.Context, txs types.Transactions, blockNumber rpc.BlockNumber, minTimestamp uint64, maxTimestamp uint64, revertingTxHashes []common.Hash) error {
return b.eth.txPool.AddMevBundle(txs, big.NewInt(blockNumber.Int64()), minTimestamp, maxTimestamp, revertingTxHashes)
}

func (b *LesApiBackend) GetPoolTransactions() (types.Transactions, error) {
Expand Down
2 changes: 1 addition & 1 deletion light/txpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,6 @@ func (pool *TxPool) MevBundles(blockNumber *big.Int, blockTimestamp uint64) ([]t
}

// AddMevBundle adds a mev bundle to the pool
func (pool *TxPool) AddMevBundle(txs types.Transactions, blockNumber *big.Int, minTimestamp uint64, maxTimestamp uint64) error {
func (pool *TxPool) AddMevBundle(txs types.Transactions, blockNumber *big.Int, minTimestamp uint64, maxTimestamp uint64, revertingTxHashes []common.Hash) error {
return nil
}
44 changes: 26 additions & 18 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -1190,11 +1190,11 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64)
log.Error("Failed to generate flashbots bundle", "err", err)
return
}
log.Info("Flashbots bundle", "ethToCoinbase", ethIntToFloat(bundle.totalEth), "gasUsed", bundle.totalGasUsed, "bundleScore", bundle.mevGasPrice, "bundleLength", len(bundle.txs))
if len(bundle.txs) == 0 {
log.Info("Flashbots bundle", "ethToCoinbase", ethIntToFloat(bundle.totalEth), "gasUsed", bundle.totalGasUsed, "bundleScore", bundle.mevGasPrice, "bundleLength", len(bundle.originalBundle.Txs))
if len(bundle.originalBundle.Txs) == 0 {
return
}
if w.commitBundle(bundle.txs, w.coinbase, interrupt) {
if w.commitBundle(bundle.originalBundle.Txs, w.coinbase, interrupt) {
return
}
}
Expand Down Expand Up @@ -1247,13 +1247,13 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st
}

type simulatedBundle struct {
txs types.Transactions
mevGasPrice *big.Int
totalEth *big.Int
totalGasUsed uint64
mevGasPrice *big.Int
totalEth *big.Int
totalGasUsed uint64
originalBundle types.MevBundle
}

func (w *worker) findMostProfitableBundle(bundles []types.Transactions, coinbase common.Address, parent *types.Block, header *types.Header, pendingTxs map[common.Address]types.Transactions) (simulatedBundle, error) {
func (w *worker) findMostProfitableBundle(bundles []types.MevBundle, coinbase common.Address, parent *types.Block, header *types.Header, pendingTxs map[common.Address]types.Transactions) (simulatedBundle, error) {
maxBundle := simulatedBundle{mevGasPrice: new(big.Int)}

for _, bundle := range bundles {
Expand All @@ -1262,7 +1262,7 @@ func (w *worker) findMostProfitableBundle(bundles []types.Transactions, coinbase
return simulatedBundle{}, err
}
gasPool := new(core.GasPool).AddGas(header.GasLimit)
if len(bundle) == 0 {
if len(bundle.Txs) == 0 {
continue
}
simmed, err := w.computeBundleGas(bundle, parent, header, state, gasPool, pendingTxs)
Expand All @@ -1280,22 +1280,30 @@ func (w *worker) findMostProfitableBundle(bundles []types.Transactions, coinbase
return maxBundle, nil
}

func containsHash(arr []common.Hash, match common.Hash) bool {
for _, elem := range arr {
if elem == match {
return true
}
}
return false
}

// Compute the adjusted gas price for a whole bundle
// Done by calculating all gas spent, adding transfers to the coinbase, and then dividing by gas used
func (w *worker) computeBundleGas(bundle types.Transactions, parent *types.Block, header *types.Header, state *state.StateDB, gasPool *core.GasPool, pendingTxs map[common.Address]types.Transactions) (simulatedBundle, error) {
func (w *worker) computeBundleGas(bundle types.MevBundle, parent *types.Block, header *types.Header, state *state.StateDB, gasPool *core.GasPool, pendingTxs map[common.Address]types.Transactions) (simulatedBundle, error) {
var totalGasUsed uint64 = 0
var tempGasUsed uint64
totalEth := new(big.Int)

for _, tx := range bundle {
for _, tx := range bundle.Txs {
coinbaseBalanceBefore := state.GetBalance(w.coinbase)

receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &w.coinbase, gasPool, state, header, tx, &tempGasUsed, *w.chain.GetVMConfig())
if err != nil {
return simulatedBundle{}, err
}
if receipt.Status == types.ReceiptStatusFailed {
return simulatedBundle{}, errors.New("revert")
if receipt.Status == types.ReceiptStatusFailed && !containsHash(bundle.RevertingTxHashes, receipt.TxHash) {
return simulatedBundle{}, errors.New("failed tx")
}

totalGasUsed += receipt.GasUsed
Expand Down Expand Up @@ -1329,10 +1337,10 @@ func (w *worker) computeBundleGas(bundle types.Transactions, parent *types.Block
}

return simulatedBundle{
txs: bundle,
mevGasPrice: new(big.Int).Div(totalEth, new(big.Int).SetUint64(totalGasUsed)),
totalEth: totalEth,
totalGasUsed: totalGasUsed,
mevGasPrice: new(big.Int).Div(totalEth, new(big.Int).SetUint64(totalGasUsed)),
totalEth: totalEth,
totalGasUsed: totalGasUsed,
originalBundle: bundle,
}, nil
}

Expand Down

0 comments on commit 6f768de

Please sign in to comment.