Skip to content
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

Constant expression evaluation at compile time #3157

Open
axic opened this issue Oct 30, 2017 · 10 comments
Open

Constant expression evaluation at compile time #3157

axic opened this issue Oct 30, 2017 · 10 comments
Labels
epic effort Multi-stage task that may require coordination between team members across multiple PRs. high impact Changes are very prominent and affect users or the project in a major way. needs design The proposal is too vague to be implemented right away selected for development It's on our short-term development

Comments

@axic
Copy link
Member

axic commented Oct 30, 2017

Variables can be declared constant which allows:

  • literals
  • (arithmetic) expressions
  • and function calls to "pure" functions, which is a hardcoded list of: keccak256, ecrecover, sha256, ripemd160, addmod, mulmod, new (for creating objects only, such as arrays)

Currently whenever a constant expression is used, the entire expression is placed into the output. This is of course reduced/optimised, but that is mostly restricted to operations on literals and some edge cases.

We should consider one or more of the following:

  1. split constant into two, constant which only allows literals and constexpr which allows more complex expressions
  2. do not allow "pure functions" above which result in a call (ecrecover, sha256, ripemd160)
  3. allow every pure function, not only the above subset
  4. evaluate constant or constexpr in a VM during compilation time and use the result only (this VM could be a subset of the EVM, since many features are not required)

Obviously 2 and 3 contradict eachother. I would opt for 2. unless 4. is implemented and then 3. could be allowed.

Somewhat relevant is #715.

@ekpyron
Copy link
Member

ekpyron commented Aug 4, 2020

I, by the way, vote for finally starting with this at least soonish...

@axic
Copy link
Member Author

axic commented Aug 4, 2020

Should we consider C++-style literals and use them in expressions, such as "stringtobehashed"_keccak256 instead of the built in function?

@ekpyron
Copy link
Member

ekpyron commented Aug 4, 2020

Going forward I'd very much like for this to work even for user-defined pure functions, e.g.

function weirdStuff(uint256 x, uint256 y) public pure returns(uint256) { return 2**4 - 3 * x / y; }
uint256[weirdStuff(1,2)] x;

Or even stuff like

function weirdStuff(bytes memory x) public pure returns(uint256 s) { for (uint256 i = 0; i < x.length; ++i) s += x[i]; }
uint256[weirdStuff(hex"12345678")] x;

Not in a first step for sure, but eventually...
So given that, I'd personally not see much need to distinguish that much between compile time constant string literal things and function calls.

@chriseth
Copy link
Contributor

chriseth commented Aug 4, 2020

Is it in any way possible to compile this via yul and run it through an interpreter? Then we would at least not have to re-implement everything.

@ekpyron
Copy link
Member

ekpyron commented Aug 4, 2020

Why not?

@aarlt
Copy link
Member

aarlt commented Aug 31, 2020

We should definitely allow compile-time evaluation of user-defined pure functions.

@cameel
Copy link
Member

cameel commented Apr 12, 2022

Some things that we might want to explicitly add to the list of stuff that should be evaluated a compilation time:

  • Constant expressions involving type conversions.
  • Ternary operator with constant expressions as arguments.
  • Indexing an array literal with a constant expression.
  • type(...).min and type(...).max

@cameel
Copy link
Member

cameel commented Jul 26, 2022

Another case that might be of practical interest, brought up by @nventuro:

  • keccak256(type(ERC20).creationCode)
  • keccak256(abi.encodePacked(type(ERC20).creationCode, "hello how are you"))

This is useful in CREATE2 address calculation, when constructor args are known constants. Currently this is done by copying the whole bytecode to memory, which is very inefficient.

@nventuro
Copy link
Contributor

This is useful in CREATE2 address calculation, when constructor args are known constants. Currently this is done by copying the whole bytecode to memory, which is very inefficient.

Note that mine was just a toy example - a real use case would have non-constant constructor arguments. I'm not sure there's many use cases for the one you mention.

@cameel
Copy link
Member

cameel commented Jul 27, 2022

ok, right. We should still have things like this handled as a part of this mechanism but I guess you're right, constant arguments for this are likely not very common.

@cameel cameel added selected for development It's on our short-term development epic effort Multi-stage task that may require coordination between team members across multiple PRs. high impact Changes are very prominent and affect users or the project in a major way. needs design The proposal is too vague to be implemented right away labels Sep 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
epic effort Multi-stage task that may require coordination between team members across multiple PRs. high impact Changes are very prominent and affect users or the project in a major way. needs design The proposal is too vague to be implemented right away selected for development It's on our short-term development
Projects
None yet
Development

No branches or pull requests

7 participants