-
Notifications
You must be signed in to change notification settings - Fork 390
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
Fix gas estimations #5973
Fix gas estimations #5973
Conversation
- No change on test suite - Ignore cancellation token for now
This PR supersedes #5968. It seems that I introduced some error that I could not figure out how to fix, so I created a new branch with the same changes. Now, all test pass successfully without need for change. I'll migrate the comments from the original PR to this one to facilitate work for future maintainers. |
About gas estimation: When a user triggers a Here is (or was) the buggy code: If the This PR limits the tx |
A different problem regarding gas estimations comes when a contract performs arbitrary checks on the remaining gas, like in #5637. Here, the contract used makes the following check: require(gasleft() >= safeTxGas, "Not enough gas to execute safe transaction"); If the remaining gas doesn't satisfy the condition, execution halts and all changes get reverted, but importantly, this does not fail with an Here, there are as far as I can tell two options:
|
long intrinsicGas = tx.GasLimit - gasTracer.IntrinsicGasAt; | ||
if (tx.GasLimit > header.GasLimit) | ||
tx.SenderAddress ??= Address.Zero; // If sender is not specified, use zero address. | ||
tx.GasLimit = Math.Min(tx.GasLimit, header.GasLimit); // Limit Gas to the header |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: Geth uses the gas value provided by the user as long as it's at least the minimum amount of gas required by any Tx (21_000
), or the block gas limit by default (so in this case, 30_000_000
).
It seems it was opted to go for The suggestion to change the contract is also weird, as it would mean changing the require to an assert. This is a change with a high impact as the gas costs for wrongly estimated txs increases. It would be nice to have more insights why it was chosen to not "fix" the nethermind client to behave the same way as other clients. Edit: the 4337 entrypoint has similar logic. Not sure if it was tested if this causes estimation issues. |
The explanation on why we decided to not spend more time with "safe transactions" is that the error when executing a contract like this is not an "OutOfGas" error, but a For a technical explanation, Nethermind (like Geth) uses a binary search to determine the optimal amount of gas to use in a transaction, where the lower bound is the minimum amount of gas per transaction, and the upper bound a value provided by the user, or the next block gas limit. Let's assume that the lower bound is 10, and upper bound is 90 to make the math simpler. On a first try, Nethermind will try to run the Tx with Is important to note that Another small example would be a contract that does the following: require(gasleft() >= y, "Too little gas");
require(gasleft() < y, "Too much gas"); This contract will never be executed, so what should the gas estimation be here?
Our options are either:
We decided to not change the semantics of the call, neither we want to make gas estimations take an unacceptable amount of time. I hope I could provide enough details on why we made this decision. |
I get your reasoning, but we see this error exclusively with Nethermind. Geth, Erigon and the old OpenEthereum clients provide correct estimates. This means we have to add special handling for Nethermind nodes. So my question is why does it work for the other nodes, but not for Nethermind. We would love to understand this as we evaluated Nethermind to be one of the nodes we request from network providers for tracing purposes, but if the estimation doesn't work then this would be a blocker for us.
An error should be returned that this transaction cannot be estimated (as it is done by other clients too).
This is exactly the difference. Geth looks for a value where it doesn't get an error (not matter if a revert error or any else). Looking at the estimate function of Geth we can see a Edit: |
Fixes #5706
Changes
Types of changes
What types of changes does your code introduce?
Testing
Requires testing
If yes, did you write tests?
Notes on testing
Some tests were updated to reflect the behavior changes.
Documentation
Requires documentation update
Requires explanation in Release Notes
Remarks
The code for Gas estimation is still very complex compared to the competition (see
go-ethereum
implementation: https://github.com/ethereum/go-ethereum/blob/2274a03e339f213361453590b54917bbfd0a0c31/internal/ethapi/api.go#L1137). A refactor would be highly suggested.