mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
AA-381: Create a "pull bundle" block building mode and a 'getRip7560Bundle' method (#18)
This commit is contained in:
parent
2ee6caf9c5
commit
0d8f19200d
9 changed files with 131 additions and 10 deletions
5
circleciconfig.toml
Normal file
5
circleciconfig.toml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[Eth]
|
||||
Rip7560MaxBundleSize = 0
|
||||
Rip7560MaxBundleGas = 0
|
||||
Rip7560PullUrls = ["http://localhost:3001/rpc"]
|
||||
Rip7560AcceptPush = false
|
||||
|
|
@ -1,21 +1,30 @@
|
|||
package rip7560pool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
MaxBundleSize uint
|
||||
MaxBundleGas uint
|
||||
MaxBundleSize *uint64
|
||||
MaxBundleGas *uint64
|
||||
PullUrls []string
|
||||
}
|
||||
|
||||
// Rip7560BundlerPool is the transaction pool dedicated to RIP-7560 AA transactions.
|
||||
|
|
@ -189,8 +198,11 @@ func (pool *Rip7560BundlerPool) PendingRip7560Bundle() (*types.ExternallyReceive
|
|||
defer pool.mu.Unlock()
|
||||
|
||||
bundle := pool.selectExternalBundle()
|
||||
if bundle != nil {
|
||||
return bundle, nil
|
||||
}
|
||||
return pool.fetchBundleFromBundler()
|
||||
}
|
||||
|
||||
// SubscribeTransactions is not needed for the External Bundler AA sub pool and 'ch' will never be sent anything.
|
||||
func (pool *Rip7560BundlerPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, _ bool) event.Subscription {
|
||||
|
|
@ -261,6 +273,64 @@ func (pool *Rip7560BundlerPool) GetRip7560BundleStatus(hash common.Hash) (*types
|
|||
return pool.includedBundles[hash], nil
|
||||
}
|
||||
|
||||
type GetRip7560BundleArgs struct {
|
||||
MinBaseFee uint64
|
||||
MaxBundleGas uint64
|
||||
MaxBundleSize uint64
|
||||
}
|
||||
|
||||
type GetRip7560BundleResult struct {
|
||||
Bundle []ethapi.TransactionArgs
|
||||
ValidForBlock *hexutil.Big
|
||||
}
|
||||
|
||||
func (pool *Rip7560BundlerPool) fetchBundleFromBundler() (*types.ExternallyReceivedBundle, error) {
|
||||
if len(pool.config.PullUrls) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
currentHead := pool.currentHead.Load()
|
||||
chosenBundle := make([]ethapi.TransactionArgs, 0)
|
||||
pullErrors := make([]error, 0)
|
||||
for _, url := range pool.config.PullUrls {
|
||||
client := rpc.WithHTTPClient(&http.Client{Timeout: 500 * time.Millisecond})
|
||||
cl, err := rpc.DialOptions(context.Background(), url, client)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("Failed to dial RIP-7560 bundler URL (%s): %v", url, err))
|
||||
}
|
||||
maxBundleGas := min(*pool.config.MaxBundleGas, currentHead.GasLimit)
|
||||
args := &GetRip7560BundleArgs{
|
||||
MinBaseFee: currentHead.BaseFee.Uint64(), // todo: adjust to account for possible change!
|
||||
MaxBundleGas: maxBundleGas,
|
||||
MaxBundleSize: *pool.config.MaxBundleSize,
|
||||
}
|
||||
result := &GetRip7560BundleResult{
|
||||
Bundle: make([]ethapi.TransactionArgs, 0),
|
||||
}
|
||||
err = cl.Call(result, "aa_getRip7560Bundle", args)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("Failed to fetch RIP-7560 bundle from URL (%s): %v", url, err))
|
||||
pullErrors = append(pullErrors, err)
|
||||
continue
|
||||
}
|
||||
chosenBundle = result.Bundle
|
||||
break
|
||||
}
|
||||
if len(pullErrors) == len(pool.config.PullUrls) {
|
||||
return nil, errors.New("failed to fetch a new RIP-7560 bundle from any bundler")
|
||||
}
|
||||
txs := make([]*types.Transaction, len(chosenBundle))
|
||||
for i, tx := range chosenBundle {
|
||||
txs[i] = tx.ToTransaction()
|
||||
}
|
||||
bundleHash := ethapi.CalculateBundleHash(txs)
|
||||
return &types.ExternallyReceivedBundle{
|
||||
BundlerId: "result.String",
|
||||
BundleHash: bundleHash,
|
||||
ValidForBlock: big.NewInt(0),
|
||||
Transactions: txs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// return first bundle
|
||||
func (pool *Rip7560BundlerPool) selectExternalBundle() *types.ExternallyReceivedBundle {
|
||||
if len(pool.pendingBundles) == 0 {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// SubmitBundle inserts the entire bundle of Type 4 transactions into the relevant pool.
|
||||
// SubmitRip7560Bundle inserts the entire bundle of Type 4 transactions into the relevant pool.
|
||||
func (p *TxPool) SubmitRip7560Bundle(bundle *types.ExternallyReceivedBundle) error {
|
||||
// todo: we cannot 'filter-out' the AA pool so just passing to all pools - only AA pool has code in SubmitBundle
|
||||
for _, subpool := range p.subpools {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import (
|
|||
|
||||
// EthAPIBackend implements ethapi.Backend and tracers.Backend for full nodes
|
||||
type EthAPIBackend struct {
|
||||
rip7560AcceptPush bool
|
||||
extRPCEnabled bool
|
||||
allowUnprotectedTxs bool
|
||||
eth *Ethereum
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@ package eth
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
func (b *EthAPIBackend) SubmitRip7560Bundle(bundle *types.ExternallyReceivedBundle) error {
|
||||
if !b.rip7560AcceptPush {
|
||||
return errors.New("illegal call to eth_sendRip7560TransactionsBundle: Config.Eth.Rip7560AcceptPush is not set")
|
||||
}
|
||||
return b.eth.txPool.SubmitRip7560Bundle(bundle)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -238,8 +238,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
legacyPool := legacypool.New(config.TxPool, eth.blockchain)
|
||||
|
||||
rip7560PoolConfig := rip7560pool.Config{
|
||||
MaxBundleGas: 10000000,
|
||||
MaxBundleSize: 100,
|
||||
MaxBundleGas: config.Rip7560MaxBundleGas,
|
||||
MaxBundleSize: config.Rip7560MaxBundleSize,
|
||||
PullUrls: config.Rip7560PullUrls,
|
||||
}
|
||||
rip7560 := rip7560pool.New(rip7560PoolConfig, eth.blockchain, config.Miner.Etherbase)
|
||||
|
||||
|
|
@ -266,7 +267,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
eth.miner = miner.New(eth, config.Miner, eth.engine)
|
||||
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))
|
||||
|
||||
eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil}
|
||||
eth.APIBackend = &EthAPIBackend{config.Rip7560AcceptPush, stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil}
|
||||
if eth.APIBackend.allowUnprotectedTxs {
|
||||
log.Info("Unprotected transactions allowed")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,6 +163,18 @@ type Config struct {
|
|||
|
||||
// OverrideVerkle (TODO: remove after the fork)
|
||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||
|
||||
// Rip7560MaxBundleGas is the maximum amount of gas that can be used by an RIP-7560 bundle
|
||||
Rip7560MaxBundleGas *uint64 `toml:",omitempty"`
|
||||
|
||||
// Rip7560MaxBundleSize is the maximum number of transactions an RIP-7560 bundle can contain
|
||||
Rip7560MaxBundleSize *uint64 `toml:",omitempty"`
|
||||
|
||||
// Rip7560PullUrls provides a list of bundlers the node will ask for new bundles for each block
|
||||
Rip7560PullUrls []string
|
||||
|
||||
// Rip7560AcceptPush when set to "true" the node will accept incoming 'eth_sendRip7560TransactionsBundle'
|
||||
Rip7560AcceptPush bool `toml:",omitempty"`
|
||||
}
|
||||
|
||||
// CreateConsensusEngine creates a consensus engine for the given chain config.
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||
RPCTxFeeCap float64
|
||||
OverrideCancun *uint64 `toml:",omitempty"`
|
||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||
Rip7560MaxBundleGas *uint64 `toml:",omitempty"`
|
||||
Rip7560MaxBundleSize *uint64 `toml:",omitempty"`
|
||||
Rip7560PullUrls []string
|
||||
Rip7560AcceptPush bool `toml:",omitempty"`
|
||||
}
|
||||
var enc Config
|
||||
enc.Genesis = c.Genesis
|
||||
|
|
@ -101,6 +105,10 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||
enc.RPCTxFeeCap = c.RPCTxFeeCap
|
||||
enc.OverrideCancun = c.OverrideCancun
|
||||
enc.OverrideVerkle = c.OverrideVerkle
|
||||
enc.Rip7560MaxBundleGas = c.Rip7560MaxBundleGas
|
||||
enc.Rip7560MaxBundleSize = c.Rip7560MaxBundleSize
|
||||
enc.Rip7560PullUrls = c.Rip7560PullUrls
|
||||
enc.Rip7560AcceptPush = c.Rip7560AcceptPush
|
||||
return &enc, nil
|
||||
}
|
||||
|
||||
|
|
@ -148,6 +156,10 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
RPCTxFeeCap *float64
|
||||
OverrideCancun *uint64 `toml:",omitempty"`
|
||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||
Rip7560MaxBundleGas *uint64 `toml:",omitempty"`
|
||||
Rip7560MaxBundleSize *uint64 `toml:",omitempty"`
|
||||
Rip7560PullUrls []string
|
||||
Rip7560AcceptPush *bool `toml:",omitempty"`
|
||||
}
|
||||
var dec Config
|
||||
if err := unmarshal(&dec); err != nil {
|
||||
|
|
@ -276,5 +288,17 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
if dec.OverrideVerkle != nil {
|
||||
c.OverrideVerkle = dec.OverrideVerkle
|
||||
}
|
||||
if dec.Rip7560MaxBundleGas != nil {
|
||||
c.Rip7560MaxBundleGas = dec.Rip7560MaxBundleGas
|
||||
}
|
||||
if dec.Rip7560MaxBundleSize != nil {
|
||||
c.Rip7560MaxBundleSize = dec.Rip7560MaxBundleSize
|
||||
}
|
||||
if dec.Rip7560PullUrls != nil {
|
||||
c.Rip7560PullUrls = dec.Rip7560PullUrls
|
||||
}
|
||||
if dec.Rip7560AcceptPush != nil {
|
||||
c.Rip7560AcceptPush = *dec.Rip7560AcceptPush
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func (s *TransactionAPI) SendRip7560TransactionsBundle(ctx context.Context, args
|
|||
ValidForBlock: creationBlock,
|
||||
Transactions: txs,
|
||||
}
|
||||
bundleHash := calculateBundleHash(txs)
|
||||
bundleHash := CalculateBundleHash(txs)
|
||||
bundle.BundleHash = bundleHash
|
||||
err := SubmitRip7560Bundle(ctx, s.b, bundle)
|
||||
if err != nil {
|
||||
|
|
@ -37,15 +37,19 @@ func (s *TransactionAPI) GetRip7560BundleStatus(ctx context.Context, hash common
|
|||
return bundleStats, err
|
||||
}
|
||||
|
||||
// CalculateBundleHash
|
||||
// TODO: If this code is indeed necessary, keep it in utils; better - remove altogether.
|
||||
func calculateBundleHash(txs []*types.Transaction) common.Hash {
|
||||
func CalculateBundleHash(txs []*types.Transaction) common.Hash {
|
||||
appendedTxIds := make([]byte, 0)
|
||||
for _, tx := range txs {
|
||||
txHash := tx.Hash()
|
||||
appendedTxIds = append(appendedTxIds, txHash[:]...)
|
||||
}
|
||||
|
||||
return rlpHash(appendedTxIds)
|
||||
bundleHash := rlpHash(appendedTxIds)
|
||||
println("calculateBundleHash")
|
||||
println(bundleHash.String())
|
||||
return bundleHash
|
||||
}
|
||||
|
||||
func rlpHash(x interface{}) (h common.Hash) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue