Skip to content

Commit

Permalink
feat: add api to simulate gasless bundle (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
irrun authored Jul 23, 2024
1 parent 3a67ebf commit f33b095
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 16 deletions.
21 changes: 21 additions & 0 deletions core/types/bundle_gasless.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package types

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)

type SimulateGaslessBundleArgs struct {
Txs []hexutil.Bytes `json:"txs"`
}

type GaslessTxSimResult struct {
Hash common.Hash
GasUsed uint64
Valid bool
}

type SimulateGaslessBundleResp struct {
Results []GaslessTxSimResult
BasedBlockNumber int64
}
4 changes: 4 additions & 0 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,10 @@ func (b *EthAPIBackend) SendBundle(ctx context.Context, bundle *types.Bundle) er
return b.eth.txPool.AddBundle(bundle)
}

func (b *EthAPIBackend) SimulateGaslessBundle(bundle *types.Bundle) (*types.SimulateGaslessBundleResp, error) {
return b.Miner().SimulateGaslessBundle(bundle)
}

func (b *EthAPIBackend) BundlePrice() *big.Int {
bundles := b.eth.txPool.AllBundles()
gasFloor := big.NewInt(b.eth.config.Miner.MevGasPriceFloor)
Expand Down
10 changes: 10 additions & 0 deletions ethclient/ethclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,16 @@ func (ec *Client) BestBidGasFee(ctx context.Context, parentHash common.Hash) (*b
return fee, nil
}

// SimulateGaslessBundle simulates a gasless bundle
func (ec *Client) SimulateGaslessBundle(ctx context.Context, args types.SimulateGaslessBundleArgs) (*types.SimulateGaslessBundleResp, error) {
var bundle types.SimulateGaslessBundleResp
err := ec.c.CallContext(ctx, &bundle, "eth_simulateGaslessBundle", args)
if err != nil {
return nil, err
}
return &bundle, nil
}

// SendBundle sends a bundle
func (ec *Client) SendBundle(ctx context.Context, args types.SendBundleArgs) (common.Hash, error) {
var hash common.Hash
Expand Down
23 changes: 23 additions & 0 deletions internal/ethapi/api_bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,29 @@ func (s *PrivateTxBundleAPI) BundlePrice(ctx context.Context) *big.Int {
return s.b.BundlePrice()
}

// SimulateGaslessBundle simulates the execution of a list of transactions with order
func (s *PrivateTxBundleAPI) SimulateGaslessBundle(_ context.Context, args types.SimulateGaslessBundleArgs) (*types.SimulateGaslessBundleResp, error) {
if len(args.Txs) == 0 {
return nil, newBundleError(errors.New("bundle missing txs"))
}

var txs types.Transactions

for _, encodedTx := range args.Txs {
tx := new(types.Transaction)
if err := tx.UnmarshalBinary(encodedTx); err != nil {
return nil, err
}
txs = append(txs, tx)
}

bundle := &types.Bundle{
Txs: txs,
}

return s.b.SimulateGaslessBundle(bundle)
}

// 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 types.SendBundleArgs) (common.Hash, error) {
Expand Down
1 change: 1 addition & 0 deletions internal/ethapi/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ type Backend interface {
// Transaction pool API
SendTx(ctx context.Context, signedTx *types.Transaction) error
SendBundle(ctx context.Context, bundle *types.Bundle) error
SimulateGaslessBundle(bundle *types.Bundle) (*types.SimulateGaslessBundleResp, error)
BundlePrice() *big.Int
GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error)
GetPoolTransactions() (types.Transactions, error)
Expand Down
62 changes: 46 additions & 16 deletions miner/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,47 @@ func (miner *Miner) GasCeil() uint64 {

func (miner *Miner) SimulateBundle(bundle *types.Bundle) (*big.Int, error) {
parent := miner.eth.BlockChain().CurrentBlock()

parentState, err := miner.eth.BlockChain().StateAt(parent.Root)
if err != nil {
return nil, err
}

env, err := miner.prepareSimulationEnv(parent, parentState)
if err != nil {
return nil, err
}

s, err := miner.worker.simulateBundle(env, bundle, parentState, env.gasPool, 0, true, true)
if err != nil {
return nil, err
}

return s.BundleGasPrice, nil
}

func (miner *Miner) SimulateGaslessBundle(bundle *types.Bundle) (*types.SimulateGaslessBundleResp, error) {
parent := miner.eth.BlockChain().CurrentBlock()

parentState, err := miner.eth.BlockChain().StateAt(parent.Root)
if err != nil {
return nil, err
}

env, err := miner.prepareSimulationEnv(parent, parentState)
if err != nil {
return nil, err
}

resp, err := miner.worker.simulateGaslessBundle(env, bundle)
if err != nil {
return nil, err
}

return resp, nil
}

func (miner *Miner) prepareSimulationEnv(parent *types.Header, state *state.StateDB) (*environment, error) {
timestamp := time.Now().Unix()
if parent.Time >= uint64(timestamp) {
timestamp = int64(parent.Time + 1)
Expand Down Expand Up @@ -351,28 +392,17 @@ func (miner *Miner) SimulateBundle(bundle *types.Bundle) (*big.Int, error) {
// }
}

state, err := miner.eth.BlockChain().StateAt(parent.Root)
if err != nil {
return nil, err
}

env := &environment{
header: header,
state: state.Copy(),
signer: types.MakeSigner(miner.worker.chainConfig, header.Number, header.Time),
header: header,
state: state.Copy(),
signer: types.MakeSigner(miner.worker.chainConfig, header.Number, header.Time),
gasPool: prepareGasPool(header.GasLimit),
}

if !miner.worker.chainConfig.IsFeynman(header.Number, header.Time) {
// Handle upgrade build-in system contract code
systemcontracts.UpgradeBuildInSystemContract(miner.worker.chainConfig, header.Number, parent.Time, header.Time, env.state)
}

gasPool := prepareGasPool(env.header.GasLimit)
s, err := miner.worker.simulateBundle(env, bundle, state, gasPool, 0, true, true)

if err != nil {
return nil, err
}

return s.BundleGasPrice, nil
return env, nil
}
38 changes: 38 additions & 0 deletions miner/worker_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,44 @@ func (w *worker) simulateBundle(
}, nil
}

func (w *worker) simulateGaslessBundle(env *environment, bundle *types.Bundle) (*types.SimulateGaslessBundleResp, error) {
result := make([]types.GaslessTxSimResult, 0)

txIdx := 0
for _, tx := range bundle.Txs {
env.state.SetTxContext(tx.Hash(), txIdx)

var (
snap = env.state.Snapshot()
gp = env.gasPool.Gas()
valid = true
)

receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &w.coinbase, env.gasPool, env.state, env.header, tx,
&env.header.GasUsed, *w.chain.GetVMConfig())
if err != nil {
env.state.RevertToSnapshot(snap)
env.gasPool.SetGas(gp)
valid = false
log.Warn("fail to simulate gasless bundle, skipped", "txHash", tx.Hash(), "err", err)
} else {
txIdx++
}

result = append(result, types.GaslessTxSimResult{
Hash: tx.Hash(),
GasUsed: receipt.GasUsed,
Valid: valid,
})
}

return &types.SimulateGaslessBundleResp{
Results: result,
BasedBlockNumber: env.header.Number.Int64(),
}, nil

}

func containsHash(arr []common.Hash, match common.Hash) bool {
for _, elem := range arr {
if elem == match {
Expand Down

0 comments on commit f33b095

Please sign in to comment.