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

2023-07-19-solidity-0.8.21-release-announcement.md #13

Merged
merged 23 commits into from
Jul 19, 2023

Conversation

NunoFilipeSantos
Copy link
Contributor

No description provided.

@cameel
Copy link
Member

cameel commented Jul 19, 2023

@NunoFilipeSantos Here's the snippet about minimal optimizations:

### Stack-to-memory mover always enabled via IR

The release addresses the the issue of unoptimized code produced by the IR-based code generation pipeline being overly prone to "Stack Too Deep" errors.
This is meant to help tools such as debuggers, which lose much of their effectiveness when working with optimized code.

The legacy pipeline can often avoid running out of reachable stack slots even in unoptimized mode, but this comes at the cost of higher complexity since many optimizations are hard-coded as a part of code generation.
The new pipeline was designed from the beginning with the goal of separating these two concerns.
It produces straightforward, but very inefficient output that is meant to be refined in discrete steps by Yul optimizer.
The transformation performed by each step can be verified and reasoned about in isolation.
The downside of this approach is that unoptimized code very often has lots of unused local variables and runs into stack issues.

Our solution is to pass the unoptimized code though minimal transformations that help with stack issues, but do not change it in significant ways like full optimization would.
Specifically, the compiler will now run [`UnusedPruner`](https://docs.soliditylang.org/en/v0.8.21/internals/optimizer.html#unused-pruner) optimizer step on such code to remove unused variables.
In addition, the stack-to-memory mover mechanism is now always enabled, which will resolve remaining stack issues, though at the cost of extra memory accesses.

Both of these things were already possible to achieve through existing optimizer settings, but were not a part of the default behavior.
Despite technically involving the optimizer module, we consider them an essential part of the new pipeline, and the new baseline for what unoptimized code means.

@NunoFilipeSantos
Copy link
Contributor Author

@NunoFilipeSantos Here's the snippet about minimal optimizations:

### Stack-to-memory mover always enabled via IR

The release addresses the the issue of unoptimized code produced by the IR-based code generation pipeline being overly prone to "Stack Too Deep" errors.
This is meant to help tools such as debuggers, which lose much of their effectiveness when working with optimized code.

The legacy pipeline can often avoid running out of reachable stack slots even in unoptimized mode, but this comes at the cost of higher complexity since many optimizations are hard-coded as a part of code generation.
The new pipeline was designed from the beginning with the goal of separating these two concerns.
It produces straightforward, but very inefficient output that is meant to be refined in discrete steps by Yul optimizer.
The transformation performed by each step can be verified and reasoned about in isolation.
The downside of this approach is that unoptimized code very often has lots of unused local variables and runs into stack issues.

Our solution is to pass the unoptimized code though minimal transformations that help with stack issues, but do not change it in significant ways like full optimization would.
Specifically, the compiler will now run [`UnusedPruner`](https://docs.soliditylang.org/en/v0.8.21/internals/optimizer.html#unused-pruner) optimizer step on such code to remove unused variables.
In addition, the stack-to-memory mover mechanism is now always enabled, which will resolve remaining stack issues, though at the cost of extra memory accesses.

Both of these things were already possible to achieve through existing optimizer settings, but were not a part of the default behavior.
Despite technically involving the optimizer module, we consider them an essential part of the new pipeline, and the new baseline for what unoptimized code means.

Where do you want it? Notable features?

@cameel
Copy link
Member

cameel commented Jul 19, 2023

Yeah, I guess that would be a good place to put it.

@nikola-matic
Copy link
Contributor

nikola-matic commented Jul 19, 2023

@cameel does this make sense?

### Relax restrictions on immutable initialization

Given the several bugs that were found in the past few months where our checks for immutable initialization were not up to par, and thus allowed several edge cases where said immutables could remain uninitialized (e.g. branches of ``try/catch`` blocks, ``for`` loops, etc.), we have decided to significantly relax restrictions on the initialization of immutables.

Whilst immutables can still only be explicitly initialized in the constructor, this initialization is now optional, as all immutables will be default (zero) initialized regardless. We have also decided to lift the *assign once* restriction, which means you may now assign to an immutable more than once, with the last assignment being retained:

```solidity
contract C
{
    uint256 public immutable foo = 1;
    
    constructor()
    {
        foo = 2;
        foo = 3;
    }
}
```

It is however important to note that we are relaxing these restrictions because the checks were ultimately there for consistency, and not for security reasons, due to artificially imposing *deployed* contract immutability checks to contract creation. While some restrictions still remain - such as initialization of immutables in functions and modifiers - we hope to eventually drop these as well.

@cameel
Copy link
Member

cameel commented Jul 19, 2023

@NunoFilipeSantos Here's another:

### Bug affecting the reproducibility of unoptimized bytecode from the IR pipeline

The release fixes a minor bug in the IR-based code generator, which resulted in different (but functionally equivalent) bytecode being produced depending on how the compiler binary was built.
In particular, binaries built using the Clang C++ compiler would in certain situations order Yul functions differently than ones built with GCC.
The case the triggers the bug is indexing of memory arrays.
This results in multiple Yul helpers being generated, in order depending on the C++ compiler.

The bug affected only unoptimized code generated by the IR pipeline, i.e. required the use of `settings.viaIR` in Standard JSON or the `--via-ir` flag on the CLI.
The use of Yul optimizer nullifies its effects since it reorders the functions.

The bug affects the official binaries provided in [solc-bin](https://github.com/ethereum/solc-bin/).
The emscripten and macOS binaries are built with Clang, Linux binaries with GCC and Windows ones with MSVC.
It is recommended that tools performing source verification of contracts take into account the possibility of the deployed contract being produced by either of these binaries.

@NunoFilipeSantos
Copy link
Contributor Author

@NunoFilipeSantos Here's another:

### Bug affecting the reproducibility of unoptimized bytecode from the IR pipeline

The release fixes a minor bug in the IR-based code generator, which resulted in different (but functionally equivalent) bytecode being produced depending on how the compiler binary was built.
In particular, binaries built using the Clang C++ compiler would in certain situations order Yul functions differently than ones built with GCC.
The case the triggers the bug is indexing of memory arrays.
This results in multiple Yul helpers being generated, in order depending on the C++ compiler.

The bug affected only unoptimized code generated by the IR pipeline, i.e. required the use of `settings.viaIR` in Standard JSON or the `--via-ir` flag on the CLI.
The use of Yul optimizer nullifies its effects since it reorders the functions.

The bug affects the official binaries provided in [solc-bin](https://github.com/ethereum/solc-bin/).
The emscripten and macOS binaries are built with Clang, Linux binaries with GCC and Windows ones with MSVC.
It is recommended that tools performing source verification of contracts take into account the possibility of the deployed contract being produced by either of these binaries.

Should I add it to the Stack-to-memory mover always enabled via-IR section?

@cameel
Copy link
Member

cameel commented Jul 19, 2023

No, it's a separate thing.

It actually should have a separate section, since it's not even a feature. More like warning for tooling people.

@cameel
Copy link
Member

cameel commented Jul 19, 2023

It expands on this bugfix:

- Code Generator: Fix not entirely deterministic order of functions in unoptimized Yul output. The choice of C++ compiler in some cases would result in different (but equivalent) bytecode (especially from native binaries vs emscripten binaries).

The stack-to-memory mover is about this compiler feature:

- Yul Optimizer: Stack-to-memory mover is now enabled by default whenever possible for via IR code generation and pure Yul compilation.

and @nikola-matic's bit is about this language feature:

- Relax restrictions on initialization of immutable variables. Reads and writes may now happen at any point at construction time outside of functions and modifiers. Explicit initialization is no longer mandatory.

They're all separate.

@NunoFilipeSantos NunoFilipeSantos marked this pull request as ready for review July 19, 2023 17:14
Copy link
Member

@cameel cameel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small adjustments to the part about immutables. Other than that looks good.

Co-authored-by: Kamil Śliwak <cameel2@gmail.com>
NunoFilipeSantos and others added 3 commits July 19, 2023 19:06
Co-authored-by: Kamil Śliwak <cameel2@gmail.com>
Co-authored-by: Nikola Matić <nikola.matic@ethereum.org>
Co-authored-by: Nikola Matić <nikola.matic@ethereum.org>
@NunoFilipeSantos NunoFilipeSantos merged commit 5065687 into main Jul 19, 2023
@wackerow wackerow deleted the NunoFilipeSantos-patch-1 branch July 20, 2023 20:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

3 participants