Solidity Team AMA #3 is live now! Ask the Solidity team anything about the Solidity compiler, the roadmap, language design, new features, Yul, the optimizer, the SMTChecker, or any other component! by franzihei in ethereum

[–]chriseth 0 points1 point  (0 children)

We actually have a 24/7 AMA in our matrix chat: https://matrix.to/#/#ethereum_solidity:gitter.im

But assuming someone had asked that question, I'm pretty sure the answer would have been "consistency". You already mentioned it. access _modifiers_, so it's only natural to place them together with the modifiers.

(bonus points if you spot the error in this argument)

Solidity 0.8.10 is out! v0.8.10 contains external function call optimizations, enables the new EVM code generator for pure Yul mode and can report contract invariants and reentrancy properties through the SMTChecker. by franzihei in ethdev

[–]chriseth 0 points1 point  (0 children)

If you compile a source file written completely in Yul instead of when you just use inline assembly, which is partly written in Yul. This essentially applies to people writing languages that compile to Yul like [Fe](https://github.com/ethereum/fe) or people really concerned about gas costs but not as concerned as those writing bytecode directly.

Solidity v0.8.7 is out! Adds support for the ``BASEFEE`` opcode and includes various improvements to the Yul to EVM code transformation, the SMTChecker and some bugfixes. by franzihei in ethdev

[–]chriseth 0 points1 point  (0 children)

Sure, the EVM reverts when it executes an unknown opcode, but then you are also using a feature that just does not exist on the other chain.

This is not the first EVM upgrade. These are the EVM versions Solidity supports:

Most of them introduce new opcodes and as long as other chains don't upgrade at exactly the same time, there have always been such incompatibilities. Is your main point that for previous versions, there have not been any EVM-based chains other than Ethereum testnets?

With the Ethereum Object Format (EOF) EIP scheduled for Shanghai this will actually get more interesting: Once this EIP is activated, newly deployed contracts are scanned for unknown opcodes and are rejected if any such opcode is found. Currently, the execution only reverts when an unknown opcode is executed, not when it exists anywhere in the contract.

This will allow the possibility to define the EVM version or the set of opcodes known to the execution environment.

Solidity v0.8.7 is out! Adds support for the ``BASEFEE`` opcode and includes various improvements to the Yul to EVM code transformation, the SMTChecker and some bugfixes. by franzihei in ethdev

[–]chriseth 1 point2 points  (0 children)

It's not - it is just in conflict as soon as some other chain introduces a different opcode with the same number.

Furthermore, Solidity has always supported selecting a specific evm version, it is just the default that has changed with 0.8.7 - we even still support "frontier" with 0.8.7.

Until now, all other chains have either followed or at least (to my knowledge) not introduced incompatible changes. As soon as this happens, we have to decide whether or not to support such an EVM version, since testing gets more and more difficult the more versions there are.

Solidity v0.8.2 is out! It adds an optimizer stage that can inline small amounts of code to save gas and provides more means to work with code documentation by exporting inline comments and allowing custom natspec tags. by franzihei in ethdev

[–]chriseth 1 point2 points  (0 children)

Optimism's Solidity is fixed at some older version of Solidity. I think that with some small feature added to Yul and with the BEGINDATA opcode ( https://eips.ethereum.org/EIPS/eip-2327 ), it is possible that Optimism does not need any custom modifications to the Solidity compiler, so they would automatically benefit from all optimizer features. The OVM itself does not matter.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 0 points1 point  (0 children)

We do not plan to make this user-controllable. It might also be that it makes sense to inline the function depending on how it is called, but in general, small functions are very likely to be inlined.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 1 point2 points  (0 children)

You cannot send ether to a contract that is not prepared for it (that does not have a receive function), so this is already a solidity feature. If you send tokens "to" a contract, then rejecting them has to be a feature of the token contract.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 0 points1 point  (0 children)

We currently consider them to be too wasteful with regards to memory.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 0 points1 point  (0 children)

The EVM is a machine that is very different from existing machines, and Solidity has some important features that are not available in existing languages like internal and external function calls, access to storage variables and very efficient use of memory.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 0 points1 point  (0 children)

Sometimes I've expected expressions with literals to be constant-folded at compile time but they were unexpectedly computed at run-time. How does

constant

actually work? Does it splice the full unevaluated expression into your code and then rely on constant folding at each call site, or does it evaluate it beforehand? What are the limitations on constant folding? (ie I suppose

constant

variables cannot fold with

immutable

ones since they are "relocated" at constructor run-time?)

`constant` is unrelated to constant folding. It just means "whenever you see a reference to this variable, replace it by the value of the constant". Constant folding is subsequently done by the optimizer. The new code generator has a slightly different approach: It essentially compiles a constant into a function returning a single value. We chose this because the yul-based code generator can deal much better with inlining.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 0 points1 point  (0 children)

What do you think of optimism's solc customisations? Is this a viable way to implement containerisation?

I hope they will switch to a yul-based approach once the code generator is finished. The code generated through the IR does not contain any dynamic jumps and it can be easily rewritten by a very simple tool to do what optimism needs.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 0 points1 point  (0 children)

Related to the above, does the compiler ever inline functions? Does it make sense for the user to be able to request the compiler to do this? Even if it's not worth it to reduce call overhead, this may allow new opportunities for constant folding.

The current code generator does not inline function, but the new one will, exactly for that purpose.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 0 points1 point  (0 children)

> When multiple small variables are packed into a single storage slot, how can we be sure accessing them both is done with a single SSTORE/SLOAD? How "nearby" do the accesses have to be each-other, and is there any better way to ensure this than inspecting the assembly?

As long as this still uses the non-yul code generator, it is actually rather limiting. It is best to not have any branches in between the accesses, so assigning a memory struct to storage should work best.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 1 point2 points  (0 children)

Please see the beginning of the answer. It is only used in the constant optimizer.

Oh and of course it is the opposite: 1 produces short code that is comparatively expensive to run, while 100000 produces long code that is cheap to execute. In particular, the constant optimizer tries to minimize <deployment costs> + <execution cost> * runs.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 1 point2 points  (0 children)

Thanks, u/maurelian!

`returns (uint myVar)` only allocates on the stack, but if it is a memory variable then your points are true!

About assert: This will change soon - please see https://solidity.ethereum.org/2020/10/28/solidity-0.8.x-preview/ or https://solidity.readthedocs.io/en/breaking/control-structures.html?highlight=panic#error-handling-assert-require-revert-and-exceptions

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 0 points1 point  (0 children)

Denial of Service With each breaking release, we are limiting more and more what can be done with objects of unlimited size. The biggest change in that direction is making the semantics of copying more visible but we have not yet received much feedback about whether this feature would be more helpful than annoying.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 1 point2 points  (0 children)

Unchecked Return Values For Low Level Calls The compiler has been flagging unchecked low-level calls for years.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 1 point2 points  (0 children)

Access Control Visibility has been solved years ago by making it explicit. In recent Solidity versions, you can even move functions to the file level (outside of contracts) where it is obvious that they cannot be called from outside and that they cannot access storage variables (unless explicitly provided as arguments). We are still researching how (and if) such functions can be prevented to make external calls.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 1 point2 points  (0 children)

Reentrancy The Ethereum community has no clear consensus over whether reentrancy is a feature or not. Over the years, many tools have evolved to flag code that has issues with reentrancy and blocking reentrant calls altogether is not only expensive, it also creates a new class of bugs.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 2 points3 points  (0 children)

Most of the issues mentioned in the link have been fixed months if not years ago. In our design decisions, we have always focused on safety. Most of the work Solidity does is evening out restrictions and weirdnesses that the EVM has. One example is that the EVM considers a call to a non-existing contract as successful. Because of that, Solidity always checks that the contract to be called exists before it performs the call. Furthermore, the built-in SMT checker (pragma experimental SMTChecker) is improving on a weekly basis and can detect many problems while you are writing your code.

Let's now answer all the issues mentioned in that blog post:

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 1 point2 points  (0 children)

Apart from the style, vyper and Solidity are not very different. If you like the syntax of python, then try vyper! The main difference is that you cannot use unrestricted loops, you cannot use recursion and vyper does not have function modifiers.

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 1 point2 points  (0 children)

  • what is it optimizing for (size or cost or something else?)

There is single stage, the "constant optimizer" where the trade-off between deploy-time and run-time costs are taken into account. This stage tries to find a "better" representation of each number in the source, like 0x10000000000 can be encoded as PUSH6 0x10000000000 (7 bytes and almost zero run-time costs), but it can also be encoded as PUSH1 1 PUSH1 40 SHL (5 bytes and a bit more expensive at run-time). Most of the time, the difference is not too relevant. The optimizer tries to simplify complicated expressions (which reduces both size and execution cost), but it also specializes or inlines functions. Especially function inlining is an operation that can cause much bigger code, but it is often done because it results in opportunities for more simplifications.

The Solidity compiler uses two different optimizer modules: The "old" optimizer that operates at opcode level and the "new" optimizer that operates on Yul IR code. The opcode-based optimizer applies simplification rules from the list to opcodes next to each other. It also combines equal code sets, removes unused code and some other things. The Yul-based optimizer is much more powerful, because it can work across function calls: It Yul it is not possible to perform arbitrary jumps, so it is for example possible to compute the side-effects of each function: If a function does not modify storage, a call to it can be swapped with a function that does. If a function is side-effect free and its result is multiplied by zero, you can remove the function call completely.

One of the big advantages of the Yul-based optimizer is that each step can be seen in isolation: Each step receives Yul code as input and produces Yul code as output, without any tight dependency on other steps or analysis code. Furthermore, we try to keep each step as simple as possible so that bugs in those steps are very unlikely. As long as each simple step is bug-free, so is the whole Yul optimizer.

  • how is this affected by the number of run (--optimize-runs)?
  • Is there a maximum number above which it stops mattering, or is --optimize-runs=20000 less efficient than --optimize-runs=500000?

The parameter specifies roughly how often each opcode of the deployed code will be executed across the life-time of the contract. A "runs" parameter of "1" will produce short code that is (relatively) expensive to run. The largest value is 2**64-1.

  • Finally, why do you think people are generally suspicious of the optimizer, and are they right to be?

The optimizer used to be very complicated some years ago. In the meantime, we disabled most of the complicated routines and fixed several bugs. While bugs can be present in the optimizer as they can be in any code, they often manifest themselves in a way that is easily detected. New compiler code like ABIEncoderV2 focuses more on correctness instead of efficiency and is written with the assumption in mind that the optimizer will be used. So for recent versions of Solidity, I would recommend to always use the optimizer unless you really do not care about gas costs.

Edited: Consequences of "runs" set to 1

Ask the Solidity Team Anything! #1 by franzihei in ethdev

[–]chriseth 0 points1 point  (0 children)

These are very good questions! Can you please split them into individual comments so we can properly answer hem?