-
Notifications
You must be signed in to change notification settings - Fork 5.7k
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
full function signature string and hash, not just selector #14360
Comments
This issue has been marked as stale due to inactivity for the last 90 days. |
still looking for feedback on this |
This issue has been marked as stale due to inactivity for the last 90 days. |
Hi everyone! This issue has been automatically closed due to inactivity. |
Abstract
We already have
function.selector
to get the 4 byte selector of some function (https://docs.soliditylang.org/en/v0.8.20/abi-spec.html#abi-function-selector).This selector is fine for collision resistance within a single contract.
For cross referencing against signature databases such as https://openchain.xyz/signatures which are open registries of signature across all possible contract, the collision resistance is too low.
It's not difficult to find selectors that collide in these databases, especially when the selectors have been clearly crafted deliberately to collide (e.g. https://openchain.xyz/signatures?query=0x00000000).
Best would be exposing the source data (abi function signature string) and perhaps intermediate step (the 32 byte hash) that goes into computing a selector in the first place, so that smart contract devs have more flexibility here.
Motivation
When applying a pattern of generic support for arbitrary data (my use case is wanting to have initializable proxy/clone contracts with
bytes memory data
as the signature ofinitialize
) the caller often needs to know the ABI in order to encode this data.In the case of a generic tool, it's unlikely that the ABI for any arbitrary contract is available. However, often signature are uploaded to signature databases, which provide just enough information to encode some bytes correctly. The response from the signature database won't contain any quality of life information, not even a name or basic description of what each value in the signature is, but at least the tooling could understand something about the structure of the bytes.
This pattern is known and has been discussed https://twitter.com/PatrickAlphaC/status/1517156225670078465
ERC-5750 even specifies that
bytes memory data
is a desirable extension method that interfaces should be compliant with in order to future proof themselves https://eips.ethereum.org/EIPS/eip-5750For example, it specifies that data can be passed to a callback. The callback may well treat the data as an encoded function to call, such as might be found in the callback of an EIP 3156 flash borrower
onFlashLoan
(where opaque bytes are shuffled around between lender/borrower and need to somehow drive the borrower to take action then repay the loan), or some kind of governance contract, etc.However, 5750 stops short of specifying how an individual contract can permissionlessly advertise exactly how that extension point should be consumed. For situations where the bytes encoding matches some function signature, one could imagine a simple solution where the function selector (available in solidity) of the extension data is emitted as an event, or available as a read only function on an interface.
But then, imagine that someone sees your contract advertising a mere 4 byte selector as the structure of its extensible data, then maliciously griefs you by generating and advertising the same selector into a signature database with a completely different ABI. At this point, automated tooling is faced with ambiguity as to how it might encode bytes. Had your contract emitted the full hash of the signature, or the string of the function signature itself, then such an attack would not be possible.
The signatures can be crafted manually with strings and keccaks in contract code, but this is fragile to do manually, especially for more complex types such as nested structs. Without going fully down the route of proposing another ERC to define all the above, Solidity could easily provide the function signature string and/or hash natively alongside the existing
selector
feature. If this pattern becomes sufficiently popular and adopted, some future ERC might naturally coalesce, in the meantime, anyone who wants this kind of thing can implement it themselves.The motivation of avoiding manual/fragile code here is essentially the same as when
selector
was originally introducedNote also that the original conversations around "function signature" vs. "cryptographic signature" being confusing still apply. We would need to be clear to disambiguate in any naming proposed.
Specification
Two new properties on interface methods, events and errors:
.abiFunctionSignature
=> canonical string of the signature e.g."foo(uint256)"
.fullSelector
=> equivalent tokeccak256(foo.abiFunctionSignature)
but perhaps more semantic and efficient as it can be reliably computed at compile time, it's exactly the 32 bytes that are normally truncated down to 4 bytes to compute.selector
Technically either one of these can be implemented without the other, although if I had to choose only one I'd pick the string representation as we can always do the hashing ourselves, but we can't go back the other way without some kind of registry service. Not enforcing the need for a registry, so that kind of thing would be opt in, seems like it can only be a good thing.
Backwards Compatibility
No backwards compatibility issues.
The text was updated successfully, but these errors were encountered: