Platform: Code4rena
Start Date: 02/10/2023
Pot Size: $1,100,000 USDC
Total HM: 28
Participants: 64
Period: 21 days
Judge: GalloDaSballo
Total Solo HM: 13
Id: 292
League: ETH
Rank: 18/64
Findings: 1
Award: $4,574.05
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: minhtrng
Also found by: BARW, HE1M, Koolex, rvierdiiev
4574.0453 USDC - $4,574.05
Transactions where the gasLimit
is too low to cover both the overhead gas cost on L2 and the gas cost to execute the transaction on L2 will pass the safety checks on L1 and will be send to L2. On L2 the transaction will fail because the gasLimit is too low. This results in wasting the users gas on L1 and not accomplishing what the user wanted to do with the transaction in the first place, forcing him to send the transaction again and pay even more gas on L1.
When requesting a L2 Transaction in Mailbox.sol
and thereby writing the PriorityOp, the function TransactionValidator ::validateL1ToL2Transaction()
is called to ensure, amongst other things, that transaction.gasLimit
is set high enough to cover both the overhead gas cost on L2 and the gas cost on L2 that accrue when the transaction is processed. For this purpose, first the overhead gas cost are deducted from transaction.gasLimit
resulting in l2GasForTxBody
, the gasLimit available for processing the transaction itself. Then the minimum cost for processing the transaction is calculated and compared to transaction.gasLimit
.
require( getMinimalPriorityTransactionGasLimit( _encoded.length, _transaction.factoryDeps.length, _transaction.gasPerPubdataByteLimit ) <= _transaction.gasLimit, "up" );
The problem is that the amount of gas needed to execute the transaction itself is compared to the total gasLimit given by the user that also includes the gas cost for overhead. This means that as long as transaction.gasLimit
is >=
the cost for processing the transaction, this check will pass even if transaction.gasLimit
is to low to cover both overhead gas cost and processing gas cost.
Example:
Transaction.gasLimit
= 10
gasCostForOverhead
= 5
gasCostForProcessingTxn
= 10
totalGasCost
= 10 + 5 = 15 => gasLimit to low to cover all gas cost but the check still passes becasue Transaction.gasLimit
is >= gasCostForProcessingTxn
.
This means that the transaction will be send to L2. There it will not be executed and fail since the gas limit will not be enough to cover both the gas cost for overhead and the gas cost for executing the transaction.
Manual review
Compare the gasCostForProcessingTxn ( MinimalPriorityTransactionGasLimit
) to l2GasForTxBody
require( getMinimalPriorityTransactionGasLimit( _encoded.length, _transaction.factoryDeps.length, _transaction.gasPerPubdataByteLimit ) <= _l2GasForTxBody, "up" );
Other
#0 - c4-pre-sort
2023-11-01T08:02:06Z
bytes032 marked the issue as low quality report
#1 - miladpiri
2023-11-09T08:09:36Z
Duplicate.
#2 - c4-judge
2023-11-26T15:00:56Z
GalloDaSballo marked the issue as duplicate of #975
#3 - c4-judge
2023-11-28T12:43:41Z
GalloDaSballo changed the severity to 2 (Med Risk)
#4 - c4-judge
2023-11-28T15:54:08Z
GalloDaSballo marked the issue as satisfactory