Solidity 0.8.0 Release Announcement
source link: https://blog.soliditylang.org/2020/12/16/solidity-v0.8.0-release-announcement/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Solidity 0.8.0 is a breaking release of the Solidity compiler and language.
Some of the new features of this release have been elaborated in the 0.8.x preview release post. Please consider the preview release binary superseded and do not use it anymore.
Notable New Features and Changes
As per ususal, this breaking release does not include many features but rather changes that require a backwards-incompatible adjustment in syntax or semantics. For a detailed explanation, please see the documentation.
The change that will affect most users is that arithmetic operations are now checked by default,
which means that overflow and underflow will cause a revert. This feature can be disabled locally by using an unchecked
block.
The second change that is very visible is that the ABI coder v2 is activated by default. You can
activate the old coder using pragma abicoder v1
, or explicitly select v2
using pragma abicoder v2
- which has the same effect as pragma experimental ABIEncoderV2
had.
ABI coder v2 is more complex than v1 but also performs additional checks on the input and supports
a larger set of types than v1.
Furthermore, internal errors like division by zero, assertion failure and others
do not use the invalid opcode anymore, but use revert
with a special error message,
in order to not waste gas in such situations.
Another important change is that we restricted the possibilities of explicit conversions to avoid ambiguities. All conversions that were possible before are still possible, but you might have to perform two conversions to get there - which does not affect the generated code, though.
These are only some of the important breaking changes in 0.8.0, please refer to the changelog below for the full list!
Checked Arithmetic
The “Checked Arithmetic” feature of Solidity 0.8.x consists of three sub-features:
- Revert on assertion failures and similar conditions instead of using the invalid opcode.
- Checked arithmetic, i.e., revert on overflows, underflows etc.
unchecked
blocks.
Revert on assertion failures and similar conditions instead of using the invalid opcode
Previously, internal errors like division by zero, failing assertions, array access out of bounds,
etc., would result in an invalid opcode being executed. The idea was to distinguish
these more critical errors from non-critical errors that lie outside of the domain
of the Smart Contract programmer like invalid input, not enough balance for a token transfer,
and so on. These non-critical errors use the revert
opcode and optionally add an error description.
The problem with the invalid opcode is that, in contrast to the revert
opcode, it consumes all gas available.
This makes it very expensive and you should try to avoid it at all cost.
We wanted to consider arithmetic overflow as a critical error, but did not want to cause it to consume all gas.
As a middle ground, we chose to use the revert
opcode, but provide different error data
so that static (and dynamic) analysis tools can easily distinguish them.
More specifically:
- Non-critical errors will revert either with empty error data or with error data that
corresponds to the ABI-encoding of a function call to a function with the signature
Error(string)
. - Critical errors revert with error data that corresponds to the ABI-encoding of a function call
to a function with the signature
Panic(uint256)
.
Because of that, we also use the term “panic” for such critical errors.
To distinguish the two situations, you can take a look at the first four bytes of the return data in case
of a failure. If it is 0x4e487b71
, then it is a panic, if it is 0x08c379a0
or if the message is empty, it is a “regular” error.
Panics use specific error codes to distinguish certain situations in which the panic is triggered. This is the current list of error codes:
- 0x01: If you call
assert
with an argument that evaluates to false. - 0x11: If an arithmetic operation results in underflow or overflow outside of an
unchecked { ... }
block. - 0x12: If you divide or divide modulo by zero (e.g.
5 / 0
or23 % 0
). - 0x21: If you convert a value that is too big or negative into an enum type.
- 0x22: If you access a storage byte array that is incorrectly encoded.
- 0x31: If you call
.pop()
on an empty array. - 0x32: If you access an array,
bytesN
or an array slice at an out-of-bounds or negative index (i.e.x[i]
wherei >= x.length
ori < 0
). - 0x41: If you allocate too much memory or create an array that is too large.
- 0x51: If you call a zero-initialized variable of internal function type.
This list of codes can be extended in the future.
Note that you currently cannot use try ... catch Panic(uint _code) { ... }
to catch a panic,
but this is planned for the near future.
Checked arithmetic, i.e., revert on overflows, underflows etc.
By default, all arithmetic operations will perform overflow and underflow checks
(Solidity already had division by zero checks). In case of an underflow or
overflow, a Panic(0x11)
error will be thrown and the call will revert.
The following code, for example, will trigger such an error:
contract C {
function f() public pure {
uint x = 0;
x--;
}
}
The checks are based on the actual type of the variable, so even if the result would fit
an EVM word of 256 bits, if your type is uint8
and if the result is larger than 255
,
it will trigger a Panic
.
We did not introduce checks for explicit type conversions from larger to smaller types, because we think that such checks might be unexpected. We would love to get your input on that matter!
The following operations (including their compound assignment versions like +=
) now have checks that they did not have before:
- addition (
+
), subtraction (-
), multiplication (*
) - increment and decrement (
++
/--
) - unary negation (
-
) - exponentiation (
**
) - division (see below) (
/
)
There are some edge cases you might not expect. For example, unary negation can trigger a panic on signed types. The problem is that in two’s complement representation, there is one more negative number for each bit width than there are positive numbers. This means that the following code will trigger a panic:
function f() pure {
int8 x = -128;
-x;
}
The reason is that 128
does not fit an 8-bit signed integer.
For the same reason, signed division can result in a panic:
function f() pure {
int8 x = -128;
x/(-1);
}
Everyone who wanted to write a SafeMath
function for exponentiation probably noticed
that it is rather expensive to do that because the EVM does not provide overflow signalling.
Essentially you have to implement your own exp
routine without using the exp
opcode
for the general case.
We hope that we found a rather efficient implementation and would also appreciate your feedback about that!
For many special cases, we actually implemented it using the exp
opcode instead of our own implementation.
More specifically, exponentiation operations that use a literal number as base will use the exp
opcode directly.
There are also specialized code paths for bases that are variables with small value. For bases up to 306,
if the exponent is smaller than a hard-coded safe upper bound, it will use the exp
opcode directly.
If the base or the exponent is too large, it might fall back to the loop-based implementation.
unchecked
Blocks
Since checked arithmetic uses more gas, as discussed in the previous section, and because there are times when you really want the wrapping behaviour, for example when implementing cryptographic routines, we provide a way to disable the checked arithmetic and re-enable the previous “wrapping” or “modulo” arithmetic:
All operations inside a block of the form unchecked { ... }
use wrapping arithmetic. You can use
this special block as a regular statement inside another block:
contract C {
function f() public pure returns (uint) {
uint x = 0;
unchecked { x--; }
return x;
}
}
An unchecked block can contain any number or any kind of statement
and will create its own variable scope.
If there is a function call inside the unchecked block, the function will
not inherit the setting - you have to use another unchecked
block inside the function
if you also want it to use wrapping arithmetic.
We decided for some restrictions for the unchecked
block:
-
In modifiers you cannot use
_;
inside anunchecked
block, because this might lead to confusion about whether the property is inherited. -
You can only use it inside a block but not as a replacement for a block. The following code snippets, for example, are both invalid:
function f() unchecked { uint x = 7; }
function f() pure { uint x; for (uint i = 0; i < 100; i++) unchecked { x += i; } }
You have to wrap the unchecked blocks in another block to make it work.
Explicit Conversions
Explicit conversions are only possible when there
is at most one change in sign, width, payability or type-category (int
, address
, bytesNN
, etc.).
For example, converting int8
to uint16
is only possible, if you go through uint8
or int16
.
Since the choice of the intermediate conversion will have an effect on the result
we wanted to make it explicit:
uint16(int16(int8(-1)))
results in0xffff
, whileuint16(uint8(int8(-1)))
is0xff
.
There are more such changes in relation to payable addresses, literals, enums and contracts. For the full list of changes, please see the documentation.
General Remarks
Since we usually do not backport bugfixes, it is recommended to upgrade all code to be compatible with Solidity v0.8.0.
You can find a guide on how to update your code here.
Note that changes listed below are the changes between 0.7.6 and 0.8.0. For changes introduced during the 0.7.x series, please see the individual changelogs or release announcements on this blog.
Full Changelog
Breaking Changes:
- Code Generator: All arithmetic is checked by default. These checks can be disabled using
unchecked { ... }
. - Code Generator: Cause a panic if a byte array in storage is accessed whose length is encoded incorrectly.
- Code Generator: Use
revert
with error signaturePanic(uint256)
and error codes instead of invalid opcode on failing assertions. - Command Line Interface: JSON fields
abi
,devdoc
,userdoc
andstorage-layout
are now sub-objects rather than strings. - Command Line Interface: Remove the
--old-reporter
option. - Command Line Interface: Remove the legacy
--ast-json
option. Only the--ast-compact-json
option is supported now. - General: Enable ABI coder v2 by default.
- General: Remove global functions
log0
,log1
,log2
,log3
andlog4
. - Parser: Exponentiation is right associative.
a**b**c
is parsed asa**(b**c)
. - Scanner: Remove support for the
\b
,\f
, and\v
escape sequences. - Standard JSON: Remove the
legacyAST
option. - Type Checker: Function call options can only be given once.
- Type System: Declarations with the name
this
,super
and_
are disallowed, with the exception of public functions and events. - Type System: Disallow
msg.data
inreceive()
function. - Type System: Disallow
type(super)
. - Type System: Disallow enums with more than 256 members.
- Type System: Disallow explicit conversions from negative literals and literals larger than
type(uint160).max
toaddress
type. - Type System: Disallow the
byte
type. It was an alias tobytes1
. - Type System: Explicit conversion to
address
type always returns a non-payableaddress
type. In particular,address(u)
,address(b)
,address(c)
andaddress(this)
have the typeaddress
instead ofaddress payable
(Hereu
,b
, andc
are arbitrary variables of typeuint160
,bytes20
and contract type respectively.) - Type System: Explicit conversions between two types are disallowed if it changes more than one of sign, width or kind at the same time.
- Type System: Explicit conversions from literals to enums are only allowed if the value fits in the enum.
- Type System: Explicit conversions from literals to integer type is as strict as implicit conversions.
- Type System: Introduce
address(...).code
to retrieve the code asbytes memory
. The size can be obtained viaaddress(...).code.length
, but it will currently always include copying the code. - Type System: Introduce
block.chainid
for retrieving the current chain id. - Type System: Support
address(...).codehash
to retrieve the codehash of an account. - Type System: The global variables
tx.origin
andmsg.sender
have typeaddress
instead ofaddress payable
. - Type System: Unary negation can only be used on signed integers, not on unsigned integers.
- View Pure Checker: Mark
chainid
as view. - Yul: Disallow the use of reserved identifiers, such as EVM instructions, even if they are not available in the given dialect / EVM version.
- Yul: The
assignimmutable
builtin in the “EVM with objects” dialect takes the base offset of the code to modify as an additional argument.
Language Features:
- Super constructors can now be called using the member notation e.g.
M.C(123)
.
Bugfixes:
- Type Checker: Perform proper truncating integer arithmetic when using constants in array length expressions.
AST Changes:
- New AST Node
IdentifierPath
replacing in many places theUserDefinedTypeName
. - New AST Node
UncheckedBlock
used forunchecked { ... }
.
A big thank you to all contributors who helped make this release possible!
Download the new version of Solidity here.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK