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

Mev 01 #1000

Closed
wants to merge 14 commits into from
Closed

Mev 01 #1000

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
1 change: 1 addition & 0 deletions cmd/cortex/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ var (
//utils.MinerOpenCLFlag,
utils.MinerDevicesFlag,
//utils.MinerAlgorithmFlag,
utils.MinerMaxMergedBundles,
utils.NATFlag,
utils.NoDiscoverFlag,
utils.DiscoveryV5Flag,
Expand Down
1 change: 1 addition & 0 deletions cmd/cortex/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ var AppHelpFlagGroups = []flagGroup{
//utils.MinerOpenCLFlag,
utils.MinerDevicesFlag,
//utils.MinerAlgorithmFlag,
utils.MinerMaxMergedBundles,
},
},
{
Expand Down
8 changes: 8 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,11 @@ var (
Usage: "Time interval to recreate the block being mined",
Value: ctxc.DefaultConfig.Miner.Recommit,
}
MinerMaxMergedBundles = cli.IntFlag{
Name: "miner.maxmergedbundles",
Usage: "flashbots - The maximum amount of bundles to merge. The miner will run this many workers in parallel to calculate if the full block is more profitable with these additional bundles.",
Value: 3,
}
MinerNoVerfiyFlag = cli.BoolFlag{
Name: "miner.noverify",
Usage: "Disable remote sealing verification",
Expand Down Expand Up @@ -1479,6 +1484,9 @@ func SetCortexConfig(ctx *cli.Context, stack *node.Node, cfg *ctxc.Config) {
if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) {
cfg.Miner.Noverify = ctx.GlobalBool(MinerNoVerfiyFlag.Name)
}
if ctx.GlobalIsSet(MinerMaxMergedBundles.Name) {
cfg.Miner.MaxMergedBundles = ctx.GlobalInt(MinerMaxMergedBundles.Name)
}

if ctx.GlobalIsSet(MiningEnabledFlag.Name) {
//cfg.Cuckoo.Mine = true
Expand Down
66 changes: 60 additions & 6 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,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 []types.MevBundle
all *txLookup // All transactions to allow lookups
priced *txPricedList // All transactions sorted by price

chainHeadCh chan ChainHeadEvent
chainHeadSub event.Subscription
Expand All @@ -282,7 +283,7 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block
config: config,
chainconfig: chainconfig,
chain: chain,
signer: types.NewEIP155Signer(chainconfig.ChainID),
signer: types.LatestSigner(chainconfig),
pending: make(map[common.Address]*txList),
queue: make(map[common.Address]*txList),
beats: make(map[common.Address]time.Time),
Expand Down Expand Up @@ -509,6 +510,59 @@ 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() []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.MevBundle, error) {
pool.mu.Lock()
defer pool.mu.Unlock()

// returned values
var ret []types.MevBundle
// rolled over values
var bundles []types.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
ret = append(ret, bundle)
// keep the bundles around internally until they need to be pruned
bundles = append(bundles, bundle)
}

pool.mevBundles = bundles
return ret, nil
}

// AddMevBundle adds a mev bundle to the pool
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, types.MevBundle{
Txs: txs,
BlockNumber: blockNumber,
MinTimestamp: minTimestamp,
MaxTimestamp: maxTimestamp,
RevertingTxHashes: revertingTxHashes,
})
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 @@ -2051,3 +2051,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)
}
}
8 changes: 8 additions & 0 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,3 +437,11 @@ func (m Message) Gas() uint64 { return m.gasLimit }
func (m Message) Nonce() uint64 { return m.nonce }
func (m Message) Data() []byte { return m.data }
func (m Message) CheckNonce() bool { return m.checkNonce }

type MevBundle struct {
Txs Transactions
BlockNumber *big.Int
MinTimestamp uint64
MaxTimestamp uint64
RevertingTxHashes []common.Hash
}
11 changes: 11 additions & 0 deletions core/types/transaction_signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
return signer
}

// Use this in transaction-handling code where the current block number is unknown. If you
// have the current block number available, use MakeSigner instead.
func LatestSigner(config *params.ChainConfig) Signer {
if config.ChainID != nil {
if config.EIP155Block != nil {
return NewEIP155Signer(config.ChainID)
}
}
return HomesteadSigner{}
}

// SignTx signs the transaction using the given signer and private key
func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
h := s.Hash(tx)
Expand Down
4 changes: 4 additions & 0 deletions ctxc/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ func (b *CortexAPIBackend) SendTx(ctx context.Context, signedTx *types.Transacti
return b.ctxc.txPool.AddLocal(signedTx)
}

func (b *CortexAPIBackend) SendBundle(ctx context.Context, txs types.Transactions, blockNumber rpc.BlockNumber, minTimestamp uint64, maxTimestamp uint64, revertingTxHashes []common.Hash) error {
return b.ctxc.txPool.AddMevBundle(txs, big.NewInt(blockNumber.Int64()), minTimestamp, maxTimestamp, revertingTxHashes)
}

func (b *CortexAPIBackend) GetPoolTransactions() (types.Transactions, error) {
pending, err := b.ctxc.txPool.Pending()
if err != nil {
Expand Down
9 changes: 5 additions & 4 deletions ctxc/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ var DefaultConfig = Config{
TrieTimeout: 60 * time.Minute,
SnapshotCache: 102,
Miner: miner.Config{
GasFloor: params.MinerGasFloor,
GasCeil: params.MinerGasCeil,
GasPrice: big.NewInt(params.GWei),
Recommit: 3 * time.Second,
GasFloor: params.MinerGasFloor,
GasCeil: params.MinerGasCeil,
GasPrice: big.NewInt(params.GWei),
Recommit: 3 * time.Second,
MaxMergedBundles: 0,
},

TxPool: core.DefaultTxPoolConfig,
Expand Down
51 changes: 51 additions & 0 deletions internal/ctxcapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1647,3 +1647,54 @@ func checkTxFee(gasPrice *big.Int, gas uint64, cap float64) error {
}
return nil
}

// ---------------------------------------------------------------- FlashBots ----------------------------------------------------------------

// PrivateTxBundleAPI offers an API for accepting bundled transactions
type PrivateTxBundleAPI struct {
b Backend
}

// NewPrivateTxBundleAPI creates a new Tx Bundle API instance.
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, 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 args.Txs {
tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return err
}
txs = append(txs, tx)
}

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

return s.b.SendBundle(ctx, txs, args.BlockNumber, minTimestamp, maxTimestamp, args.RevertingTxHashes)
}
6 changes: 6 additions & 0 deletions internal/ctxcapi/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type Backend interface {

// TxPool API
SendTx(ctx context.Context, signedTx *types.Transaction) error
SendBundle(ctx context.Context, txs types.Transactions, blockNumber rpc.BlockNumber, minTimestamp uint64, maxTimestamp uint64, revertingTxHashes []common.Hash) error
GetPoolTransactions() (types.Transactions, error)
GetPoolTransaction(txHash common.Hash) *types.Transaction
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
Expand Down Expand Up @@ -116,6 +117,11 @@ func GetAPIs(apiBackend Backend, vmConfig vm.Config) []rpc.API {
Version: "1.0",
Service: NewPrivateAccountAPI(apiBackend, nonceLock),
Public: false,
}, {
Namespace: "ctxc",
Version: "1.0",
Service: NewPrivateTxBundleAPI(apiBackend),
Public: true,
},
}
}
5 changes: 5 additions & 0 deletions internal/web3ext/web3ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,11 @@ web3._extend({
params: 2,
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter, web3._extend.utils.toHex]
}),
new web3._extend.Method({
name: 'sendBundle',
call: 'ctxc_sendBundle',
params: 1
}),
],
properties: [
new web3._extend.Property({
Expand Down
19 changes: 13 additions & 6 deletions miner/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,16 @@ type Config struct {
Recommit time.Duration // The time interval for miner to re-create mining work.
Noverify bool // Disable remote mining solution verification(only useful in cuckoo).

MaxMergedBundles int

Cuda bool
Devices string
}

// Miner creates blocks and searches for proof-of-work values.
type Miner struct {
mux *event.TypeMux
worker *worker
worker *multiWorker
coinbase common.Address
ctxc Backend
engine consensus.Engine
Expand All @@ -76,7 +78,7 @@ func New(ctxc Backend, config *Config, chainConfig *params.ChainConfig, mux *eve
mux: mux,
engine: engine,
exitCh: make(chan struct{}),
worker: newWorker(config, chainConfig, engine, ctxc, mux, isLocalBlock, true),
worker: newMultiWorker(config, chainConfig, engine, ctxc, mux, isLocalBlock, true),
startCh: make(chan common.Address),
stopCh: make(chan struct{}),
}
Expand Down Expand Up @@ -185,7 +187,12 @@ func (miner *Miner) SetRecommitInterval(interval time.Duration) {

// Pending returns the currently pending block and associated state.
func (miner *Miner) Pending() (*types.Block, *state.StateDB) {
return miner.worker.pending()
return miner.worker.regularWorker.pending()
}

// PendingBlockAndReceipts returns the currently pending block and corresponding receipts.
func (miner *Miner) PendingBlockAndReceipts() (*types.Block, types.Receipts) {
return miner.worker.pendingBlockAndReceipts()
}

// PendingBlock returns the currently pending block.
Expand All @@ -194,7 +201,7 @@ func (miner *Miner) Pending() (*types.Block, *state.StateDB) {
// simultaneously, please use Pending(), as the pending state can
// change between multiple method calls
func (miner *Miner) PendingBlock() *types.Block {
return miner.worker.pendingBlock()
return miner.worker.regularWorker.pendingBlock()
}

func (miner *Miner) SetCoinbase(addr common.Address) {
Expand All @@ -205,7 +212,7 @@ func (miner *Miner) SetCoinbase(addr common.Address) {
// SetGasCeil sets the gaslimit to strive for when mining blocks post 1559.
// For pre-1559 blocks, it sets the ceiling.
func (miner *Miner) SetGasCeil(ceil uint64) {
miner.worker.setGasCeil(ceil)
miner.worker.regularWorker.setGasCeil(ceil)
}

// EnablePreseal turns on the preseal mining feature. It's enabled by default.
Expand All @@ -228,5 +235,5 @@ func (miner *Miner) DisablePreseal() {
// SubscribePendingLogs starts delivering logs from pending transactions
// to the given channel.
func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscription {
return miner.worker.pendingLogsFeed.Subscribe(ch)
return miner.worker.regularWorker.pendingLogsFeed.Subscribe(ch)
}
Loading