Gas Griefing Attack
Exploring the gas griefing attack's implications in meta-transactions and strategies to protect users from relayer malpractices.
Consensys Diligence has acknowledged the issue (SWC-126) from previously section in their documentation, indicating a potential problem. However, they have not provided a suitable solution to address the issue, which suggests a misunderstanding of the problem at hand. Their attempts to propose a resolution have fallen short in effectively resolving the issue.
Imagine you have a smart contract that uses the require
statement to perform a call to another contract using the to.call
function. You want to make sure that the callee contract receives a specific amount of gas that you specify.
However, there are two reasons why the require
call alone cannot guarantee this:
Gas required for the call itself: When you make the call, the gas required for the call's operations and memory usage will further reduce the available gas. This means that the actual gas available at the moment of the call will be lower than what you initially expected.
The 63/64 rule: Even if the gas available at the point of the call seems sufficient, the Ethereum protocol applies the 63/64 rule. This rule reduces the available gas even more, potentially affecting the amount of gas the callee contract receives. The remaining gas (1/64 of the gas required) can still be enough for the rest of the transaction to succeed, allowing the call to continue.
Relayers and Gas Manipulation: Understanding the Vulnerabilities
Now, let's consider a meta-transaction scenario. In meta-transactions, a relayer signs and submits transactions on behalf of users. Here's where the issue arises: a malicious or unaware relayer could sign a transaction with a low amount of gas, intentionally or unintentionally causing the inner call to fail. However, they would still set the overall transaction up for success by providing enough gas for the transaction itself. In this scenario, the relayer would be rewarded for executing the transaction, while the user would experience a failed meta-transaction.
Furthermore, if a relayer manages to make the first meta-transaction fail, it could impact the entire series of meta-transactions generated by the user.
To address this issue, there is a need for a mechanism that ensures smart contracts can reliably guarantee that the callee contract receives the exact amount of gas specified, regardless of the gas reductions caused by the call and the 63/64 rule.
Mitigating Gas Griefing Attack
To properly guard against the issue, we need to ensure there is enough gas at the point of the call being made. There are two ways to achieve this within the current EVM framework:
First Solution
Check before the call:
In this approach, we calculate the available gas by subtracting the gas used in the operations preceding the call (E) from the current gas available gasleft()
. We then compare this value with the required gas for the call txGas
minus 1/64 of the available gas. If the comparison fails, indicating insufficient gas, the call is not made. This method relies on estimating the gas required for the operations preceding the call and the call itself, which is opcode pricing dependent.
Second Solution
Check after the call:
Here, we make the call first using the specified gas txGas
, and then we assert that the gas remaining after the call is greater than txGas
divided by 63. If the remaining gas is not sufficient, the assertion fails, causing the current call to revert. This workaround does not require estimating the gas required for the preceding operations and is not dependent on specific opcode pricing.
Potential Pitfalls of the Second Approach
It's important to note that the second approach may still pass the check if the gas provided was less, and the external call reverted or succeeded early, leaving enough gas remaining. This can be problematic if the code executed during the call reverts due to a check against the gas provided. To address this, an assert
statement is used to consume all gas, emulating an out-of-gas exception. However, it's worth mentioning that the assert
statement may not consume all gas in newer versions of Solidity (>= 0.8.0), requiring the use of assembly to emit an invalid opcode.
However, these workarounds have limitations, and a proper solution would involve making changes to the EVM itself to ensure reliable gas allocation for callee contracts.
Last updated