Skip to content

Commit

Permalink
Add mempool l1 gas check (#2358)
Browse files Browse the repository at this point in the history
* bump l2 gas limit (#2356)

* bump l2 gas limit

* bump l2 gas limit

* add l1 gas check to mempool
  • Loading branch information
tudor-malene authored Mar 3, 2025
1 parent c131bb7 commit a5afd05
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 37 deletions.
2 changes: 1 addition & 1 deletion go/config/defaults/0-base-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ network:
baseFee: 100000000
minGasPrice: 100000000
paymentAddress: 0xd6C9230053f45F873Cb66D8A02439380a37A4fbF
batchExecutionLimit: 30000000 # same as Ethereum blocks
batchExecutionLimit: 300000000
localExecutionCap: 300000000000 # 300 gwei
l1:
chainId: 1337
Expand Down
2 changes: 1 addition & 1 deletion go/enclave/components/batch_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func (executor *batchExecutor) verifyContext(ec *BatchExecutionContext) error {
func (executor *batchExecutor) prepareState(ec *BatchExecutionContext) error {
var err error
// Create a new batch based on the provided context
ec.currentBatch = core.DeterministicEmptyBatch(ec.parentBatch, ec.l1block, ec.AtTime, ec.SequencerNo, ec.BaseFee, ec.Creator)
ec.currentBatch = core.DeterministicEmptyBatch(ec.parentBatch, ec.l1block, ec.AtTime, ec.SequencerNo, ec.BaseFee, ec.Creator, executor.batchGasLimit)
ec.stateDB, err = executor.batchRegistry.GetBatchState(ec.ctx, rpc.BlockNumberOrHash{BlockHash: &ec.currentBatch.Header.ParentHash})
if err != nil {
return fmt.Errorf("could not create stateDB. Cause: %w", err)
Expand Down
101 changes: 80 additions & 21 deletions go/enclave/components/txpool.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package components

import (
"context"
"fmt"
"math/big"
"reflect"
Expand All @@ -10,6 +11,9 @@ import (
"time"
"unsafe"

"github.com/ten-protocol/go-ten/go/enclave/gas"
"github.com/ten-protocol/go-ten/go/enclave/storage"

"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/params"
"github.com/ten-protocol/go-ten/go/common/log"
Expand Down Expand Up @@ -46,20 +50,24 @@ var startMempoolTimeout = 90 * time.Second

// TxPool is an obscuro wrapper around geths transaction pool
type TxPool struct {
txPoolConfig legacypool.Config
chainconfig *params.ChainConfig
legacyPool *legacypool.LegacyPool
pool *gethtxpool.TxPool
Chain *EthChainAdapter
gasTip *big.Int
running atomic.Bool
stateMutex sync.Mutex
logger gethlog.Logger
validateOnly atomic.Bool
txPoolConfig legacypool.Config
chainconfig *params.ChainConfig
legacyPool *legacypool.LegacyPool
pool *gethtxpool.TxPool
Chain *EthChainAdapter
gasOracle gas.Oracle
batchRegistry BatchRegistry
storage storage.Storage
l1BlockProcessor L1BlockProcessor
gasTip *big.Int
running atomic.Bool
stateMutex sync.Mutex
logger gethlog.Logger
validateOnly atomic.Bool
}

// NewTxPool returns a new instance of the tx pool
func NewTxPool(blockchain *EthChainAdapter, gasTip *big.Int, validateOnly bool, logger gethlog.Logger) (*TxPool, error) {
func NewTxPool(blockchain *EthChainAdapter, storage storage.Storage, batchRegistry BatchRegistry, l1BlockProcessor L1BlockProcessor, gasOracle gas.Oracle, gasTip *big.Int, validateOnly bool, logger gethlog.Logger) (*TxPool, error) {
txPoolConfig := legacypool.Config{
Locals: nil,
NoLocals: false,
Expand All @@ -76,14 +84,18 @@ func NewTxPool(blockchain *EthChainAdapter, gasTip *big.Int, validateOnly bool,
legacyPool := legacypool.New(txPoolConfig, blockchain)

txp := &TxPool{
Chain: blockchain,
chainconfig: blockchain.Config(),
txPoolConfig: txPoolConfig,
legacyPool: legacyPool,
gasTip: gasTip,
stateMutex: sync.Mutex{},
validateOnly: atomic.Bool{},
logger: logger,
Chain: blockchain,
chainconfig: blockchain.Config(),
txPoolConfig: txPoolConfig,
storage: storage,
gasOracle: gasOracle,
batchRegistry: batchRegistry,
l1BlockProcessor: l1BlockProcessor,
legacyPool: legacyPool,
gasTip: gasTip,
stateMutex: sync.Mutex{},
validateOnly: atomic.Bool{},
logger: logger,
}
txp.validateOnly.Store(validateOnly)
go txp.start()
Expand Down Expand Up @@ -245,9 +257,14 @@ func (t *TxPool) validate(tx *common.L2Tx) error {
}

t.stateMutex.Lock()
defer t.stateMutex.Unlock()
// validate against the state. Things like nonce, balance, etc
return validateTx(t.legacyPool, tx, false)
err = validateTx(t.legacyPool, tx, false)
if err != nil {
t.stateMutex.Unlock()
return err
}
t.stateMutex.Unlock()
return t.validateL1Gas(tx)
}

func (t *TxPool) Stats() (int, int) {
Expand Down Expand Up @@ -291,3 +308,45 @@ func (t *TxPool) validateTxBasics(tx *types.Transaction, local bool) error {
}
return nil
}

// check that the tx gas can pay for the l1
func (t *TxPool) validateL1Gas(tx *common.L2Tx) error {
headBatchSeq := t.batchRegistry.HeadBatchSeq()

// don't perform the check while the network is initialising
if headBatchSeq == nil {
return nil
}

headBatch, err := t.storage.FetchBatchHeaderBySeqNo(context.Background(), headBatchSeq.Uint64())
if err != nil {
return fmt.Errorf("could not retrieve head batch. Cause: %w", err)
}
headBlock, err := t.l1BlockProcessor.GetHead(context.Background())
if err != nil {
return fmt.Errorf("could not retrieve head block. Cause: %w", err)
}

l1Cost, err := t.gasOracle.EstimateL1StorageGasCost(tx, headBlock, headBatch)
if err != nil {
t.logger.Error("Unable to get gas cost for tx. Should not happen at this point.", log.TxKey, tx.Hash(), log.ErrKey, err)
return fmt.Errorf("unable to get gas cost for tx. Cause: %w", err)
}

// calculate the cost in l2 gas
l2Gas := big.NewInt(0).Div(l1Cost, headBatch.BaseFee)

intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, true, true)
if err != nil {
return err
}

leastGas := l2Gas.Uint64() + intrGas
// The gas limit of the transaction (evm message) should always be higher than the gas overhead
// used to cover the l1 cost
if tx.Gas() < leastGas {
return fmt.Errorf("insufficient gas. Want at least: %d have: %d", leastGas, tx.Gas())
}

return nil
}
11 changes: 2 additions & 9 deletions go/enclave/core/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,7 @@ func ToBatch(extBatch *common.ExtBatch, transactionBlobCrypto *crypto.DAEncrypti
}, nil
}

func DeterministicEmptyBatch(
parent *common.BatchHeader,
block *types.Header,
time uint64,
sequencerNo *big.Int,
baseFee *big.Int,
coinbase gethcommon.Address,
) *Batch {
func DeterministicEmptyBatch(parent *common.BatchHeader, block *types.Header, time uint64, sequencerNo *big.Int, baseFee *big.Int, coinbase gethcommon.Address, gasLimit uint64) *Batch {
h := common.BatchHeader{
ParentHash: parent.Hash(),
L1Proof: block.Hash(),
Expand All @@ -111,7 +104,7 @@ func DeterministicEmptyBatch(
Time: time,
BaseFee: baseFee,
Coinbase: coinbase,
GasLimit: parent.GasLimit,
GasLimit: gasLimit,
}
b := Batch{
Header: &h,
Expand Down
7 changes: 4 additions & 3 deletions go/enclave/enclave.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,14 @@ func NewEnclave(config *enclaveconfig.EnclaveConfig, genesis *genesis.Genesis, m
logger.Crit("failed to load system contracts", log.ErrKey, err)
}

gasOracle := gas.NewGasOracle()
blockProcessor := components.NewBlockProcessor(storage, crossChainProcessors, gasOracle, logger)

// start the mempool in validate only. Based on the config, it might become sequencer
evmEntropyService := crypto.NewEvmEntropyService(sharedSecretService, logger)
gethEncodingService := gethencoding.NewGethEncodingService(storage, cachingService, evmEntropyService, logger)
batchRegistry := components.NewBatchRegistry(storage, config, gethEncodingService, logger)
mempool, err := components.NewTxPool(batchRegistry.EthChain(), config.MinGasPrice, true, logger)
mempool, err := components.NewTxPool(batchRegistry.EthChain(), storage, batchRegistry, blockProcessor, gasOracle, config.MinGasPrice, true, logger)
if err != nil {
logger.Crit("unable to init eth tx pool", log.ErrKey, err)
}
Expand All @@ -105,8 +108,6 @@ func NewEnclave(config *enclaveconfig.EnclaveConfig, genesis *genesis.Genesis, m
visibilityReader := evm.NewContractVisibilityReader(logger)
evmFacade := evm.NewEVMExecutor(chainContext, chainConfig, config, config.GasLocalExecutionCapFlag, storage, gethEncodingService, visibilityReader, logger)

gasOracle := gas.NewGasOracle()
blockProcessor := components.NewBlockProcessor(storage, crossChainProcessors, gasOracle, logger)
dataCompressionService := compression.NewBrotliDataCompressionService(int64(config.DecompressionLimit))
batchExecutor := components.NewBatchExecutor(storage, batchRegistry, evmFacade, config, gethEncodingService, crossChainProcessors, genesis, gasOracle, chainConfig, scb, evmEntropyService, mempool, dataCompressionService, logger)

Expand Down
1 change: 0 additions & 1 deletion go/enclave/evm/l1_publishing_gas.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ func adjustPublishingCostGas(tx *common.L2PricedTransaction, msg *gethcore.Messa

// The gas limit of the transaction (evm message) should always be higher than the gas overhead
// used to cover the l1 cost
// todo - this check has to be added to the mempool as well
if msg.GasLimit < l1Gas.Uint64() {
return nil, fmt.Errorf("%w. Want at least: %d have: %d", ErrGasNotEnoughForL1, l1Gas, msg.GasLimit)
}
Expand Down
6 changes: 5 additions & 1 deletion go/enclave/rpc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,11 @@ func (s *RPCServer) ExportCrossChainData(ctx context.Context, request *generated
func (s *RPCServer) GetRollupData(ctx context.Context, request *generated.GetRollupDataRequest) (*generated.GetRollupDataResponse, error) {
rollupMetadata, sysError := s.enclave.GetRollupData(ctx, gethcommon.BytesToHash(request.Hash))
if sysError != nil {
s.logger.Error("Error fetching rollup metadata", log.ErrKey, sysError)
if errors.Is(sysError, errutil.ErrNotFound) {
s.logger.Debug("Error fetching rollup metadata", log.ErrKey, sysError)
} else {
s.logger.Error("Error fetching rollup metadata", log.ErrKey, sysError)
}
return nil, sysError
}

Expand Down

0 comments on commit a5afd05

Please sign in to comment.