-
Notifications
You must be signed in to change notification settings - Fork 11.8k
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
Behavior of ERC165Checker when less than 30k gas available #1750
Comments
Hello @wighawag, thank you for reporting this! How would you suggest to change the implementation? If, as you've mentioned, that function is called with less than 30k gas available, then the execution will error out with an 'out of gas' error, which is different from a regular revert. However, if there's indeed not enough gas, what could the contract do, other than erroring out early? |
Hi @nventuro I mention various solution available today on EIP-1930 as well as on EIP-165 discussion It can
But the best solution is to add functionality in the EVM for that : see EIP-1930 |
What is the intent behind this? What should a contract do if it has less than 30k gas available to make the call?
30k will be sent if they are available: the only way for the implementer to quit early is if the transaction doesn't have enough gas, in which case the caller will revert with an out of gas error. |
where E is the gas required for the operations between the call to For the intent, the idea is that if
While it is unlikely in the context of ERC-165 I wanted to make it clear that the "after-the-call" check does not work if the implementer of |
Thanks for bringing this up @wighawag. Super interesting.
To be clear, by "gas pricing" you mean the gas cost of each opcode, right? |
I'm looking at the EIP and it seems rather clear that a reverting
Note how the second list doesn't mention anything about a failing call. This impies that reverts must be propagated. So there are two bugs in our implementation:
|
The second bug is easy to fix. The first one is the tricky one.
@wighawag In this case it is the implementer who is buggy. Because of the following line from the EIP:
This implies that if the implementer indeed does With this in mind, do you think an after-the-call check would work? I will give this a bit more thought and get back. |
Thanks for reporting this @wighawag, I had forgotten about the 63/64ths rule. In the worst case, a contract needs 30k gas to execute its function, and is provided only 29,999. This means that the caller will end up with 476 gas ( |
Pasting here @wighawag's suggestion from ethereum/EIPs#881 (comment):
Given the considerations above, I think this is the best course of action. |
@frangio is the idea behind that check to not require the caller tx to have over 30k gas? Shouldn't we also only revert if the call failed? i.e. if the call failed and it possibly run out of gas (there's less than 30k/63 remaining), then we revert. |
Yes. Why "possibly" though? |
A call may return with less than that value and not have reverted, or It may have reverted for a different reason. |
Technically we can assume that the implementer will use at most 30000 gas. So we could send like 30001 (or a similarly small value), and then we can be sure that if there is less than 30k/64 we can assume that it was an out of gas error. I really am not sure about all these numbers though. I need to sit down and think them through. |
...but the whole point of this is what happens when less than 30k are sent? And a post-check will not know how much was actually sent. |
yes that's what I meant
That's true, but this is not very clear since it does not mention the 30,000 rules neither here
Possibly but the Also it is worth noting that an
The thing is that the caller might not have to do anything. I actually discovered the bug while I was investigating the use of 165 for token receiver in #1155 the context is that a contract that want to act on token reception must implement The logic for the caller could be (like in the case of an
The last step could be doing nothing else, just returning, this is where it does not need much gas. |
That requirement is mentioned in the general description for `supportsInterface:
|
What I meant is that the 2nd list is less clear, it could have at least said "call supportsInterface(interfaceID) with at least 30,000 gas" I agree though that your interpretation is correct. |
This is still an issue but I don't believe it would be right to encode the 63/64ths rule in the Solidity code. I think this is just a limitation that users of this EIP have to consider. It needs to be documented. |
if this issued is solved then we can close the issue. |
EIP-165 stipulate that
supportsInterface
can use up to 30,000 gas.But as you can see in openzeppelin implementation here, the call is executed without making sure 30,000 gas is indeed given to the call. Remember, the gas provided as part of the STATIC_CALL is just a maximum.
And because of EIP-150 behaviour, it is possible for
supportsInterface
to get less gas than required for it to complete (and thus throw which is interpreted wrongly as non-implementation) while the rest of the transaction continue and complete.I described the issue in more details here as the issue is also present in the example implementation described at EIP-165.
Various solution are presented here but the best option is EIP-1930 which also solve issue present in other use cases like meta-transactions.
Also find some test case regarding EIP-165 here
The text was updated successfully, but these errors were encountered: