diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..81c5f96c2e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,145 @@ +cmake_minimum_required(VERSION 3.13.0) + +set(ETH_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake" CACHE PATH "The the path to the cmake directory") +list(APPEND CMAKE_MODULE_PATH ${ETH_CMAKE_DIR}) + +# Set the build type, if none was specified. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + if(EXISTS "${CMAKE_SOURCE_DIR}/.git") + set(DEFAULT_BUILD_TYPE "RelWithDebInfo") + else() + set(DEFAULT_BUILD_TYPE "Release") + endif() + set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "RelWithDebInfo" "MinSizeRel") +endif() + +include(EthToolchains) + +# Set cmake_policies +include(EthPolicy) +eth_policy() + +# project name and version should be set after cmake_policy CMP0048 +set(PROJECT_VERSION "0.8.18") +# OSX target needed in order to support std::visit +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") +project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) + +include(TestBigEndian) +TEST_BIG_ENDIAN(IS_BIG_ENDIAN) +if (IS_BIG_ENDIAN) + message(FATAL_ERROR "${PROJECT_NAME} currently does not support big endian systems.") +endif() + +option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms" OFF) +option(SOLC_STATIC_STDLIBS "Link solc against static versions of libgcc and libstdc++ on supported platforms" OFF) +option(STRICT_Z3_VERSION "Use the latest version of Z3" ON) +option(PEDANTIC "Enable extra warnings and pedantic build flags. Treat all warnings as errors." ON) + +# Setup cccache. +include(EthCcache) + +# Let's find our dependencies +include(EthDependencies) +include(fmtlib) +include(jsoncpp) +include(range-v3) +include_directories(SYSTEM ${JSONCPP_INCLUDE_DIR}) + +find_package(Threads) + +if(NOT PEDANTIC) + message(WARNING "-- Pedantic build flags turned off. Warnings will not make compilation fail. This is NOT recommended in development builds.") +endif() +# Figure out what compiler and system are we using +include(EthCompilerSettings) + +# Include utils +include(EthUtils) + +# Create license.h from LICENSE.txt and template +# Converting to char array is required due to MSVC's string size limit. +file(READ ${CMAKE_SOURCE_DIR}/LICENSE.txt LICENSE_TEXT HEX) +string(REGEX MATCHALL ".." LICENSE_TEXT "${LICENSE_TEXT}") +string(REGEX REPLACE ";" ",\n\t0x" LICENSE_TEXT "${LICENSE_TEXT}") +set(LICENSE_TEXT "0x${LICENSE_TEXT}") + +configure_file("${CMAKE_SOURCE_DIR}/cmake/templates/license.h.in" include/license.h) + +include(EthOptions) +configure_project(TESTS) +set(LATEST_Z3_VERSION "4.11.0") +set(MINIMUM_Z3_VERSION "4.8.0") +find_package(Z3) +if (${Z3_FOUND}) + if (${STRICT_Z3_VERSION}) + if (NOT ("${Z3_VERSION_STRING}" VERSION_EQUAL ${LATEST_Z3_VERSION})) + message( + FATAL_ERROR + "SMTChecker tests require Z3 ${LATEST_Z3_VERSION} for all tests to pass.\n\ +Build with -DSTRICT_Z3_VERSION=OFF if you want to use a different version. \ +You can also use -DUSE_Z3=OFF to build without Z3. In both cases use --no-smt when running tests." + ) + endif() + else() + if ("${Z3_VERSION_STRING}" VERSION_LESS ${MINIMUM_Z3_VERSION}) + message( + FATAL_ERROR + "Solidity requires Z3 ${MINIMUM_Z3_VERSION} or newer. You can also use -DUSE_Z3=OFF to build without Z3." + ) + endif() + endif() +endif() + +if(${USE_Z3_DLOPEN}) + add_definitions(-DHAVE_Z3) + add_definitions(-DHAVE_Z3_DLOPEN) + find_package(Python3 COMPONENTS Interpreter) + if(${Z3_FOUND}) + get_target_property(Z3_HEADER_HINTS z3::libz3 INTERFACE_INCLUDE_DIRECTORIES) + endif() + find_path(Z3_HEADER_PATH z3.h HINTS ${Z3_HEADER_HINTS}) + if(Z3_HEADER_PATH) + set(Z3_FOUND TRUE) + else() + message(SEND_ERROR "Dynamic loading of Z3 requires Z3 headers to be present at build time.") + endif() + if(NOT ${Python3_FOUND}) + message(SEND_ERROR "Dynamic loading of Z3 requires Python 3 to be present at build time.") + endif() + if(${SOLC_LINK_STATIC}) + message(SEND_ERROR "solc cannot be linked statically when dynamically loading Z3.") + endif() +elseif (${Z3_FOUND}) + add_definitions(-DHAVE_Z3) + message("Z3 SMT solver found. This enables optional SMT checking with Z3.") +endif() + +find_package(CVC4 QUIET) +if (${CVC4_FOUND}) + add_definitions(-DHAVE_CVC4) + message("CVC4 SMT solver found. This enables optional SMT checking with CVC4.") +endif() + +if (NOT (${Z3_FOUND} OR ${CVC4_FOUND})) + message("No SMT solver found (or it has been forcefully disabled). Optional SMT checking will not be available.\ + \nPlease install Z3 or CVC4 or remove the option disabling them (USE_Z3, USE_CVC4).") +endif() + +add_subdirectory(libsolutil) +add_subdirectory(liblangutil) +add_subdirectory(libsmtutil) +add_subdirectory(libevmasm) +add_subdirectory(libyul) +add_subdirectory(libsolidity) +add_subdirectory(libsolc) +add_subdirectory(tools) + +if (NOT EMSCRIPTEN) + add_subdirectory(solc) +endif() + +if (TESTS AND NOT EMSCRIPTEN) + add_subdirectory(test) +endif() diff --git a/docs/050-breaking-changes.rst b/docs/050-breaking-changes.rst index 90af865267..3f41ac860a 100644 --- a/docs/050-breaking-changes.rst +++ b/docs/050-breaking-changes.rst @@ -89,8 +89,8 @@ For most of the topics the compiler will provide suggestions. * Explicit data location for all variables of struct, array or mapping types is now mandatory. This is also applied to function parameters and return - variables. For example, change ``uint[] x = m_x`` to ``uint[] storage x = - m_x``, and ``function f(uint[][] x)`` to ``function f(uint[][] memory x)`` + variables. For example, change ``uint[] x = z`` to ``uint[] storage x = + z``, and ``function f(uint[][] x)`` to ``function f(uint[][] memory x)`` where ``memory`` is the data location and might be replaced by ``storage`` or ``calldata`` accordingly. Note that ``external`` functions require parameters with a data location of ``calldata``. @@ -483,7 +483,7 @@ New version: return data; } - using address_make_payable for address; + using AddressMakePayable for address; // Data location for 'arr' must be specified function g(uint[] memory /* arr */, bytes8 x, OtherContract otherContract, address unknownContract) public payable { // 'otherContract.transfer' is not provided. @@ -500,7 +500,7 @@ New version: // 'address payable' should be used whenever possible. // To increase clarity, we suggest the use of a library for // the conversion (provided after the contract in this example). - address payable addr = unknownContract.make_payable(); + address payable addr = unknownContract.makePayable(); require(addr.send(1 ether)); // Since uint32 (4 bytes) is smaller than bytes8 (8 bytes), @@ -516,8 +516,8 @@ New version: // We can define a library for explicitly converting ``address`` // to ``address payable`` as a workaround. - library address_make_payable { - function make_payable(address x) internal pure returns (address payable) { + library AddressMakePayable { + function makePayable(address x) internal pure returns (address payable) { return address(uint160(x)); } } diff --git a/docs/060-breaking-changes.rst b/docs/060-breaking-changes.rst index 915a9f3352..4f5571d54a 100644 --- a/docs/060-breaking-changes.rst +++ b/docs/060-breaking-changes.rst @@ -53,6 +53,8 @@ For most of the topics the compiler will provide suggestions. If the name contains a dot, its prefix up to the dot may not conflict with any declaration outside the inline assembly block. +* In inline assembly, opcodes that do not take arguments are now represented as "built-in functions" instead of standalone identifiers. So ``gas`` is now ``gas()``. + * State variable shadowing is now disallowed. A derived contract can only declare a state variable ``x``, if there is no visible state variable with the same name in any of its bases. @@ -174,3 +176,6 @@ This section gives detailed instructions on how to update prior code for every b ``override`` to every overriding function. For multiple inheritance, add ``override(A, B, ..)``, where you list all contracts that define the overridden function in the parentheses. When multiple bases define the same function, the inheriting contract must override all conflicting functions. + +* In inline assembly, add ``()`` to all opcodes that do not otherwise accept an argument. + For example, change ``pc`` to ``pc()``, and ``gas`` to ``gas()``. diff --git a/docs/_static/js/toggle.js b/docs/_static/js/toggle.js index f46a3a6662..780ea9ee71 100644 --- a/docs/_static/js/toggle.js +++ b/docs/_static/js/toggle.js @@ -4,15 +4,16 @@ document.addEventListener('DOMContentLoaded', function() { var mode = (isDay ? "Day" : "Night"); localStorage.setItem("css-mode", mode); - var daysheet = $('link[href="_static/pygments.css"]')[0].sheet; + var url_root = DOCUMENTATION_OPTIONS.URL_ROOT == "./" ? "" : DOCUMENTATION_OPTIONS.URL_ROOT; + var daysheet = $(`link[href="${url_root}_static/pygments.css"]`)[0].sheet; daysheet.disabled = !isDay; - var nightsheet = $('link[href="_static/css/dark.css"]')[0]; + var nightsheet = $(`link[href="${url_root}_static/css/dark.css"]`)[0]; if (!isDay && nightsheet === undefined) { var element = document.createElement("link"); element.setAttribute("rel", "stylesheet"); element.setAttribute("type", "text/css"); - element.setAttribute("href", "_static/css/dark.css"); + element.setAttribute("href", `${url_root}_static/css/dark.css`); document.getElementsByTagName("head")[0].appendChild(element); return; } diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index 02e5f8b2a4..7906d75ffe 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -13,13 +13,13 @@ The Contract Application Binary Interface (ABI) is the standard way to interact from outside the blockchain and for contract-to-contract interaction. Data is encoded according to its type, as described in this specification. The encoding is not self describing and thus requires a schema in order to decode. -We assume the interface functions of a contract are strongly typed, known at compilation time and static. +We assume that the interface functions of a contract are strongly typed, known at compilation time and static. We assume that all contracts will have the interface definitions of any contracts they call available at compile-time. This specification does not address contracts whose interface is dynamic or otherwise known only at run-time. .. _abi_function_selector: -.. index:: selector +.. index:: ! selector; of a function Function Selector ================= @@ -29,7 +29,7 @@ first (left, high-order in big-endian) four bytes of the Keccak-256 hash of the the function. The signature is defined as the canonical expression of the basic prototype without data location specifier, i.e. the function name with the parenthesised list of parameter types. Parameter types are split by a single -comma - no spaces are used. +comma — no spaces are used. .. note:: The return type of a function is not part of this signature. In @@ -133,7 +133,7 @@ The encoding is designed to have the following properties, which are especially previous version of the ABI, the number of reads scaled linearly with the total number of dynamic parameters in the worst case. -2. The data of a variable or array element is not interleaved with other data and it is +2. The data of a variable or an array element is not interleaved with other data and it is relocatable, i.e. it only uses relative "addresses". @@ -191,9 +191,9 @@ on the type of ``X`` being - ``T[]`` where ``X`` has ``k`` elements (``k`` is assumed to be of type ``uint256``): - ``enc(X) = enc(k) enc([X[0], ..., X[k-1]])`` + ``enc(X) = enc(k) enc((X[0], ..., X[k-1]))`` - i.e. it is encoded as if it were an array of static size ``k``, prefixed with + i.e. it is encoded as if it were a tuple with ``k`` elements of the same type (resp. an array of static size ``k``), prefixed with the number of elements. - ``bytes``, of length ``k`` (which is assumed to be of type ``uint256``): @@ -252,7 +252,7 @@ Given the contract: } -Thus for our ``Foo`` example if we wanted to call ``baz`` with the parameters ``69`` and +Thus, for our ``Foo`` example if we wanted to call ``baz`` with the parameters ``69`` and ``true``, we would pass 68 bytes total, which can be broken down into: - ``0xcdcd77c0``: the Method ID. This is derived as the first 4 bytes of the Keccak hash of @@ -308,7 +308,7 @@ In total: Use of Dynamic Types ==================== -A call to a function with the signature ``f(uint,uint32[],bytes10,bytes)`` with values +A call to a function with the signature ``f(uint256,uint32[],bytes10,bytes)`` with values ``(0x123, [0x456, 0x789], "1234567890", "Hello, world!")`` is encoded in the following way: We take the first four bytes of ``sha3("f(uint256,uint32[],bytes10,bytes)")``, i.e. ``0x8be65246``. @@ -348,7 +348,7 @@ All together, the encoding is (newline after function selector and each 32-bytes 000000000000000000000000000000000000000000000000000000000000000d 48656c6c6f2c20776f726c642100000000000000000000000000000000000000 -Let us apply the same principle to encode the data for a function with a signature ``g(uint[][],string[])`` +Let us apply the same principle to encode the data for a function with a signature ``g(uint256[][],string[])`` with values ``([[1, 2], [3]], ["one", "two", "three"])`` but start from the most atomic parts of the encoding: First we encode the length and data of the first embedded dynamic array ``[1, 2]`` of the first root array ``[[1, 2], [3]]``: @@ -417,7 +417,7 @@ thus ``e = 0x00000000000000000000000000000000000000000000000000000000000000e0``. Note that the encodings of the embedded elements of the root arrays are not dependent on each other -and have the same encodings for a function with a signature ``g(string[],uint[][])``. +and have the same encodings for a function with a signature ``g(string[],uint256[][])``. Then we encode the length of the first root array: @@ -503,6 +503,7 @@ efficient search and arbitrary legibility by defining events with two arguments indexed, one not — intended to hold the same value. .. _abi_errors: +.. index:: error, selector; of an error Errors ====== @@ -596,7 +597,7 @@ Errors look as follows: .. note:: There can be multiple errors with the same name and even with identical signature - in the JSON array, for example if the errors originate from different + in the JSON array; for example, if the errors originate from different files in the smart contract or are referenced from another smart contract. For the ABI, only the name of the error itself is relevant and not where it is defined. @@ -645,7 +646,7 @@ would result in the JSON: Handling tuple types -------------------- -Despite that names are intentionally not part of the ABI encoding they do make a lot of sense to be included +Despite the fact that names are intentionally not part of the ABI encoding, they do make a lot of sense to be included in the JSON to enable displaying it to the end user. The structure is nested in the following way: An object with members ``name``, ``type`` and potentially ``components`` describes a typed variable. @@ -653,7 +654,7 @@ The canonical type is determined until a tuple type is reached and the string de to that point is stored in ``type`` prefix with the word ``tuple``, i.e. it will be ``tuple`` followed by a sequence of ``[]`` and ``[k]`` with integers ``k``. The components of the tuple are then stored in the member ``components``, -which is of array type and has the same structure as the top-level object except that +which is of an array type and has the same structure as the top-level object except that ``indexed`` is not allowed there. As an example, the code @@ -737,10 +738,10 @@ Strict Encoding Mode ==================== Strict encoding mode is the mode that leads to exactly the same encoding as defined in the formal specification above. -This means offsets have to be as small as possible while still not creating overlaps in the data areas and thus no gaps are +This means that offsets have to be as small as possible while still not creating overlaps in the data areas, and thus no gaps are allowed. -Usually, ABI decoders are written in a straightforward way just following offset pointers, but some decoders +Usually, ABI decoders are written in a straightforward way by just following offset pointers, but some decoders might enforce strict mode. The Solidity ABI decoder currently does not enforce strict mode, but the encoder always creates data in strict mode. @@ -776,7 +777,7 @@ More specifically: encoding of its elements **with** padding. - Dynamically-sized types like ``string``, ``bytes`` or ``uint[]`` are encoded without their length field. -- The encoding of ``string`` or ``bytes`` does not apply padding at the end +- The encoding of ``string`` or ``bytes`` does not apply padding at the end, unless it is part of an array or struct (then it is padded to a multiple of 32 bytes). @@ -804,7 +805,7 @@ Encoding of Indexed Event Parameters ==================================== Indexed event parameters that are not value types, i.e. arrays and structs are not -stored directly but instead a keccak256-hash of an encoding is stored. This encoding +stored directly but instead a Keccak-256 hash of an encoding is stored. This encoding is defined as follows: - the encoding of a ``bytes`` and ``string`` value is just the string contents diff --git a/docs/assembly.rst b/docs/assembly.rst index c26a53e49a..b527ffbafd 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -8,7 +8,7 @@ Inline Assembly You can interleave Solidity statements with inline assembly in a language close -to the one of the Ethereum virtual machine. This gives you more fine-grained control, +to the one of the Ethereum Virtual Machine. This gives you more fine-grained control, which is especially useful when you are enhancing the language by writing libraries. The language used for inline assembly in Solidity is called :ref:`Yul ` @@ -45,19 +45,19 @@ Solidity language without a compiler change. pragma solidity >=0.4.16 <0.9.0; library GetCode { - function at(address _addr) public view returns (bytes memory o_code) { + function at(address addr) public view returns (bytes memory code) { assembly { // retrieve the size of the code, this needs assembly - let size := extcodesize(_addr) + let size := extcodesize(addr) // allocate output byte array - this could also be done without assembly - // by using o_code = new bytes(size) - o_code := mload(0x40) + // by using code = new bytes(size) + code := mload(0x40) // new "memory end" including padding - mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + mstore(0x40, add(code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) // store length in memory - mstore(o_code, size) + mstore(code, size) // actually retrieve the code, this needs assembly - extcodecopy(_addr, add(o_code, 0x20), 0, size) + extcodecopy(addr, add(code, 0x20), 0, size) } } } @@ -74,49 +74,49 @@ efficient code, for example: library VectorSum { // This function is less efficient because the optimizer currently fails to // remove the bounds checks in array access. - function sumSolidity(uint[] memory _data) public pure returns (uint sum) { - for (uint i = 0; i < _data.length; ++i) - sum += _data[i]; + function sumSolidity(uint[] memory data) public pure returns (uint sum) { + for (uint i = 0; i < data.length; ++i) + sum += data[i]; } // We know that we only access the array in bounds, so we can avoid the check. // 0x20 needs to be added to an array because the first slot contains the // array length. - function sumAsm(uint[] memory _data) public pure returns (uint sum) { - for (uint i = 0; i < _data.length; ++i) { + function sumAsm(uint[] memory data) public pure returns (uint sum) { + for (uint i = 0; i < data.length; ++i) { assembly { - sum := add(sum, mload(add(add(_data, 0x20), mul(i, 0x20)))) + sum := add(sum, mload(add(add(data, 0x20), mul(i, 0x20)))) } } } // Same as above, but accomplish the entire code within inline assembly. - function sumPureAsm(uint[] memory _data) public pure returns (uint sum) { + function sumPureAsm(uint[] memory data) public pure returns (uint sum) { assembly { // Load the length (first 32 bytes) - let len := mload(_data) + let len := mload(data) // Skip over the length field. // // Keep temporary variable so it can be incremented in place. // - // NOTE: incrementing _data would result in an unusable - // _data variable after this assembly block - let data := add(_data, 0x20) + // NOTE: incrementing data would result in an unusable + // data variable after this assembly block + let dataElementLocation := add(data, 0x20) // Iterate until the bound is not met. for - { let end := add(data, mul(len, 0x20)) } - lt(data, end) - { data := add(data, 0x20) } + { let end := add(dataElementLocation, mul(len, 0x20)) } + lt(dataElementLocation, end) + { dataElementLocation := add(dataElementLocation, 0x20) } { - sum := add(sum, mload(data)) + sum := add(sum, mload(dataElementLocation)) } } } } - +.. index:: selector; of a function Access to External Variables, Functions and Libraries ----------------------------------------------------- @@ -126,20 +126,20 @@ You can access Solidity variables and other identifiers by using their name. Local variables of value type are directly usable in inline assembly. They can both be read and assigned to. -Local variables that refer to memory evaluate to the address of the variable in memory not the value itself. +Local variables that refer to memory evaluate to the address of the variable in memory, not the value itself. Such variables can also be assigned to, but note that an assignment will only change the pointer and not the data and that it is your responsibility to respect Solidity's memory management. See :ref:`Conventions in Solidity `. Similarly, local variables that refer to statically-sized calldata arrays or calldata structs evaluate to the address of the variable in calldata, not the value itself. -The variable can also be assigned a new offset, but note that no validation to ensure that -the variable will not point beyond ``calldatasize()`` is performed. +The variable can also be assigned a new offset, but note that no validation is performed to ensure that +the variable will not point beyond ``calldatasize()``. For external function pointers the address and the function selector can be accessed using ``x.address`` and ``x.selector``. The selector consists of four right-aligned bytes. -Both values are can be assigned to. For example: +Both values can be assigned to. For example: .. code-block:: solidity :force: @@ -205,7 +205,7 @@ Local Solidity variables are available for assignments, for example: ``assembly { signextend(, x) }`` -Since Solidity 0.6.0 the name of a inline assembly variable may not +Since Solidity 0.6.0, the name of a inline assembly variable may not shadow any declaration visible in the scope of the inline assembly block (including variable, contract and function declarations). @@ -228,6 +228,11 @@ of their block is reached. Conventions in Solidity ----------------------- +.. _assembly-typed-variables: + +Values of Typed Variables +========================= + In contrast to EVM assembly, Solidity has types which are narrower than 256 bits, e.g. ``uint24``. For efficiency, most arithmetic operations ignore the fact that types can be shorter than 256 @@ -237,13 +242,18 @@ This means that if you access such a variable from within inline assembly, you might have to manually clean the higher-order bits first. +.. _assembly-memory-management: + +Memory Management +================= + Solidity manages memory in the following way. There is a "free memory pointer" at position ``0x40`` in memory. If you want to allocate memory, use the memory starting from where this pointer points at and update it. There is no guarantee that the memory has not been used before and thus you cannot assume that its contents are zero bytes. There is no built-in mechanism to release or free allocated memory. -Here is an assembly snippet you can use for allocating memory that follows the process outlined above +Here is an assembly snippet you can use for allocating memory that follows the process outlined above: .. code-block:: yul @@ -266,5 +276,103 @@ first slot of the array and followed by the array elements. .. warning:: Statically-sized memory arrays do not have a length field, but it might be added later - to allow better convertibility between statically- and dynamically-sized arrays, so + to allow better convertibility between statically and dynamically-sized arrays; so, do not rely on this. + +Memory Safety +============= + +Without the use of inline assembly, the compiler can rely on memory to remain in a well-defined +state at all times. This is especially relevant for :ref:`the new code generation pipeline via Yul IR `: +this code generation path can move local variables from stack to memory to avoid stack-too-deep errors and +perform additional memory optimizations, if it can rely on certain assumptions about memory use. + +While we recommend to always respect Solidity's memory model, inline assembly allows you to use memory +in an incompatible way. Therefore, moving stack variables to memory and additional memory optimizations are, +by default, globally disabled in the presence of any inline assembly block that contains a memory operation +or assigns to Solidity variables in memory. + +However, you can specifically annotate an assembly block to indicate that it in fact respects Solidity's memory +model as follows: + +.. code-block:: solidity + + assembly ("memory-safe") { + ... + } + +In particular, a memory-safe assembly block may only access the following memory ranges: + +- Memory allocated by yourself using a mechanism like the ``allocate`` function described above. +- Memory allocated by Solidity, e.g. memory within the bounds of a memory array you reference. +- The scratch space between memory offset 0 and 64 mentioned above. +- Temporary memory that is located *after* the value of the free memory pointer at the beginning of the assembly block, + i.e. memory that is "allocated" at the free memory pointer without updating the free memory pointer. + +Furthermore, if the assembly block assigns to Solidity variables in memory, you need to assure that accesses to +the Solidity variables only access these memory ranges. + +Since this is mainly about the optimizer, these restrictions still need to be followed, even if the assembly block +reverts or terminates. As an example, the following assembly snippet is not memory safe, because the value of +``returndatasize()`` may exceed the 64 byte scratch space: + +.. code-block:: solidity + + assembly { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + +On the other hand, the following code *is* memory safe, because memory beyond the location pointed to by the +free memory pointer can safely be used as temporary scratch space: + +.. code-block:: solidity + + assembly ("memory-safe") { + let p := mload(0x40) + returndatacopy(p, 0, returndatasize()) + revert(p, returndatasize()) + } + +Note that you do not need to update the free memory pointer if there is no following allocation, +but you can only use memory starting from the current offset given by the free memory pointer. + +If the memory operations use a length of zero, it is also fine to just use any offset (not only if it falls into the scratch space): + +.. code-block:: solidity + + assembly ("memory-safe") { + revert(0, 0) + } + +Note that not only memory operations in inline assembly itself can be memory-unsafe, but also assignments to +Solidity variables of reference type in memory. For example the following is not memory-safe: + +.. code-block:: solidity + + bytes memory x; + assembly { + x := 0x40 + } + x[0x20] = 0x42; + +Inline assembly that neither involves any operations that access memory nor assigns to any Solidity variables +in memory is automatically considered memory-safe and does not need to be annotated. + +.. warning:: + It is your responsibility to make sure that the assembly actually satisfies the memory model. If you annotate + an assembly block as memory-safe, but violate one of the memory assumptions, this **will** lead to incorrect and + undefined behaviour that cannot easily be discovered by testing. + +In case you are developing a library that is meant to be compatible across multiple versions +of Solidity, you can use a special comment to annotate an assembly block as memory-safe: + +.. code-block:: solidity + + /// @solidity memory-safe-assembly + assembly { + ... + } + +Note that we will disallow the annotation via comment in a future breaking release; so, if you are not concerned with +backwards-compatibility with older compiler versions, prefer using the dialect string. diff --git a/docs/bugs.json b/docs/bugs.json index 0b72c05c7d..03dafbe45b 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,84 @@ [ + { + "uid": "SOL-2022-7", + "name": "StorageWriteRemovalBeforeConditionalTermination", + "summary": "Calling functions that conditionally terminate the external EVM call using the assembly statements ``return(...)`` or ``stop()`` may result in incorrect removals of prior storage writes.", + "description": "A call to a Yul function that conditionally terminates the external EVM call could result in prior storage writes being incorrectly removed by the Yul optimizer. This used to happen in cases in which it would have been valid to remove the store, if the Yul function in question never actually terminated the external call, and the control flow always returned back to the caller instead. Conditional termination within the same Yul block instead of within a called function was not affected. In Solidity with optimized via-IR code generation, any storage write before a function conditionally calling ``return(...)`` or ``stop()`` in inline assembly, may have been incorrectly removed, whenever it would have been valid to remove the write without the ``return(...)`` or ``stop()``. In optimized legacy code generation, only inline assembly that did not refer to any Solidity variables and that involved conditionally-terminating user-defined assembly functions could be affected.", + "link": "https://blog.soliditylang.org/2022/09/08/storage-write-removal-before-conditional-termination/", + "introduced": "0.8.13", + "fixed": "0.8.17", + "severity": "medium/high", + "conditions": { + "yulOptimizer": true + } + }, + { + "uid": "SOL-2022-6", + "name": "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "summary": "ABI-encoding a tuple with a statically-sized calldata array in the last component would corrupt 32 leading bytes of its first dynamically encoded component.", + "description": "When ABI-encoding a statically-sized calldata array, the compiler always pads the data area to a multiple of 32-bytes and ensures that the padding bytes are zeroed. In some cases, this cleanup used to be performed by always writing exactly 32 bytes, regardless of how many needed to be zeroed. This was done with the assumption that the data that would eventually occupy the area past the end of the array had not yet been written, because the encoder processes tuple components in the order they were given. While this assumption is mostly true, there is an important corner case: dynamically encoded tuple components are stored separately from the statically-sized ones in an area called the *tail* of the encoding and the tail immediately follows the *head*, which is where the statically-sized components are placed. The aforementioned cleanup, if performed for the last component of the head would cross into the tail and overwrite up to 32 bytes of the first component stored there with zeros. The only array type for which the cleanup could actually result in an overwrite were arrays with ``uint256`` or ``bytes32`` as the base element type and in this case the size of the corrupted area was always exactly 32 bytes. The problem affected tuples at any nesting level. This included also structs, which are encoded as tuples in the ABI. Note also that lists of parameters and return values of functions, events and errors are encoded as tuples.", + "link": "https://blog.soliditylang.org/2022/08/08/calldata-tuple-reencoding-head-overflow-bug/", + "introduced": "0.5.8", + "fixed": "0.8.16", + "severity": "medium", + "conditions": { + "ABIEncoderV2": true + } + }, + { + "uid": "SOL-2022-5", + "name": "DirtyBytesArrayToStorage", + "summary": "Copying ``bytes`` arrays from memory or calldata to storage may result in dirty storage values.", + "description": "Copying ``bytes`` arrays from memory or calldata to storage is done in chunks of 32 bytes even if the length is not a multiple of 32. Thereby, extra bytes past the end of the array may be copied from calldata or memory to storage. These dirty bytes may then become observable after a ``.push()`` without arguments to the bytes array in storage, i.e. such a push will not result in a zero value at the end of the array as expected. This bug only affects the legacy code generation pipeline, the new code generation pipeline via IR is not affected.", + "link": "https://blog.soliditylang.org/2022/06/15/dirty-bytes-array-to-storage-bug/", + "introduced": "0.0.1", + "fixed": "0.8.15", + "severity": "low" + }, + { + "uid": "SOL-2022-4", + "name": "InlineAssemblyMemorySideEffects", + "summary": "The Yul optimizer may incorrectly remove memory writes from inline assembly blocks, that do not access solidity variables.", + "description": "The Yul optimizer considers all memory writes in the outermost Yul block that are never read from as unused and removes them. This is valid when that Yul block is the entire Yul program, which is always the case for the Yul code generated by the new via-IR pipeline. Inline assembly blocks are never optimized in isolation when using that pipeline. Instead they are optimized as a part of the whole Yul input. However, the legacy code generation pipeline (which is still the default) runs the Yul optimizer individually on an inline assembly block if the block does not refer to any local variables defined in the surrounding Solidity code. Consequently, memory writes in such inline assembly blocks are removed as well, if the written memory is never read from in the same assembly block, even if the written memory is accessed later, for example by a subsequent inline assembly block.", + "link": "https://blog.soliditylang.org/2022/06/15/inline-assembly-memory-side-effects-bug/", + "introduced": "0.8.13", + "fixed": "0.8.15", + "severity": "medium", + "conditions": { + "yulOptimizer": true + } + }, + { + "uid": "SOL-2022-3", + "name": "DataLocationChangeInInternalOverride", + "summary": "It was possible to change the data location of the parameters or return variables from ``calldata`` to ``memory`` and vice-versa while overriding internal and public functions. This caused invalid code to be generated when calling such a function internally through virtual function calls.", + "description": "When calling external functions, it is irrelevant if the data location of the parameters is ``calldata`` or ``memory``, the encoding of the data does not change. Because of that, changing the data location when overriding external functions is allowed. The compiler incorrectly also allowed a change in the data location for overriding public and internal functions. Since public functions can be called internally as well as externally, this causes invalid code to be generated when such an incorrectly overridden function is called internally through the base contract. The caller provides a memory pointer, but the called function interprets it as a calldata pointer or vice-versa.", + "link": "https://blog.soliditylang.org/2022/05/17/data-location-inheritance-bug/", + "introduced": "0.6.9", + "fixed": "0.8.14", + "severity": "very low" + }, + { + "uid": "SOL-2022-2", + "name": "NestedCallataArrayAbiReencodingSizeValidation", + "summary": "ABI-reencoding of nested dynamic calldata arrays did not always perform proper size checks against the size of calldata and could read beyond ``calldatasize()``.", + "description": "Calldata validation for nested dynamic types is deferred until the first access to the nested values. Such an access may for example be a copy to memory or an index or member access to the outer type. While in most such accesses calldata validation correctly checks that the data area of the nested array is completely contained in the passed calldata (i.e. in the range [0, calldatasize()]), this check may not be performed, when ABI encoding such nested types again directly from calldata. For instance, this can happen, if a value in calldata with a nested dynamic array is passed to an external call, used in ``abi.encode`` or emitted as event. In such cases, if the data area of the nested array extends beyond ``calldatasize()``, ABI encoding it did not revert, but continued reading values from beyond ``calldatasize()`` (i.e. zero values).", + "link": "https://blog.soliditylang.org/2022/05/17/calldata-reencode-size-check-bug/", + "introduced": "0.5.8", + "fixed": "0.8.14", + "severity": "very low" + }, + { + "uid": "SOL-2022-1", + "name": "AbiEncodeCallLiteralAsFixedBytesBug", + "summary": "Literals used for a fixed length bytes parameter in ``abi.encodeCall`` were encoded incorrectly.", + "description": "For the encoding, the compiler only considered the types of the expressions in the second argument of ``abi.encodeCall`` itself, but not the parameter types of the function given as first argument. In almost all cases the abi encoding of the type of the expression matches the abi encoding of the parameter type of the given function. This is because the type checker ensures the expression is implicitly convertible to the respective parameter type. However this is not true for number literals used for fixed bytes types shorter than 32 bytes, nor for string literals used for any fixed bytes type. Number literals were encoded as numbers instead of being shifted to become left-aligned. String literals were encoded as dynamically sized memory strings instead of being converted to a left-aligned bytes value.", + "link": "https://blog.soliditylang.org/2022/03/16/encodecall-bug/", + "introduced": "0.8.11", + "fixed": "0.8.13", + "severity": "very low" + + }, { "uid": "SOL-2021-4", "name": "UserDefinedValueTypesBug", @@ -8,7 +88,6 @@ "introduced": "0.8.8", "fixed": "0.8.9", "severity": "very low" - }, { "uid": "SOL-2021-3", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 608ba3dfda..11ddd40b07 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1,6 +1,7 @@ { "0.1.0": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -22,6 +23,7 @@ }, "0.1.1": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -43,6 +45,7 @@ }, "0.1.2": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -64,6 +67,7 @@ }, "0.1.3": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -85,6 +89,7 @@ }, "0.1.4": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -107,6 +112,7 @@ }, "0.1.5": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -129,6 +135,7 @@ }, "0.1.6": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -153,6 +160,7 @@ }, "0.1.7": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -177,6 +185,7 @@ }, "0.2.0": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -202,6 +211,7 @@ }, "0.2.1": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -227,6 +237,7 @@ }, "0.2.2": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -252,6 +263,7 @@ }, "0.3.0": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -279,6 +291,7 @@ }, "0.3.1": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -305,6 +318,7 @@ }, "0.3.2": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -331,6 +345,7 @@ }, "0.3.3": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -356,6 +371,7 @@ }, "0.3.4": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -381,6 +397,7 @@ }, "0.3.5": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -406,6 +423,7 @@ }, "0.3.6": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -429,6 +447,7 @@ }, "0.4.0": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -452,6 +471,7 @@ }, "0.4.1": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -475,6 +495,7 @@ }, "0.4.10": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -497,6 +518,7 @@ }, "0.4.11": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -518,6 +540,7 @@ }, "0.4.12": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -538,6 +561,7 @@ }, "0.4.13": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -558,6 +582,7 @@ }, "0.4.14": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -577,6 +602,7 @@ }, "0.4.15": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -595,6 +621,7 @@ }, "0.4.16": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -616,6 +643,7 @@ }, "0.4.17": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -638,6 +666,7 @@ }, "0.4.18": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -659,6 +688,7 @@ }, "0.4.19": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -681,6 +711,7 @@ }, "0.4.2": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -703,6 +734,7 @@ }, "0.4.20": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -725,6 +757,7 @@ }, "0.4.21": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -747,6 +780,7 @@ }, "0.4.22": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -769,6 +803,7 @@ }, "0.4.23": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -790,6 +825,7 @@ }, "0.4.24": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -811,6 +847,7 @@ }, "0.4.25": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -830,6 +867,7 @@ }, "0.4.26": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -846,6 +884,7 @@ }, "0.4.3": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -867,6 +906,7 @@ }, "0.4.4": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -887,6 +927,7 @@ }, "0.4.5": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -910,6 +951,7 @@ }, "0.4.6": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -932,6 +974,7 @@ }, "0.4.7": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -954,6 +997,7 @@ }, "0.4.8": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -976,6 +1020,7 @@ }, "0.4.9": { "bugs": [ + "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", "DynamicArrayCleanup", @@ -998,6 +1043,7 @@ }, "0.5.0": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1017,6 +1063,7 @@ }, "0.5.1": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1036,6 +1083,9 @@ }, "0.5.10": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1051,6 +1101,9 @@ }, "0.5.11": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1065,6 +1118,9 @@ }, "0.5.12": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1079,6 +1135,9 @@ }, "0.5.13": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1093,6 +1152,9 @@ }, "0.5.14": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1109,6 +1171,9 @@ }, "0.5.15": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1124,6 +1189,9 @@ }, "0.5.16": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1138,6 +1206,9 @@ }, "0.5.17": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1151,6 +1222,7 @@ }, "0.5.2": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1170,6 +1242,7 @@ }, "0.5.3": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1189,6 +1262,7 @@ }, "0.5.4": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1208,6 +1282,7 @@ }, "0.5.5": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1229,6 +1304,7 @@ }, "0.5.6": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1250,6 +1326,7 @@ }, "0.5.7": { "bugs": [ + "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1269,6 +1346,9 @@ }, "0.5.8": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1287,6 +1367,9 @@ }, "0.5.9": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1304,6 +1387,9 @@ }, "0.6.0": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1319,6 +1405,9 @@ }, "0.6.1": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1333,6 +1422,10 @@ }, "0.6.10": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1343,6 +1436,10 @@ }, "0.6.11": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1353,6 +1450,10 @@ }, "0.6.12": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1363,6 +1464,9 @@ }, "0.6.2": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1377,6 +1481,9 @@ }, "0.6.3": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1391,6 +1498,9 @@ }, "0.6.4": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1405,6 +1515,9 @@ }, "0.6.5": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1419,6 +1532,9 @@ }, "0.6.6": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1432,6 +1548,9 @@ }, "0.6.7": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1445,6 +1564,9 @@ }, "0.6.8": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1455,6 +1577,10 @@ }, "0.6.9": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1466,6 +1592,10 @@ }, "0.7.0": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1476,6 +1606,10 @@ }, "0.7.1": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1487,6 +1621,10 @@ }, "0.7.2": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1497,6 +1635,10 @@ }, "0.7.3": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1506,6 +1648,10 @@ }, "0.7.4": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" @@ -1514,6 +1660,10 @@ }, "0.7.5": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" @@ -1522,6 +1672,10 @@ }, "0.7.6": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" @@ -1530,6 +1684,10 @@ }, "0.8.0": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" @@ -1538,6 +1696,10 @@ }, "0.8.1": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" @@ -1545,15 +1707,77 @@ "released": "2021-01-27" }, "0.8.10": { - "bugs": [], + "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation" + ], "released": "2021-11-09" }, "0.8.11": { - "bugs": [], + "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", + "AbiEncodeCallLiteralAsFixedBytesBug" + ], "released": "2021-12-20" }, + "0.8.12": { + "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", + "AbiEncodeCallLiteralAsFixedBytesBug" + ], + "released": "2022-02-16" + }, + "0.8.13": { + "bugs": [ + "StorageWriteRemovalBeforeConditionalTermination", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "InlineAssemblyMemorySideEffects", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation" + ], + "released": "2022-03-16" + }, + "0.8.14": { + "bugs": [ + "StorageWriteRemovalBeforeConditionalTermination", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "InlineAssemblyMemorySideEffects" + ], + "released": "2022-05-17" + }, + "0.8.15": { + "bugs": [ + "StorageWriteRemovalBeforeConditionalTermination", + "AbiReencodingHeadOverflowWithStaticArrayCleanup" + ], + "released": "2022-06-15" + }, + "0.8.16": { + "bugs": [ + "StorageWriteRemovalBeforeConditionalTermination" + ], + "released": "2022-08-08" + }, + "0.8.17": { + "bugs": [], + "released": "2022-09-08" + }, "0.8.2": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" @@ -1562,6 +1786,10 @@ }, "0.8.3": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory" ], @@ -1569,37 +1797,62 @@ }, "0.8.4": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables" ], "released": "2021-04-21" }, "0.8.5": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables" ], "released": "2021-06-10" }, "0.8.6": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables" ], "released": "2021-06-22" }, "0.8.7": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "SignedImmutables" ], "released": "2021-08-11" }, "0.8.8": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation", "UserDefinedValueTypesBug", "SignedImmutables" ], "released": "2021-09-27" }, "0.8.9": { - "bugs": [], + "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCallataArrayAbiReencodingSizeValidation" + ], "released": "2021-09-29" } } \ No newline at end of file diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst index eab1e3d52a..3a7d478b1b 100644 --- a/docs/cheatsheet.rst +++ b/docs/cheatsheet.rst @@ -2,70 +2,11 @@ Cheatsheet ********** -.. index:: precedence - -.. _order: +.. index:: operator; precedence Order of Precedence of Operators ================================ - -The following is the order of precedence for operators, listed in order of evaluation. - -+------------+-------------------------------------+--------------------------------------------+ -| Precedence | Description | Operator | -+============+=====================================+============================================+ -| *1* | Postfix increment and decrement | ``++``, ``--`` | -+ +-------------------------------------+--------------------------------------------+ -| | New expression | ``new `` | -+ +-------------------------------------+--------------------------------------------+ -| | Array subscripting | ``[]`` | -+ +-------------------------------------+--------------------------------------------+ -| | Member access | ``.`` | -+ +-------------------------------------+--------------------------------------------+ -| | Function-like call | ``()`` | -+ +-------------------------------------+--------------------------------------------+ -| | Parentheses | ``()`` | -+------------+-------------------------------------+--------------------------------------------+ -| *2* | Prefix increment and decrement | ``++``, ``--`` | -+ +-------------------------------------+--------------------------------------------+ -| | Unary minus | ``-`` | -+ +-------------------------------------+--------------------------------------------+ -| | Unary operations | ``delete`` | -+ +-------------------------------------+--------------------------------------------+ -| | Logical NOT | ``!`` | -+ +-------------------------------------+--------------------------------------------+ -| | Bitwise NOT | ``~`` | -+------------+-------------------------------------+--------------------------------------------+ -| *3* | Exponentiation | ``**`` | -+------------+-------------------------------------+--------------------------------------------+ -| *4* | Multiplication, division and modulo | ``*``, ``/``, ``%`` | -+------------+-------------------------------------+--------------------------------------------+ -| *5* | Addition and subtraction | ``+``, ``-`` | -+------------+-------------------------------------+--------------------------------------------+ -| *6* | Bitwise shift operators | ``<<``, ``>>`` | -+------------+-------------------------------------+--------------------------------------------+ -| *7* | Bitwise AND | ``&`` | -+------------+-------------------------------------+--------------------------------------------+ -| *8* | Bitwise XOR | ``^`` | -+------------+-------------------------------------+--------------------------------------------+ -| *9* | Bitwise OR | ``|`` | -+------------+-------------------------------------+--------------------------------------------+ -| *10* | Inequality operators | ``<``, ``>``, ``<=``, ``>=`` | -+------------+-------------------------------------+--------------------------------------------+ -| *11* | Equality operators | ``==``, ``!=`` | -+------------+-------------------------------------+--------------------------------------------+ -| *12* | Logical AND | ``&&`` | -+------------+-------------------------------------+--------------------------------------------+ -| *13* | Logical OR | ``||`` | -+------------+-------------------------------------+--------------------------------------------+ -| *14* | Ternary operator | `` ? : `` | -+ +-------------------------------------+--------------------------------------------+ -| | Assignment operators | ``=``, ``|=``, ``^=``, ``&=``, ``<<=``, | -| | | ``>>=``, ``+=``, ``-=``, ``*=``, ``/=``, | -| | | ``%=`` | -+------------+-------------------------------------+--------------------------------------------+ -| *15* | Comma operator | ``,`` | -+------------+-------------------------------------+--------------------------------------------+ +.. include:: types/operator-precedence-table.rst .. index:: assert, block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, gas price, origin, revert, require, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, codehash, send @@ -86,13 +27,15 @@ Global Variables to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature)), ...)`` - ``bytes.concat(...) returns (bytes memory)``: :ref:`Concatenates variable number of arguments to one byte array` +- ``string.concat(...) returns (string memory)``: :ref:`Concatenates variable number of + arguments to one string array` - ``block.basefee`` (``uint``): current block's base fee (`EIP-3198 `_ and `EIP-1559 `_) - ``block.chainid`` (``uint``): current chain id - ``block.coinbase`` (``address payable``): current block miner's address - ``block.difficulty`` (``uint``): current block difficulty - ``block.gaslimit`` (``uint``): current block gaslimit - ``block.number`` (``uint``): current block number -- ``block.timestamp`` (``uint``): current block timestamp +- ``block.timestamp`` (``uint``): current block timestamp in seconds since Unix epoch - ``gasleft() returns (uint256)``: remaining gas - ``msg.data`` (``bytes``): complete calldata - ``msg.sender`` (``address``): sender of the message (current call) @@ -133,35 +76,6 @@ Global Variables - ``type(T).min`` (``T``): the minimum value representable by the integer type ``T``, see :ref:`Type Information`. - ``type(T).max`` (``T``): the maximum value representable by the integer type ``T``, see :ref:`Type Information`. -.. note:: - When contracts are evaluated off-chain rather than in context of a transaction included in a - block, you should not assume that ``block.*`` and ``tx.*`` refer to values from any specific - block or transaction. These values are provided by the EVM implementation that executes the - contract and can be arbitrary. - -.. note:: - Do not rely on ``block.timestamp`` or ``blockhash`` as a source of randomness, - unless you know what you are doing. - - Both the timestamp and the block hash can be influenced by miners to some degree. - Bad actors in the mining community can for example run a casino payout function on a chosen hash - and just retry a different hash if they did not receive any money. - - The current block timestamp must be strictly larger than the timestamp of the last block, - but the only guarantee is that it will be somewhere between the timestamps of two - consecutive blocks in the canonical chain. - -.. note:: - The block hashes are not available for all blocks for scalability reasons. - You can only access the hashes of the most recent 256 blocks, all other - values will be zero. - -.. note:: - In version 0.5.0, the following aliases were removed: ``suicide`` as alias for ``selfdestruct``, - ``msg.gas`` as alias for ``gasleft``, ``block.blockhash`` as alias for ``blockhash`` and - ``sha3`` as alias for ``keccak256``. -.. note:: - In version 0.7.0, the alias ``now`` (for ``block.timestamp``) was removed. .. index:: visibility, public, private, external, internal @@ -198,13 +112,3 @@ Modifiers - ``override``: States that this function, modifier or public state variable changes the behaviour of a function or modifier in a base contract. -Reserved Keywords -================= - -These keywords are reserved in Solidity. They might become part of the syntax in the future: - -``after``, ``alias``, ``apply``, ``auto``, ``byte``, ``case``, ``copyof``, ``default``, -``define``, ``final``, ``implements``, ``in``, ``inline``, ``let``, ``macro``, ``match``, -``mutable``, ``null``, ``of``, ``partial``, ``promise``, ``reference``, ``relocatable``, -``sealed``, ``sizeof``, ``static``, ``supports``, ``switch``, ``typedef``, ``typeof``, -``var``. diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index 86c81dbfb9..1793ebd2f2 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -163,9 +163,9 @@ restrictions highly readable. // prepend a check that only passes // if the function is called from // a certain address. - modifier onlyBy(address _account) + modifier onlyBy(address account) { - if (msg.sender != _account) + if (msg.sender != account) revert Unauthorized(); // Do not forget the "_;"! It will // be replaced by the actual function @@ -173,17 +173,17 @@ restrictions highly readable. _; } - /// Make `_newOwner` the new owner of this + /// Make `newOwner` the new owner of this /// contract. - function changeOwner(address _newOwner) + function changeOwner(address newOwner) public onlyBy(owner) { - owner = _newOwner; + owner = newOwner; } - modifier onlyAfter(uint _time) { - if (block.timestamp < _time) + modifier onlyAfter(uint time) { + if (block.timestamp < time) revert TooEarly(); _; } @@ -205,21 +205,21 @@ restrictions highly readable. // refunded, but only after the function body. // This was dangerous before Solidity version 0.4.0, // where it was possible to skip the part after `_;`. - modifier costs(uint _amount) { - if (msg.value < _amount) + modifier costs(uint amount) { + if (msg.value < amount) revert NotEnoughEther(); _; - if (msg.value > _amount) - payable(msg.sender).transfer(msg.value - _amount); + if (msg.value > amount) + payable(msg.sender).transfer(msg.value - amount); } - function forceOwnerChange(address _newOwner) + function forceOwnerChange(address newOwner) public payable costs(200 ether) { - owner = _newOwner; + owner = newOwner; // just some example condition if (uint160(owner) & 0 == 1) // This did not refund for Solidity @@ -315,8 +315,8 @@ function finishes. uint public creationTime = block.timestamp; - modifier atStage(Stages _stage) { - if (stage != _stage) + modifier atStage(Stages stage_) { + if (stage != stage_) revert FunctionInvalidAtThisStage(); _; } diff --git a/docs/contracts/abstract-contracts.rst b/docs/contracts/abstract-contracts.rst index 34792f58c9..fb1beb2dab 100644 --- a/docs/contracts/abstract-contracts.rst +++ b/docs/contracts/abstract-contracts.rst @@ -6,12 +6,15 @@ Abstract Contracts ****************** -Contracts need to be marked as abstract when at least one of their functions is not implemented. -Contracts may be marked as abstract even though all functions are implemented. - -This can be done by using the ``abstract`` keyword as shown in the following example. Note that this contract needs to be -defined as abstract, because the function ``utterance()`` was defined, but no implementation was -provided (no implementation body ``{ }`` was given). +Contracts must be marked as abstract when at least one of their functions is not implemented or when +they do not provide arguments for all of their base contract constructors. +Even if this is not the case, a contract may still be marked abstract, such as when you do not intend +for the contract to be created directly. Abstract contracts are similar to :ref:`interfaces` but an +interface is more limited in what it can declare. + +An abstract contract is declared using the ``abstract`` keyword as shown in the following example. +Note that this contract needs to be defined as abstract, because the function ``utterance()`` is declared, +but no implementation was provided (no implementation body ``{ }`` was given). .. code-block:: solidity diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst index b67068d635..2e94397b12 100644 --- a/docs/contracts/constant-state-variables.rst +++ b/docs/contracts/constant-state-variables.rst @@ -41,14 +41,14 @@ Not all types for constants and immutables are implemented at this time. The onl uint immutable maxBalance; address immutable owner = msg.sender; - constructor(uint _decimals, address _reference) { - decimals = _decimals; + constructor(uint decimals_, address ref) { + decimals = decimals_; // Assignments to immutables can even access the environment. - maxBalance = _reference.balance; + maxBalance = ref.balance; } - function isBalanceTooHigh(address _other) public view returns (bool) { - return _other.balance > maxBalance; + function isBalanceTooHigh(address other) public view returns (bool) { + return other.balance > maxBalance; } } @@ -81,7 +81,7 @@ construction time. The contract creation code generated by the compiler will modify the contract's runtime code before it is returned by replacing all references -to immutables by the values assigned to the them. This is important if +to immutables with the values assigned to them. This is important if you are comparing the runtime code generated by the compiler with the one actually stored in the blockchain. @@ -95,4 +95,4 @@ blockchain. This is a safeguard against different interpretations about the order of state variable initialization and constructor execution, especially - with regards to inheritance. \ No newline at end of file + with regards to inheritance. diff --git a/docs/contracts/creating-contracts.rst b/docs/contracts/creating-contracts.rst index f1fd3b0b50..f574a5a6aa 100644 --- a/docs/contracts/creating-contracts.rst +++ b/docs/contracts/creating-contracts.rst @@ -48,7 +48,7 @@ This means that cyclic creation dependencies are impossible. // This is the constructor which registers the // creator and the assigned name. - constructor(bytes32 _name) { + constructor(bytes32 name_) { // State variables are accessed via their name // and not via e.g. `this.owner`. Functions can // be accessed directly or through `this.f`, @@ -65,7 +65,7 @@ This means that cyclic creation dependencies are impossible. // no real way to verify that. // This does not create a new contract. creator = TokenCreator(msg.sender); - name = _name; + name = name_; } function changeName(bytes32 newName) public { diff --git a/docs/contracts/errors.rst b/docs/contracts/errors.rst index 7800317a85..19577a3872 100644 --- a/docs/contracts/errors.rst +++ b/docs/contracts/errors.rst @@ -1,5 +1,4 @@ -.. index:: ! error, revert - +.. index:: ! error, revert, ! selector; of an error .. _errors: ******************************* @@ -80,3 +79,8 @@ of the built-in type ``Panic(uint256)``. by default. This means that an inner call can "forge" revert data that looks like it could have come from the contract that called it. + +Members of Errors +================= + +- ``error.selector``: A ``bytes4`` value containing the error selector. diff --git a/docs/contracts/events.rst b/docs/contracts/events.rst index 6e99a332bc..8618e7524b 100644 --- a/docs/contracts/events.rst +++ b/docs/contracts/events.rst @@ -1,4 +1,4 @@ -.. index:: ! event +.. index:: ! event, ! event; anonymous, ! event; indexed, ! event; topic .. _events: @@ -73,6 +73,18 @@ four indexed arguments rather than three. In particular, it is possible to "fake" the signature of another event using an anonymous event. +.. index:: ! selector; of an event + +Members of Events +================= + +- ``event.selector``: For non-anonymous events, this is a ``bytes32`` value + containing the ``keccak256`` hash of the event signature, as used in the default topic. + + +Example +======= + .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 @@ -80,18 +92,18 @@ four indexed arguments rather than three. contract ClientReceipt { event Deposit( - address indexed _from, - bytes32 indexed _id, - uint _value + address indexed from, + bytes32 indexed id, + uint value ); - function deposit(bytes32 _id) public payable { + function deposit(bytes32 id) public payable { // Events are emitted using `emit`, followed by // the name of the event and the arguments // (if any) in parentheses. Any such invocation // (even deeply nested) can be detected from // the JavaScript API by filtering for `Deposit`. - emit Deposit(msg.sender, _id, msg.value); + emit Deposit(msg.sender, id, msg.value); } } @@ -126,9 +138,9 @@ The output of the above looks like the following (trimmed): { "returnValues": { - "_from": "0x1111…FFFFCCCC", - "_id": "0x50…sd5adb20", - "_value": "0x420042" + "from": "0x1111…FFFFCCCC", + "id": "0x50…sd5adb20", + "value": "0x420042" }, "raw": { "data": "0x7f…91385", @@ -137,7 +149,7 @@ The output of the above looks like the following (trimmed): } Additional Resources for Understanding Events -============================================== +============================================= - `Javascript documentation `_ - `Example usage of events `_ diff --git a/docs/contracts/function-modifiers.rst b/docs/contracts/function-modifiers.rst index 0d4c8e8c26..f231195448 100644 --- a/docs/contracts/function-modifiers.rst +++ b/docs/contracts/function-modifiers.rst @@ -72,8 +72,8 @@ if they are marked ``virtual``. For details, please see registeredAddresses[msg.sender] = true; } - function changePrice(uint _price) public onlyOwner { - price = _price; + function changePrice(uint price_) public onlyOwner { + price = price_; } } @@ -111,6 +111,12 @@ whitespace-separated list and are evaluated in the order presented. Modifiers cannot implicitly access or change the arguments and return values of functions they modify. Their values can only be passed to them explicitly at the point of invocation. +In function modifiers, it is necessary to specify when you want the function to which the modifier is +applied to be run. The placeholder statement (denoted by a single underscore character ``_``) is used to +denote where the body of the function being modified should be inserted. Note that the +placeholder operator is different from using underscores as leading or trailing characters in variable +names, which is a stylistic choice. + Explicit returns from a modifier or function body only leave the current modifier or function body. Return variables are assigned and control flow continues after the ``_`` in the preceding modifier. diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index ff49e4f281..f14e4b8a54 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -17,17 +17,17 @@ that call them, similar to internal library functions. // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.1 <0.9.0; - function sum(uint[] memory _arr) pure returns (uint s) { - for (uint i = 0; i < _arr.length; i++) - s += _arr[i]; + function sum(uint[] memory arr) pure returns (uint s) { + for (uint i = 0; i < arr.length; i++) + s += arr[i]; } contract ArrayExample { bool found; - function f(uint[] memory _arr) public { + function f(uint[] memory arr) public { // This calls the free function internally. // The compiler will add its code to the contract. - uint s = sum(_arr); + uint s = sum(arr); require(s >= 10); found = true; } @@ -35,10 +35,10 @@ that call them, similar to internal library functions. .. note:: Functions defined outside a contract are still always executed - in the context of a contract. They still have access to the variable ``this``, - can call other contracts, send them Ether and destroy the contract that called them, + in the context of a contract. + They still can call other contracts, send them Ether and destroy the contract that called them, among other things. The main difference to functions defined inside a contract - is that free functions do not have direct access to storage variables and functions + is that free functions do not have direct access to the variable ``this``, storage variables and functions not in their scope. .. _function-parameters-return-variables: @@ -65,23 +65,13 @@ with two integers, you would use something like the following: contract Simple { uint sum; - function taker(uint _a, uint _b) public { - sum = _a + _b; + function taker(uint a, uint b) public { + sum = a + b; } } Function parameters can be used as any other local variable and they can also be assigned to. -.. note:: - - An :ref:`external function` cannot accept a - multi-dimensional array as an input - parameter. This functionality is possible if you enable the ABI coder v2 - by adding ``pragma abicoder v2;`` to your source file. - - An :ref:`internal function` can accept a - multi-dimensional array without enabling the feature. - .. index:: return array, return string, array, string, array of strings, dynamic array, variably sized array, return struct, struct Return Variables @@ -99,13 +89,13 @@ two integers passed as function parameters, then you use something like: pragma solidity >=0.4.16 <0.9.0; contract Simple { - function arithmetic(uint _a, uint _b) + function arithmetic(uint a, uint b) public pure - returns (uint o_sum, uint o_product) + returns (uint sum, uint product) { - o_sum = _a + _b; - o_product = _a * _b; + sum = a + b; + product = a * b; } } @@ -126,12 +116,12 @@ statement: pragma solidity >=0.4.16 <0.9.0; contract Simple { - function arithmetic(uint _a, uint _b) + function arithmetic(uint a, uint b) public pure - returns (uint o_sum, uint o_product) + returns (uint sum, uint product) { - return (_a + _b, _a * _b); + return (a + b, a * b); } } @@ -139,12 +129,16 @@ If you use an early ``return`` to leave a function that has return variables, you must provide return values together with the return statement. .. note:: - You cannot return some types from non-internal functions, notably - multi-dimensional dynamic arrays and structs. If you enable the - ABI coder v2 by adding ``pragma abicoder v2;`` - to your source file then more types are available, but - ``mapping`` types are still limited to inside a single contract and you - cannot transfer them. + You cannot return some types from non-internal functions. + This includes the types listed below and any composite types that recursively contain them: + + - mappings, + - internal function types, + - reference types with location set to ``storage``, + - multi-dimensional arrays (applies only to :ref:`ABI coder v1 `), + - structs (applies only to :ref:`ABI coder v1 `). + + This restriction does not apply to library functions because of their different :ref:`internal ABI `. .. _multi-return: @@ -317,12 +311,13 @@ will consume more gas than the 2300 gas stipend: - Sending Ether .. warning:: - Contracts that receive Ether directly (without a function call, i.e. using ``send`` or ``transfer``) - but do not define a receive Ether function or a payable fallback function - throw an exception, sending back the Ether (this was different - before Solidity v0.4.0). So if you want your contract to receive Ether, + When Ether is sent directly to a contract (without a function call, i.e. sender uses ``send`` or ``transfer``) + but the receiving contract does not define a receive Ether function or a payable fallback function, + an exception will be thrown, sending back the Ether (this was different + before Solidity v0.4.0). If you want your contract to receive Ether, you have to implement a receive Ether function (using payable fallback functions for receiving Ether is - not recommended, since it would not fail on interface confusions). + not recommended, since the fallback is invoked and would not fail for interface confusions + on the part of the sender). .. warning:: @@ -362,7 +357,7 @@ Fallback Function ----------------- A contract can have at most one ``fallback`` function, declared using either ``fallback () external [payable]`` -or ``fallback (bytes calldata _input) external [payable] returns (bytes memory _output)`` +or ``fallback (bytes calldata input) external [payable] returns (bytes memory output)`` (both without the ``function`` keyword). This function must have ``external`` visibility. A fallback function can be virtual, can override and can have modifiers. @@ -373,8 +368,8 @@ all and there is no :ref:`receive Ether function `. The fallback function always receives data, but in order to also receive Ether it must be marked ``payable``. -If the version with parameters is used, ``_input`` will contain the full data sent to the contract -(equal to ``msg.data``) and can return data in ``_output``. The returned data will not be +If the version with parameters is used, ``input`` will contain the full data sent to the contract +(equal to ``msg.data``) and can return data in ``output``. The returned data will not be ABI-encoded. Instead it will be returned without modifications (not even padding). In the worst case, if a payable fallback function is also used in @@ -397,7 +392,7 @@ operations as long as there is enough gas passed on to it. for the function selector and then you can use ``abi.decode`` together with the array slice syntax to decode ABI-encoded data: - ``(c, d) = abi.decode(_input[4:], (uint256, uint256));`` + ``(c, d) = abi.decode(input[4:], (uint256, uint256));`` Note that this should only be used as a last resort and proper functions should be used instead. @@ -486,13 +481,13 @@ The following example shows overloading of the function pragma solidity >=0.4.16 <0.9.0; contract A { - function f(uint _in) public pure returns (uint out) { - out = _in; + function f(uint value) public pure returns (uint out) { + out = value; } - function f(uint _in, bool _really) public pure returns (uint out) { - if (_really) - out = _in; + function f(uint value, bool really) public pure returns (uint out) { + if (really) + out = value; } } @@ -506,12 +501,12 @@ externally visible functions differ by their Solidity types but not by their ext // This will not compile contract A { - function f(B _in) public pure returns (B out) { - out = _in; + function f(B value) public pure returns (B out) { + out = value; } - function f(address _in) public pure returns (address out) { - out = _in; + function f(address value) public pure returns (address out) { + out = value; } } @@ -539,12 +534,12 @@ candidate, resolution fails. pragma solidity >=0.4.16 <0.9.0; contract A { - function f(uint8 _in) public pure returns (uint8 out) { - out = _in; + function f(uint8 val) public pure returns (uint8 out) { + out = val; } - function f(uint256 _in) public pure returns (uint256 out) { - out = _in; + function f(uint256 val) public pure returns (uint256 out) { + out = val; } } diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst index b77feda0a1..a33a36d27b 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -76,9 +76,9 @@ Details are given in the following example. } - // Multiple inheritance is possible. Note that `owned` is + // Multiple inheritance is possible. Note that `Owned` is // also a base class of `Destructible`, yet there is only a single - // instance of `owned` (as for virtual inheritance in C++). + // instance of `Owned` (as for virtual inheritance in C++). contract Named is Owned, Destructible { constructor(bytes32 name) { Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970); @@ -421,8 +421,8 @@ equivalent to ``constructor() {}``. For example: abstract contract A { uint public a; - constructor(uint _a) { - a = _a; + constructor(uint a_) { + a = a_; } } @@ -443,7 +443,7 @@ cannot be assigned valid values from outside but only through the constructors o ``internal`` or ``public``. -.. index:: ! base;constructor +.. index:: ! base;constructor, inheritance list, contract;abstract, abstract contract Arguments for Base Constructors =============================== @@ -459,7 +459,7 @@ derived contracts need to specify all of them. This can be done in two ways: contract Base { uint x; - constructor(uint _x) { x = _x; } + constructor(uint x_) { x = x_; } } // Either directly specify in the inheritance list... @@ -467,14 +467,23 @@ derived contracts need to specify all of them. This can be done in two ways: constructor() {} } - // or through a "modifier" of the derived constructor. + // or through a "modifier" of the derived constructor... contract Derived2 is Base { - constructor(uint _y) Base(_y * _y) {} + constructor(uint y) Base(y * y) {} + } + + // or declare abstract... + abstract contract Derived3 is Base { + } + + // and have the next concrete derived contract initialize it. + contract DerivedFromDerived is Derived3 { + constructor() Base(10 + 10) {} } One way is directly in the inheritance list (``is Base(7)``). The other is in the way a modifier is invoked as part of -the derived constructor (``Base(_y * _y)``). The first way to +the derived constructor (``Base(y * y)``). The first way to do it is more convenient if the constructor argument is a constant and defines the behaviour of the contract or describes it. The second way has to be used if the @@ -484,7 +493,12 @@ inheritance list or in modifier-style in the derived constructor. Specifying arguments in both places is an error. If a derived contract does not specify the arguments to all of its base -contracts' constructors, it will be abstract. +contracts' constructors, it must be declared abstract. In that case, when +another contract derives from it, that other contract's inheritance list +or constructor must provide the necessary parameters +for all base classes that haven't had their parameters specified (otherwise, +that other contract must be declared abstract as well). For example, in the above +code snippet, see ``Derived3`` and ``DerivedFromDerived``. .. index:: ! inheritance;multiple, ! linearization, ! C3 linearization diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst index a4581a15f9..cc71cf64e6 100644 --- a/docs/contracts/interfaces.rst +++ b/docs/contracts/interfaces.rst @@ -10,7 +10,7 @@ Interfaces are similar to abstract contracts, but they cannot have any functions There are further restrictions: - They cannot inherit from other contracts, but they can inherit from other interfaces. -- All declared functions must be external. +- All declared functions must be external in the interface, even if they are public in the contract. - They cannot declare a constructor. - They cannot declare state variables. - They cannot declare modifiers. diff --git a/docs/contracts/libraries.rst b/docs/contracts/libraries.rst index 76bedba49b..7256ebe031 100644 --- a/docs/contracts/libraries.rst +++ b/docs/contracts/libraries.rst @@ -146,16 +146,16 @@ custom types without the overhead of external function calls: r.limbs[0] = x; } - function add(bigint memory _a, bigint memory _b) internal pure returns (bigint memory r) { - r.limbs = new uint[](max(_a.limbs.length, _b.limbs.length)); + function add(bigint memory a, bigint memory b) internal pure returns (bigint memory r) { + r.limbs = new uint[](max(a.limbs.length, b.limbs.length)); uint carry = 0; for (uint i = 0; i < r.limbs.length; ++i) { - uint a = limb(_a, i); - uint b = limb(_b, i); + uint limbA = limb(a, i); + uint limbB = limb(b, i); unchecked { - r.limbs[i] = a + b + carry; + r.limbs[i] = limbA + limbB + carry; - if (a + b < a || (a + b == type(uint).max && carry > 0)) + if (limbA + limbB < limbA || (limbA + limbB == type(uint).max && carry > 0)) carry = 1; else carry = 0; @@ -172,8 +172,8 @@ custom types without the overhead of external function calls: } } - function limb(bigint memory _a, uint _limb) internal pure returns (uint) { - return _limb < _a.limbs.length ? _a.limbs[_limb] : 0; + function limb(bigint memory a, uint index) internal pure returns (uint) { + return index < a.limbs.length ? a.limbs[index] : 0; } function max(uint a, uint b) private pure returns (uint) { @@ -215,7 +215,7 @@ In comparison to contracts, libraries are restricted in the following ways: (These might be lifted at a later point.) .. _library-selectors: -.. index:: selector +.. index:: ! selector; of a library function Function Signatures and Selectors in Libraries ============================================== diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst index 582409904f..b4a60585a9 100644 --- a/docs/contracts/using-for.rst +++ b/docs/contracts/using-for.rst @@ -6,71 +6,95 @@ Using For ********* -The directive ``using A for B;`` can be used to attach library -functions (from the library ``A``) to any type (``B``) -in the context of a contract. +The directive ``using A for B;`` can be used to attach +functions (``A``) as member functions to any type (``B``). These functions will receive the object they are called on as their first parameter (like the ``self`` variable in Python). -The effect of ``using A for *;`` is that the functions from -the library ``A`` are attached to *any* type. +It is valid either at file level or inside a contract, +at contract level. -In both situations, *all* functions in the library are attached, +The first part, ``A``, can be one of: + +- a list of file-level or library functions (``using {f, g, h, L.t} for uint;``) - + only those functions will be attached to the type. +- the name of a library (``using L for uint;``) - + all functions (both public and internal ones) of the library are attached to the type + +At file level, the second part, ``B``, has to be an explicit type (without data location specifier). +Inside contracts, you can also use ``using L for *;``, +which has the effect that all functions of the library ``L`` +are attached to *all* types. + +If you specify a library, *all* functions in the library are attached, even those where the type of the first parameter does not match the type of the object. The type is checked at the point the function is called and function overload resolution is performed. +If you use a list of functions (``using {f, g, h, L.t} for uint;``), +then the type (``uint``) has to be implicitly convertible to the +first parameter of each of these functions. This check is +performed even if none of these functions are called. + The ``using A for B;`` directive is active only within the current -contract, including within all of its functions, and has no effect -outside of the contract in which it is used. The directive -may only be used inside a contract, not inside any of its functions. +scope (either the contract or the current module/source unit), +including within all of its functions, and has no effect +outside of the contract or module in which it is used. + +When the directive is used at file level and applied to a +user-defined type which was defined at file level in the same file, +the word ``global`` can be added at the end. This will have the +effect that the functions are attached to the type everywhere +the type is available (including other files), not only in the +scope of the using statement. Let us rewrite the set example from the -:ref:`libraries` in this way: +:ref:`libraries` section in this way, using file-level functions +instead of library functions. .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.6.0 <0.9.0; + pragma solidity ^0.8.13; - - // This is the same code as before, just without comments struct Data { mapping(uint => bool) flags; } + // Now we attach functions to the type. + // The attached functions can be used throughout the rest of the module. + // If you import the module, you have to + // repeat the using directive there, for example as + // import "flags.sol" as Flags; + // using {Flags.insert, Flags.remove, Flags.contains} + // for Flags.Data; + using {insert, remove, contains} for Data; + + function insert(Data storage self, uint value) + returns (bool) + { + if (self.flags[value]) + return false; // already there + self.flags[value] = true; + return true; + } - library Set { - function insert(Data storage self, uint value) - public - returns (bool) - { - if (self.flags[value]) - return false; // already there - self.flags[value] = true; - return true; - } - - function remove(Data storage self, uint value) - public - returns (bool) - { - if (!self.flags[value]) - return false; // not there - self.flags[value] = false; - return true; - } + function remove(Data storage self, uint value) + returns (bool) + { + if (!self.flags[value]) + return false; // not there + self.flags[value] = false; + return true; + } - function contains(Data storage self, uint value) - public - view - returns (bool) - { - return self.flags[value]; - } + function contains(Data storage self, uint value) + view + returns (bool) + { + return self.flags[value]; } contract C { - using Set for Data; // this is the crucial change Data knownValues; function register(uint value) public { @@ -82,12 +106,13 @@ Let us rewrite the set example from the } } -It is also possible to extend elementary types in that way: +It is also possible to extend built-in types in that way. +In this example, we will use a library. .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.6.8 <0.9.0; + pragma solidity ^0.8.13; library Search { function indexOf(uint[] storage self, uint value) @@ -100,27 +125,27 @@ It is also possible to extend elementary types in that way: return type(uint).max; } } + using Search for uint[]; contract C { - using Search for uint[]; uint[] data; function append(uint value) public { data.push(value); } - function replace(uint _old, uint _new) public { + function replace(uint from, uint to) public { // This performs the library function call - uint index = data.indexOf(_old); + uint index = data.indexOf(from); if (index == type(uint).max) - data.push(_new); + data.push(to); else - data[index] = _new; + data[index] = to; } } Note that all external library calls are actual EVM function calls. This means that -if you pass memory or value types, a copy will be performed, even of the +if you pass memory or value types, a copy will be performed, even in case of the ``self`` variable. The only situation where no copy will be performed is when storage reference variables are used or when internal library functions are called. diff --git a/docs/contracts/visibility-and-getters.rst b/docs/contracts/visibility-and-getters.rst index f04945cfdb..8932c5079b 100644 --- a/docs/contracts/visibility-and-getters.rst +++ b/docs/contracts/visibility-and-getters.rst @@ -1,20 +1,41 @@ .. index:: ! visibility, external, public, private, internal +.. |visibility-caveat| replace:: Making something ``private`` or ``internal`` only prevents other contracts from reading or modifying the information, but it will still be visible to the whole world outside of the blockchain. + .. _visibility-and-getters: ********************** Visibility and Getters ********************** -Solidity knows two kinds of function calls: internal -ones that do not create an actual EVM call (also called -a "message call") and external -ones that do. Because of that, there are four types of visibility for -functions and state variables. +State Variable Visibility +========================= + +``public`` + Public state variables differ from internal ones only in that the compiler automatically generates + :ref:`getter functions` for them, which allows other contracts to read their values. + When used within the same contract, the external access (e.g. ``this.x``) invokes the getter + while internal access (e.g. ``x``) gets the variable value directly from storage. + Setter functions are not generated so other contracts cannot directly modify their values. + +``internal`` + Internal state variables can only be accessed from within the contract they are defined in + and in derived contracts. + They cannot be accessed externally. + This is the default visibility level for state variables. + +``private`` + Private state variables are like internal ones but they are not visible in derived contracts. + +.. warning:: + |visibility-caveat| -Functions have to be specified as being ``external``, -``public``, ``internal`` or ``private``. -For state variables, ``external`` is not possible. +Function Visibility +=================== + +Solidity knows two kinds of function calls: external ones that do create an actual EVM message call and internal ones that do not. +Furthermore, internal functions can be made inaccessible to derived contracts. +This gives rise to four types of visibility for functions. ``external`` External functions are part of the contract interface, @@ -24,27 +45,19 @@ For state variables, ``external`` is not possible. ``public`` Public functions are part of the contract interface - and can be either called internally or via - messages. For public state variables, an automatic getter - function (see below) is generated. + and can be either called internally or via message calls. ``internal`` - Those functions and state variables can only be - accessed internally (i.e. from within the current contract - or contracts deriving from it), without using ``this``. - This is the default visibility level for state variables. + Internal functions can only be accessed from within the current contract + or contracts deriving from it. + They cannot be accessed externally. + Since they are not exposed to the outside through the contract's ABI, they can take parameters of internal types like mappings or storage references. ``private`` - Private functions and state variables are only - visible for the contract they are defined in and not in - derived contracts. - -.. note:: - Everything that is inside a contract is visible to - all observers external to the blockchain. Making something ``private`` - only prevents other contracts from reading or modifying - the information, but it will still be visible to the - whole world outside of the blockchain. + Private functions are like internal ones but they are not visible in derived contracts. + +.. warning:: + |visibility-caveat| The visibility specifier is given after the type for state variables and between parameter list and diff --git a/docs/contributing.rst b/docs/contributing.rst index aa871189f9..1b438b0640 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -2,7 +2,11 @@ 기여하기 ############ +<<<<<<< HEAD 도움은 항상 환영하며 Solidity에 기여하는 방법은 여러가지가 있습니다. +======= +Help is always welcome and there are plenty of options to contribute to Solidity. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 특히 다음 분야에서 많은 도움을 기다리고 있습니다: @@ -20,8 +24,12 @@ 먼저 솔리디티의 컴포넌트와 빌드 프로세스에 익숙해지려면 :ref:`building-from-source` 를 참고하십시오. 또한 솔리디티로 스마트 컨트랙트를 작성하는 방법을 숙지하는 것도 좋습니다. +<<<<<<< HEAD 이 프로젝트는 다음 `컨트리뷰터 행동 지침 `_ 와 함께 릴리즈되었습니다. 프로젝트에 참여하면 (이슈, 풀리퀘스트, Gitter 채널 등) 이에 동의하게 됩니다. +======= +Please note that this project is released with a `Contributor Code of Conduct `_. By participating in this project — in the issues, pull requests, or Gitter channels — you agree to abide by its terms. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 Team Calls ========== @@ -29,8 +37,12 @@ Team Calls 논의가 필요한 이슈 또는 풀리퀘스트가 있거나, 혹은 팀 또는 컨트리뷰터들이 무엇을 하고 있는지 듣고 싶으면 다음 공개 팀 콜에 참여하실 수 있습니다: +<<<<<<< HEAD - 월요일 3pm CET/CEST. - 수요일 2pm CET/CEST. +======= +- Mondays and Wednesdays at 3pm CET/CEST. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 둘 다 `Jitsi `_ 에서 참여할 수 있습니다. @@ -47,8 +59,13 @@ Team Calls * 이슈 재현을 위한 단계 * 실제 작동과 의도한 작동 비교 +<<<<<<< HEAD 이슈를 발생시킨 소스코드를 최소한으로 줄이는 것 항상 많은 도움이 되며 때로는 오해를 해결하기도 합니다. +======= +Reducing the source code that caused the issue to a bare minimum is always +very helpful, and sometimes even clarifies a misunderstanding. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 풀리퀘스트 워크플로우 ========================== @@ -62,8 +79,14 @@ Team Calls 또한, 새로운 피쳐를 작성 중이라면, ``test/`` 하단에 필요한 테스트 케이스를 반드시 추가하십시오 (아래 참고). +<<<<<<< HEAD 다만, 더 큰 변경을 하는 경우, `Solidity Development Gitter channel `_ 과 먼저 논의하십히오 (상기의 채널과 별개로, 이는 언어의 사용이 아닌 컴파일러와 언어 개발에 중점을 두고 있습니다). +======= +However, if you are making a larger change, please consult with the `Solidity Development Gitter channel +`_ (different from the one mentioned above — this one is +focused on compiler and language development instead of language usage) first. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 새로운 피쳐와 버그픽스 내역는 ``Changelog.md`` 파일에 추가되어야 합니다. 해당하는 경우 이전 엔트리의 스타일을 따르십시오. @@ -84,8 +107,20 @@ Prerequisites (`evmone `_, `libz3 `_, `libhera `_). +<<<<<<< HEAD MacOS의 경우 일부 테스트 스크립트는 GNU coreutils가 설치되어야 합니다. 이는 Homebrew를 사용하는게 가장 쉬울 수 있습니다: ``brew install coreutils``. +======= +On macOS systems, some of the testing scripts expect GNU coreutils to be installed. +This can be easiest accomplished using Homebrew: ``brew install coreutils``. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 + +On Windows systems, make sure that you have a privilege to create symlinks, +otherwise several tests may fail. +Administrators should have that privilege, but you may also +`grant it to other users `_ +or +`enable Developer Mode `_. Running the Tests ----------------- @@ -101,9 +136,15 @@ Solidity는 여러 종류의 테스트가 있으며, 대부분은 `Boost C++ Tes 테스트 시스템은 semantic 테스트를 실행하기 위해 `evmone `_ 의 위치를 자동으로 파악하려 합니다. +<<<<<<< HEAD ``evmone`` 라이브러리는 반드시 현재 작업 디렉토리, 또는 이의 부모, 또는 이의 부모의 부모에서 상대경로로 ``deps`` 또는 ``deps/lib`` 디렉토리에 위치해야합니다. 대안으로 ``evmone`` 공유 객체에 대한 명시적 위치를 ``ETH_EVMONE`` 환경변수에 지정할 수 있습니다. +======= +The ``evmone`` library must be located in the ``deps`` or ``deps/lib`` directory relative to the +current working directory, to its parent or its parent's parent. Alternatively, an explicit location +for the ``evmone`` shared object can be specified via the ``ETH_EVMONE`` environment variable. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 ``evmone`` 주로 semantic 과 가스 테스트 실행에 필요합니다. 설치하지 않은 경우, ``scripts/soltest.sh`` 에 ``--no-semantic-tests`` 플래그를 추가해 해당하는 테스트를 건너뛸 수 있습니다. @@ -226,7 +267,11 @@ Writing and Running Syntax Tests - ``skip``: 해당 특정 테스트를 건너뜁니다. - ``quit``: ``isoltest`` 를 종료합니다. +<<<<<<< HEAD 테스트 프로세스를 종료하는 ``quit`` 를 제외하고 위 모든 옵션들은 현재 컨트랙트에 적용됩니다. +======= +All of these options apply to the current contract, except ``quit`` which stops the entire testing process. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 위 테스트를 자동으로 업데이트하면 다음과 같이 바뀝니다. @@ -273,7 +318,7 @@ Next, build Solidity (or just the ``solfuzzer`` binary) with AFL as your compile cmake .. -DCMAKE_C_COMPILER=path/to/afl-gcc -DCMAKE_CXX_COMPILER=path/to/afl-g++ make solfuzzer -At this stage you should be able to see a message similar to the following: +At this stage, you should be able to see a message similar to the following: .. code-block:: text @@ -456,13 +501,13 @@ For example ``pragma solidity >=0.4.0 <0.9.0;``. Running Documentation Tests --------------------------- -Make sure your contributions pass our documentation tests by running ``./scripts/docs.sh`` that installs dependencies +Make sure your contributions pass our documentation tests by running ``./docs/docs.sh`` that installs dependencies needed for documentation and checks for any problems such as broken links or syntax issues. Solidity Language Design ======================== -To actively get involved in the language design process and share your ideas concerning the future of Solidity, +To actively get involved in the language design process and to share your ideas concerning the future of Solidity, please join the `Solidity forum `_. The Solidity forum serves as the place to propose and discuss new language features and their implementation in @@ -481,7 +526,7 @@ If you want to know where the team is standing in terms or implementing new feat Issues in the design backlog need further specification and will either be discussed in a language design call or in a regular team call. You can see the upcoming changes for the next breaking release by changing from the default branch (`develop`) to the `breaking branch `_. -For ad-hoc cases and questions you can reach out to us via the `Solidity-dev Gitter channel `_, a +For ad-hoc cases and questions, you can reach out to us via the `Solidity-dev Gitter channel `_ — a dedicated chatroom for conversations around the Solidity compiler and language development. We are happy to hear your thoughts on how we can improve the language design process to be even more collaborative and transparent. diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 0ce7d21e33..18a522217f 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -150,8 +150,8 @@ throws an exception or goes out of gas. use ``f.value(x).gas(g)()``. This was deprecated in Solidity 0.6.2 and is no longer possible since Solidity 0.7.0. -Named Calls and Anonymous Function Parameters ---------------------------------------------- +Function Calls with Named Parameters +------------------------------------ Function call arguments can be given by name, in any order, if they are enclosed in ``{ }`` as can be seen in the following @@ -176,11 +176,13 @@ parameters from the function declaration, but can be in arbitrary order. } -Omitted Function Parameter Names --------------------------------- +Omitted Names in Function Definitions +------------------------------------- -The names of unused parameters (especially return parameters) can be omitted. -Those parameters will still be present on the stack, but they are inaccessible. +The names of parameters and return values in the function declaration can be omitted. +Those items with omitted names will still be present on the stack, but they are +inaccessible by name. An omitted return value name +can still return a value to the caller by use of the ``return`` statement. .. code-block:: solidity @@ -283,7 +285,7 @@ which only need to be created if there is a dispute. salt, keccak256(abi.encodePacked( type(D).creationCode, - arg + abi.encode(arg) )) ))))); diff --git a/docs/docs.sh b/docs/docs.sh new file mode 100755 index 0000000000..f2c5667612 --- /dev/null +++ b/docs/docs.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +#------------------------------------------------------------------------------ +# Bash script to build the Solidity Sphinx documentation locally. +# +# The documentation for solidity is hosted at: +# +# https://docs.soliditylang.org +# +# ------------------------------------------------------------------------------ +# This file is part of solidity. +# +# solidity is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# solidity is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with solidity. If not, see +# +# (c) 2016 solidity contributors. +#------------------------------------------------------------------------------ + +set -euo pipefail + +script_dir="$(dirname "$0")" + +cd "${script_dir}" +pip3 install -r requirements.txt --upgrade --upgrade-strategy eager +sphinx-build -nW -b html -d _build/doctrees . _build/html diff --git a/docs/examples/modular.rst b/docs/examples/modular.rst index 7903ae27fd..697699ae6e 100644 --- a/docs/examples/modular.rst +++ b/docs/examples/modular.rst @@ -7,7 +7,7 @@ Modular Contracts A modular approach to building your contracts helps you reduce the complexity and improve the readability which will help to identify bugs and vulnerabilities during development and code review. -If you specify and control the behaviour or each module in isolation, the +If you specify and control the behaviour of each module in isolation, the interactions you have to consider are only those between the module specifications and not every other moving part of the contract. In the example below, the contract uses the ``move`` method diff --git a/docs/examples/voting.rst b/docs/examples/voting.rst index 0c57165a97..97dae4d937 100644 --- a/docs/examples/voting.rst +++ b/docs/examples/voting.rst @@ -95,6 +95,7 @@ function delegate(address to) external { // 참조값을 할당합니다. Voter storage sender = voters[msg.sender]; + require(sender.weight != 0, "You have no right to vote"); require(!sender.voted, "You already voted."); require(to != msg.sender, "Self-delegation is disallowed."); @@ -112,11 +113,21 @@ require(to != msg.sender, "Found loop in delegation."); } +<<<<<<< HEAD // `sender`가 참조값이므로 // `voters[msg.sender].voted`를 수정합니다. +======= + Voter storage delegate_ = voters[to]; + + // Voters cannot delegate to accounts that cannot vote. + require(delegate_.weight >= 1); + + // Since `sender` is a reference, this + // modifies `voters[msg.sender]`. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 sender.voted = true; sender.delegate = to; - Voter storage delegate_ = voters[to]; + if (delegate_.voted) { // 만일 위임자가 이미 투표하였을 경우, // 투표수에 직접적으로 추가합니다. @@ -170,5 +181,13 @@ 가능한 개선 사항들 ===================== +<<<<<<< HEAD 현재로썬 모든 참가자들에게 투표권을 부여하기 위해 많은 트랜잭션이 필요합니다. 더 나은 방법이 있을까요? +======= +Currently, many transactions are needed to +assign the rights to vote to all participants. +Moreover, if two or more proposals have the same +number of votes, ``winningProposal()`` is not able +to register a tie. Can you think of a way to fix these issues? +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 diff --git a/docs/grammar/SolidityLexer.g4 b/docs/grammar/SolidityLexer.g4 index 5a73be85fd..c47dc411cd 100644 --- a/docs/grammar/SolidityLexer.g4 +++ b/docs/grammar/SolidityLexer.g4 @@ -9,10 +9,9 @@ ReservedKeywords: | 'partial' | 'promise' | 'reference' | 'relocatable' | 'sealed' | 'sizeof' | 'static' | 'supports' | 'switch' | 'typedef' | 'typeof' | 'var'; -Pragma: 'pragma' -> pushMode(PragmaMode); Abstract: 'abstract'; -Anonymous: 'anonymous'; Address: 'address'; +Anonymous: 'anonymous'; As: 'as'; Assembly: 'assembly' -> pushMode(AssemblyBlockMode); Bool: 'bool'; @@ -30,13 +29,11 @@ Else: 'else'; Emit: 'emit'; Enum: 'enum'; Error: 'error'; // not a real keyword -Revert: 'revert'; // not a real keyword Event: 'event'; External: 'external'; Fallback: 'fallback'; False: 'false'; Fixed: 'fixed' | ('fixed' [1-9][0-9]* 'x' [1-9][0-9]*); -From: 'from'; // not a real keyword /** * Bytes types of fixed length. */ @@ -46,7 +43,9 @@ FixedBytes: 'bytes17' | 'bytes18' | 'bytes19' | 'bytes20' | 'bytes21' | 'bytes22' | 'bytes23' | 'bytes24' | 'bytes25' | 'bytes26' | 'bytes27' | 'bytes28' | 'bytes29' | 'bytes30' | 'bytes31' | 'bytes32'; For: 'for'; +From: 'from'; // not a real keyword Function: 'function'; +Global: 'global'; // not a real keyword Hex: 'hex'; If: 'if'; Immutable: 'immutable'; @@ -66,12 +65,14 @@ New: 'new'; NumberUnit: 'wei' | 'gwei' | 'ether' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years'; Override: 'override'; Payable: 'payable'; +Pragma: 'pragma' -> pushMode(PragmaMode); Private: 'private'; Public: 'public'; Pure: 'pure'; Receive: 'receive'; Return: 'return'; Returns: 'returns'; +Revert: 'revert'; // not a real keyword /** * Sized signed integer types. * int is an alias of int256. @@ -251,6 +252,12 @@ mode AssemblyBlockMode; AssemblyDialect: '"evmasm"'; AssemblyLBrace: '{' -> popMode, pushMode(YulMode); +AssemblyFlagString: '"' DoubleQuotedStringCharacter+ '"'; + +AssemblyBlockLParen: '('; +AssemblyBlockRParen: ')'; +AssemblyBlockComma: ','; + AssemblyBlockWS: [ \t\r\n\u000C]+ -> skip ; AssemblyBlockCOMMENT: '/*' .*? '*/' -> channel(HIDDEN) ; AssemblyBlockLINE_COMMENT: '//' ~[\r\n]* -> channel(HIDDEN) ; diff --git a/docs/grammar/SolidityParser.g4 b/docs/grammar/SolidityParser.g4 index 110773fede..92718b9752 100644 --- a/docs/grammar/SolidityParser.g4 +++ b/docs/grammar/SolidityParser.g4 @@ -12,6 +12,7 @@ options { tokenVocab=SolidityLexer; } sourceUnit: ( pragmaDirective | importDirective + | usingDirective | contractDefinition | interfaceDefinition | libraryDefinition @@ -311,10 +312,10 @@ errorDefinition: Semicolon; /** - * Using directive to bind library functions to types. - * Can occur within contracts and libraries. + * Using directive to bind library functions and free functions to types. + * Can occur within contracts and libraries and at the file level. */ -usingDirective: Using identifierPath For (Mul | typeName) Semicolon; +usingDirective: Using (identifierPath | (LBrace identifierPath (Comma identifierPath)* RBrace)) For (Mul | typeName) Global? Semicolon; /** * A type name can be an elementary type, a function type, a mapping type, a user-defined type * (e.g. a contract or struct) or an array type. @@ -388,7 +389,7 @@ inlineArrayExpression: LBrack (expression ( Comma expression)* ) RBrack; /** * Besides regular non-keyword Identifiers, some keywords like 'from' and 'error' can also be used as identifiers. */ -identifier: Identifier | From | Error | Revert; +identifier: Identifier | From | Error | Revert | Global; literal: stringLiteral | numberLiteral | booleanLiteral | hexStringLiteral | unicodeStringLiteral; booleanLiteral: True | False; @@ -476,7 +477,13 @@ revertStatement: Revert expression callArgumentList Semicolon; * The contents of an inline assembly block use a separate scanner/lexer, i.e. the set of keywords and * allowed identifiers is different inside an inline assembly block. */ -assemblyStatement: Assembly AssemblyDialect? AssemblyLBrace yulStatement* YulRBrace; +assemblyStatement: Assembly AssemblyDialect? assemblyFlags? AssemblyLBrace yulStatement* YulRBrace; + +/** + * Assembly flags. + * Comma-separated list of double-quoted strings as flags. + */ +assemblyFlags: AssemblyBlockLParen AssemblyFlagString (AssemblyBlockComma AssemblyFlagString)* AssemblyBlockRParen; //@doc:inline variableDeclarationList: variableDeclarations+=variableDeclaration (Comma variableDeclarations+=variableDeclaration)*; diff --git a/docs/index.rst b/docs/index.rst index 689228c298..4f1ed28c2c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,9 +4,14 @@ 솔리디티는 스마트 컨트랙트를 시도하기 위한 객체지향적인 고급 프로그래밍 언어입니다. 여기서 스마트 컨트랙트란 이더리움 상태 내부에 있는 여러 계정들의 행동들을 통제할 수 있는 프로그램을 의미합니다. +<<<<<<< HEAD 솔리디티는 `curly-bracket language `_ 입니다. C++, 파이썬 및 자바스크립트의 영향을 받았으며 이더리움 가상 머신(EVM)을 공략하기 위해 고안되었습니다. 솔리디티가 어떤 언어로부터 영감을 받았는지에 대한 자세한 설명은 :doc:`language influeces ` 섹션에서 확인하실 수 있습니다. +======= +Solidity is a `curly-bracket language `_ designed to target the Ethereum Virtual Machine (EVM). +It is influenced by C++, Python and JavaScript. You can find more details about which languages Solidity has been inspired by in the :doc:`language influences ` section. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 솔리디티는 정적 타입 언어로서 다른 특징 중에서도 상속, 라이브러리 그리고 유저가 스스로 정의한 복잡한 타입에 대한 정의 등을 지원합니다. @@ -70,6 +75,7 @@ Ethereum에 대한 더 많은 문서, 다양한 튜토리얼, 툴, 그리고 개 번역 ------------ +<<<<<<< HEAD 현재 커뮤니티 자원자분들께서 본 공식 문서를 몇몇 언어로 번역하고 계십니다. 완성도 및 업데이트 상황은 언어별로 상이하며, 영문이 원본입니다. @@ -86,6 +92,27 @@ Ethereum에 대한 더 많은 문서, 다양한 튜토리얼, 툴, 그리고 개 * `중국어(간체) `_ (진행 중) * `스페인어 `_ * `터키어 `_ (부분적으로 진행) +======= +Community contributors help translate this documentation into several languages. +Note that they have varying degrees of completeness and up-to-dateness. The English +version stands as a reference. + +You can switch between languages by clicking on the flyout menu in the bottom-left corner +and selecting the preferred language. + +* `French `_ +* `Indonesian `_ +* `Persian `_ +* `Japanese `_ +* `Korean `_ +* `Chinese `_ + +.. note:: + + We recently set up a new GitHub organization and translation workflow to help streamline the + community efforts. Please refer to the `translation guide `_ + for information on how to start a new language or contribute to the community translations. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 차례 ======== diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index 90786a0eb0..b2c6674842 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -9,12 +9,31 @@ Solidity 컴파일러 설치하기 버저닝 ========== +<<<<<<< HEAD Solidity 버전들은 `semantic versioning `_ 방식을 따르며 **nightly 빌드** 또한 가능합니다. nightly 빌드는 항상 동작한다고 보기에는 힘들며, The nightly builds are not guaranteed to be working and despite best efforts they might contain undocumented and/or broken changes. We recommend using the latest release. Package installers below will use the latest release. +======= +Solidity versions follow `Semantic Versioning `_. In +addition, patch level releases with major release 0 (i.e. 0.x.y) will not +contain breaking changes. That means code that compiles with version 0.x.y +can be expected to compile with 0.x.z where z > y. + +In addition to releases, we provide **nightly development builds** with the +intention of making it easy for developers to try out upcoming features and +provide early feedback. Note, however, that while the nightly builds are usually +very stable, they contain bleeding-edge code from the development branch and are +not guaranteed to be always working. Despite our best efforts, they might +contain undocumented and/or broken changes that will not become a part of an +actual release. They are not meant for production use. + +When deploying contracts, you should use the latest released version of Solidity. This +is because breaking changes, as well as new features and bug fixes are introduced regularly. +We currently use a 0.x version number `to indicate this fast pace of change `_. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 Remix ===== @@ -305,7 +324,22 @@ Static Binaries 만일 여러분께서 CMake에 ``-DSTRICT_Z3_VERSION=OFF`` 옵션을 추가해주신다면 상기 표에 있는 요구 사항을 충족하는 모든 버전을 통해 빌드하실 수 있습니다. 그러나 이 경우 SMT 테스트를 건너뛰기 위해 ``scripts/tests.sh`` 에 ``--no-smt`` 옵션을 추가해주시기 바랍니다. +<<<<<<< HEAD 컴파일러 최소 사양 +======= +.. note:: + By default the build is performed in *pedantic mode*, which enables extra warnings and tells the + compiler to treat all warnings as errors. + This forces developers to fix warnings as they arise, so they do not accumulate "to be fixed later". + If you are only interested in creating a release build and do not intend to modify the source code + to deal with such warnings, you can pass ``-DPEDANTIC=OFF`` option to CMake to disable this mode. + Doing this is not recommended for general use but may be necessary when using a toolchain we are + not testing with or trying to build an older version with newer tools. + If you encounter such warnings, please consider + `reporting them `_. + +Minimum Compiler Versions +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 ^^^^^^^^^^^^^^^^^^^^^^^^^ 다음 C++ 컴파일러와 최소 사양들은 Solidity codebase를 빌드할 수 있습니다. @@ -498,10 +532,18 @@ Solidity 커밋과 결합된 플랫폼이 SemVer 빌드의 메타데이터를 예시: +<<<<<<< HEAD 1. 0.4.0 버전이 만들어집니다. 2. nightly 빌드는 현 시점부터 0.4.1의 버전을 가지게 됩니다. 3. 충돌이 없는 변경점이 새로 발견되었습니다 --> 현 버전에 변경점이 없습니다. 4. 충돌이 있는 변경점이 새로 발견되었습니다 --> 버전은 0.5.0으로 변경됩니다. 5. 0.5.0 릴리즈가 만들어집니다. +======= +1. The 0.4.0 release is made. +2. The nightly build has a version of 0.4.1 from now on. +3. Non-breaking changes are introduced --> no change in version. +4. A breaking change is introduced --> version is bumped to 0.5.0. +5. The 0.5.0 release is made. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 이러한 패턴은 :ref:`version pragma ` 와 잘 작동합니다. diff --git a/docs/internals/layout_in_storage.rst b/docs/internals/layout_in_storage.rst index b1b89a6a3c..53670eeb85 100644 --- a/docs/internals/layout_in_storage.rst +++ b/docs/internals/layout_in_storage.rst @@ -56,7 +56,8 @@ as individual values. of Solidity due to the fact that storage pointers can be passed to libraries. This means that any change to the rules outlined in this section is considered a breaking change of the language and due to its critical nature should be considered very carefully before - being executed. + being executed. In the event of such a breaking change, we would want to release a + compatibility mode in which the compiler would generate bytecode supporting the old layout. Mappings and Dynamic Arrays @@ -90,7 +91,7 @@ The value corresponding to a mapping key ``k`` is located at ``keccak256(h(k) . where ``.`` is concatenation and ``h`` is a function that is applied to the key depending on its type: - for value types, ``h`` pads the value to 32 bytes in the same way as when storing the value in memory. -- for strings and byte arrays, ``h`` computes the ``keccak256`` hash of the unpadded data. +- for strings and byte arrays, ``h(k)`` is just the unpadded data. If the mapping value is a non-value type, the computed slot marks the start of the data. If the value is of struct type, @@ -139,8 +140,7 @@ by checking if the lowest bit is set: short (not set) and long (set). .. note:: Handling invalidly encoded slots is currently not supported but may be added in the future. - If you are compiling via the experimental IR-based compiler pipeline, reading an invalidly encoded - slot results in a ``Panic(0x22)`` error. + If you are compiling via IR, reading an invalidly encoded slot results in a ``Panic(0x22)`` error. JSON Output =========== @@ -153,7 +153,7 @@ the :ref:`standard JSON interface `. The output is a JSON object element has the following form: -.. code:: +.. code-block:: json { @@ -181,7 +181,7 @@ The given ``type``, in this case ``t_uint256`` represents an element in ``types``, which has the form: -.. code:: +.. code-block:: json { "encoding": "inplace", @@ -238,7 +238,7 @@ value and reference types, types that are encoded packed, and nested types. bytes b1; } -.. code:: json +.. code-block:: json { "storage": [ diff --git a/docs/internals/optimizer.rst b/docs/internals/optimizer.rst index a7eff7346b..c9d10a8f6b 100644 --- a/docs/internals/optimizer.rst +++ b/docs/internals/optimizer.rst @@ -23,9 +23,13 @@ call completely. Currently, the parameter ``--optimize`` activates the opcode-based optimizer for the generated bytecode and the Yul optimizer for the Yul code generated internally, for example for ABI coder v2. One can use ``solc --ir-optimized --optimize`` to produce an -optimized experimental Yul IR for a Solidity source. Similarly, one can use ``solc --strict-assembly --optimize`` +optimized Yul IR for a Solidity source. Similarly, one can use ``solc --strict-assembly --optimize`` for a stand-alone Yul mode. +.. note:: + The `peephole optimizer `_ and the inliner are always + enabled by default and can only be turned off via the :ref:`Standard JSON `. + You can find more details on both optimizer modules and their optimization steps below. Benefits of Optimizing Solidity Code @@ -277,60 +281,85 @@ The following transformation steps are the main components: - Redundant Assign Eliminator - Full Inliner +.. _optimizer-steps: + Optimizer Steps --------------- This is a list of all steps the Yul-based optimizer sorted alphabetically. You can find more information on the individual steps and their sequence below. -- :ref:`block-flattener`. -- :ref:`circular-reference-pruner`. -- :ref:`common-subexpression-eliminator`. -- :ref:`conditional-simplifier`. -- :ref:`conditional-unsimplifier`. -- :ref:`control-flow-simplifier`. -- :ref:`dead-code-eliminator`. -- :ref:`equal-store-eliminator`. -- :ref:`equivalent-function-combiner`. -- :ref:`expression-joiner`. -- :ref:`expression-simplifier`. -- :ref:`expression-splitter`. -- :ref:`for-loop-condition-into-body`. -- :ref:`for-loop-condition-out-of-body`. -- :ref:`for-loop-init-rewriter`. -- :ref:`expression-inliner`. -- :ref:`full-inliner`. -- :ref:`function-grouper`. -- :ref:`function-hoister`. -- :ref:`function-specializer`. -- :ref:`literal-rematerialiser`. -- :ref:`load-resolver`. -- :ref:`loop-invariant-code-motion`. -- :ref:`redundant-assign-eliminator`. -- :ref:`reasoning-based-simplifier`. -- :ref:`rematerialiser`. -- :ref:`SSA-reverser`. -- :ref:`SSA-transform`. -- :ref:`structural-simplifier`. -- :ref:`unused-function-parameter-pruner`. -- :ref:`unused-pruner`. -- :ref:`var-decl-initializer`. +============ =============================== +Abbreviation Full name +============ =============================== +``f`` :ref:`block-flattener` +``l`` :ref:`circular-reference-pruner` +``c`` :ref:`common-subexpression-eliminator` +``C`` :ref:`conditional-simplifier` +``U`` :ref:`conditional-unsimplifier` +``n`` :ref:`control-flow-simplifier` +``D`` :ref:`dead-code-eliminator` +``E`` :ref:`equal-store-eliminator` +``v`` :ref:`equivalent-function-combiner` +``e`` :ref:`expression-inliner` +``j`` :ref:`expression-joiner` +``s`` :ref:`expression-simplifier` +``x`` :ref:`expression-splitter` +``I`` :ref:`for-loop-condition-into-body` +``O`` :ref:`for-loop-condition-out-of-body` +``o`` :ref:`for-loop-init-rewriter` +``i`` :ref:`full-inliner` +``g`` :ref:`function-grouper` +``h`` :ref:`function-hoister` +``F`` :ref:`function-specializer` +``T`` :ref:`literal-rematerialiser` +``L`` :ref:`load-resolver` +``M`` :ref:`loop-invariant-code-motion` +``r`` :ref:`redundant-assign-eliminator` +``R`` :ref:`reasoning-based-simplifier` - highly experimental +``m`` :ref:`rematerialiser` +``V`` :ref:`SSA-reverser` +``a`` :ref:`SSA-transform` +``t`` :ref:`structural-simplifier` +``p`` :ref:`unused-function-parameter-pruner` +``u`` :ref:`unused-pruner` +``d`` :ref:`var-decl-initializer` +============ =============================== + +Some steps depend on properties ensured by ``BlockFlattener``, ``FunctionGrouper``, ``ForLoopInitRewriter``. +For this reason the Yul optimizer always applies them before applying any steps supplied by the user. + +The ReasoningBasedSimplifier is an optimizer step that is currently not enabled +in the default set of steps. It uses an SMT solver to simplify arithmetic expressions +and boolean conditions. It has not received thorough testing or validation yet and can produce +non-reproducible results, so please use with care! Selecting Optimizations ----------------------- -By default the optimizer applies its predefined sequence of optimization steps to -the generated assembly. You can override this sequence and supply your own using -the ``--yul-optimizations`` option: +By default the optimizer applies its predefined sequence of optimization steps to the generated assembly. +You can override this sequence and supply your own using the ``--yul-optimizations`` option: .. code-block:: bash - solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul' + solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul:fDnTOc' + +The order of steps is significant and affects the quality of the output. +Moreover, applying a step may uncover new optimization opportunities for others that were already applied, +so repeating steps is often beneficial. The sequence inside ``[...]`` will be applied multiple times in a loop until the Yul code remains unchanged or until the maximum number of rounds (currently 12) has been reached. +Brackets (``[]``) may be used multiple times in a sequence, but can not be nested. + +An important thing to note, is that there are some hardcoded steps that are always run before and after the +user-supplied sequence, or the default sequence if one was not supplied by the user. -Available abbreviations are listed in the `Yul optimizer docs `_. +The cleanup sequence delimiter ``:`` is optional, and is used to supply a custom cleanup sequence +in order to replace the default one. If omitted, the optimizer will simply apply the default cleanup +sequence. In addition, the delimiter may be placed at the beginning of the user-supplied sequence, +which will result in the optimization sequence being empty, whereas conversely, if placed at the end of +the sequence, will be treated as an empty cleanup sequence. Preprocessing ------------- @@ -683,7 +712,7 @@ Conflicting values are resolved in the following way: - "unused", "undecided" -> "undecided" - "unused", "used" -> "used" -- "undecided, "used" -> "used" +- "undecided", "used" -> "used" For for-loops, the condition, body and post-part are visited twice, taking the joining control-flow at the condition into account. diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 4f3fea17c5..6964fedbc5 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -8,8 +8,14 @@ 간단한 스마트 컨트랙트 *********************** +<<<<<<< HEAD 변수값을 설정하고 이를 다른 컨트랙트에서 접근 가능하도록 노출시켜보는 간단한 예제를 만드는 것부터 시작해보겠습니다. 지금 당장 이해가 안되더라도 걱정 마십시오. 앞으로 더 자세한 내용을 다룰 예정입니다. +======= +Let us begin with a basic example that sets the value of a variable and exposes +it for other contracts to access. It is fine if you do not understand +everything right now, we will go into more details later. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 Storage 예제 =============== @@ -146,8 +152,8 @@ Subcurrency 예제 .. code-block:: solidity - function balances(address _account) external view returns (uint) { - return balances[_account]; + function balances(address account) external view returns (uint) { + return balances[account]; } 해당 함수를 개인 계정에 남아 있는 잔액을 조회할 때 사용할 수 있습니다. @@ -158,8 +164,16 @@ Subcurrency 예제 이렇게 웹 어플리케이션과 같은 Ethereum 클라이언트는 큰 비용을 지불하지 않고도 블록체인 내부의 event들을 주시할 수 있습니다. event가 발생할 경우 listener는 트랜잭션을 추적할 수 있도록 도와주는 ``from``, ``to`` 그리고 ``amount`` 인수를 받게 됩니다. +<<<<<<< HEAD event를 주시하기 위해 아래 ``Coin`` 컨트랙트 객체를 만들기 위해 사용되는 `web3.js `_ JavaScript 코드를 사용해보실 수도 있습니다. 그리고 모든 유저 인터페이스는 위에서 자동적으로 생성된 ``balances`` 함수를 호출합니다. +======= +To listen for this event, you could use the following +JavaScript code, which uses `web3.js `_ to create the ``Coin`` contract object, +and any user interface calls the automatically generated ``balances`` function from above: + +.. code-block:: javascript +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 Coin.Sent().watch({}, '', function(error, result) { if (!error) { @@ -186,11 +200,21 @@ event를 주시하기 위해 아래 ``Coin`` 컨트랙트 객체를 만들기 기본적인 :ref:`Checked arithmetic ` 으로 인해, ``balances[receiver] += amount;`` 부분에서 overflow가 발생할 경우 (즉 ``balances[receiver] + amount`` 부분의 arbitrary precision arithmetic이 ``uint`` (``2**256 - 1``)의 최댓값보다 클 경우) 트랜잭션은 되돌아갑니다. +<<<<<<< HEAD :ref:`Errors ` 는 호출자에게 조건 혹은 처리 과정이 왜 실패했는지에 대한 정보를 제공해줍니다. Error는 :ref:`revert statement ` 와 함께 사용됩니다. revert statement는 무조건적으로 종료하고 ``require`` 함수와 비슷하게 모든 변경 사항들을 원상복귀시킵니다. 다만, 동시에 호출자(궁극적으로는 프론트엔드 어플리케이션 혹은 블록 탐색자)에게 전달될 오류 이름과 추가적인 데이터를 제공하기도 합니다. 따라서 실패를 쉽게 디버깅하거나 조기에 발견할 수 있게 됩니다. +======= +:ref:`Errors ` allow you to provide more information to the caller about +why a condition or operation failed. Errors are used together with the +:ref:`revert statement `. The ``revert`` statement unconditionally +aborts and reverts all changes similar to the ``require`` function, but it also +allows you to provide the name of an error and additional data which will be supplied to the caller +(and eventually to the front-end application or block explorer) so that +a failure can more easily be debugged or reacted upon. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 ``send`` 함수는 (가지고 있는 코인을) 어느 누구에게든지 보내고자 하는 모든 사람들에 의해 사용될 수 있습니다. 만일 전송자가 전송하고자 하는 코인의 양이 충분치 않을 경우, ``if`` 조건은 참으로 판별하게 됩니다. @@ -316,6 +340,7 @@ Ethereum에는 동일한 주소를 공유하고 있는 두 가지 종류의 계 가스 === +<<<<<<< HEAD 생성이 되고 난 후, 각 트랜잭션은 일정량의 **가스**를 지불하게 됩니다. 이는 트랜잭션을 실행하기 위해 필요한 작업량을 제한함과 동시에 작업을 수행하기 위하여 지불하기 위함입니다. EVM이 트랜잭션을 실행하는 동안, 가스는 특정 규칙에 따라 점차적으로 고갈됩니다. @@ -324,14 +349,41 @@ EVM이 트랜잭션을 실행하는 동안, 가스는 특정 규칙에 따라 만일 실행 이후 약간의 가스가 남게 된다면, 그 가스는 똑같이 생성자에게 환불됩니다. 만일 가스가 일정 수준까지 사용하게 될 경우 (즉 음수가 될 경우), out-of-gas 예외가 발생되며 현재 프레임의 상태에 맞춰 모든 변경 사항이 취소가 됩니다. +======= +Upon creation, each transaction is charged with a certain amount of **gas** +that has to be paid for by the originator of the transaction (``tx.origin``). +While the EVM executes the +transaction, the gas is gradually depleted according to specific rules. +If the gas is used up at any point (i.e. it would be negative), +an out-of-gas exception is triggered, which ends execution and reverts all modifications +made to the state in the current call frame. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 + +This mechanism incentivizes economical use of EVM execution time +and also compensates EVM executors (i.e. miners / stakers) for their work. +Since each block has a maximum amount of gas, it also limits the amount +of work needed to validate a block. + +The **gas price** is a value set by the originator of the transaction, who +has to pay ``gas_price * gas`` up front to the EVM executor. +If some gas is left after execution, it is refunded to the transaction originator. +In case of an exception that reverts changes, already used up gas is not refunded. + +Since EVM executors can choose to include a transaction or not, +transaction senders cannot abuse the system by setting a low gas price. .. index:: ! storage, ! memory, ! stack 스토리지, 메모리 및 스택 ============================= +<<<<<<< HEAD Ethereum 가상 머신은 데이터를 저장할 수 있는 세 가지 공간이 있는데, 바로 스토리지, 메모리 그리고 스택입니다. 다음 단락에서 바로 설명드리도록 하겠습니다. +======= +The Ethereum Virtual Machine has three areas where it can store data: +storage, memory and the stack. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 각 계정은 **스토리지**라는 데이터 공간이 있는데 함수의 호출과 트랜잭션 사이에서 지속적으로 존재합니다. 스토리지는 256 비트 단어를 256 비트의 단어로 매핑해주는 키-값 저장소입니다. @@ -385,14 +437,21 @@ call payload에 접근할 수 있게 되는데, 이는 **calldata**라 하는 콜들은 1024만큼의 depth로 **한정되어 있는데**, 이는 더욱 복잡한 작업의 경우 재귀 호출보다는 루프가 더 선호된다는 의미입니다. 또한, 63 혹은 64번째의 가스만 message call에 전달될 수 있으며 이는 실제론 1000보다 작은 depth limit이 걸리게 됩니다. -.. index:: delegatecall, callcode, library +.. index:: delegatecall, library -Delegatecall / Callcode and Libraries -===================================== +Delegatecall and Libraries +========================== +<<<<<<< HEAD **deleegatecall**이라 하는 message call의 특수 변형 형태가 있습니다. message call과 동일하지만 호출 중인 컨트랙트의 컨텍스트 내에서 실행되는 타겟 주소의 코드와 ``msg.sender`` 및 ``msg.value``가 그 값들을 변경하지 않는다는 점만 다릅니다. +======= +There exists a special variant of a message call, named **delegatecall** +which is identical to a message call apart from the fact that +the code at the target address is executed in the context (i.e. at the address) of the calling +contract and ``msg.sender`` and ``msg.value`` do not change their values. +>>>>>>> 2201526a90a7ae318273e16480a88b4c7df8e690 이는 컨트랙트가 런타임에서 다른 주소로부터 코드를 동적으로 로드할 수 있음을 의미합니다. 스토리지, 현 주소 그리고 잔고는 여전히 호출 중인 컨트랙트를 참조하며 오직 코드만이 호출된 주소로부터 가져와집니다. @@ -421,7 +480,7 @@ Create 이렇게 **create call**과 일반 message call 간의 유일한 차이는 payload 데이터가 실행되고 코드로 결과가 저장되며 호출자 혹은 생성자가 스택 상에 새로운 컨트랙트의 주소를 받는다는 점입니다. -.. index:: selfdestruct, self-destruct, deactivate +.. index:: ! selfdestruct, deactivate Deactivate and Self-destruct ============================ diff --git a/docs/ir-breaking-changes.rst b/docs/ir-breaking-changes.rst index c1f6deb57f..7e4efce688 100644 --- a/docs/ir-breaking-changes.rst +++ b/docs/ir-breaking-changes.rst @@ -1,6 +1,8 @@ .. index: ir breaking changes +.. _ir-breaking-changes: + ********************************* Solidity IR-based Codegen Changes ********************************* @@ -13,11 +15,7 @@ The IR-based code generator was introduced with an aim to not only allow code generation to be more transparent and auditable but also to enable more powerful optimization passes that span across functions. -Currently, the IR-based code generator is still marked experimental, -but it supports all language features and has received a lot of testing, -so we consider it almost ready for production use. - -You can enable it on the command line using ``--experimental-via-ir`` +You can enable it on the command line using ``--via-ir`` or with the option ``{"viaIR": true}`` in standard-json and we encourage everyone to try it out! @@ -32,6 +30,48 @@ Semantic Only Changes This section lists the changes that are semantic-only, thus potentially hiding new and different behavior in existing code. +- The order of state variable initialization has changed in case of inheritance. + + The order used to be: + + - All state variables are zero-initialized at the beginning. + - Evaluate base constructor arguments from most derived to most base contract. + - Initialize all state variables in the whole inheritance hierarchy from most base to most derived. + - Run the constructor, if present, for all contracts in the linearized hierarchy from most base to most derived. + + New order: + + - All state variables are zero-initialized at the beginning. + - Evaluate base constructor arguments from most derived to most base contract. + - For every contract in order from most base to most derived in the linearized hierarchy: + + 1. Initialize state variables. + 2. Run the constructor (if present). + + This causes differences in contracts where the initial value of a state + variable relies on the result of the constructor in another contract: + + .. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.7.1; + + contract A { + uint x; + constructor() { + x = 42; + } + function f() public view returns(uint256) { + return x; + } + } + contract B is A { + uint public y = f(); + } + + Previously, ``y`` would be set to 0. This is due to the fact that we would first initialize state variables: First, ``x`` is set to 0, and when initializing ``y``, ``f()`` would return 0 causing ``y`` to be 0 as well. + With the new rules, ``y`` will be set to 42. We first initialize ``x`` to 0, then call A's constructor which sets ``x`` to 42. Finally, when initializing ``y``, ``f()`` returns 42 causing ``y`` to be 42. + - When storage structs are deleted, every storage slot that contains a member of the struct is set to zero entirely. Formerly, padding space was left untouched. @@ -76,8 +116,8 @@ hiding new and different behavior in existing code. // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0; contract C { - function f(uint _a) public pure mod() returns (uint _r) { - _r = _a++; + function f(uint a) public pure mod() returns (uint r) { + r = a++; } modifier mod() { _; _; } } @@ -114,78 +154,6 @@ hiding new and different behavior in existing code. - New code generator: ``0`` as all parameters, including return parameters, will be re-initialized before each ``_;`` evaluation. -- The order of contract initialization has changed in case of inheritance. - - The order used to be: - - - All state variables are zero-initialized at the beginning. - - Evaluate base constructor arguments from most derived to most base contract. - - Initialize all state variables in the whole inheritance hierarchy from most base to most derived. - - Run the constructor, if present, for all contracts in the linearized hierarchy from most base to most derived. - - New order: - - - All state variables are zero-initialized at the beginning. - - Evaluate base constructor arguments from most derived to most base contract. - - For every contract in order from most base to most derived in the linearized hierarchy execute: - - 1. If present at declaration, initial values are assigned to state variables. - 2. Constructor, if present. - -This causes differences in some contracts, for example: - - .. code-block:: solidity - - // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.7.1; - - contract A { - uint x; - constructor() { - x = 42; - } - function f() public view returns(uint256) { - return x; - } - } - contract B is A { - uint public y = f(); - } - - Previously, ``y`` would be set to 0. This is due to the fact that we would first initialize state variables: First, ``x`` is set to 0, and when initializing ``y``, ``f()`` would return 0 causing ``y`` to be 0 as well. - With the new rules, ``y`` will be set to 42. We first initialize ``x`` to 0, then call A's constructor which sets ``x`` to 42. Finally, when initializing ``y``, ``f()`` returns 42 causing ``y`` to be 42. - -- Copying ``bytes`` arrays from memory to storage is implemented in a different way. - The old code generator always copies full words, while the new one cuts the byte - array after its end. The old behaviour can lead to dirty data being copied after - the end of the array (but still in the same storage slot). - This causes differences in some contracts, for example: - - .. code-block:: solidity - - // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.8.1; - - contract C { - bytes x; - function f() public returns (uint _r) { - bytes memory m = "tmp"; - assembly { - mstore(m, 8) - mstore(add(m, 32), "deadbeef15dead") - } - x = m; - assembly { - _r := sload(x.slot) - } - } - } - - Previously ``f()`` would return ``0x6465616462656566313564656164000000000000000000000000000000000010`` - (it has correct length, and correct first 8 elements, but then it contains dirty data which was set via assembly). - Now it is returning ``0x6465616462656566000000000000000000000000000000000000000000000010`` (it has - correct length, and correct elements, but does not contain superfluous data). - .. index:: ! evaluation order; expression - For the old code generator, the evaluation order of expressions is unspecified. @@ -199,8 +167,8 @@ This causes differences in some contracts, for example: // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.1; contract C { - function preincr_u8(uint8 _a) public pure returns (uint8) { - return ++_a + _a; + function preincr_u8(uint8 a) public pure returns (uint8) { + return ++a + a; } } @@ -220,11 +188,11 @@ This causes differences in some contracts, for example: // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.1; contract C { - function add(uint8 _a, uint8 _b) public pure returns (uint8) { - return _a + _b; + function add(uint8 a, uint8 b) public pure returns (uint8) { + return a + b; } - function g(uint8 _a, uint8 _b) public pure returns (uint8) { - return add(++_a + ++_b, _a + _b); + function g(uint8 a, uint8 b) public pure returns (uint8) { + return add(++a + ++b, a + b); } } @@ -323,13 +291,13 @@ For example: // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.1; contract C { - function f(uint8 _a) public pure returns (uint _r1, uint _r2) + function f(uint8 a) public pure returns (uint r1, uint r2) { - _a = ~_a; + a = ~a; assembly { - _r1 := _a + r1 := a } - _r2 = _a; + r2 = a; } } @@ -338,6 +306,6 @@ The function ``f(1)`` returns the following values: - Old code generator: (``fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe``, ``00000000000000000000000000000000000000000000000000000000000000fe``) - New code generator: (``00000000000000000000000000000000000000000000000000000000000000fe``, ``00000000000000000000000000000000000000000000000000000000000000fe``) -Note that, unlike the new code generator, the old code generator does not perform a cleanup after the bit-not assignment (``_a = ~_a``). -This results in different values being assigned (within the inline assembly block) to return value ``_r1`` between the old and new code generators. -However, both code generators perform a cleanup before the new value of ``_a`` is assigned to ``_r2``. +Note that, unlike the new code generator, the old code generator does not perform a cleanup after the bit-not assignment (``a = ~a``). +This results in different values being assigned (within the inline assembly block) to return value ``r1`` between the old and new code generators. +However, both code generators perform a cleanup before the new value of ``a`` is assigned to ``r2``. diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index b3a27bf1ed..9a58478586 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -3,8 +3,8 @@ Layout of a Solidity Source File ******************************** Source files can contain an arbitrary number of -:ref:`contract definitions`, import_ directives, -:ref:`pragma directives` and +:ref:`contract definitions`, import_ , +:ref:`pragma` and :ref:`using for` directives and :ref:`struct`, :ref:`enum`, :ref:`function`, :ref:`error` and :ref:`constant variable` definitions. @@ -27,6 +27,9 @@ it does include the supplied string in the :ref:`bytecode metadata `. If you do not want to specify a license or if the source code is not open-source, please use the special value ``UNLICENSED``. +Note that ``UNLICENSED`` (no usage allowed, not present in SPDX license list) +is different from ``UNLICENSE`` (grants all rights to everyone). +Solidity follows `the npm recommendation `_. Supplying this comment of course does not free you from other obligations related to licensing like having to mention @@ -53,7 +56,7 @@ you have to add the pragma to all your files if you want to enable it in your whole project. If you :ref:`import` another file, the pragma from that file does *not* automatically apply to the importing file. -.. index:: ! pragma, version +.. index:: ! pragma;version .. _version_pragma: @@ -88,6 +91,9 @@ these follow the same syntax used by `npm `. You have to publish the metadata file to IPFS, Swarm, or another service so that others can access it. You create the file by using the ``solc --metadata`` -command that generates a file called ``ContractName_meta.json``. It contains -IPFS and Swarm references to the source code, so you have to upload all source -files and the metadata file. +command together with the ``--output-dir`` parameter. Without the parameter, +the metadata will be written to standard output. +The metadata contains IPFS and Swarm references to the source code, so you have to +upload all source files in addition to the metadata file. For IPFS, the hash contained +in the CID returned by ``ipfs add`` (not the direct sha2-256 hash of the file) +shall match with the one contained in the bytecode. The metadata file has the following format. The example below is presented in a human-readable way. Properly formatted metadata should use quotes correctly, @@ -43,20 +46,20 @@ explanatory purposes. // to the language. "compiler": { // Required for Solidity: Version of the compiler - "version": "0.4.6+commit.2dabbdf0.Emscripten.clang", + "version": "0.8.2+commit.661d1103", // Optional: Hash of the compiler binary which produced this output "keccak256": "0x123..." }, - // Required: Compilation source files/source units, keys are file names + // Required: Compilation source files/source units, keys are file paths "sources": { - "myFile.sol": { + "myDirectory/myFile.sol": { // Required: keccak256 hash of the source file "keccak256": "0x123...", // Required (unless "content" is used, see below): Sorted URL(s) - // to the source file, protocol is more or less arbitrary, but a - // Swarm URL is recommended - "urls": [ "bzzr://56ab..." ], + // to the source file, protocol is more or less arbitrary, but an + // IPFS URL is recommended + "urls": [ "bzz-raw://7d7a...", "dweb:/ipfs/QmN..." ], // Optional: SPDX license identifier as given in the source file "license": "MIT" }, @@ -70,7 +73,7 @@ explanatory purposes. // Required: Compiler settings "settings": { - // Required for Solidity: Sorted list of remappings + // Required for Solidity: Sorted list of import remappings "remappings": [ ":g=/dir" ], // Optional: Optimizer settings. The fields "enabled" and "runs" are deprecated // and are only given for backwards-compatibility. @@ -97,15 +100,15 @@ explanatory purposes. } }, "metadata": { - // Reflects the setting used in the input json, defaults to false + // Reflects the setting used in the input json, defaults to "false" "useLiteralContent": true, // Reflects the setting used in the input json, defaults to "ipfs" "bytecodeHash": "ipfs" }, - // Required for Solidity: File and name of the contract or library this + // Required for Solidity: File path and the name of the contract or library this // metadata is created for. "compilationTarget": { - "myFile.sol": "MyContract" + "myDirectory/myFile.sol": "MyContract" }, // Required for Solidity: Addresses for libraries used "libraries": { @@ -115,12 +118,66 @@ explanatory purposes. // Required: Generated information about the contract. "output": { - // Required: ABI definition of the contract + // Required: ABI definition of the contract. See "Contract ABI Specification" "abi": [/* ... */], + // Required: NatSpec developer documentation of the contract. + "devdoc": { + "version": 1 // NatSpec version + "kind": "dev", + // Contents of the @author NatSpec field of the contract + "author": "John Doe", + // Contents of the @title NatSpec field of the contract + "title": "MyERC20: an example ERC20" + // Contents of the @dev NatSpec field of the contract + "details": "Interface of the ERC20 standard as defined in the EIP. See https://eips.ethereum.org/EIPS/eip-20 for details", + "methods": { + "transfer(address,uint256)": { + // Contents of the @dev NatSpec field of the method + "details": "Returns a boolean value indicating whether the operation succeeded. Must be called by the token holder address", + // Contents of the @param NatSpec fields of the method + "params": { + "_value": "The amount tokens to be transferred", + "_to": "The receiver address" + } + // Contents of the @return NatSpec field. + "returns": { + // Return var name (here "success") if exists. "_0" as key if return var is unnamed + "success": "a boolean value indicating whether the operation succeeded" + } + } + }, + "stateVariables": { + "owner": { + // Contents of the @dev NatSpec field of the state variable + "details": "Must be set during contract creation. Can then only be changed by the owner" + } + } + "events": { + "Transfer(address,address,uint256)": { + "details": "Emitted when `value` tokens are moved from one account (`from`) toanother (`to`)." + "params": { + "from": "The sender address" + "to": "The receiver address" + "value": "The token amount" + } + } + } + }, // Required: NatSpec user documentation of the contract - "userdoc": [/* ... */], - // Required: NatSpec developer documentation of the contract - "devdoc": [/* ... */] + "userdoc": { + "version": 1 // NatSpec version + "kind": "user", + "methods": { + "transfer(address,uint256)": { + "notice": "Transfers `_value` tokens to address `_to`" + } + }, + "events": { + "Transfer(address,address,uint256)": { + "notice": "`_value` tokens have been moved from `from` to `to`" + } + } + } } } @@ -157,7 +214,7 @@ to the end of the deployed bytecode 0x00 0x33 So in order to retrieve the data, the end of the deployed bytecode can be checked -to match that pattern and use the IPFS hash to retrieve the file. +to match that pattern and the IPFS hash can be used to retrieve the file (if pinned/published). Whereas release builds of solc use a 3 byte encoding of the version as shown above (one byte each for major, minor and patch version number), prerelease builds @@ -181,14 +238,15 @@ Usage for Automatic Interface Generation and NatSpec ==================================================== The metadata is used in the following way: A component that wants to interact -with a contract (e.g. Mist or any wallet) retrieves the code of the contract, -from that the IPFS/Swarm hash of a file which is then retrieved. That file +with a contract (e.g. a wallet) retrieves the code of the contract. +It decodes the CBOR encoded section containing the IPFS/Swarm hash of the +metadata file. With that hash, the metadata file is retrieved. That file is JSON-decoded into a structure like above. The component can then use the ABI to automatically generate a rudimentary user interface for the contract. -Furthermore, the wallet can use the NatSpec user documentation to display a confirmation message to the user +Furthermore, the wallet can use the NatSpec user documentation to display a human-readable confirmation message to the user whenever they interact with the contract, together with requesting authorization for the transaction signature. diff --git a/docs/natspec-format.rst b/docs/natspec-format.rst index 297bbc8c62..28848dae43 100644 --- a/docs/natspec-format.rst +++ b/docs/natspec-format.rst @@ -36,7 +36,7 @@ tools. Documentation Example ===================== -Documentation is inserted above each ``contract``, ``interface``, +Documentation is inserted above each ``contract``, ``interface``, ``library``, ``function``, and ``event`` using the Doxygen notation format. A ``public`` state variable is equivalent to a ``function`` for the purposes of NatSpec. @@ -183,7 +183,7 @@ other to be used by the developer. If the above contract is saved as ``ex1.sol`` then you can generate the documentation using: -.. code:: +.. code-block:: shell solc --userdoc --devdoc ex1.sol @@ -202,7 +202,7 @@ User Documentation The above documentation will produce the following user documentation JSON file as output: -.. code:: +.. code-block:: json { "version" : 1, @@ -230,7 +230,7 @@ Developer Documentation Apart from the user documentation file, a developer documentation JSON file should also be produced and should look like this: -.. code:: +.. code-block:: json { "version" : 1, diff --git a/docs/resources.rst b/docs/resources.rst index 5b8d0013ab..c70b35fbf8 100644 --- a/docs/resources.rst +++ b/docs/resources.rst @@ -14,7 +14,7 @@ General Resources * `Solidity Compiler Developers Chat `_ * `Awesome Solidity `_ * `Solidity by Example `_ - +* `Solidity Documentation Community Translations `_ Integrated (Ethereum) Development Environments ============================================== @@ -28,15 +28,15 @@ Integrated (Ethereum) Development Environments * `Embark `_ Developer platform for building and deploying decentralized applications. + * `Foundry `_ + Fast, portable and modular toolkit for Ethereum application development written in Rust. + * `Hardhat `_ Ethereum development environment with local Ethereum network, debugging features and plugin ecosystem. * `Remix `_ Browser-based IDE with integrated compiler and Solidity runtime environment without server-side components. - * `Scaffold-ETH `_ - Ethereum development stack focused on fast product iterations. - * `Truffle `_ Ethereum development framework. @@ -82,6 +82,9 @@ Editor Integrations * `Visual Studio Code extension `_ Solidity plugin for Microsoft Visual Studio Code that includes syntax highlighting and the Solidity compiler. + * `Solidity Visual Auditor extension `_ + Adds security centric syntax and semantic highlighting to Visual Studio Code. + Solidity Tools ============== @@ -112,6 +115,9 @@ Solidity Tools * `PIET `_ A tool to develop, audit and use Solidity smart contracts through a simple graphical interface. +* `Scaffold-ETH `_ + Forkable Ethereum development stack focused on fast product iterations. + * `sol2uml `_ Unified Modeling Language (UML) class diagram generator for Solidity contracts. @@ -130,6 +136,9 @@ Solidity Tools * `Solhint `_ Solidity linter that provides security, style guide and best practice rules for smart contract validation. +* `Sourcify `_ + Decentralized automated contract verification service and public repository of contract metadata. + * `Sūrya `_ Utility tool for smart contract systems, offering a number of visual outputs and information about the contracts' structure. Also supports querying the function call graph. diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 09770c5707..6507f7c1c2 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -98,7 +98,7 @@ as it uses ``call`` which forwards all remaining gas by default: } To avoid re-entrancy, you can use the Checks-Effects-Interactions pattern as -outlined further below: +demonstrated below: .. code-block:: solidity @@ -116,6 +116,13 @@ outlined further below: } } +The Checks-Effects-Interactions pattern ensures that all code paths through a contract complete all required checks +of the supplied parameters before modifying the contract's state (Checks); only then it makes any changes to the state (Effects); +it may make calls to functions in other contracts *after* all planned state changes have been written to +storage (Interactions). This is a common foolproof way to prevent *re-entrancy attacks*, where an externally called +malicious contract is able to double-spend an allowance, double-withdraw a balance, among other things, by using logic that calls back into the +original contract before it has finalized its transaction. + Note that re-entrancy is not only an effect of Ether transfer but of any function call on another contract. Furthermore, you also have to take multi-contract situations into account. A called contract could modify the @@ -210,9 +217,9 @@ using a second proxy: contract ProxyWithMoreFunctionality { PermissionlessProxy proxy; - function callOther(address _addr, bytes memory _payload) public + function callOther(address addr, bytes memory payload) public returns (bool, bytes memory) { - return proxy.callOther(_addr, _payload); + return proxy.callOther(addr, payload); } // Other functions and other functionality } @@ -220,9 +227,9 @@ using a second proxy: // This is the full contract, it has no other functionality and // requires no privileges to work. contract PermissionlessProxy { - function callOther(address _addr, bytes memory _payload) public + function callOther(address addr, bytes memory payload) public returns (bool, bytes memory) { - return _addr.call(_payload); + return addr.call(payload); } } @@ -331,17 +338,17 @@ field of a ``struct`` that is the base type of a dynamic storage array. The contract Map { mapping (uint => uint)[] array; - function allocate(uint _newMaps) public { - for (uint i = 0; i < _newMaps; i++) + function allocate(uint newMaps) public { + for (uint i = 0; i < newMaps; i++) array.push(); } - function writeMap(uint _map, uint _key, uint _value) public { - array[_map][_key] = _value; + function writeMap(uint map, uint key, uint value) public { + array[map][key] = value; } - function readMap(uint _map, uint _key) public view returns (uint) { - return array[_map][_key]; + function readMap(uint map, uint key) public view returns (uint) { + return array[map][key]; } function eraseMaps() public { diff --git a/docs/smtchecker.rst b/docs/smtchecker.rst index 791659897e..6d2f4373b2 100644 --- a/docs/smtchecker.rst +++ b/docs/smtchecker.rst @@ -82,12 +82,12 @@ Overflow uint immutable x; uint immutable y; - function add(uint _x, uint _y) internal pure returns (uint) { - return _x + _y; + function add(uint x_, uint y_) internal pure returns (uint) { + return x_ + y_; } - constructor(uint _x, uint _y) { - (x, y) = (_x, _y); + constructor(uint x_, uint y_) { + (x, y) = (x_, y_); } function stateAdd() public view returns (uint) { @@ -116,7 +116,7 @@ Here, it reports the following: Overflow.add(1, 115792089237316195423570985008687907853269984665640564039457584007913129639935) -- internal call --> o.sol:9:20: | - 9 | return _x + _y; + 9 | return x_ + y_; | ^^^^^^^ If we add ``require`` statements that filter out overflow cases, @@ -131,12 +131,12 @@ the SMTChecker proves that no overflow is reachable (by not reporting warnings): uint immutable x; uint immutable y; - function add(uint _x, uint _y) internal pure returns (uint) { - return _x + _y; + function add(uint x_, uint y_) internal pure returns (uint) { + return x_ + y_; } - constructor(uint _x, uint _y) { - (x, y) = (_x, _y); + constructor(uint x_, uint y_) { + (x, y) = (x_, y_); } function stateAdd() public view returns (uint) { @@ -155,7 +155,7 @@ An assertion represents an invariant in your code: a property that must be true The code below defines a function ``f`` that guarantees no overflow. Function ``inv`` defines the specification that ``f`` is monotonically increasing: -for every possible pair ``(_a, _b)``, if ``_b > _a`` then ``f(_b) > f(_a)``. +for every possible pair ``(a, b)``, if ``b > a`` then ``f(b) > f(a)``. Since ``f`` is indeed monotonically increasing, the SMTChecker proves that our property is correct. You are encouraged to play with the property and the function definition to see what results come out! @@ -166,14 +166,14 @@ definition to see what results come out! pragma solidity >=0.8.0; contract Monotonic { - function f(uint _x) internal pure returns (uint) { - require(_x < type(uint128).max); - return _x * 42; + function f(uint x) internal pure returns (uint) { + require(x < type(uint128).max); + return x * 42; } - function inv(uint _a, uint _b) public pure { - require(_b > _a); - assert(f(_b) > f(_a)); + function inv(uint a, uint b) public pure { + require(b > a); + assert(f(b) > f(a)); } } @@ -188,14 +188,14 @@ equal every element in the array. pragma solidity >=0.8.0; contract Max { - function max(uint[] memory _a) public pure returns (uint) { + function max(uint[] memory a) public pure returns (uint) { uint m = 0; - for (uint i = 0; i < _a.length; ++i) - if (_a[i] > m) - m = _a[i]; + for (uint i = 0; i < a.length; ++i) + if (a[i] > m) + m = a[i]; - for (uint i = 0; i < _a.length; ++i) - assert(m >= _a[i]); + for (uint i = 0; i < a.length; ++i) + assert(m >= a[i]); return m; } @@ -222,15 +222,15 @@ For example, changing the code to pragma solidity >=0.8.0; contract Max { - function max(uint[] memory _a) public pure returns (uint) { - require(_a.length >= 5); + function max(uint[] memory a) public pure returns (uint) { + require(a.length >= 5); uint m = 0; - for (uint i = 0; i < _a.length; ++i) - if (_a[i] > m) - m = _a[i]; + for (uint i = 0; i < a.length; ++i) + if (a[i] > m) + m = a[i]; - for (uint i = 0; i < _a.length; ++i) - assert(m > _a[i]); + for (uint i = 0; i < a.length; ++i) + assert(m > a[i]); return m; } @@ -243,7 +243,7 @@ gives us: Warning: CHC: Assertion violation happens here. Counterexample: - _a = [0, 0, 0, 0, 0] + a = [0, 0, 0, 0, 0] = 0 Transaction trace: @@ -251,7 +251,7 @@ gives us: Test.max([0, 0, 0, 0, 0]) --> max.sol:14:4: | - 14 | assert(m > _a[i]); + 14 | assert(m > a[i]); State Properties @@ -383,9 +383,9 @@ anything, including reenter the caller contract. Unknown immutable unknown; - constructor(Unknown _u) { - require(address(_u) != address(0)); - unknown = _u; + constructor(Unknown u) { + require(address(u) != address(0)); + unknown = u; } modifier mutex { @@ -395,8 +395,8 @@ anything, including reenter the caller contract. lock = false; } - function set(uint _x) mutex public { - x = _x; + function set(uint x_) mutex public { + x = x_; } function run() mutex public { @@ -629,6 +629,11 @@ option ``--model-checker-solvers {all,cvc4,smtlib2,z3}`` or the JSON option - if a dynamic ``z3`` library of version 4.8.x is installed in a Linux system (from Solidity 0.7.6); - statically in ``soljson.js`` (from Solidity 0.6.9), that is, the Javascript binary of the compiler. +.. note:: + z3 version 4.8.16 broke ABI compatibility with previous versions and cannot + be used with solc <=0.8.13. If you are using z3 >=4.8.16 please use solc + >=0.8.14. + Since both BMC and CHC use ``z3``, and ``z3`` is available in a greater variety of environments, including in the browser, most users will almost never need to be concerned about this option. More advanced users might apply this option to try @@ -679,7 +684,7 @@ Types that are not yet supported are abstracted by a single 256-bit unsigned integer, where their unsupported operations are ignored. For more details on how the SMT encoding works internally, see the paper -`SMT-based Verification of Solidity Smart Contracts `_. +`SMT-based Verification of Solidity Smart Contracts `_. Function Calls ============== @@ -754,15 +759,15 @@ not mean loss of proving power. { function f( bytes32 hash, - uint8 _v1, uint8 _v2, - bytes32 _r1, bytes32 _r2, - bytes32 _s1, bytes32 _s2 + uint8 v1, uint8 v2, + bytes32 r1, bytes32 r2, + bytes32 s1, bytes32 s2 ) public pure returns (address) { - address a1 = ecrecover(hash, _v1, _r1, _s1); - require(_v1 == _v2); - require(_r1 == _r2); - require(_s1 == _s2); - address a2 = ecrecover(hash, _v2, _r2, _s2); + address a1 = ecrecover(hash, v1, r1, s1); + require(v1 == v2); + require(r1 == r2); + require(s1 == s2); + address a2 = ecrecover(hash, v2, r2, s2); assert(a1 == a2); return a1; } diff --git a/docs/style-guide.rst b/docs/style-guide.rst index 177f4a7987..75de18ac09 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -8,7 +8,7 @@ Style Guide Introduction ************ -This guide is intended to provide coding conventions for writing solidity code. +This guide is intended to provide coding conventions for writing Solidity code. This guide should be thought of as an evolving document that will change over time as useful conventions are found and old conventions are rendered obsolete. @@ -20,7 +20,7 @@ taken from python's `pep8 style guide `_. The goal of this guide is *not* to be the right way or the best way to write -solidity code. The goal of this guide is *consistency*. A quote from python's +Solidity code. The goal of this guide is *consistency*. A quote from python's `pep8 `_ captures this concept well. @@ -28,7 +28,7 @@ captures this concept well. A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is most important. - But most importantly: **know when to be inconsistent** -- sometimes the style guide just doesn't apply. When in doubt, use your best judgement. Look at other examples and decide what looks best. And don't hesitate to ask! + But most importantly: **know when to be inconsistent** -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don't hesitate to ask! *********** @@ -51,7 +51,7 @@ Mixing tabs and spaces should be avoided. Blank Lines =========== -Surround top level declarations in solidity source with two blank lines. +Surround top level declarations in Solidity source with two blank lines. Yes: @@ -146,8 +146,7 @@ No: Maximum Line Length =================== -Keeping lines under the `PEP 8 recommendation `_ to a maximum of 79 (or 99) -characters helps readers easily parse the code. +Maximum suggested line length is 120 characters. Wrapped lines should conform to the following guidelines. @@ -204,7 +203,7 @@ Yes: .. code-block:: solidity - thisIsALongNestedMapping[being][set][to_some_value] = someFunction( + thisIsALongNestedMapping[being][set][toSomeValue] = someFunction( argument1, argument2, argument3, @@ -215,7 +214,7 @@ No: .. code-block:: solidity - thisIsALongNestedMapping[being][set][to_some_value] = someFunction(argument1, + thisIsALongNestedMapping[being][set][toSomeValue] = someFunction(argument1, argument2, argument3, argument4); @@ -281,6 +280,7 @@ Yes: // ... } + contract B is Owned { // ... } @@ -438,15 +438,15 @@ Yes: x = 1; y = 2; - long_variable = 3; + longVariable = 3; No: .. code-block:: solidity - x = 1; - y = 2; - long_variable = 3; + x = 1; + y = 2; + longVariable = 3; Don't include a whitespace in the receive and fallback functions: @@ -679,7 +679,7 @@ No: } For long function declarations, it is recommended to drop each argument onto -it's own line at the same indentation level as the function body. The closing +its own line at the same indentation level as the function body. The closing parenthesis and opening bracket should be placed on their own line as well at the same indentation level as the function declaration. @@ -846,15 +846,20 @@ Yes: constructor(uint) { } } + + contract C { constructor(uint, uint) { } } + + contract D { constructor(uint) { } } + contract A is B, C, D { uint x; @@ -927,7 +932,7 @@ Permissible: function shortFunction() public { doSomething(); } These guidelines for function declarations are intended to improve readability. -Authors should use their best judgement as this guide does not try to cover all +Authors should use their best judgment as this guide does not try to cover all possible permutations for function declarations. Mappings @@ -1017,7 +1022,7 @@ No: * Operators with a higher priority than others can exclude surrounding whitespace in order to denote precedence. This is meant to allow for - improved readability for complex statement. You should always use the same + improved readability for complex statements. You should always use the same amount of whitespace on either side of an operator: Yes: @@ -1086,12 +1091,10 @@ naming styles. * ``b`` (single lowercase letter) * ``B`` (single uppercase letter) * ``lowercase`` -* ``lower_case_with_underscores`` * ``UPPERCASE`` * ``UPPER_CASE_WITH_UNDERSCORES`` * ``CapitalizedWords`` (or CapWords) * ``mixedCase`` (differs from CapitalizedWords by initial lowercase character!) -* ``Capitalized_Words_With_Underscores`` .. note:: When using initialisms in CapWords, capitalize all the letters of the initialisms. Thus HTTPServerError is better than HttpServerError. When using initialisms in mixedCase, capitalize all the letters of the initialisms, except keep the first one lower case if it is the beginning of the name. Thus xmlHTTPRequest is better than XMLHTTPRequest. @@ -1250,10 +1253,10 @@ Enums, in the style of simple type declarations, should be named using the CapWo Avoiding Naming Collisions ========================== -* ``single_trailing_underscore_`` +* ``singleTrailingUnderscore_`` -This convention is suggested when the desired name collides with that of a -built-in or otherwise reserved name. +This convention is suggested when the desired name collides with that of +an existing state variable, function, built-in or otherwise reserved name. .. _style_guide_natspec: diff --git a/docs/types/conversion.rst b/docs/types/conversion.rst index 7e266d1bd4..e6c68df412 100644 --- a/docs/types/conversion.rst +++ b/docs/types/conversion.rst @@ -188,6 +188,10 @@ Addresses As described in :ref:`address_literals`, hex literals of the correct size that pass the checksum test are of ``address`` type. No other literals can be implicitly converted to the ``address`` type. -Explicit conversions from ``bytes20`` or any integer type to ``address`` result in ``address payable``. +Explicit conversions to ``address`` are allowed only from ``bytes20`` and ``uint160``. -An ``address a`` can be converted to ``address payable`` via ``payable(a)``. +An ``address a`` can be converted explicitly to ``address payable`` via ``payable(a)``. + +.. note:: + Prior to version 0.8.0, it was possible to explicitly convert from any integer type (of any size, signed or unsigned) to ``address`` or ``address payable``. + Starting with in 0.8.0 only conversion from ``uint160`` is allowed. \ No newline at end of file diff --git a/docs/types/mapping-types.rst b/docs/types/mapping-types.rst index 18f3bf8275..c59d6e8454 100644 --- a/docs/types/mapping-types.rst +++ b/docs/types/mapping-types.rst @@ -4,12 +4,12 @@ Mapping Types ============= -Mapping types use the syntax ``mapping(_KeyType => _ValueType)`` and variables -of mapping type are declared using the syntax ``mapping(_KeyType => _ValueType) _VariableName``. -The ``_KeyType`` can be any +Mapping types use the syntax ``mapping(KeyType => ValueType)`` and variables +of mapping type are declared using the syntax ``mapping(KeyType => ValueType) VariableName``. +The ``KeyType`` can be any built-in value type, ``bytes``, ``string``, or any contract or enum type. Other user-defined or complex types, such as mappings, structs or array types are not allowed. -``_ValueType`` can be any type, including mappings, arrays and structs. +``ValueType`` can be any type, including mappings, arrays and structs. You can think of mappings as `hash tables `_, which are virtually initialised such that every possible key exists and is mapped to a value whose @@ -29,10 +29,10 @@ of contract functions that are publicly visible. These restrictions are also true for arrays and structs that contain mappings. You can mark state variables of mapping type as ``public`` and Solidity creates a -:ref:`getter ` for you. The ``_KeyType`` becomes a parameter for the getter. -If ``_ValueType`` is a value type or a struct, the getter returns ``_ValueType``. -If ``_ValueType`` is an array or a mapping, the getter has one parameter for -each ``_KeyType``, recursively. +:ref:`getter ` for you. The ``KeyType`` becomes a parameter for the getter. +If ``ValueType`` is a value type or a struct, the getter returns ``ValueType``. +If ``ValueType`` is an array or a mapping, the getter has one parameter for +each ``KeyType``, recursively. In the example below, the ``MappingExample`` contract defines a public ``balances`` mapping, with the key type an ``address``, and a value type a ``uint``, mapping @@ -119,14 +119,14 @@ Iterable Mappings You cannot iterate over mappings, i.e. you cannot enumerate their keys. It is possible, though, to implement a data structure on top of them and iterate over that. For example, the code below implements an -``IterableMapping`` library that the ``User`` contract then adds data too, and +``IterableMapping`` library that the ``User`` contract then adds data to, and the ``sum`` function iterates over to sum all the values. .. code-block:: solidity :force: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.6.8 <0.9.0; + pragma solidity ^0.8.8; struct IndexValue { uint keyIndex; uint value; } struct KeyFlag { uint key; bool deleted; } @@ -137,6 +137,8 @@ the ``sum`` function iterates over to sum all the values. uint size; } + type Iterator is uint; + library IterableMapping { function insert(itmap storage self, uint key, uint value) internal returns (bool replaced) { uint keyIndex = self.data[key].keyIndex; @@ -166,25 +168,29 @@ the ``sum`` function iterates over to sum all the values. return self.data[key].keyIndex > 0; } - function iterate_start(itmap storage self) internal view returns (uint keyIndex) { - return iterate_next(self, type(uint).max); + function iterateStart(itmap storage self) internal view returns (Iterator) { + return iteratorSkipDeleted(self, 0); } - function iterate_valid(itmap storage self, uint keyIndex) internal view returns (bool) { - return keyIndex < self.keys.length; + function iterateValid(itmap storage self, Iterator iterator) internal view returns (bool) { + return Iterator.unwrap(iterator) < self.keys.length; } - function iterate_next(itmap storage self, uint keyIndex) internal view returns (uint r_keyIndex) { - keyIndex++; - while (keyIndex < self.keys.length && self.keys[keyIndex].deleted) - keyIndex++; - return keyIndex; + function iterateNext(itmap storage self, Iterator iterator) internal view returns (Iterator) { + return iteratorSkipDeleted(self, Iterator.unwrap(iterator) + 1); } - function iterate_get(itmap storage self, uint keyIndex) internal view returns (uint key, uint value) { + function iterateGet(itmap storage self, Iterator iterator) internal view returns (uint key, uint value) { + uint keyIndex = Iterator.unwrap(iterator); key = self.keys[keyIndex].key; value = self.data[key].value; } + + function iteratorSkipDeleted(itmap storage self, uint keyIndex) private view returns (Iterator) { + while (keyIndex < self.keys.length && self.keys[keyIndex].deleted) + keyIndex++; + return Iterator.wrap(keyIndex); + } } // How to use it @@ -206,11 +212,11 @@ the ``sum`` function iterates over to sum all the values. // Computes the sum of all stored data. function sum() public view returns (uint s) { for ( - uint i = data.iterate_start(); - data.iterate_valid(i); - i = data.iterate_next(i) + Iterator i = data.iterateStart(); + data.iterateValid(i); + i = data.iterateNext(i) ) { - (, uint value) = data.iterate_get(i); + (, uint value) = data.iterateGet(i); s += value; } } diff --git a/docs/types/operator-precedence-table.rst b/docs/types/operator-precedence-table.rst new file mode 100644 index 0000000000..65034045bb --- /dev/null +++ b/docs/types/operator-precedence-table.rst @@ -0,0 +1,57 @@ +The following is the order of precedence for operators, listed in order of evaluation. + ++------------+-------------------------------------+--------------------------------------------+ +| Precedence | Description | Operator | ++============+=====================================+============================================+ +| *1* | Postfix increment and decrement | ``++``, ``--`` | ++ +-------------------------------------+--------------------------------------------+ +| | New expression | ``new `` | ++ +-------------------------------------+--------------------------------------------+ +| | Array subscripting | ``[]`` | ++ +-------------------------------------+--------------------------------------------+ +| | Member access | ``.`` | ++ +-------------------------------------+--------------------------------------------+ +| | Function-like call | ``()`` | ++ +-------------------------------------+--------------------------------------------+ +| | Parentheses | ``()`` | ++------------+-------------------------------------+--------------------------------------------+ +| *2* | Prefix increment and decrement | ``++``, ``--`` | ++ +-------------------------------------+--------------------------------------------+ +| | Unary minus | ``-`` | ++ +-------------------------------------+--------------------------------------------+ +| | Unary operations | ``delete`` | ++ +-------------------------------------+--------------------------------------------+ +| | Logical NOT | ``!`` | ++ +-------------------------------------+--------------------------------------------+ +| | Bitwise NOT | ``~`` | ++------------+-------------------------------------+--------------------------------------------+ +| *3* | Exponentiation | ``**`` | ++------------+-------------------------------------+--------------------------------------------+ +| *4* | Multiplication, division and modulo | ``*``, ``/``, ``%`` | ++------------+-------------------------------------+--------------------------------------------+ +| *5* | Addition and subtraction | ``+``, ``-`` | ++------------+-------------------------------------+--------------------------------------------+ +| *6* | Bitwise shift operators | ``<<``, ``>>`` | ++------------+-------------------------------------+--------------------------------------------+ +| *7* | Bitwise AND | ``&`` | ++------------+-------------------------------------+--------------------------------------------+ +| *8* | Bitwise XOR | ``^`` | ++------------+-------------------------------------+--------------------------------------------+ +| *9* | Bitwise OR | ``|`` | ++------------+-------------------------------------+--------------------------------------------+ +| *10* | Inequality operators | ``<``, ``>``, ``<=``, ``>=`` | ++------------+-------------------------------------+--------------------------------------------+ +| *11* | Equality operators | ``==``, ``!=`` | ++------------+-------------------------------------+--------------------------------------------+ +| *12* | Logical AND | ``&&`` | ++------------+-------------------------------------+--------------------------------------------+ +| *13* | Logical OR | ``||`` | ++------------+-------------------------------------+--------------------------------------------+ +| *14* | Ternary operator | `` ? : `` | ++ +-------------------------------------+--------------------------------------------+ +| | Assignment operators | ``=``, ``|=``, ``^=``, ``&=``, ``<<=``, | +| | | ``>>=``, ``+=``, ``-=``, ``*=``, ``/=``, | +| | | ``%=`` | ++------------+-------------------------------------+--------------------------------------------+ +| *15* | Comma operator | ``,`` | ++------------+-------------------------------------+--------------------------------------------+ diff --git a/docs/types/operators.rst b/docs/types/operators.rst index 450963e11d..1d71352d60 100644 --- a/docs/types/operators.rst +++ b/docs/types/operators.rst @@ -5,7 +5,7 @@ Operators Arithmetic and bit operators can be applied even if the two operands do not have the same type. For example, you can compute ``y = x + z``, where ``x`` is a ``uint8`` and ``z`` has -the type ``int32``. In these cases, the following mechanism will be used to determine +the type ``uint32``. In these cases, the following mechanism will be used to determine the type in which the operation is computed (this is important in case of overflow) and the type of the operator's result: @@ -18,7 +18,9 @@ and the type of the operator's result: In case one of the operands is a :ref:`literal number ` it is first converted to its "mobile type", which is the smallest type that can hold the value (unsigned types of the same bit-width are considered "smaller" than the signed types). -If both are literal numbers, the operation is computed with arbitrary precision. +If both are literal numbers, the operation is computed with effectively unlimited precision in +that the expression is evaluated to whatever precision is necessary so that none is lost +when the result is used with a non-literal type. The operator's result type is the same as the type the operation is performed in, except for comparison operators where the result is always ``bool``. @@ -26,6 +28,23 @@ except for comparison operators where the result is always ``bool``. The operators ``**`` (exponentiation), ``<<`` and ``>>`` use the type of the left operand for the operation and the result. +Ternary Operator +---------------- +The ternary operator is used in expressions of the form `` ? : ``. +It evaluates one of the latter two given expressions depending upon the result of the evaluation of the main ````. +If ```` evaluates to ``true``, then ```` will be evaluated, otherwise ```` is evaluated. + +The result of the ternary operator does not have a rational number type, even if all of its operands are rational number literals. +The result type is determined from the types of the two operands in the same way as above, converting to their mobile type first if required. + +As a consequence, ``255 + (true ? 1 : 0)`` will revert due to arithmetic overflow. +The reason is that ``(true ? 1 : 0)`` is of ``uint8`` type, which forces the addition to be performed in ``uint8`` as well, +and 256 exceeds the range allowed for this type. + +Another consequence is that an expression like ``1.5 + 1.5`` is valid but ``1.5 + (true ? 1.5 : 2.5)`` is not. +This is because the former is a rational expression evaluated in unlimited precision and only its final value matters. +The latter involves a conversion of a fractional rational number to an integer, which is currently disallowed. + .. index:: assignment, lvalue, ! compound operators Compound and Increment/Decrement Operators @@ -91,3 +110,11 @@ value it referred to previously. assert(y.length == 0); } } + +.. index:: ! operator; precedence +.. _order: + +Order of Precedence of Operators +-------------------------------- + +.. include:: types/operator-precedence-table.rst diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index 126440321c..a6b5728c95 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -85,8 +85,10 @@ Data locations are not only relevant for persistency of data, but also for the s // The following does not work; it would need to create a new temporary / // unnamed array in storage, but storage is "statically" allocated: // y = memoryArray; - // This does not work either, since it would "reset" the pointer, but there - // is no sensible location it could point to. + // Similarly, "delete y" is not valid, as assignments to local variables + // referencing storage objects can only be made from existing storage objects. + // It would "reset" the pointer, but there is no sensible location it could point to. + // For more details see the documentation of the "delete" operator. // delete y; g(x); // calls g, handing over a reference to x h(x); // calls h and creates an independent, temporary copy in memory @@ -150,7 +152,7 @@ length or index access. Solidity does not have string manipulation functions, but there are third-party string libraries. You can also compare two strings by their keccak256-hash using ``keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))`` and -concatenate two strings using ``bytes.concat(bytes(s1), bytes(s2))``. +concatenate two strings using ``string.concat(s1, s2)``. You should use ``bytes`` over ``bytes1[]`` because it is cheaper, since using ``bytes1[]`` in ``memory`` adds 31 padding bytes between the elements. Note that in ``storage``, the @@ -165,31 +167,40 @@ always use one of the value types ``bytes1`` to ``bytes32`` because they are muc that you are accessing the low-level bytes of the UTF-8 representation, and not the individual characters. -.. index:: ! bytes-concat +.. index:: ! bytes-concat, ! string-concat .. _bytes-concat: +.. _string-concat: -``bytes.concat`` function -^^^^^^^^^^^^^^^^^^^^^^^^^ +The functions ``bytes.concat`` and ``string.concat`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -You can concatenate a variable number of ``bytes`` or ``bytes1 ... bytes32`` using ``bytes.concat``. +You can concatenate an arbitrary number of ``string`` values using ``string.concat``. +The function returns a single ``string memory`` array that contains the contents of the arguments without padding. +If you want to use parameters of other types that are not implicitly convertible to ``string``, you need to convert them to ``string`` first. + +Analogously, the ``bytes.concat`` function can concatenate an arbitrary number of ``bytes`` or ``bytes1 ... bytes32`` values. The function returns a single ``bytes memory`` array that contains the contents of the arguments without padding. -If you want to use string parameters or other types, you need to convert them to ``bytes`` or ``bytes1``/.../``bytes32`` first. +If you want to use string parameters or other types that are not implicitly convertible to ``bytes``, you need to convert them to ``bytes`` or ``bytes1``/.../``bytes32`` first. + .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 - pragma solidity ^0.8.4; + pragma solidity ^0.8.12; contract C { - bytes s = "Storage"; - function f(bytes calldata c, string memory m, bytes16 b) public view { - bytes memory a = bytes.concat(s, c, c[:2], "Literal", bytes(m), b); - assert((s.length + c.length + 2 + 7 + bytes(m).length + 16) == a.length); + string s = "Storage"; + function f(bytes calldata bc, string memory sm, bytes16 b) public view { + string memory concatString = string.concat(s, string(bc), "Literal", sm); + assert((bytes(s).length + bc.length + 7 + bytes(sm).length) == bytes(concatString).length); + + bytes memory concatBytes = bytes.concat(bytes(s), bc, bc[:2], "Literal", bytes(sm), b); + assert((bytes(s).length + bc.length + 2 + 7 + bytes(sm).length + b.length) == concatBytes.length); } } -If you call ``bytes.concat`` without arguments it will return an empty ``bytes`` array. +If you call ``string.concat`` or ``bytes.concat`` without arguments they return an empty array. .. index:: ! array;allocating, new @@ -337,10 +348,10 @@ Array Members Dynamic storage arrays and ``bytes`` (not ``string``) have a member function called ``push(x)`` that you can use to append a given element at the end of the array. The function returns nothing. -**pop**: +**pop()**: Dynamic storage arrays and ``bytes`` (not ``string``) have a member - function called ``pop`` that you can use to remove an element from the - end of the array. This also implicitly calls :ref:`delete` on the removed element. + function called ``pop()`` that you can use to remove an element from the + end of the array. This also implicitly calls :ref:`delete` on the removed element. The function returns nothing. .. note:: Increasing the length of a storage array by calling ``push()`` @@ -367,20 +378,22 @@ Array Members pragma solidity >=0.6.0 <0.9.0; contract ArrayContract { - uint[2**20] m_aLotOfIntegers; + uint[2**20] aLotOfIntegers; // Note that the following is not a pair of dynamic arrays but a // dynamic array of pairs (i.e. of fixed size arrays of length two). - // Because of that, T[] is always a dynamic array of T, even if T - // itself is an array. + // In Solidity, T[k] and T[] are always arrays with elements of type T, + // even if T itself is an array. + // Because of that, bool[2][] is a dynamic array of elements + // that are bool[2]. This is different from other languages, like C. // Data location for all state variables is storage. - bool[2][] m_pairsOfFlags; + bool[2][] pairsOfFlags; // newPairs is stored in memory - the only possibility // for public contract function arguments function setAllFlagPairs(bool[2][] memory newPairs) public { // assignment to a storage array performs a copy of ``newPairs`` and - // replaces the complete array ``m_pairsOfFlags``. - m_pairsOfFlags = newPairs; + // replaces the complete array ``pairsOfFlags``. + pairsOfFlags = newPairs; } struct StructType { @@ -402,45 +415,45 @@ Array Members function setFlagPair(uint index, bool flagA, bool flagB) public { // access to a non-existing index will throw an exception - m_pairsOfFlags[index][0] = flagA; - m_pairsOfFlags[index][1] = flagB; + pairsOfFlags[index][0] = flagA; + pairsOfFlags[index][1] = flagB; } function changeFlagArraySize(uint newSize) public { // using push and pop is the only way to change the // length of an array - if (newSize < m_pairsOfFlags.length) { - while (m_pairsOfFlags.length > newSize) - m_pairsOfFlags.pop(); - } else if (newSize > m_pairsOfFlags.length) { - while (m_pairsOfFlags.length < newSize) - m_pairsOfFlags.push(); + if (newSize < pairsOfFlags.length) { + while (pairsOfFlags.length > newSize) + pairsOfFlags.pop(); + } else if (newSize > pairsOfFlags.length) { + while (pairsOfFlags.length < newSize) + pairsOfFlags.push(); } } function clear() public { // these clear the arrays completely - delete m_pairsOfFlags; - delete m_aLotOfIntegers; + delete pairsOfFlags; + delete aLotOfIntegers; // identical effect here - m_pairsOfFlags = new bool[2][](0); + pairsOfFlags = new bool[2][](0); } - bytes m_byteData; + bytes byteData; function byteArrays(bytes memory data) public { // byte arrays ("bytes") are different as they are stored without padding, // but can be treated identical to "uint8[]" - m_byteData = data; + byteData = data; for (uint i = 0; i < 7; i++) - m_byteData.push(); - m_byteData[3] = 0x08; - delete m_byteData[2]; + byteData.push(); + byteData[3] = 0x08; + delete byteData[2]; } function addFlag(bool[2] memory flag) public returns (uint) { - m_pairsOfFlags.push(flag); - return m_pairsOfFlags.length; + pairsOfFlags.push(flag); + return pairsOfFlags.length; } function createMemoryArray(uint size) public pure returns (bytes memory) { @@ -459,6 +472,120 @@ Array Members } } +.. index:: ! array;dangling storage references + +Dangling References to Storage Array Elements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When working with storage arrays, you need to take care to avoid dangling references. +A dangling reference is a reference that points to something that no longer exists or has been +moved without updating the reference. A dangling reference can for example occur, if you store a +reference to an array element in a local variable and then ``.pop()`` from the containing array: + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.8.0 <0.9.0; + + contract C { + uint[][] s; + + function f() public { + // Stores a pointer to the last array element of s. + uint[] storage ptr = s[s.length - 1]; + // Removes the last array element of s. + s.pop(); + // Writes to the array element that is no longer within the array. + ptr.push(0x42); + // Adding a new element to ``s`` now will not add an empty array, but + // will result in an array of length 1 with ``0x42`` as element. + s.push(); + assert(s[s.length - 1][0] == 0x42); + } + } + +The write in ``ptr.push(0x42)`` will **not** revert, despite the fact that ``ptr`` no +longer refers to a valid element of ``s``. Since the compiler assumes that unused storage +is always zeroed, a subsequent ``s.push()`` will not explicitly write zeroes to storage, +so the last element of ``s`` after that ``push()`` will have length ``1`` and contain +``0x42`` as its first element. + +Note that Solidity does not allow to declare references to value types in storage. These kinds +of explicit dangling references are restricted to nested reference types. However, dangling references +can also occur temporarily when using complex expressions in tuple assignments: + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.8.0 <0.9.0; + + contract C { + uint[] s; + uint[] t; + constructor() { + // Push some initial values to the storage arrays. + s.push(0x07); + t.push(0x03); + } + + function g() internal returns (uint[] storage) { + s.pop(); + return t; + } + + function f() public returns (uint[] memory) { + // The following will first evaluate ``s.push()`` to a reference to a new element + // at index 1. Afterwards, the call to ``g`` pops this new element, resulting in + // the left-most tuple element to become a dangling reference. The assignment still + // takes place and will write outside the data area of ``s``. + (s.push(), g()[0]) = (0x42, 0x17); + // A subsequent push to ``s`` will reveal the value written by the previous + // statement, i.e. the last element of ``s`` at the end of this function will have + // the value ``0x42``. + s.push(); + return s; + } + } + +It is always safer to only assign to storage once per statement and to avoid +complex expressions on the left-hand-side of an assignment. + +You need to take particular care when dealing with references to elements of +``bytes`` arrays, since a ``.push()`` on a bytes array may switch :ref:`from short +to long layout in storage`. + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.8.0 <0.9.0; + + // This will report a warning + contract C { + bytes x = "012345678901234567890123456789"; + + function test() external returns(uint) { + (x.push(), x.push()) = (0x01, 0x02); + return x.length; + } + } + +Here, when the first ``x.push()`` is evaluated, ``x`` is still stored in short +layout, thereby ``x.push()`` returns a reference to an element in the first storage slot of +``x``. However, the second ``x.push()`` switches the bytes array to large layout. +Now the element that ``x.push()`` referred to is in the data area of the array while +the reference still points at its original location, which is now a part of the length field +and the assignment will effectively garble the length of ``x``. +To be safe, only enlarge bytes arrays by at most one element during a single +assignment and do not simultaneously index-access the array in the same statement. + +While the above describes the behaviour of dangling storage references in the +current version of the compiler, any code with dangling references should be +considered to have *undefined behaviour*. In particular, this means that +any future version of the compiler may change the behaviour of code that +involves dangling references. + +Be sure to avoid dangling references in your code! + .. index:: ! array;slice .. _array-slices: @@ -502,21 +629,21 @@ Array slices are useful to ABI-decode secondary data passed in function paramete /// @dev Address of the client contract managed by proxy i.e., this contract address client; - constructor(address _client) { - client = _client; + constructor(address client_) { + client = client_; } /// Forward call to "setOwner(address)" that is implemented by client /// after doing basic validation on the address argument. - function forward(bytes calldata _payload) external { - bytes4 sig = bytes4(_payload[:4]); - // Due to truncating behaviour, bytes4(_payload) performs identically. - // bytes4 sig = bytes4(_payload); + function forward(bytes calldata payload) external { + bytes4 sig = bytes4(payload[:4]); + // Due to truncating behaviour, bytes4(payload) performs identically. + // bytes4 sig = bytes4(payload); if (sig == bytes4(keccak256("setOwner(address)"))) { - address owner = abi.decode(_payload[4:], (address)); + address owner = abi.decode(payload[4:], (address)); require(owner != address(0), "Address of owner cannot be zero."); } - (bool status,) = client.delegatecall(_payload); + (bool status,) = client.delegatecall(payload); require(status, "Forwarded call failed."); } } diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 215a18ceec..1e8e3e7fd9 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -188,7 +188,8 @@ The address type comes in two flavours, which are largely identical: - ``address payable``: Same as ``address``, but with the additional members ``transfer`` and ``send``. The idea behind this distinction is that ``address payable`` is an address you can send Ether to, -while a plain ``address`` cannot be sent Ether. +while you are not supposed to send Ether to a plain ``address``, for example because it might be a smart contract +that was not built to accept Ether. Type conversions: @@ -209,22 +210,25 @@ an exception to this rule. declare its type as ``address payable`` to make this requirement visible. Also, try to make this distinction or conversion as early as possible. + The distinction between ``address`` and ``address payable`` was introduced with version 0.5.0. + Also starting from that version, contracts are not implicitly convertible to the ``address`` type, but can still be explicitly converted to + ``address`` or to ``address payable``, if they have a receive or payable fallback function. + + Operators: * ``<=``, ``<``, ``==``, ``!=``, ``>=`` and ``>`` .. warning:: If you convert a type that uses a larger byte size to an ``address``, for example ``bytes32``, then the ``address`` is truncated. - To reduce conversion ambiguity version 0.4.24 and higher of the compiler force you make the truncation explicit in the conversion. + To reduce conversion ambiguity, starting with version 0.4.24, the compiler will force you to make the truncation explicit in the conversion. Take for example the 32-byte value ``0x111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFFCCCC``. You can use ``address(uint160(bytes20(b)))``, which results in ``0x111122223333444455556666777788889999aAaa``, or you can use ``address(uint160(uint256(b)))``, which results in ``0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc``. .. note:: - The distinction between ``address`` and ``address payable`` was introduced with version 0.5.0. - Also starting from that version, contracts do not derive from the address type, but can still be explicitly converted to - ``address`` or to ``address payable``, if they have a receive or payable fallback function. + Mixed-case hexadecimal numbers conforming to `EIP-55 `_ are automatically treated as literals of the ``address`` type. See :ref:`Address Literals`. .. _members-of-addresses: @@ -331,7 +335,9 @@ on ``call``. * ``code`` and ``codehash`` -You can query the deployed code for any smart contract. Use ``code`` to get the EVM bytecode as a string, which might be empty. Use ``codehash`` get the Keccak-256 hash of that code. +You can query the deployed code for any smart contract. Use ``.code`` to get the EVM bytecode as a +``bytes memory``, which might be empty. Use ``.codehash`` to get the Keccak-256 hash of that code +(as a ``bytes32``). Note that ``addr.codehash`` is cheaper than using ``keccak256(addr.code)``. .. note:: All contracts can be converted to ``address`` type, so it is possible to query the balance of the @@ -445,8 +451,8 @@ Integer literals are formed from a sequence of digits in the range 0-9. They are interpreted as decimals. For example, ``69`` means sixty nine. Octal literals do not exist in Solidity and leading zeros are invalid. -Decimal fractional literals are formed by a ``.`` with at least one number on -one side. Examples include ``1.``, ``.1`` and ``1.3``. +Decimal fractional literals are formed by a ``.`` with at least one number after the decimal point. +Examples include ``.1`` and ``1.3`` (but not ``1.``). Scientific notation in the form of ``2e10`` is also supported, where the mantissa can be fractional but the exponent has to be an integer. @@ -460,7 +466,7 @@ There is no additional semantic meaning added to a number literal containing und the underscores are ignored. Number literal expressions retain arbitrary precision until they are converted to a non-literal type (i.e. by -using them together with a non-literal expression or by explicit conversion). +using them together with anything other than a number literal expression (like boolean literals) or by explicit conversion). This means that computations do not overflow and divisions do not truncate in number literal expressions. @@ -468,6 +474,15 @@ For example, ``(2**800 + 1) - 2**800`` results in the constant ``1`` (of type `` although intermediate results would not even fit the machine word size. Furthermore, ``.5 * 8`` results in the integer ``4`` (although non-integers were used in between). +.. warning:: + While most operators produce a literal expression when applied to literals, there are certain operators that do not follow this pattern: + + - Ternary operator (``... ? ... : ...``), + - Array subscript (``[]``). + + You might expect expressions like ``255 + (true ? 1 : 0)`` or ``255 + [1, 2, 3][0]`` to be equivalent to using the literal 256 + directly, but in fact they are computed within the type ``uint8`` and can overflow. + Any operator that can be applied to integers can also be applied to number literal expressions as long as the operands are integers. If any of the two is fractional, bit operations are disallowed and exponentiation is disallowed if the exponent is fractional (because that might result in diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 70125636c2..b19396299c 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -154,6 +154,14 @@ Members of bytes - ``bytes.concat(...) returns (bytes memory)``: :ref:`Concatenates variable number of bytes and bytes1, ..., bytes32 arguments to one byte array` +.. index:: string members + +Members of string +----------------- + +- ``string.concat(...) returns (string memory)``: :ref:`Concatenates variable number of string arguments to one string array` + + .. index:: assert, revert, require Error Handling @@ -376,3 +384,14 @@ The following properties are available for an integer type ``T``: ``type(T).max`` The largest value representable by type ``T``. + +Reserved Keywords +================= + +These keywords are reserved in Solidity. They might become part of the syntax in the future: + +``after``, ``alias``, ``apply``, ``auto``, ``byte``, ``case``, ``copyof``, ``default``, +``define``, ``final``, ``implements``, ``in``, ``inline``, ``let``, ``macro``, ``match``, +``mutable``, ``null``, ``of``, ``partial``, ``promise``, ``reference``, ``relocatable``, +``sealed``, ``sizeof``, ``static``, ``supports``, ``switch``, ``typedef``, ``typeof``, +``var``. \ No newline at end of file diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index c6c40cacc0..d6bf94a2cb 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -298,7 +298,7 @@ Input Description // tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul or berlin "evmVersion": "byzantium", // Optional: Change compilation pipeline to go through the Yul intermediate representation. - // This is a highly EXPERIMENTAL feature, not to be used for production. This is false by default. + // This is false by default. "viaIR": true, // Optional: Debugging settings "debug": { @@ -410,12 +410,13 @@ Input Description "source1.sol": ["contract1"], "source2.sol": ["contract2", "contract3"] }, - // Choose whether division and modulo operations should be replaced by - // multiplication with slack variables. Default is `true`. - // Using `false` here is recommended if you are using the CHC engine + // Choose how division and modulo operations should be encoded. + // When using `false` they are replaced by multiplication with slack + // variables. This is the default. + // Using `true` here is recommended if you are using the CHC engine // and not using Spacer as the Horn solver (using Eldarica, for example). // See the Formal Verification section for a more detailed explanation of this option. - "divModWithSlacks": true, + "divModNoSlacks": false, // Choose which model checker engine to use: all (default), bmc, chc, none. "engine": "chc", // Choose which types of invariants should be reported to the user: contract, reentrancy. @@ -613,8 +614,9 @@ Error Types 10. ``Exception``: Unknown failure during compilation - this should be reported as an issue. 11. ``CompilerError``: Invalid use of the compiler stack - this should be reported as an issue. 12. ``FatalError``: Fatal error not processed correctly - this should be reported as an issue. -13. ``Warning``: A warning, which didn't stop the compilation, but should be addressed if possible. -14. ``Info``: Information that the compiler thinks the user might find useful, but is not dangerous and does not necessarily need to be addressed. +13. ``YulException``: Error during Yul Code generation - this should be reported as an issue. +14. ``Warning``: A warning, which didn't stop the compilation, but should be addressed if possible. +15. ``Info``: Information that the compiler thinks the user might find useful, but is not dangerous and does not necessarily need to be addressed. .. _compiler-tools: diff --git a/docs/yul.rst b/docs/yul.rst index 60a2da5b94..f6109a1255 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -663,10 +663,10 @@ We will use a destructuring notation for the AST nodes. E(G, L, : Assignment) = let G1, L1, v1, ..., vn = E(G, L, rhs) let L2 be a copy of L1 where L2[$var_i] = vi for i = 1, ..., n - G, L2, regular + G1, L2, regular E(G, L, : ForLoop) = if n >= 1: - let G1, L, mode = E(G, L, i1, ..., in) + let G1, L1, mode = E(G, L, i1, ..., in) // mode has to be regular or leave due to the syntactic restrictions if mode is leave then G1, L1 restricted to variables of L, leave @@ -686,7 +686,7 @@ We will use a destructuring notation for the AST nodes. else: G3, L3, mode = E(G2, L2, post) if mode is leave: - G2, L3, leave + G3, L3, leave otherwise E(G3, L3, for {} condition post body) E(G, L, break: BreakContinue) = @@ -768,7 +768,7 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a +-------------------------+-----+---+-----------------------------------------------------------------+ | Instruction | | | Explanation | +=========================+=====+===+=================================================================+ -| stop() + `-` | F | stop execution, identical to return(0, 0) | +| stop() | `-` | F | stop execution, identical to return(0, 0) | +-------------------------+-----+---+-----------------------------------------------------------------+ | add(x, y) | | F | x + y | +-------------------------+-----+---+-----------------------------------------------------------------+ @@ -1124,6 +1124,11 @@ regular strings in native encoding. For code, Above, ``Block`` refers to ``Block`` in the Yul code grammar explained in the previous chapter. +.. note:: + + An object with a name that ends in ``_deployed`` is treated as deployed code by the Yul optimizer. + The only consequence of this is a different gas cost heuristic in the optimizer. + .. note:: Data objects or sub-objects whose names contain a ``.`` can be defined @@ -1157,6 +1162,7 @@ An example Yul Object is shown below: code { function allocate(size) -> ptr { ptr := mload(0x40) + // Note that Solidity generated IR code reserves memory offset ``0x60`` as well, but a pure Yul object is free to use memory as it chooses. if iszero(ptr) { ptr := 0x60 } mstore(0x40, add(ptr, size)) } @@ -1172,20 +1178,21 @@ An example Yul Object is shown below: // now return the runtime object (the currently // executing code is the constructor code) - size := datasize("runtime") + size := datasize("Contract1_deployed") offset := allocate(size) // This will turn into a memory->memory copy for Ewasm and // a codecopy for EVM - datacopy(offset, dataoffset("runtime"), size) + datacopy(offset, dataoffset("Contract1_deployed"), size) return(offset, size) } data "Table2" hex"4123" - object "runtime" { + object "Contract1_deployed" { code { function allocate(size) -> ptr { ptr := mload(0x40) + // Note that Solidity generated IR code reserves memory offset ``0x60`` as well, but a pure Yul object is free to use memory as it chooses. if iszero(ptr) { ptr := 0x60 } mstore(0x40, add(ptr, size)) } @@ -1204,7 +1211,7 @@ An example Yul Object is shown below: // code here ... } - object "runtime" { + object "Contract2_deployed" { code { // code here ... } @@ -1233,68 +1240,13 @@ and optionally specify the :ref:`expected number of contract executions `. .. _erc20yul: