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

[Gas Mechanics] Implement Gas history; Migrate to Arbitrum Gas model #1714

Merged
merged 31 commits into from
Jan 22, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,12 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
setTimeout(fail, 30_000)
const messageBusContract = (await hre.ethers.getContractAt('MessageBus', '0x526c84529b2b8c11f57d93d3f5537aca3aecef9b'));
const gasLimit = await messageBusContract.estimateGas.verifyMessageFinalized(messages[1], {
maxFeePerGas: 2,
maxFeePerGas: 1000000001,
})
try {
while (await messageBusContract.callStatic.verifyMessageFinalized(messages[1], {
maxFeePerGas: 2,
gasLimit: gasLimit.mul(2),
maxFeePerGas: 1000000001,
gasLimit: gasLimit.add(gasLimit.div(2)),
from: l2Accounts.deployer
}) != true) {
console.log(`Messages not stored on L2 yet, retrying...`);
Expand Down
14 changes: 14 additions & 0 deletions go/common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ type (
L2Receipt = types.Receipt
L2Receipts = types.Receipts

L2PricedTransaction struct {
Tx *L2Tx
PublishingCost *big.Int
}
L2PricedTransactions []L2PricedTransaction

CrossChainMessage = MessageBus.StructsCrossChainMessage
CrossChainMessages = []CrossChainMessage
ValueTransferEvent struct {
Expand Down Expand Up @@ -72,6 +78,14 @@ type (
EncodedBatchRequest []byte
)

func (txs L2PricedTransactions) ToTransactions() types.Transactions {
ret := make(types.Transactions, 0)
for _, tx := range txs {
ret = append(ret, tx.Tx)
}
return ret
}

const (
L2GenesisHeight = uint64(0)
L1GenesisHeight = uint64(0)
Expand Down
7 changes: 4 additions & 3 deletions go/config/enclave_cli_flags.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"github.com/ethereum/go-ethereum/params"
"github.com/ten-protocol/go-ten/go/common"
"github.com/ten-protocol/go-ten/go/common/flag"
)
Expand Down Expand Up @@ -53,16 +54,16 @@ var EnclaveFlags = map[string]*flag.TenFlag{
SequencerIDFlag: flag.NewStringFlag(SequencerIDFlag, "", "The 20 bytes of the address of the sequencer for this network"),
MaxBatchSizeFlag: flag.NewUint64Flag(MaxBatchSizeFlag, 1024*25, "The maximum size a batch is allowed to reach uncompressed"),
MaxRollupSizeFlag: flag.NewUint64Flag(MaxRollupSizeFlag, 1024*64, "The maximum size a rollup is allowed to reach"),
L2BaseFeeFlag: flag.NewUint64Flag(L2BaseFeeFlag, 1, ""),
L2BaseFeeFlag: flag.NewUint64Flag(L2BaseFeeFlag, params.InitialBaseFee, ""),
L2CoinbaseFlag: flag.NewStringFlag(L2CoinbaseFlag, "0xd6C9230053f45F873Cb66D8A02439380a37A4fbF", ""),
GasBatchExecutionLimit: flag.NewUint64Flag(GasBatchExecutionLimit, 30_000_000, "Max gas that can be executed in a single batch"),
GasBatchExecutionLimit: flag.NewUint64Flag(GasBatchExecutionLimit, 3_000_000_000, "Max gas that can be executed in a single batch"),
ObscuroGenesisFlag: flag.NewStringFlag(ObscuroGenesisFlag, "", "The json string with the obscuro genesis"),
L1ChainIDFlag: flag.NewInt64Flag(L1ChainIDFlag, 1337, "An integer representing the unique chain id of the Ethereum chain used as an L1 (default 1337)"),
ObscuroChainIDFlag: flag.NewInt64Flag(ObscuroChainIDFlag, 443, "An integer representing the unique chain id of the Obscuro chain (default 443)"),
UseInMemoryDBFlag: flag.NewBoolFlag(UseInMemoryDBFlag, true, "Whether the enclave will use an in-memory DB rather than persist data"),
ProfilerEnabledFlag: flag.NewBoolFlag(ProfilerEnabledFlag, false, "Runs a profiler instance (Defaults to false)"),
DebugNamespaceEnabledFlag: flag.NewBoolFlag(DebugNamespaceEnabledFlag, false, "Whether the debug namespace is enabled"),
GasLocalExecutionCapFlag: flag.NewUint64Flag(GasLocalExecutionCapFlag, 40_000_000, "Max gas usage when executing local transactions"),
GasLocalExecutionCapFlag: flag.NewUint64Flag(GasLocalExecutionCapFlag, 4_000_000_000, "Max gas usage when executing local transactions"),
}

// enclaveRestrictedFlags are the flags that the enclave can receive ONLY over the Ego signed enclave.json
Expand Down
80 changes: 34 additions & 46 deletions go/enclave/components/batch_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ func NewBatchExecutor(
}
}

// payL1Fees - this function modifies the state db according to the transactions contained within the batch context
// in order to subtract gas fees from the balance. It returns a list of the transactions that have prepaid for their L1
// publishing costs.
func (executor *batchExecutor) payL1Fees(stateDB *state.StateDB, context *BatchExecutionContext) (common.L2Transactions, common.L2Transactions) {
transactions := make(common.L2Transactions, 0)
freeTransactions := make(common.L2Transactions, 0)
// filterTransactionsWithSufficientFunds - this function estimates hte l1 fees for the transaction in a given batch execution context. It does so by taking the price of the
// pinned L1 block and using it as the cost per gas for the estimated gas of the calldata encoding of a transaction. It filters out any transactions that cannot afford to pay for their L1
// publishing cost.
func (executor *batchExecutor) filterTransactionsWithSufficientFunds(stateDB *state.StateDB, context *BatchExecutionContext) (common.L2PricedTransactions, common.L2PricedTransactions) {
transactions := make(common.L2PricedTransactions, 0)
freeTransactions := make(common.L2PricedTransactions, 0)
block, _ := executor.storage.FetchBlock(context.BlockPtr)

for _, tx := range context.Transactions {
Expand All @@ -97,43 +97,25 @@ func (executor *batchExecutor) payL1Fees(stateDB *state.StateDB, context *BatchE
isFreeTransaction = isFreeTransaction && tx.GasPrice().Cmp(gethcommon.Big0) == 0

if isFreeTransaction {
freeTransactions = append(freeTransactions, tx)
freeTransactions = append(freeTransactions, common.L2PricedTransaction{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite clear what prevents a user from setting the "GasFeeCap=0", and become a "free transaction"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mempool would reject such a transaction. The only way to get it in is bypass the mempool.

Tx: tx,
PublishingCost: big.NewInt(0),
})
continue
}
if accBalance.Cmp(cost) == -1 {
executor.logger.Info(fmt.Sprintf("insufficient account balance for tx - want: %d have: %d", cost, accBalance), log.TxKey, tx.Hash(), "addr", sender.Hex())
continue
}
stateDB.SubBalance(*sender, cost)
stateDB.AddBalance(context.Creator, cost)
// todo - add refund logic.

transactions = append(transactions, tx)
transactions = append(transactions, common.L2PricedTransaction{
Tx: tx,
PublishingCost: big.NewInt(0).Set(cost),
})
}
return transactions, freeTransactions
}

func (executor *batchExecutor) refundL1Fees(stateDB *state.StateDB, context *BatchExecutionContext, transactions []*common.L2Tx) {
block, _ := executor.storage.FetchBlock(context.BlockPtr)
for _, tx := range transactions {
cost, err := executor.gasOracle.EstimateL1StorageGasCost(tx, block)
if err != nil {
executor.logger.Warn("Unable to get gas cost for tx", log.TxKey, tx.Hash(), log.ErrKey, err)
continue
}

sender, err := core.GetAuthenticatedSender(context.ChainConfig.ChainID.Int64(), tx)
if err != nil {
// todo @siliev - is this critical? Potential desync spot
executor.logger.Warn("Unable to extract sender for tx", log.TxKey, tx.Hash())
continue
}

stateDB.AddBalance(*sender, cost)
stateDB.SubBalance(context.Creator, cost)
}
}

func (executor *batchExecutor) ComputeBatch(context *BatchExecutionContext, failForEmptyBatch bool) (*ComputedBatch, error) { //nolint:gocognit
defer core.LogMethodDuration(executor.logger, measure.NewStopwatch(), "Batch context processed")

Expand Down Expand Up @@ -183,23 +165,29 @@ func (executor *batchExecutor) ComputeBatch(context *BatchExecutionContext, fail
crossChainTransactions := executor.crossChainProcessors.Local.CreateSyntheticTransactions(messages, stateDB)
executor.crossChainProcessors.Local.ExecuteValueTransfers(transfers, stateDB)

transactionsToProcess, freeTransactions := executor.payL1Fees(stateDB, context)
transactionsToProcess, freeTransactions := executor.filterTransactionsWithSufficientFunds(stateDB, context)

xchainTxs := make(common.L2PricedTransactions, 0)
for _, xTx := range crossChainTransactions {
xchainTxs = append(xchainTxs, common.L2PricedTransaction{
Tx: xTx,
PublishingCost: big.NewInt(0),
})
}

crossChainTransactions = append(crossChainTransactions, freeTransactions...)
syntheticTransactions := append(xchainTxs, freeTransactions...)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

much clearer


successfulTxs, excludedTxs, txReceipts, err := executor.processTransactions(batch, 0, transactionsToProcess, stateDB, context.ChainConfig, false)
if err != nil {
return nil, fmt.Errorf("could not process transactions. Cause: %w", err)
}

executor.refundL1Fees(stateDB, context, excludedTxs)

ccSuccessfulTxs, _, ccReceipts, err := executor.processTransactions(batch, len(successfulTxs), crossChainTransactions, stateDB, context.ChainConfig, true)
ccSuccessfulTxs, _, ccReceipts, err := executor.processTransactions(batch, len(successfulTxs), syntheticTransactions, stateDB, context.ChainConfig, true)
if err != nil {
return nil, err
}

if err = executor.verifyInboundCrossChainTransactions(crossChainTransactions, ccSuccessfulTxs, ccReceipts); err != nil {
if err = executor.verifyInboundCrossChainTransactions(syntheticTransactions, ccSuccessfulTxs, ccReceipts); err != nil {
return nil, fmt.Errorf("batch computation failed due to cross chain messages. Cause: %w", err)
}

Expand All @@ -220,7 +208,7 @@ func (executor *batchExecutor) ComputeBatch(context *BatchExecutionContext, fail
// we need to copy the batch to reset the internal hash cache
copyBatch := *batch
copyBatch.Header.Root = stateDB.IntermediateRoot(false)
copyBatch.Transactions = append(successfulTxs, freeTransactions...)
copyBatch.Transactions = append(successfulTxs, freeTransactions.ToTransactions()...)
copyBatch.ResetHash()

if err = executor.populateOutboundCrossChainData(&copyBatch, block, txReceipts); err != nil {
Expand Down Expand Up @@ -387,8 +375,8 @@ func (executor *batchExecutor) populateHeader(batch *core.Batch, receipts types.
}
}

func (executor *batchExecutor) verifyInboundCrossChainTransactions(transactions types.Transactions, executedTxs types.Transactions, receipts types.Receipts) error {
if transactions.Len() != executedTxs.Len() {
func (executor *batchExecutor) verifyInboundCrossChainTransactions(transactions common.L2PricedTransactions, executedTxs types.Transactions, receipts types.Receipts) error {
if len(transactions) != executedTxs.Len() {
return fmt.Errorf("some synthetic transactions have not been executed")
}

Expand All @@ -404,7 +392,7 @@ func (executor *batchExecutor) verifyInboundCrossChainTransactions(transactions
func (executor *batchExecutor) processTransactions(
batch *core.Batch,
tCount int,
txs []*common.L2Tx,
txs common.L2PricedTransactions,
stateDB *state.StateDB,
cc *params.ChainConfig,
noBaseFee bool,
Expand All @@ -424,18 +412,18 @@ func (executor *batchExecutor) processTransactions(
executor.logger,
)
for _, tx := range txs {
result, f := txResults[tx.Hash()]
result, f := txResults[tx.Tx.Hash()]
if !f {
return nil, nil, nil, fmt.Errorf("there should be an entry for each transaction")
}
rec, foundReceipt := result.(*types.Receipt)
if foundReceipt {
executedTransactions = append(executedTransactions, tx)
executedTransactions = append(executedTransactions, tx.Tx)
txReceipts = append(txReceipts, rec)
} else {
// Exclude all errors
excludedTransactions = append(excludedTransactions, tx)
executor.logger.Info("Excluding transaction from batch", log.TxKey, tx.Hash(), log.BatchHashKey, batch.Hash(), "cause", result)
excludedTransactions = append(excludedTransactions, tx.Tx)
executor.logger.Info("Excluding transaction from batch", log.TxKey, tx.Tx.Hash(), log.BatchHashKey, batch.Hash(), "cause", result)
}
}
sort.Sort(sortByTxIndex(txReceipts))
Expand Down
2 changes: 1 addition & 1 deletion go/enclave/crosschain/message_bus_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (m *MessageBusManager) GenerateMessageBusDeployTx() (*common.L2Tx, error) {
tx := &types.LegacyTx{
Nonce: 0, // The first transaction of the owner identity should always be deploying the contract
Value: gethcommon.Big0,
Gas: 5_000_000, // It's quite the expensive contract.
Gas: 500_000_000, // It's quite the expensive contract.
GasPrice: gethcommon.Big0, // Synthetic transactions are on the house. Or the house.
Data: gethcommon.FromHex(MessageBus.MessageBusMetaData.Bin),
To: nil, // Geth requires nil instead of gethcommon.Address{} which equates to zero address in order to return receipt.
Expand Down
77 changes: 59 additions & 18 deletions go/enclave/enclave.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,10 @@ type enclaveImpl struct {
crossChainProcessors *crosschain.Processors
sharedSecretProcessor *components.SharedSecretProcessor

chain l2chain.ObscuroChain
service nodetype.NodeType
registry components.BatchRegistry
chain l2chain.ObscuroChain
service nodetype.NodeType
registry components.BatchRegistry
gasOracle gas.Oracle

mgmtContractLib mgmtcontractlib.MgmtContractLib
attestationProvider components.AttestationProvider // interface for producing attestation reports and verifying them
Expand Down Expand Up @@ -268,9 +269,10 @@ func NewEnclave(
debugger: debug,
stopControl: stopcontrol.New(),

chain: chain,
registry: registry,
service: service,
chain: chain,
registry: registry,
service: service,
gasOracle: gasOracle,

mainMutex: sync.Mutex{},
}
Expand Down Expand Up @@ -678,25 +680,36 @@ func (e *enclaveImpl) GetTransactionCount(encryptedParams common.EncryptedParams

address := gethcommon.HexToAddress(addressStr)

seqNo := e.registry.HeadBatchSeq().Uint64()
if len(paramList) == 3 {
tag, err := gethencoding.ExtractBlockNumber(paramList[2])
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("unexpected tag parameter. Cause: %w", err)), nil
}

b, err := e.registry.GetBatchAtHeight(*tag)
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("cant retrieve batch for tag. Cause: %w", err)), nil
}
seqNo = b.SeqNo().Uint64()
}
Comment on lines +683 to +695
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The update to the GetTransactionCount method includes conditional logic for batch retrieval based on the presence of a third parameter. The error message on line 687 could be more descriptive by including the tag value that caused the error.

- return responses.AsPlaintextError(fmt.Errorf("unexpected tag parameter. Cause: %w", err)), nil
+ return responses.AsPlaintextError(fmt.Errorf("unexpected tag parameter '%v'. Cause: %w", tag, err)), nil

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
seqNo := e.registry.HeadBatchSeq().Uint64()
if len(paramList) == 3 {
tag, err := gethencoding.ExtractBlockNumber(paramList[2])
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("unexpected tag parameter. Cause: %w", err)), nil
}
b, err := e.registry.GetBatchAtHeight(*tag)
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("cant retrieve batch for tag. Cause: %w", err)), nil
}
seqNo = b.SeqNo().Uint64()
}
seqNo := e.registry.HeadBatchSeq().Uint64()
if len(paramList) == 3 {
tag, err := gethencoding.ExtractBlockNumber(paramList[2])
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("unexpected tag parameter '%v'. Cause: %w", tag, err)), nil
}
b, err := e.registry.GetBatchAtHeight(*tag)
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("cant retrieve batch for tag. Cause: %w", err)), nil
}
seqNo = b.SeqNo().Uint64()
}


// extract, create and validate the VK encryption handler
vkHandler, err := createVKHandler(&address, paramList[0], e.config.ObscuroChainID)
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("unable to create VK encryptor - %w", err)), nil
}

var nonce uint64
headBatch := e.registry.HeadBatchSeq()
if headBatch != nil {
l2Head, err := e.storage.FetchBatchBySeqNo(headBatch.Uint64())
if err == nil {
// todo - we should return an error when head state is not available, but for current test situations with race
// conditions we allow it to return zero while head state is uninitialized
s, err := e.storage.CreateStateDB(l2Head.Hash())
if err != nil {
return nil, responses.ToInternalError(err)
}
nonce = s.GetNonce(address)
l2Head, err := e.storage.FetchBatchBySeqNo(seqNo)
StefanIliev545 marked this conversation as resolved.
Show resolved Hide resolved
if err == nil {
// todo - we should return an error when head state is not available, but for current test situations with race
// conditions we allow it to return zero while head state is uninitialized
s, err := e.storage.CreateStateDB(l2Head.Hash())
if err != nil {
return nil, responses.ToInternalError(err)
}
nonce = s.GetNonce(address)
Comment on lines +704 to +712
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic in the GetTransactionCount method for retrieving the nonce seems correct. However, the comment on line 706 suggests that there might be a known issue with race conditions that should be addressed. It would be prudent to track this as a TODO for future resolution.

}

encoded := hexutil.EncodeUint64(nonce)
Expand Down Expand Up @@ -1025,6 +1038,32 @@ func (e *enclaveImpl) EstimateGas(encryptedParams common.EncryptedParamsEstimate
return responses.AsEncryptedError(err, vkHandler), nil
}

block, err := e.blockResolver.FetchHeadBlock()
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("internal server error")), err
}

// The message is ran through the l1 publishing cost estimation for the current
// known head block.
l1Cost, err := e.gasOracle.EstimateL1CostForMsg(callMsg, block)
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("internal server error")), err
}
Comment on lines +1041 to +1051
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The EstimateGas function now includes additional calculations for gas estimation, which aligns with the PR's objectives. However, the error messages on lines 1042 and 1049 are generic and do not provide enough context about the failure. It would be beneficial to include more details in the error messages to aid in debugging.

- return responses.AsPlaintextError(fmt.Errorf("internal server error")), err
+ return responses.AsPlaintextError(fmt.Errorf("failed to fetch head block for gas estimation: %w", err)), nil

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
block, err := e.blockResolver.FetchHeadBlock()
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("internal server error")), err
}
// The message is ran through the l1 publishing cost estimation for the current
// known head block.
l1Cost, err := e.gasOracle.EstimateL1CostForMsg(callMsg, block)
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("internal server error")), err
}
block, err := e.blockResolver.FetchHeadBlock()
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("failed to fetch head block for gas estimation: %w", err)), nil
}
// The message is ran through the l1 publishing cost estimation for the current
// known head block.
l1Cost, err := e.gasOracle.EstimateL1CostForMsg(callMsg, block)
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("failed to fetch head block for gas estimation: %w", err)), nil
}


batch, err := e.storage.FetchHeadBatch()
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("internal server error")), err
}

// We divide the total estimated l1 cost by the l2 fee per gas in order to convert
// the expected cost into l2 gas based on current pricing.
// todo @siliev - add overhead when the base fee becomes dynamic.
publishingGas := big.NewInt(0).Div(l1Cost, batch.Header.BaseFee)

// The one additional gas captures the modulo leftover in some edge cases
// where BaseFee is bigger than the l1cost.
publishingGas = big.NewInt(0).Add(publishingGas, gethcommon.Big1)
Comment on lines +1041 to +1065
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The EstimateGas function now includes additional calculations for gas estimation, which aligns with the PR's objectives. However, the error messages on lines 1042, 1049, and 1055 are generic and do not provide enough context about the failure. It would be beneficial to include more details in the error messages to aid in debugging.

- return responses.AsPlaintextError(fmt.Errorf("internal server error")), err
+ return responses.AsPlaintextError(fmt.Errorf("failed to fetch head block for gas estimation: %w", err)), nil

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
block, err := e.blockResolver.FetchHeadBlock()
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("internal server error")), err
}
// The message is ran through the l1 publishing cost estimation for the current
// known head block.
l1Cost, err := e.gasOracle.EstimateL1CostForMsg(callMsg, block)
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("internal server error")), err
}
batch, err := e.storage.FetchHeadBatch()
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("internal server error")), err
}
// We divide the total estimated l1 cost by the l2 fee per gas in order to convert
// the expected cost into l2 gas based on current pricing.
// todo @siliev - add overhead when the base fee becomes dynamic.
publishingGas := big.NewInt(0).Div(l1Cost, batch.Header.BaseFee)
// The one additional gas captures the modulo leftover in some edge cases
// where BaseFee is bigger than the l1cost.
publishingGas = big.NewInt(0).Add(publishingGas, gethcommon.Big1)
block, err := e.blockResolver.FetchHeadBlock()
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("failed to fetch head block for gas estimation: %w", err)), nil
}
// The message is ran through the l1 publishing cost estimation for the current
// known head block.
l1Cost, err := e.gasOracle.EstimateL1CostForMsg(callMsg, block)
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("failed to fetch head block for gas estimation: %w", err)), nil
}
batch, err := e.storage.FetchHeadBatch()
if err != nil {
return responses.AsPlaintextError(fmt.Errorf("failed to fetch head block for gas estimation: %w", err)), nil
}
// We divide the total estimated l1 cost by the l2 fee per gas in order to convert
// the expected cost into l2 gas based on current pricing.
// todo @siliev - add overhead when the base fee becomes dynamic.
publishingGas := big.NewInt(0).Div(l1Cost, batch.Header.BaseFee)
// The one additional gas captures the modulo leftover in some edge cases
// where BaseFee is bigger than the l1cost.
publishingGas = big.NewInt(0).Add(publishingGas, gethcommon.Big1)

Comment on lines +1061 to +1065
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic for converting L1 cost to L2 gas seems to be implemented correctly. However, the comment on line 1060 mentions adding overhead when the base fee becomes dynamic. This should be tracked as a TODO to ensure that the dynamic base fee is handled correctly in the future.


executionGasEstimate, err := e.DoEstimateGas(callMsg, blockNumber, e.config.GasLocalExecutionCapFlag)
if err != nil {
err = fmt.Errorf("unable to estimate transaction - %w", err)
Expand All @@ -1042,7 +1081,9 @@ func (e *enclaveImpl) EstimateGas(encryptedParams common.EncryptedParamsEstimate
return responses.AsEncryptedError(err, vkHandler), nil
}

return responses.AsEncryptedResponse(&executionGasEstimate, vkHandler), nil
totalGasEstimate := hexutil.Uint64(publishingGas.Uint64() + uint64(executionGasEstimate))

return responses.AsEncryptedResponse(&totalGasEstimate, vkHandler), nil
}

func (e *enclaveImpl) GetLogs(encryptedParams common.EncryptedParamsGetLogs) (*responses.Logs, common.SystemError) { //nolint
Expand Down
Loading
Loading