-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
Move away from INVALID and use custom error types instead. #9824
Comments
I'm really not sure if that's a good idea :-) - but we could for each of them introduce an integer-encoded error code that explains what happens... But yeah - while it would be a cheap and nice way to be both coarse and fine-grained in error reporting... maintaining a list of this that then will never break would probably drive us mad :-). |
While this is a good idea, still the main question is if such a distinction is useful. What you want to know is in which context the error happened and not what kind of error happened. Note that since we have error forwarding, it can also have happened inside a called contract. |
I think it is kind of set that we want to be able to distinguish between |
The reason behind using |
I think that it's dangerous to allow handling For that reason maybe it would make more sense to just reclassify overflow/underflow as something allowed to happen? They stand out to me as the only case where checks are tricky enough to make users not want to validate the input explicitly. |
You can switch from checked to wrapping arithmetic using the |
Because of that, I think catching an error and especially reacting on it depending on the reason has a very limited use-case. |
But if I switch to The use case for catching a |
I still don't properly understand the use-case, but I do want fine-grained error codes, just as a second step to make quicker progress on this. |
We could add But I don't have a specific use case so it might well be that this is not relevant in practical use. It's just my general opinion that silencing stuff in a broad way is a bad practice and this approach might encourage it in some situations without giving the user an alternative. It's also that it's not clear to me how long the gap between the first and the second step will be and in the worst case we might be stuck with just the first one for quite some time. |
Got and email from Franziska Heintel about this topic. Replying here, as she requested.
Yes and yes. Awesome that this is being implemented.
This sounds good to me. As someone else mentioned on the email thread: it would be more convenient to also have a string description of what the error code means. Like you said 0 means "unknown panic". However, I'm assuming these codes will be clearly documented on https://solidity.readthedocs.io/ so if one doesn't know the code, they can quickly look it up. |
The following situations currently create an invalid opcode or a Panic in the future:
Note that the old code-generator still contains code that uses "invalid opcode". Suggestions for how to assign error codes:
|
I wonder whether we should be more generous and at least use 16 bits for it and reserve 256 slots in each category or even more... it's not like we don't have enough space in the uint256. Just, s.t. if we ever need a larger category, it's can still be the same part that designates the category. |
My motivation for staying within one byte is to save deployment gas costs. |
I would also be good to be able to identify abi decoding errors. Especially using abiencoder v2, there is usually quite a few paths that end at the decoding stage already if one doesn't specialize the calldata to a specific function signature. |
@MrChico abi decoding errors will either return no data or data with a signature of |
@chriseth The proposal looks good to me. The only change I would consider is not using |
In all of my time as a dapp developer I have never seen anyone care about contract deployment gas costs. Runtime gas costs are all that anyone I have talked to cares about. For deployment, either you are deploying a contract once (ever) or you are deploying multiple copies of a contract that has a very high per-contract value (where gas costs are negligible compared to what you are doing) or you are using a proxy. I have heard this argument of "to reduce deployment gas costs" come up multiple times from the Solidity dev team, and I would like to better understand where it comes from? Who are these people who care about deployment gas costs? What situation are they in where that is a thing that matters? |
@wuestholz this is a very good suggestion! It allows analysis tools to distinguish between explicit @MicahZoltu people are not worried about deployment gas costs, but they are worried about staying within the code size limit, so i think it is still reasonable to only use a single byte for the error code. |
@chriseth Great! Yeah, this would make things much easier for bytecode-only analysis tools. Thanks! |
For now, I allocated |
We briefly discussed today whether The answer to b) was yes. The answer to a) is that some prefer to do this via #9282 and also considering the "standard library". Please note one can manually encode the panics in inline assembly:
Also see a similar discussion about |
Note that "could use anything given we revert" is not true anymore if we want to properly support the stack limit evader. |
Well, as long as the |
Implemented in #10013 |
Since checked arithmetic might be used for input validation, the need to move away from the invalid opcode (which consumes all gas) is stronger once we make checked arithmetic the default.
The middle ground between just using
revert()
for all internal errors and using the invalid opcode is introducing different error types (#7877) forrevert()
and internal errors.The following situations currently or potentially in the future generate internal errors which we regard as "should never happen":
The following error situations are considered as "validating input" and thus might be OK to happen:
The bottom ones either use empty returndata or the signature of
Error(string)
if a reason was provided.We could create individual errors for the "should never happen" errors (and also for the others), but I would guess that people will not ant to react differently to each of them anyway (user-defined errors are a different matter).
So maybe we should just create a single error type that is used in that case? Should it contain a message?
Suggestions for the name:
Panic()
Failure()
Fault()
Critical()
CriticalError()
The text was updated successfully, but these errors were encountered: