Background
NEAR has a gas limit on each function call action (contract call). As of today the limit is 300 Tgas. The purpose of this proposal is to suggest an increase to this gas limit.
Motivation
Aurora is the EVM compatibility solution on NEAR. The project includes a smart contract on NEAR, called the Engine, which is a full EVM implementation. This contract allows submitting Ethereum transactions to NEAR. Naturally, calls to the Engine contract can be very computationally complex because they contain entire Ethereum transactions (which may involve multiple EVM smart contract executions). As a result, transactions that would pass on Ethereum can fail on Aurora due to the function call gas limit.
This issue has been known for a long time, and we have worked towards resolving it (see for example this post). While the Aurora team continues to work with the nearcore team to improve the efficiency of the Engine (how much EVM gas we can execute per NEAR Tgas), there are still important use cases that remain impossible on Aurora today due to hitting the gas limit. For example:
- The number of distinct assets that can be borrowed by users in defi platforms on Aurora is limited due to the gas required for liquidation transactions scaling with the number of assets.
- Flash loans are currently impossible on Aurora since the gas consumed by the borrowing and repay logic at the start and end of the transaction does not leave enough for interesting usage of the borrowed tokens.
- Some blockchain-based video games also have actions that cannot fit within the current gas limit.
Therefore, we hope to enable more use-cases on Aurora by increasing the amount of NEAR gas the Engine can burn in a single transaction.
Of course this change would not just be for Aurora’s contact, any contract on NEAR could burn more gas in a single call. Are there other use-cases on NEAR itself such a change could enable? If you know of any please comment below.
Proposal
We propose increasing the function call gas limit to 500 Tgas. Similarly, the maximum allowed prepaid gas would need to be raised to 500 Tgas as well.
Justification
For use-cases that scale linearly, a 1.67x increase translates directly to them being able to do more (e.g. allowing users to borrow more asset types). Of course, that reasoning continues, and would imply we make the limit as high as possible. However, there are other considerations besides Aurora (see possible drawback below). The proposed 500 number is meant to be a compromise between the gas-hungry use-cases on Aurora and the potential issues increasing the limit too much may cause. That said, the specific value is open to discussion on this forum post and we look forward to getting input from others in the community.
This increase is not sufficient to allow the highest benchmarked use-case to fit within the limit as it uses 750 Tgas. However, this does move that use-case within reach because only a 1.5x increase in Engine efficiency would be needed, instead of 2.5x.
Possible Drawbacks
Excess compute time in nearcore
Presently, NEAR nodes use a simple approach to determining what receipts can fit in a chunk. The pending receipts are executed one by one until the total gas burnt exceeds the chunk gas limit. This means, at worst, the node can do computational work in excess of the chunk gas limit by an amount equal to the single receipt gas limit.
The reason this matters is because NEAR gas values are tuned to correlate with wall-clock time; 1 Tgas being approximately 1 ms. Therefore, a chunk gas limit of 1000 Tgas allows for NEAR’s target 1 second block time. However, if the node can exceed the chunk limit, then it may spend more than 1 second processing a chunk and thus cause a slowdown of the block time. The more the single receipt gas limit is increased, the worse this potential slowdown gets.
One way to mitigate this drawback would be a change to how receipts are selected to be included in a chunk. Instead of executing each receipt with its full prepaid gas, use min(chunk_gas_limit - total_gas_burnt, prepaid_gas)
. If a receipt runs out of gas when it is executed with a gas limit lower than its prepaid gas, delay that receipt to the next chunk, along with all remaining pending receipts. With this change, the node would never do more computational work on a single chunk than the chunk gas limit, thus preventing the potential slowdown. However, the downside to this change is that some work would be “wasted” in the sense that the receipt which was partially executed and ran out of gas, due to being at the end of the chunk, will need to be executed again in the following chunk. Additionally, changes would need to be made around how the gas price moves in times of congestion. Congestion would need to be defined in terms of how many delayed receipts there are as opposed to how full the chunk is because chunks will rarely be 100% filled with this model. Indeed, in the worst case where the last receipt of a chunk would have used the full 500 Tgas we propose here, then chunks could appear to be only half filled even when there is “congestion”. Overall, it is unclear whether this is better or worse than allowing a slowdown of the block time. Discussion on this point is welcomed.
Reduced safety margin for gas estimations
As mentioned above, NEAR gas costs are meant to be correlated with wall-clock time. However, due to the complexity of smart contracts it is nearly impossible to guarantee this correlation. It is possible that some operation may be under-costed relative to the amount of time it takes to execute. Such a misestimation of the cost could result in a slowdown of the block time, especially if used maliciously. One tool the NEAR team has to combat this risk is to lower the chunk gas limit in response to a misestimation. For example, suppose some operation takes 50% longer to execute than the amount of gas it costs would suggest and an attacker spams the network with such transactions, reducing the block time from 1 second to 1.5 seconds. In this case, NEAR could lower the chunk gas limit to 660 Tgas, then each chunk could still execute within 1 second even if it takes 50% longer than the amount of gas.
However, NEAR can never lower the chunk gas limit to be less than the gas limit of a single function call because that would break existing contracts. Therefore, increasing the gas limit of a single call reduces the amount of room NEAR has to move the chunk gas limit in response to gas cost misestimation exploits.
We believe the proposed value of 500 Tgas still leaves the NEAR team enough room to respond to issues. This is effectively a 2x safety margin, on top of the 3x safety multiplier that is applied to all gas costs in the first place. However, input from the nearcore runtime team is welcomed, as they do the gas cost estimation work.