diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..18af34d26b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,152 @@ +cmake_minimum_required(VERSION 3.13.0) + +set(ETH_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake" CACHE PATH "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 "${PROJECT_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.25") +# 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) +option(PROFILE_OPTIMIZER_STEPS "Output performance metrics for the optimiser steps." OFF) + +# 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() + +if (PROFILE_OPTIMIZER_STEPS) + add_definitions(-DPROFILE_OPTIMIZER_STEPS) +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 ${PROJECT_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("${PROJECT_SOURCE_DIR}/cmake/templates/license.h.in" include/license.h) + +include(EthOptions) +configure_project(TESTS) +set(LATEST_Z3_VERSION "4.12.1") +set(MINIMUM_Z3_VERSION "4.8.16") +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(libstdlib) +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..a40bbcf6e9 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``. @@ -137,7 +137,7 @@ For most of the topics the compiler will provide suggestions. ``payable`` or create a new internal function for the program logic that uses ``msg.value``. -* For clarity reasons, the command line interface now requires ``-`` if the +* For clarity reasons, the command-line interface now requires ``-`` if the standard input is used as source. Deprecated Elements @@ -147,18 +147,18 @@ This section lists changes that deprecate prior features or syntax. Note that many of these changes were already enabled in the experimental mode ``v0.5.0``. -Command Line and JSON Interfaces +Command-line and JSON Interfaces -------------------------------- -* The command line option ``--formal`` (used to generate Why3 output for +* The command-line option ``--formal`` (used to generate Why3 output for further formal verification) was deprecated and is now removed. A new formal verification module, the SMTChecker, is enabled via ``pragma experimental SMTChecker;``. -* The command line option ``--julia`` was renamed to ``--yul`` due to the +* The command-line option ``--julia`` was renamed to ``--yul`` due to the renaming of the intermediate language ``Julia`` to ``Yul``. -* The ``--clone-bin`` and ``--combined-json clone-bin`` command line options +* The ``--clone-bin`` and ``--combined-json clone-bin`` command-line options were removed. * Remappings with empty prefix are disallowed. @@ -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..e7c93057f6 100644 --- a/docs/060-breaking-changes.rst +++ b/docs/060-breaking-changes.rst @@ -12,7 +12,7 @@ For the full list check Changes the Compiler Might not Warn About ========================================= -This section lists changes where the behaviour of your code might +This section lists changes where the behavior of your code might change without the compiler telling you about it. * The resulting type of an exponentiation is the type of the base. It used to be the smallest type @@ -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. @@ -103,23 +105,23 @@ Interface Changes ================= This section lists changes that are unrelated to the language itself, but that have an effect on the interfaces of -the compiler. These may change the way how you use the compiler on the command line, how you use its programmable +the compiler. These may change the way how you use the compiler on the command-line, how you use its programmable interface, or how you analyze the output produced by it. New Error Reporter ~~~~~~~~~~~~~~~~~~ -A new error reporter was introduced, which aims at producing more accessible error messages on the command line. -It is enabled by default, but passing ``--old-reporter`` falls back to the the deprecated old error reporter. +A new error reporter was introduced, which aims at producing more accessible error messages on the command-line. +It is enabled by default, but passing ``--old-reporter`` falls back to the deprecated old error reporter. Metadata Hash Options ~~~~~~~~~~~~~~~~~~~~~ The compiler now appends the `IPFS `_ hash of the metadata file to the end of the bytecode by default (for details, see documentation on :doc:`contract metadata `). Before 0.6.0, the compiler appended the -`Swarm `_ hash by default, and in order to still support this behaviour, -the new command line option ``--metadata-hash`` was introduced. It allows you to select the hash to be produced and -appended, by passing either ``ipfs`` or ``swarm`` as value to the ``--metadata-hash`` command line option. +`Swarm `_ hash by default, and in order to still support this behavior, +the new command-line option ``--metadata-hash`` was introduced. It allows you to select the hash to be produced and +appended, by passing either ``ipfs`` or ``swarm`` as value to the ``--metadata-hash`` command-line option. Passing the value ``none`` completely removes the hash. These changes can also be used via the :ref:`Standard JSON Interface` and effect the metadata JSON generated by the compiler. @@ -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/080-breaking-changes.rst b/docs/080-breaking-changes.rst index b322d2a489..524d12ac3b 100644 --- a/docs/080-breaking-changes.rst +++ b/docs/080-breaking-changes.rst @@ -10,18 +10,18 @@ For the full list check Silent Changes of the Semantics =============================== -This section lists changes where existing code changes its behaviour without +This section lists changes where existing code changes its behavior without the compiler notifying you about it. * Arithmetic operations revert on underflow and overflow. You can use ``unchecked { ... }`` to use - the previous wrapping behaviour. + the previous wrapping behavior. Checks for overflow are very common, so we made them the default to increase readability of code, even if it comes at a slight increase of gas costs. * ABI coder v2 is activated by default. - You can choose to use the old behaviour using ``pragma abicoder v1;``. + You can choose to use the old behavior using ``pragma abicoder v1;``. The pragma ``pragma experimental ABIEncoderV2;`` is still valid, but it is deprecated and has no effect. If you want to be explicit, please use ``pragma abicoder v2;`` instead. @@ -57,7 +57,7 @@ New Restrictions This section lists changes that might cause existing contracts to not compile anymore. -* There are new restrictions related to explicit conversions of literals. The previous behaviour in +* There are new restrictions related to explicit conversions of literals. The previous behavior in the following cases was likely ambiguous: 1. Explicit conversions from negative literals and literals larger than ``type(uint160).max`` to @@ -106,7 +106,7 @@ This section lists changes that might cause existing contracts to not compile an * The global functions ``log0``, ``log1``, ``log2``, ``log3`` and ``log4`` have been removed. - These are low-level functions that were largely unused. Their behaviour can be accessed from inline assembly. + These are low-level functions that were largely unused. Their behavior can be accessed from inline assembly. * ``enum`` definitions cannot contain more than 256 members. @@ -173,4 +173,4 @@ How to update your code - Change ``msg.sender.transfer(x)`` to ``payable(msg.sender).transfer(x)`` or use a stored variable of ``address payable`` type. - Change ``x**y**z`` to ``(x**y)**z``. - Use inline assembly as a replacement for ``log0``, ..., ``log4``. -- Negate unsigned integers by subtracting them from the maximum value of the type and adding 1 (e.g. ``type(uint256).max - x + 1``, while ensuring that `x` is not zero) +- Negate unsigned integers by subtracting them from the maximum value of the type and adding 1 (e.g. ``type(uint256).max - x + 1``, while ensuring that ``x`` is not zero) diff --git a/docs/Makefile b/docs/Makefile index 3cc98f6990..01660bd388 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -34,7 +34,6 @@ help: @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @@ -116,12 +115,6 @@ latexpdf: $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..a3b5f25aed --- /dev/null +++ b/docs/README.md @@ -0,0 +1,23 @@ +# Solidity Language Docs + +## Local environment setup + +1. Install python https://www.python.org/downloads/ +1. Install sphinx (the tool used to generate the docs) https://www.sphinx-doc.org/en/master/usage/installation.html + +Go to `/docs` and run `./docs.sh` to install dependencies and build the project: + +```sh +cd docs +./docs.sh +``` + +That will output the generated htmls under _build/ + +## Serve environment + +```py +python3 -m http.server -d _build/html --cgi 8080 +``` + +Visit dev server at http://localhost:8080 diff --git a/docs/_static/css/custom-dark.css b/docs/_static/css/custom-dark.css new file mode 100644 index 0000000000..044a8f800d --- /dev/null +++ b/docs/_static/css/custom-dark.css @@ -0,0 +1,595 @@ + + +/* DARK MODE STYLING */ + +/* code directives */ + +:root[style*=dark] .method dt, +:root[style*=dark] .class dt, +:root[style*=dark] .data dt, +:root[style*=dark] .attribute dt, +:root[style*=dark] .function dt, +:root[style*=dark] .classmethod dt, +:root[style*=dark] .exception dt, +:root[style*=dark] .descclassname, +:root[style*=dark] .descname { + background-color: #2d2d2d !important; +} + +:root[style*=dark] .rst-content dl:not(.docutils) dt { + background-color: #0008; + border-top: solid 3px #fff2; + border-left: solid 3px #fff2; +} + +:root[style*=dark] em.property { + color: #888888; +} + + +/* tables */ + +:root[style*=dark] .rst-content table.docutils td { + border: 0px; +} + +:root[style*=dark] .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td { + background-color: #0002; +} + +:root[style*=dark] .rst-content pre { + background: none; +} + +/* inlined code highlights */ + +:root[style*=dark] .xref, +:root[style*=dark] .py-meth { + color: #aaddff !important; + font-weight: normal !important; +} + +/* highlight color search text */ + +:root[style*=dark] .rst-content .highlighted { + background: #ff5722; + box-shadow: 0 0 0 2px #f0978b; +} + +/* notes, warnings, hints */ + +:root[style*=dark] .hint .admonition-title { + background: #2aa87c !important; +} + +:root[style*=dark] .warning .admonition-title { + background: #cc4444 !important; +} + +:root[style*=dark] .admonition-title { + background: #3a7ca8 !important; +} + +:root[style*=dark] .admonition, +:root[style*=dark] .note { + background-color: #0008 !important; +} + + +/* table of contents */ + +:root[style*=dark] .sidebar { + background-color: #191919 !important; +} + +:root[style*=dark] .sidebar-title { + background-color: #2b2b2b !important; +} + +:root[style*=dark] .wy-menu-vertical code.docutils.literal.notranslate { + background: none !important; + border: none !important; +} + + +:root[style*=dark] .toc-backref { + color: grey !important; +} + +:root[style*=dark] .highlight { + background: #0008; + color: #f8f8f2 +} + +:root[style*=dark] .highlight .c { + color: #888 +} + + +/* Comment */ + +:root[style*=dark] .highlight .err { + color: #960050; + background-color: #1e0010 +} + + +/* Error */ + +:root[style*=dark] .highlight .k { + color: #66d9ef +} + + +/* Keyword */ + +:root[style*=dark] .highlight .l { + color: #ae81ff +} + + +/* Literal */ + +:root[style*=dark] .highlight .n { + color: #f8f8f2 +} + + +/* Name */ + +:root[style*=dark] .highlight .o { + color: #f92672 +} + + +/* Operator */ + +:root[style*=dark] .highlight .p { + color: #f8f8f2 +} + + +/* Punctuation */ + +:root[style*=dark] .highlight .ch { + color: #888 +} + + +/* Comment.Hashbang */ + +:root[style*=dark] .highlight .cm { + color: #888 +} + + +/* Comment.Multiline */ + +:root[style*=dark] .highlight .cp { + color: #888 +} + + +/* Comment.Preproc */ + +:root[style*=dark] .highlight .cpf { + color: #888 +} + + +/* Comment.PreprocFile */ + +:root[style*=dark] .highlight .c1 { + color: #888 +} + + +/* Comment.Single */ + +:root[style*=dark] .highlight .cs { + color: #888 +} + + +/* Comment.Special */ + +:root[style*=dark] .highlight .gd { + color: #f92672 +} + + +/* Generic.Deleted */ + +:root[style*=dark] .highlight .ge { + font-style: italic +} + + +/* Generic.Emph */ + +:root[style*=dark] .highlight .gi { + color: #a6e22e +} + + +/* Generic.Inserted */ + +:root[style*=dark] .highlight .gs { + font-weight: bold +} + + +/* Generic.Strong */ + +:root[style*=dark] .highlight .gu { + color: #888 +} + + +/* Generic.Subheading */ + +:root[style*=dark] .highlight .kc { + color: #66d9ef +} + + +/* Keyword.Constant */ + +:root[style*=dark] .highlight .kd { + color: #66d9ef +} + + +/* Keyword.Declaration */ + +:root[style*=dark] .highlight .kn { + color: #f92672 +} + + +/* Keyword.Namespace */ + +:root[style*=dark] .highlight .kp { + color: #66d9ef +} + + +/* Keyword.Pseudo */ + +:root[style*=dark] .highlight .kr { + color: #66d9ef +} + + +/* Keyword.Reserved */ + +:root[style*=dark] .highlight .kt { + color: #66d9ef +} + + +/* Keyword.Type */ + +:root[style*=dark] .highlight .ld { + color: #e6db74 +} + + +/* Literal.Date */ + +:root[style*=dark] .highlight .m { + color: #ae81ff +} + + +/* Literal.Number */ + +:root[style*=dark] .highlight .s { + color: #e6db74 +} + + +/* Literal.String */ + +:root[style*=dark] .highlight .na { + color: #a6e22e +} + + +/* Name.Attribute */ + +:root[style*=dark] .highlight .nb { + color: #f8f8f2 +} + + +/* Name.Builtin */ + +:root[style*=dark] .highlight .nc { + color: #a6e22e +} + + +/* Name.Class */ + +:root[style*=dark] .highlight .no { + color: #66d9ef +} + + +/* Name.Constant */ + +:root[style*=dark] .highlight .nd { + color: #a6e22e +} + + +/* Name.Decorator */ + +:root[style*=dark] .highlight .ni { + color: #f8f8f2 +} + + +/* Name.Entity */ + +:root[style*=dark] .highlight .ne { + color: #a6e22e +} + + +/* Name.Exception */ + +:root[style*=dark] .highlight .nf { + color: #a6e22e +} + + +/* Name.Function */ + +:root[style*=dark] .highlight .nl { + color: #f8f8f2 +} + + +/* Name.Label */ + +:root[style*=dark] .highlight .nn { + color: #f8f8f2 +} + + +/* Name.Namespace */ + +:root[style*=dark] .highlight .nx { + color: #a6e22e +} + + +/* Name.Other */ + +:root[style*=dark] .highlight .py { + color: #f8f8f2 +} + + +/* Name.Property */ + +:root[style*=dark] .highlight .nt { + color: #f92672 +} + + +/* Name.Tag */ + +:root[style*=dark] .highlight .nv { + color: #f8f8f2 +} + + +/* Name.Variable */ + +:root[style*=dark] .highlight .ow { + color: #f92672 +} + + +/* Operator.Word */ + +:root[style*=dark] .highlight .w { + color: #f8f8f2 +} + + +/* Text.Whitespace */ + +:root[style*=dark] .highlight .mb { + color: #ae81ff +} + + +/* Literal.Number.Bin */ + +:root[style*=dark] .highlight .mf { + color: #ae81ff +} + + +/* Literal.Number.Float */ + +:root[style*=dark] .highlight .mh { + color: #ae81ff +} + + +/* Literal.Number.Hex */ + +:root[style*=dark] .highlight .mi { + color: #ae81ff +} + + +/* Literal.Number.Integer */ + +:root[style*=dark] .highlight .mo { + color: #ae81ff +} + + +/* Literal.Number.Oct */ + +:root[style*=dark] .highlight .sa { + color: #e6db74 +} + + +/* Literal.String.Affix */ + +:root[style*=dark] .highlight .sb { + color: #e6db74 +} + + +/* Literal.String.Backtick */ + +:root[style*=dark] .highlight .sc { + color: #e6db74 +} + + +/* Literal.String.Char */ + +:root[style*=dark] .highlight .dl { + color: #e6db74 +} + + +/* Literal.String.Delimiter */ + +:root[style*=dark] .highlight .sd { + color: #e6db74 +} + + +/* Literal.String.Doc */ + +:root[style*=dark] .highlight .s2 { + color: #e6db74 +} + + +/* Literal.String.Double */ + +:root[style*=dark] .highlight .se { + color: #ae81ff +} + + +/* Literal.String.Escape */ + +:root[style*=dark] .highlight .sh { + color: #e6db74 +} + + +/* Literal.String.Heredoc */ + +:root[style*=dark] .highlight .si { + color: #e6db74 +} + + +/* Literal.String.Interpol */ + +:root[style*=dark] .highlight .sx { + color: #e6db74 +} + + +/* Literal.String.Other */ + +:root[style*=dark] .highlight .sr { + color: #e6db74 +} + + +/* Literal.String.Regex */ + +:root[style*=dark] .highlight .s1 { + color: #e6db74 +} + + +/* Literal.String.Single */ + +:root[style*=dark] .highlight .ss { + color: #e6db74 +} + + +/* Literal.String.Symbol */ + +:root[style*=dark] .highlight .bp { + color: #f8f8f2 +} + + +/* Name.Builtin.Pseudo */ + +:root[style*=dark] .highlight .fm { + color: #a6e22e +} + + +/* Name.Function.Magic */ + +:root[style*=dark] .highlight .vc { + color: #f8f8f2 +} + + +/* Name.Variable.Class */ + +:root[style*=dark] .highlight .vg { + color: #f8f8f2 +} + + +/* Name.Variable.Global */ + +:root[style*=dark] .highlight .vi { + color: #f8f8f2 +} + + +/* Name.Variable.Instance */ + +:root[style*=dark] .highlight .vm { + color: #f8f8f2 +} + + +/* Name.Variable.Magic */ + +:root[style*=dark] .highlight .il { + color: #ae81ff +} + + +/* Grammar */ + +:root[style*=dark] .railroad-diagram { + fill: white; +} + +:root[style*=dark] .railroad-diagram path { + stroke: white; +} + +:root[style*=dark] .railroad-diagram rect { + stroke: white; +} + +:root[style*=dark] .a4 .sig-name { + background-color: transparent !important; +} diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css index 4ff53f3a7b..25ab265443 100644 --- a/docs/_static/css/custom.css +++ b/docs/_static/css/custom.css @@ -1,23 +1,185 @@ +/* ROOT DECLARATIONS */ +:root { + /* Text */ + --color-a: #2B247C; + --color-b: #672AC8; + --color-c: #5554D9; + --color-d: #9F94E8; + --color-e: #AEC0F1; + --color-f: #E6E3EC; + /* Background */ + + --white: #FAF8FF; + --black: #110C4E; + --menu-bg: #2B247C06; + --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + + --navHeight: 4.5rem; + --sideWidth: 300px; + --maxWidth: 80rem; + --desktopInlinePadding: 2rem; + --mobileInlinePadding: 1rem; + --currentVersionHeight: 45px; + + text-rendering: geometricPrecision; + -webkit-font-smoothing: antialiased; +} + +a, +button { + border-radius: 0; +} + +:root[style*=dark] { + --color-a: #E6E3EC !important; + --color-b: #AEC0F1 !important; + --color-c: #9F94E8 !important; + --color-d: #5554D9 !important; + --color-e: #672AC8 !important; + --color-f: #2B247C !important; + + --white: #110C4E !important; + --black: #FAF8FF !important; + --menu-bg: #E6E3EC06 !important; +} + +html, +body, +.unified-header::before, +.wy-nav-side, +.rst-versions, +code, +div, +input[type=text], +a, +.wy-grid-for-nav { + transition: background 150ms ease-in-out; +} + +html, +body, +.wy-grid-for-nav { + background-color: var(--color-f) !important; +} + +body { + font-family: "Overpass", sans-serif; +} + +a { + color: var(--color-c); +} + +a, section { + scroll-margin-top: calc(var(--navHeight) + 2rem); +} + +hr { + margin-block: 2rem; + border-color: var(--color-d) !important; +} + + +/* HEADER STYLES */ +h1 { + font-family: 'Overpass', sans-serif; + font-weight: 700; + font-size: 44px; + color: var(--color-a) !important; + line-height: 1.1; + text-wrap: balance; + margin-top: 4rem; + margin-bottom: 1.5rem; +} + +section:first-of-type h1:first-of-type { + font-family: 'Overpass mono', monospace; + font-size: 48px; + margin-top: 3rem; + margin-bottom: 5rem; +} + +h2 { + font-family: 'Overpass', sans-serif; + font-weight: 700; + font-size: 38px; + color: var(--color-a) !important; + line-height: 46px; + text-wrap: balance; + margin-top: 4rem; + margin-bottom: 1.5rem; +} + +*:not([role=navigation])>p[role=heading]>span, +h3 { + font-family: 'Overpass', sans-serif; + font-weight: 700; + font-size: 32px; + color: var(--color-a) !important; + line-height: 46px; + text-wrap: balance; + margin-top: 4rem; + margin-bottom: 1.5rem; +} + +h4 { + font-family: 'Overpass', sans-serif; + font-weight: 700; + font-size: 32px; + color: var(--color-a) !important; + line-height: 46px; + text-wrap: balance; + margin-top: 3rem; + margin-bottom: 1.5rem; +} + +h5 { + font-family: 'Overpass', sans-serif; + font-weight: 700; + font-size: 18px; + color: var(--color-a) !important; + line-height: 1.4; + text-wrap: balance; +} + +h6 { + font-family: 'Overpass', sans-serif; + font-weight: 700; + font-size: 16px; + color: var(--color-a) !important; + line-height: 1.4; + text-wrap: balance; +} + +span.pre, pre { - white-space: pre-wrap; /* css-3 */ - white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ - white-space: -pre-wrap; /* Opera 4-6 */ - white-space: -o-pre-wrap; /* Opera 7 */ + /* css-3 */ + white-space: pre-wrap; + /* Mozilla, since 1999 */ + white-space: -moz-pre-wrap; + /* Opera 4-6 */ + white-space: -pre-wrap; + /* Opera 7 */ + white-space: -o-pre-wrap; word-wrap: break-word; + font-family: 'Overpass Mono', monospace; } -.wy-table-responsive table td, .wy-table-responsive table th { +small, +small * { + font-size: 12px; +} + +.wy-table-responsive table td, +.wy-table-responsive table th { white-space: normal; } + .rst-content table.docutils td { vertical-align: top; } /* links */ -.rst-content a:not(:visited) { - color: #002fa7; -} - .rst-content .highlighted { background: #eac545; } @@ -27,60 +189,638 @@ pre { background: #fafafa; } -.wy-side-nav-search img.logo { - width: 100px !important; - padding: 0; +/* project version (displayed under project logo) */ +.wy-side-nav-search>div.version { + color: var(--color-b); + margin-top: 0; + margin-bottom: 0.5rem; + text-align: start; } -.wy-side-nav-search > a { - padding: 0; +/* Link to Remix IDE shown next to code snippets */ +.rst-content p.remix-link-container { + display: block; + text-align: right; margin: 0; + line-height: 1em; } -/* project version (displayed under project logo) */ -.wy-side-nav-search .version { - color: #272525 !important; +.rst-content .remix-link-container a.remix-link { + font-size: 0.7em; + padding: 0.1em 0.5em; + background: transparent; + color: var(--color-a) !important; + border: 1px solid var(--color-a); + text-decoration: none; } -/* menu section headers */ -.wy-menu .caption { - color: #65afff !important; +.rst-content div.highlight-solidity, +.rst-content div.highlight-yul { + margin-top: 0; } -/* Link to Remix IDE shown next to code snippets */ -p.remix-link-container { +/* CUSTOMIZATION UPDATES */ + +.wy-nav-content-wrap, +.wy-nav-content { + background: transparent !important; +} + +.wy-side-nav-search { + background-color: transparent !important; + color: var(--color-a) !important; + box-shadow: 0 4 4 0 var(--color-a); + border-bottom: 1px solid var(--color-d) !important; +} + +.wy-side-nav-search svg { + color: var(--color-a) !important; +} + +.wy-nav-top { + background-color: transparent !important; + color: var(--color-a) !important; +} + +.wy-nav-top a { + color: var(--color-a) !important; +} + +.wy-breadcrumbs a.icon-home:before { + content: "Documentation"; + font-family: "Overpass", sans-serif; +} + +.rst-content table.docutils thead { + color: var(--color-a); +} + +code.docutils.literal.notranslate { + padding: 2px 4px; + font-size: 0.875em; + font-family: "Overpass Mono", monospace; + background: var(--white); + color: var(--color-c); + border: 0px; +} + +dt code.docutils.literal.notranslate { + background: none; +} + +.wy-nav-content { + color: var(--color-a); +} + +/* .rst-content a:not(:visited) { */ +/* color: var(--color-b) !important; */ +/* } */ + +.rst-content a:visited { + color: var(--color-c) !important; +} + +.rst-content a { + text-decoration: underline; +} + +.rst-content a:where(:focus, :focus-visible, :hover) { + color: var(--color-d) !important; +} + +.wy-side-scroll a { + color: var(--color-a); + background: transparent; + font-size: 1rem; + line-height: 125%; +} + +.wy-menu-vertical li.current a, +.wy-menu-vertical li.current li a, +.wy-menu-vertical li.current li a code { + border: none; + color: var(--color-a); +} + +ul.current ul, +.wy-menu-vertical li.current a:hover, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a, +.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a, +.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a, +.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a, +.wy-menu-vertical li.current { + background: var(--menu-bg) !important; +} + +.wy-menu.wy-menu-vertical>ul { + margin-bottom: 3rem; +} + +.wy-menu.wy-menu-vertical>p { + color: var(--color-c); +} + +.wy-menu-vertical li.on a, +.wy-menu-vertical li.current>a { + background: var(--menu-bg) !important; + border-bottom: 0px !important; + border-top: 0px !important; +} + +.btn { + border-radius: 0; + text-decoration: none !important; +} + +.wy-breadcrumbs-aside a, +.wy-breadcrumbs-aside a:visited, +a.fa.fa-github, +a.fa.fa-github:visited, +a.fa.fa-github:not(:visited), +a.btn.btn-neutral:visited, +a.btn.btn-neutral:not(:visited), +a.btn.btn-neutral { + background: transparent !important; + color: var(--color-a) !important; + border: 2px solid var(--color-a) !important; + text-decoration: none; +} + +.rst-content .remix-link-container a.remix-link:hover, +.wy-breadcrumbs-aside a:hover, +a.fa.fa-github:hover, +a.btn.btn-neutral:hover { + background: var(--white) !important; + color: var(--color-b) !important; + border-color: var(--color-b) !important; +} + +footer .rst-footer-buttons { + display: flex; + justify-content: center; + gap: 2rem; +} + +/** + * Customization for the unified layout + */ + +/* Site wrapper, and two children: header and rest */ +.unified-wrapper { position: relative; - right: -100%; /* Positioned next to the the top-right corner of the code block following it. */ + display: flex; + flex-direction: column; + inset: 0; + max-width: var(--maxWidth); + margin-inline: auto; +} + +/* Site header */ +.unified-header { + position: fixed; + top: 0; + inset-inline: 0; + z-index: 99999; + display: flex; + align-items: center; + box-shadow: var(--shadow); } -a.remix-link { - position: absolute; /* Remove it from normal flow not to affect the original position of the snippet. */ - top: 0.5em; - width: 3.236em; /* Size of the margin (= right-side padding in .wy-nav-content in the current theme). */ +.unified-header .inner-header { + display: flex; + margin-inline: auto; + width: 100%; + max-width: var(--maxWidth); + align-items: center; + justify-content: space-between; + padding-inline: var(--desktopInlinePadding); + padding-block: 1rem; } -a.remix-link .link-icon { - background: url("../img/solid-share-arrow.svg") no-repeat; +.unified-header::before { + content: ""; + position: absolute; + inset: 0; + opacity: 95%; + background: var(--color-f); + z-index: -1; + backdrop-filter: blur(3px); +} + +.unified-header .home-link { display: block; - width: 1.5em; - height: 1.5em; - margin: auto; + text-decoration: none; + width: 25px; + height: 40px; } -a.remix-link .link-text { - display: none; /* Visible only on hover. */ - width: 3.3em; /* Narrow enough to get two lines of text. */ - margin: auto; - text-align: center; - font-size: 0.8em; - line-height: normal; - color: black; +.unified-header .home-link:hover .solidity-logo { + transform: scale(1.1); + transition: transform 100ms ease-in-out; } -a.remix-link:hover { +.unified-header img.solidity-logo { + transform: scale(1); + transition: transform 100ms ease-in-out; + width: 100%; + height: 100%; +} + +.unified-header .nav-bar { + display: flex; + align-items: center; + justify-content: flex-end; +} + +.unified-header .nav-bar .nav-button-container { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; +} + +.unified-header .nav-link { + display: inline-block; + padding-inline: 8px; + padding-block: 4px; + font-size: 14px; + font-family: 'Overpass Mono', monospace; + text-decoration: none; + color: var(--color-a); + letter-spacing: -0.02em; + font-weight: 400; + box-sizing: content-box; + border-bottom: 1px solid transparent; + white-space: nowrap; +} + +.unified-header .nav-link.active { + background: var(--white); +} + +.unified-header .nav-link:hover { + color: var(--color-c); + border-bottom: 1px solid var(--color-c); +} + +/* Rest: Flex-row, with two children: side bar, and content */ +.unified-wrapper .wy-grid-for-nav { + position: relative !important; + display: flex; + margin-inline: auto; +} + +/* First child: Side bar */ +.unified-wrapper .wy-grid-for-nav nav.wy-nav-side { + position: fixed; + display: flex; + flex-direction: column; + background: var(--color-f); + color: var(--color-a); + padding-bottom: unset !important; + z-index: 10 !important; + min-height: unset !important; + width: var(--sideWidth) !important; + top: var(--navHeight); + bottom: 0; + left: auto; + overflow: auto; +} + +.unified-wrapper .wy-grid-for-nav nav.wy-nav-side .wy-side-scroll { + position: static !important; + width: unset !important; + overflow: unset !important; + height: unset !important; + padding-bottom: 2rem; +} + +.unified-wrapper .wy-grid-for-nav nav.wy-nav-side .wy-side-scroll .wy-side-nav-search { + margin: 0 !important; + width: var(--sideWidth) !important; +} + +.wy-nav-side, +.wy-side-scroll, +.wy-side-nav-search, +.my-menu { + width: 100% !important; +} + +.wy-nav-side input[type=text] { + font-family: "Overpass", sans-serif; + border-radius: 0; + border-color: var(--color-d); + background: var(--white); + box-shadow: none; + color: var(--color-a); +} + +.wy-nav-side input[type=text]::placeholder { + font-family: "Overpass", sans-serif; + color: var(--color-e); + font-size: 16px; + position: relative; + top: 4px; +} + +/* Second child: Content */ +.unified-wrapper .wy-grid-for-nav .wy-nav-content { + width: 100%; + max-width: unset !important; /* override */ + padding-inline: var(--desktopInlinePadding); + margin-inline-start: var(--sideWidth); + margin-top: var(--navHeight); +} + +.unified-wrapper .wy-grid-for-nav .wy-nav-content .rst-content { + max-width: min(70ch, calc(100vw - 2 * var(--desktopInlinePadding) - var(--sideWidth))); + margin-inline: auto; +} + +.unified-wrapper.menu-open .backdrop { opacity: 0.5; } -a.remix-link:hover .link-text { +.unified-wrapper .wy-nav-side, +.unified-wrapper .rst-versions { + left: auto; + +} + +.unified-wrapper .backdrop { + opacity: 0; + transition: opacity 200ms ease-in-out; +} + +@media (max-width: 768px) { + h2 { + margin-top: 3rem; + margin-bottom: 1rem; + } + + h3 { + margin-top: 3rem; + margin-bottom: 1rem; + } + + h4 { + margin-top: 2rem; + margin-bottom: 1rem; + } + + /* Menu closed styles */ + .unified-header .nav-link { + display: none; + } + + .unified-header .inner-header { + padding-inline: var(--mobileInlinePadding); + } + + .unified-wrapper .wy-grid-for-nav nav.wy-nav-side { + transform: translateX(-100%); + transition: transform 200ms ease-in-out; + } + + /* Menu open styles */ + .unified-wrapper.menu-open nav.wy-nav-side { + transform: translateX(0); + transition: transform 200ms ease-in-out; + } + + .unified-wrapper.menu-open .rst-versions { + position: sticky; + bottom: 0; + width: 100%; + } + + .unified-wrapper.menu-open .backdrop { + display: block; + position: fixed; + inset: 0; + opacity: 1; + transition: opacity 200ms ease-in-out; + z-index: 5; + background: #0006; + } + + a.skip-to-content { + display: none; + } + + .wy-nav-content { + margin-inline-start: 0 !important; + } + + .rst-content { + max-width: 100% !important; + } + + .wy-side-scroll { + padding-bottom: 0 !important; + } +} + +ul.search .context { + color: var(--color-a) !important; +} + +.rst-versions { + background: var(--color-f); +} + +.rst-versions.shift-up { + height: unset !important; + max-height: unset !important; + overflow-y: unset !important; +} + +.rst-content dl:not(.docutils) dt { + color: var(--color-a); + background-color: #fff8; + border-top: solid 3px #0002; + border-inline-start: solid 3px #0002; + padding: 2px 6px; +} + +.rst-versions .rst-current-version { + border-color: var(--color-d) !important; +} + +.rst-current-version *, +.rst-current-version .fa:before, +.rst-current-version .fa-element { + color: var(--color-b) !important; +} + +.rst-current-version dt, +.rst-current-version dd, +.rst-current-version dd a, +.rst-other-versions dl:last-of-type dt, +.rst-other-versions dl:last-of-type dd, +.rst-other-versions dl:last-of-type dd a { + font-size: 14px !important; +} + +.rst-other-versions { + background: var(--white) !important; + color: var(--color-a) !important; + max-height: calc(100vh - var(--navHeight) - var(--currentVersionHeight)); + overflow-y: scroll; +} + +.rst-other-versions a { + text-decoration: underline; + color: var(--color-c) !important; +} + +.rst-other-versions dt { + color: var(--color-a) !important; +} + +.rst-other-versions dl { + margin-bottom: 1.5rem !important; +} + +.rst-other-versions dl:last-of-type { + margin-top: 2rem !important; +} + +/* Bottom Search */ +.wy-nav-side input[type=text], +.rst-other-versions dl:last-of-type dd { + width: 100%; +} + +.rst-other-versions dl:last-of-type dt { + color: var(--color-b) !important; +} + +.rst-other-versions dl:last-of-type div[style*=padding], +.rst-other-versions dl dd:first-of-type a { + padding-inline-start: 0 !important; +} + +button.toctree-expand { + color: var(--black) !important; +} + +/* Light/dark color mode toggle 🌓 */ +button.color-toggle { + display: inline-flex; + appearance: none; + -webkit-box-align: center; + align-items: center; + -webkit-box-pack: center; + justify-content: center; + user-select: none; + outline: none; + height: 28px; + width: 28px; + background: none; + border: none; + padding: 6px; + margin: 6px; + transition-duration: 200ms; + transition-property: background-color, + color, + fill, + stroke, + opacity; +} + +button.color-toggle:focus-visible { + outline: 2px solid var(--color-c); + color: var(--color-c); +} + +button.color-toggle:hover { + color: var(--color-c); + background: #0002; +} + +button.color-toggle .color-toggle-icon { + width: 100%; + height: 100%; + margin: 0; + display: inline-block; + line-height: 1em; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + vertical-align: middle; + /* color: var(--color-a); */ +} + + +button.mobile-menu-button { + display: none; +} + +@media (max-width: 768px) { + nav.wy-nav-top { + display: none; + } + + button.mobile-menu-button { + display: flex; + } +} + + +.hidden { + display: none; +} + +#search-results .search li:first-child, +#search-results .search li { + border-color: var(--color-d); +} + +#search-results .search li:last-child { + border: 0px; +} + +.forum-link::after { + content: ' ↗'; + font-size: 14px; + font-family: 'Overpass Mono', monospace; +} + +.wy-breadcrumbs>li { + padding-top: 8px; +} + +.wy-breadcrumbs-aside a { + padding: 0.5rem 0.75rem; + font-size: 12px; + font-family: "'Overpass'", sans-serif; + font-weight: 700; +} + +a.skip-to-content:visited, +a.skip-to-content:not(:visited), +a.skip-to-content { display: block; + pointer-events: none; + width: fit-content; + opacity: 0; + transition: opacity 200ms ease-in-out; + padding: 2px 4px; + font-size: 14px; + margin-inline-end: auto; + margin-inline-start: 1.5rem; + color: var(--color-a); + white-space: nowrap; } + +a.skip-to-content:focus { + opacity: 1; + transition: opacity 200ms ease-in-out; +} + +#content { + scroll-margin-top: 6rem; + scroll-behavior: smooth; +} \ No newline at end of file diff --git a/docs/_static/css/dark.css b/docs/_static/css/dark.css deleted file mode 100644 index a87ff09ebe..0000000000 --- a/docs/_static/css/dark.css +++ /dev/null @@ -1,635 +0,0 @@ -/* links */ - -.rst-content a:not(:visited) { - color: #aaddff !important; -} - -/* code directives */ - -.method dt, -.class dt, -.data dt, -.attribute dt, -.function dt, -.classmethod dt, -.exception dt, -.descclassname, -.descname { - background-color: #2d2d2d !important; -} - -.rst-content dl:not(.docutils) dt { - color: #aaddff; - background-color: #2d2d2d; - border-top: solid 3px #525252; - border-left: solid 3px #525252; -} - -em.property { - color: #888888; -} - - -/* tables */ - -.rst-content table.docutils thead { - color: #ddd; -} - -.rst-content table.docutils td { - border: 0px; -} - -.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td { - background-color: #5a5a5a; -} - -.rst-content pre { - background: none; -} - -/* inlined code highlights */ - -.xref, -.py-meth, -.rst-content a code { - color: #aaddff !important; - font-weight: normal !important; -} - -.rst-content code { - color: #eee !important; - font-weight: normal !important; -} - -code.literal { - background-color: #2d2d2d !important; - border: 1px solid #6d6d6d !important; -} - -code.docutils.literal.notranslate { - color: #ddd; -} - -/* highlight color search text */ - -.rst-content .highlighted { - background: #ff5722; - box-shadow: 0 0 0 2px #f0978b; -} - -/* notes, warnings, hints */ - -.hint .admonition-title { - background: #2aa87c !important; -} - -.warning .admonition-title { - background: #cc4444 !important; -} - -.admonition-title { - background: #3a7ca8 !important; -} - -.admonition, -.note { - background-color: #2d2d2d !important; -} - - -/* table of contents */ - -.wy-nav-content-wrap { - background-color: rgba(0, 0, 0, 0.6) !important; -} - -.sidebar { - background-color: #191919 !important; -} - -.sidebar-title { - background-color: #2b2b2b !important; -} - -.wy-menu-vertical a { - color: #ddd; -} - -.wy-menu-vertical code.docutils.literal.notranslate { - color: #404040; - background: none !important; - border: none !important; -} - -.wy-nav-content { - background: #3c3c3c; - color: #dddddd; -} - -.wy-menu-vertical li.on a, -.wy-menu-vertical li.current>a { - background: #a3a3a3; - border-bottom: 0px !important; - border-top: 0px !important; -} - -.wy-menu-vertical li.current { - background: #b3b3b3; -} - -.toc-backref { - color: grey !important; -} - -.highlight .hll { - background-color: #49483e -} - -.highlight { - background: #222; - color: #f8f8f2 -} - -.highlight .c { - color: #888 -} - - -/* Comment */ - -.highlight .err { - color: #960050; - background-color: #1e0010 -} - - -/* Error */ - -.highlight .k { - color: #66d9ef -} - - -/* Keyword */ - -.highlight .l { - color: #ae81ff -} - - -/* Literal */ - -.highlight .n { - color: #f8f8f2 -} - - -/* Name */ - -.highlight .o { - color: #f92672 -} - - -/* Operator */ - -.highlight .p { - color: #f8f8f2 -} - - -/* Punctuation */ - -.highlight .ch { - color: #888 -} - - -/* Comment.Hashbang */ - -.highlight .cm { - color: #888 -} - - -/* Comment.Multiline */ - -.highlight .cp { - color: #888 -} - - -/* Comment.Preproc */ - -.highlight .cpf { - color: #888 -} - - -/* Comment.PreprocFile */ - -.highlight .c1 { - color: #888 -} - - -/* Comment.Single */ - -.highlight .cs { - color: #888 -} - - -/* Comment.Special */ - -.highlight .gd { - color: #f92672 -} - - -/* Generic.Deleted */ - -.highlight .ge { - font-style: italic -} - - -/* Generic.Emph */ - -.highlight .gi { - color: #a6e22e -} - - -/* Generic.Inserted */ - -.highlight .gs { - font-weight: bold -} - - -/* Generic.Strong */ - -.highlight .gu { - color: #888 -} - - -/* Generic.Subheading */ - -.highlight .kc { - color: #66d9ef -} - - -/* Keyword.Constant */ - -.highlight .kd { - color: #66d9ef -} - - -/* Keyword.Declaration */ - -.highlight .kn { - color: #f92672 -} - - -/* Keyword.Namespace */ - -.highlight .kp { - color: #66d9ef -} - - -/* Keyword.Pseudo */ - -.highlight .kr { - color: #66d9ef -} - - -/* Keyword.Reserved */ - -.highlight .kt { - color: #66d9ef -} - - -/* Keyword.Type */ - -.highlight .ld { - color: #e6db74 -} - - -/* Literal.Date */ - -.highlight .m { - color: #ae81ff -} - - -/* Literal.Number */ - -.highlight .s { - color: #e6db74 -} - - -/* Literal.String */ - -.highlight .na { - color: #a6e22e -} - - -/* Name.Attribute */ - -.highlight .nb { - color: #f8f8f2 -} - - -/* Name.Builtin */ - -.highlight .nc { - color: #a6e22e -} - - -/* Name.Class */ - -.highlight .no { - color: #66d9ef -} - - -/* Name.Constant */ - -.highlight .nd { - color: #a6e22e -} - - -/* Name.Decorator */ - -.highlight .ni { - color: #f8f8f2 -} - - -/* Name.Entity */ - -.highlight .ne { - color: #a6e22e -} - - -/* Name.Exception */ - -.highlight .nf { - color: #a6e22e -} - - -/* Name.Function */ - -.highlight .nl { - color: #f8f8f2 -} - - -/* Name.Label */ - -.highlight .nn { - color: #f8f8f2 -} - - -/* Name.Namespace */ - -.highlight .nx { - color: #a6e22e -} - - -/* Name.Other */ - -.highlight .py { - color: #f8f8f2 -} - - -/* Name.Property */ - -.highlight .nt { - color: #f92672 -} - - -/* Name.Tag */ - -.highlight .nv { - color: #f8f8f2 -} - - -/* Name.Variable */ - -.highlight .ow { - color: #f92672 -} - - -/* Operator.Word */ - -.highlight .w { - color: #f8f8f2 -} - - -/* Text.Whitespace */ - -.highlight .mb { - color: #ae81ff -} - - -/* Literal.Number.Bin */ - -.highlight .mf { - color: #ae81ff -} - - -/* Literal.Number.Float */ - -.highlight .mh { - color: #ae81ff -} - - -/* Literal.Number.Hex */ - -.highlight .mi { - color: #ae81ff -} - - -/* Literal.Number.Integer */ - -.highlight .mo { - color: #ae81ff -} - - -/* Literal.Number.Oct */ - -.highlight .sa { - color: #e6db74 -} - - -/* Literal.String.Affix */ - -.highlight .sb { - color: #e6db74 -} - - -/* Literal.String.Backtick */ - -.highlight .sc { - color: #e6db74 -} - - -/* Literal.String.Char */ - -.highlight .dl { - color: #e6db74 -} - - -/* Literal.String.Delimiter */ - -.highlight .sd { - color: #e6db74 -} - - -/* Literal.String.Doc */ - -.highlight .s2 { - color: #e6db74 -} - - -/* Literal.String.Double */ - -.highlight .se { - color: #ae81ff -} - - -/* Literal.String.Escape */ - -.highlight .sh { - color: #e6db74 -} - - -/* Literal.String.Heredoc */ - -.highlight .si { - color: #e6db74 -} - - -/* Literal.String.Interpol */ - -.highlight .sx { - color: #e6db74 -} - - -/* Literal.String.Other */ - -.highlight .sr { - color: #e6db74 -} - - -/* Literal.String.Regex */ - -.highlight .s1 { - color: #e6db74 -} - - -/* Literal.String.Single */ - -.highlight .ss { - color: #e6db74 -} - - -/* Literal.String.Symbol */ - -.highlight .bp { - color: #f8f8f2 -} - - -/* Name.Builtin.Pseudo */ - -.highlight .fm { - color: #a6e22e -} - - -/* Name.Function.Magic */ - -.highlight .vc { - color: #f8f8f2 -} - - -/* Name.Variable.Class */ - -.highlight .vg { - color: #f8f8f2 -} - - -/* Name.Variable.Global */ - -.highlight .vi { - color: #f8f8f2 -} - - -/* Name.Variable.Instance */ - -.highlight .vm { - color: #f8f8f2 -} - - -/* Name.Variable.Magic */ - -.highlight .il { - color: #ae81ff -} - - -/* Literal.Number.Integer.Long */ - - -/* Link to Remix IDE shown over code snippets */ -a.remix-link { - filter: invert(1); /* The icon is black. In dark mode we want it white. */ -} diff --git a/docs/_static/css/fonts.css b/docs/_static/css/fonts.css new file mode 100644 index 0000000000..1a987a6da1 --- /dev/null +++ b/docs/_static/css/fonts.css @@ -0,0 +1,2 @@ +@import url("https://fonts.cdnfonts.com/css/overpass"); +@import url("https://fonts.cdnfonts.com/css/overpass-mono"); \ No newline at end of file diff --git a/docs/_static/css/pygments.css b/docs/_static/css/pygments.css new file mode 100644 index 0000000000..0e640681de --- /dev/null +++ b/docs/_static/css/pygments.css @@ -0,0 +1,399 @@ +pre { + line-height: 125%; +} + +td.linenos .normal { + color: inherit; + background-color: transparent; + padding-left: 5px; + padding-right: 5px; +} + +span.linenos { + color: inherit; + background-color: transparent; + padding-left: 5px; + padding-right: 5px; +} + +td.linenos .special { + color: #000000; + background-color: #ffffc0; + padding-left: 5px; + padding-right: 5px; +} + +span.linenos.special { + color: #000000; + background-color: #ffffc0; + padding-left: 5px; + padding-right: 5px; +} + +.highlight .hll { + background-color: #ffffcc +} + +.highlight { + background: #eeffcc; +} + +.highlight .c { + color: #408090; + font-style: italic +} + +/* Comment */ +.highlight .err { + border: 1px solid #FF0000 +} + +/* Error */ +.highlight .k { + color: #007020; + font-weight: bold +} + +/* Keyword */ +.highlight .o { + color: #666666 +} + +/* Operator */ +.highlight .ch { + color: #408090; + font-style: italic +} + +/* Comment.Hashbang */ +.highlight .cm { + color: #408090; + font-style: italic +} + +/* Comment.Multiline */ +.highlight .cp { + color: #007020 +} + +/* Comment.Preproc */ +.highlight .cpf { + color: #408090; + font-style: italic +} + +/* Comment.PreprocFile */ +.highlight .c1 { + color: #408090; + font-style: italic +} + +/* Comment.Single */ +.highlight .cs { + color: #408090; + background-color: #fff0f0 +} + +/* Comment.Special */ +.highlight .gd { + color: #A00000 +} + +/* Generic.Deleted */ +.highlight .ge { + font-style: italic +} + +/* Generic.Emph */ +.highlight .gr { + color: #FF0000 +} + +/* Generic.Error */ +.highlight .gh { + color: #000080; + font-weight: bold +} + +/* Generic.Heading */ +.highlight .gi { + color: #00A000 +} + +/* Generic.Inserted */ +.highlight .go { + color: #333333 +} + +/* Generic.Output */ +.highlight .gp { + color: #c65d09; + font-weight: bold +} + +/* Generic.Prompt */ +.highlight .gs { + font-weight: bold +} + +/* Generic.Strong */ +.highlight .gu { + color: #800080; + font-weight: bold +} + +/* Generic.Subheading */ +.highlight .gt { + color: #0044DD +} + +/* Generic.Traceback */ +.highlight .kc { + color: #007020; + font-weight: bold +} + +/* Keyword.Constant */ +.highlight .kd { + color: #007020; + font-weight: bold +} + +/* Keyword.Declaration */ +.highlight .kn { + color: #007020; + font-weight: bold +} + +/* Keyword.Namespace */ +.highlight .kp { + color: #007020 +} + +/* Keyword.Pseudo */ +.highlight .kr { + color: #007020; + font-weight: bold +} + +/* Keyword.Reserved */ +.highlight .kt { + color: #902000 +} + +/* Keyword.Type */ +.highlight .m { + color: #208050 +} + +/* Literal.Number */ +.highlight .s { + color: #4070a0 +} + +/* Literal.String */ +.highlight .na { + color: #4070a0 +} + +/* Name.Attribute */ +.highlight .nb { + color: #007020 +} + +/* Name.Builtin */ +.highlight .nc { + color: #0e84b5; + font-weight: bold +} + +/* Name.Class */ +.highlight .no { + color: #60add5 +} + +/* Name.Constant */ +.highlight .nd { + color: #555555; + font-weight: bold +} + +/* Name.Decorator */ +.highlight .ni { + color: #d55537; + font-weight: bold +} + +/* Name.Entity */ +.highlight .ne { + color: #007020 +} + +/* Name.Exception */ +.highlight .nf { + color: #06287e +} + +/* Name.Function */ +.highlight .nl { + color: #002070; + font-weight: bold +} + +/* Name.Label */ +.highlight .nn { + color: #0e84b5; + font-weight: bold +} + +/* Name.Namespace */ +.highlight .nt { + color: #062873; + font-weight: bold +} + +/* Name.Tag */ +.highlight .nv { + color: #bb60d5 +} + +/* Name.Variable */ +.highlight .ow { + color: #007020; + font-weight: bold +} + +/* Operator.Word */ +.highlight .w { + color: #bbbbbb +} + +/* Text.Whitespace */ +.highlight .mb { + color: #208050 +} + +/* Literal.Number.Bin */ +.highlight .mf { + color: #208050 +} + +/* Literal.Number.Float */ +.highlight .mh { + color: #208050 +} + +/* Literal.Number.Hex */ +.highlight .mi { + color: #208050 +} + +/* Literal.Number.Integer */ +.highlight .mo { + color: #208050 +} + +/* Literal.Number.Oct */ +.highlight .sa { + color: #4070a0 +} + +/* Literal.String.Affix */ +.highlight .sb { + color: #4070a0 +} + +/* Literal.String.Backtick */ +.highlight .sc { + color: #4070a0 +} + +/* Literal.String.Char */ +.highlight .dl { + color: #4070a0 +} + +/* Literal.String.Delimiter */ +.highlight .sd { + color: #4070a0; + font-style: italic +} + +/* Literal.String.Doc */ +.highlight .s2 { + color: #4070a0 +} + +/* Literal.String.Double */ +.highlight .se { + color: #4070a0; + font-weight: bold +} + +/* Literal.String.Escape */ +.highlight .sh { + color: #4070a0 +} + +/* Literal.String.Heredoc */ +.highlight .si { + color: #70a0d0; + font-style: italic +} + +/* Literal.String.Interpol */ +.highlight .sx { + color: #c65d09 +} + +/* Literal.String.Other */ +.highlight .sr { + color: #235388 +} + +/* Literal.String.Regex */ +.highlight .s1 { + color: #4070a0 +} + +/* Literal.String.Single */ +.highlight .ss { + color: #517918 +} + +/* Literal.String.Symbol */ +.highlight .bp { + color: #007020 +} + +/* Name.Builtin.Pseudo */ +.highlight .fm { + color: #06287e +} + +/* Name.Function.Magic */ +.highlight .vc { + color: #bb60d5 +} + +/* Name.Variable.Class */ +.highlight .vg { + color: #bb60d5 +} + +/* Name.Variable.Global */ +.highlight .vi { + color: #bb60d5 +} + +/* Name.Variable.Instance */ +.highlight .vm { + color: #bb60d5 +} + +/* Name.Variable.Magic */ +.highlight .il { + color: #208050 +} + +/* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/_static/css/toggle.css b/docs/_static/css/toggle.css index add134f6c2..6f03e6fb6a 100644 --- a/docs/_static/css/toggle.css +++ b/docs/_static/css/toggle.css @@ -9,6 +9,13 @@ input[type=checkbox] { padding: 10px; display: flex; justify-content: space-between; + background-color: var(--color-f); + border-top: 1px solid var(--color-c); +} + +.fa-caret-down, +.fa-book { + color: var(--color-a) !important; } .rst-versions .rst-current-version .fa-book, @@ -76,8 +83,6 @@ html.transition *:after { transition-delay: 0 !important; } -nav.wy-nav-side { - /* The default padding of 2em is too small and the "Keyword Index" link gets obscured - * by the version toggle. */ - padding-bottom: 3em; -} +.wy-menu-vertical a:hover { + background-color: #0002; +} \ No newline at end of file diff --git a/docs/_static/img/favicon.ico b/docs/_static/img/favicon.ico new file mode 100644 index 0000000000..a2b8f877a3 Binary files /dev/null and b/docs/_static/img/favicon.ico differ diff --git a/docs/_static/img/favicon.png b/docs/_static/img/favicon.png new file mode 100644 index 0000000000..3991d87e98 Binary files /dev/null and b/docs/_static/img/favicon.png differ diff --git a/docs/_static/img/hamburger-dark.svg b/docs/_static/img/hamburger-dark.svg new file mode 100644 index 0000000000..26d9fed9df --- /dev/null +++ b/docs/_static/img/hamburger-dark.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/docs/_static/img/hamburger-light.svg b/docs/_static/img/hamburger-light.svg new file mode 100644 index 0000000000..d5d0d0aed2 --- /dev/null +++ b/docs/_static/img/hamburger-light.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/docs/_static/img/logo-dark.svg b/docs/_static/img/logo-dark.svg new file mode 100644 index 0000000000..92a12a9fed --- /dev/null +++ b/docs/_static/img/logo-dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/docs/_static/img/logo.svg b/docs/_static/img/logo.svg new file mode 100644 index 0000000000..19391843b4 --- /dev/null +++ b/docs/_static/img/logo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/docs/_static/img/moon.svg b/docs/_static/img/moon.svg new file mode 100644 index 0000000000..607dc1b47f --- /dev/null +++ b/docs/_static/img/moon.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/docs/_static/img/sun.svg b/docs/_static/img/sun.svg new file mode 100644 index 0000000000..f86fd22b2d --- /dev/null +++ b/docs/_static/img/sun.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/docs/_static/js/constants.js b/docs/_static/js/constants.js new file mode 100644 index 0000000000..67fa16cdb0 --- /dev/null +++ b/docs/_static/js/constants.js @@ -0,0 +1,38 @@ +// Site URL +const SITE_URL = "https://docs.soliditylang.org" +const { origin, pathname } = location; +const pathSplit = pathname.split("/"); +const rootPath = origin.includes(SITE_URL) && pathSplit.length > 3 ? pathSplit.splice(1, 2).join("/") : '' +const ROOT_URL = `${origin}/${rootPath}`; + +// Color mode constants +const [DARK, LIGHT] = ["dark", "light"]; +const LIGHT_LOGO_PATH = `${ROOT_URL}/_static/img/logo.svg`; +const DARK_LOGO_PATH = `${ROOT_URL}/_static/img/logo-dark.svg`; +const SUN_ICON_PATH = `${ROOT_URL}/_static/img/sun.svg`; +const MOON_ICON_PATH = `${ROOT_URL}/_static/img/moon.svg`; +const LIGHT_HAMBURGER_PATH = `${ROOT_URL}/_static/img/hamburger-light.svg`; +const DARK_HAMBURGER_PATH = `${ROOT_URL}/_static/img/hamburger-dark.svg`; +const COLOR_TOGGLE_ICON_CLASS = "color-toggle-icon"; +const SOLIDITY_LOGO_CLASS = "solidity-logo"; +const LS_COLOR_SCHEME = "color-scheme"; + +// Solidity navigation constants +const SOLIDITY_HOME_URL = "https://soliditylang.org"; +const BLOG_URL = `${SOLIDITY_HOME_URL}/blog`; +const DOCS_URL = "/"; +const USE_CASES_PATH = `${SOLIDITY_HOME_URL}/use-cases`; +const CONTRIBUTE_PATH = `/en/latest/contributing.html`; +const ABOUT_PATH = `${SOLIDITY_HOME_URL}/about`; +const FORUM_URL = "https://forum.soliditylang.org/"; +const NAV_LINKS = [ + { name: "Blog", href: BLOG_URL }, + { name: "Documentation", href: DOCS_URL }, + { name: "Use cases", href: USE_CASES_PATH }, + { name: "Contribute", href: CONTRIBUTE_PATH }, + { name: "About", href: ABOUT_PATH }, + { name: "Forum", href: FORUM_URL }, +]; + +const MOBILE_MENU_TOGGLE_CLASS = "shift"; +const WRAPPER_CLASS = "unified-wrapper"; diff --git a/docs/_static/js/initialize.js b/docs/_static/js/initialize.js new file mode 100644 index 0000000000..a20d4fce71 --- /dev/null +++ b/docs/_static/js/initialize.js @@ -0,0 +1,250 @@ +const getLogoSrc = (isDark) => (isDark ? DARK_LOGO_PATH : LIGHT_LOGO_PATH); + +const getModeIconSrc = (isDark) => (isDark ? SUN_ICON_PATH : MOON_ICON_PATH); + +const getMenuIconSrc = (isDark) => + isDark ? DARK_HAMBURGER_PATH : LIGHT_HAMBURGER_PATH; + +function addFooterNote() { + const contentInfo = document.querySelector("div[role=contentinfo]"); + const footerNote = document.createElement("p"); + footerNote.classList.add("footer-note"); + footerNote.innerHTML = + 'Customized with ❤️ by the ethereum.org team.'; + contentInfo.parentNode.insertBefore(footerNote, contentInfo.nextSibling); +} + +function rearrangeDom() { + const bodyDivs = document.querySelectorAll("body>div"); + bodyDivs.forEach((div) => div.remove()); + const wrapperDiv = document.createElement("div"); + wrapperDiv.classList.add(WRAPPER_CLASS); + bodyDivs.forEach((div) => wrapperDiv.appendChild(div)); + document.body.prepend(wrapperDiv); + + const rstVersions = document.querySelector(".rst-versions"); + rstVersions.remove(); + const wyNavSide = document.querySelector("nav.wy-nav-side"); + wyNavSide.appendChild(rstVersions); + const backdrop = document.createElement("div"); + backdrop.classList.add("backdrop"); + wrapperDiv.appendChild(backdrop); + + const content = document.querySelector(".wy-nav-content"); + content.id = "content"; + const oldWrap = document.querySelector("section.wy-nav-content-wrap"); + oldWrap.remove(); + document.querySelector(".wy-grid-for-nav").appendChild(content); +} + +function buildHeader() { + const isDarkMode = localStorage.getItem(LS_COLOR_SCHEME) == DARK; + + const header = document.createElement("div"); + header.classList.add("unified-header"); + document.querySelector(`.${WRAPPER_CLASS}`).prepend(header); + + const innerHeader = document.createElement("div"); + innerHeader.classList.add("inner-header"); + header.appendChild(innerHeader); + + const homeLink = document.createElement("a"); + homeLink.classList.add("home-link"); + homeLink.href = SOLIDITY_HOME_URL; + homeLink.ariaLabel = "Solidity home"; + innerHeader.appendChild(homeLink); + + const logo = document.createElement("img"); + logo.classList.add(SOLIDITY_LOGO_CLASS); + logo.src = getLogoSrc(isDarkMode); + logo.alt = "Solidity logo"; + homeLink.appendChild(logo); + + const skipToContent = document.createElement("a"); + skipToContent.classList.add("skip-to-content"); + skipToContent.href = "#content"; + skipToContent.innerText = "{skip to content}"; + innerHeader.appendChild(skipToContent); + + const navBar = document.createElement("nav"); + navBar.classList.add("nav-bar"); + innerHeader.appendChild(navBar); + + const linkElements = NAV_LINKS.map(({ name, href }) => { + const link = document.createElement("a"); + link.classList.add("nav-link"); + link.setAttribute("key", name); + link.setAttribute("href", href); + link.setAttribute("aria-label", name); + if (href === FORUM_URL) { + link.classList.add("forum-link"); + link.setAttribute("target", "_blank"); + link.setAttribute("rel", "noopener noreferrer"); + } + link.innerText = name; + return link; + }); + linkElements.forEach((link) => navBar.appendChild(link)); + + // Flex wrapper for color mode and mobile menu buttons + const navButtonContainer = document.createElement("div"); + navButtonContainer.classList.add("nav-button-container"); + navBar.appendChild(navButtonContainer); + + // Build color toggle + const toggleIcon = document.createElement("img"); + toggleIcon.classList.add(COLOR_TOGGLE_ICON_CLASS); + toggleIcon.src = getModeIconSrc(isDarkMode); + toggleIcon.alt = "Color mode toggle icon"; + toggleIcon.setAttribute("aria-hidden", "true"); + toggleIcon.setAttribute("key", "toggle icon"); + const colorModeButton = document.createElement("button"); + colorModeButton.classList.add("color-toggle"); + colorModeButton.setAttribute("type", "button"); + colorModeButton.setAttribute("aria-label", "Toggle light dark mode"); + colorModeButton.setAttribute("key", "color mode button"); + colorModeButton.addEventListener("click", toggleColorMode); + colorModeButton.appendChild(toggleIcon); + navButtonContainer.appendChild(colorModeButton); + + // Build mobile hamburger menu + const menuIcon = document.createElement("img"); + menuIcon.classList.add(COLOR_TOGGLE_ICON_CLASS); + menuIcon.src = getMenuIconSrc(isDarkMode); + menuIcon.alt = "Toggle menu"; + menuIcon.setAttribute("aria-hidden", "true"); + menuIcon.setAttribute("key", "menu icon"); + const menuButton = document.createElement("button"); + menuButton.classList.add("color-toggle"); + menuButton.classList.add("mobile-menu-button"); + menuButton.setAttribute("type", "button"); + menuButton.setAttribute("aria-label", "Toggle menu"); + menuButton.setAttribute("key", "menu button"); + menuButton.addEventListener("click", toggleMenu); + menuButton.appendChild(menuIcon); + navButtonContainer.appendChild(menuButton); +} + +const updateActiveNavLink = () => { + const navLinks = document.querySelectorAll(".unified-header .nav-link"); + navLinks.forEach((link) => { + const href = link.getAttribute("href"); + if (document.documentURI.includes("contributing.html")) { + link.classList[href.includes("contributing.html") ? "add" : "remove"]( + "active" + ); + } else { + link.classList[document.documentURI.includes(href) ? "add" : "remove"]( + "active" + ); + } + }); +}; + +document.addEventListener("locationchange", updateActiveNavLink); + +function updateGitHubEditPath() { + // Replaces the version number in the GitHub edit path with "develop" + const gitHubEditAnchor = document.querySelector(".wy-breadcrumbs-aside > a"); + const url = new URL(gitHubEditAnchor.href); + const split = url.pathname.split("/"); + const versionIndex = split.indexOf("blob") + 1; + split[versionIndex] = "develop"; + url.pathname = split.join("/"); + gitHubEditAnchor.setAttribute("href", url.toString()); + gitHubEditAnchor.setAttribute("target", "_blank"); + gitHubEditAnchor.setAttribute("rel", "noopener noreferrer"); +} + +function initialize() { + // Rearrange DOM elements for styling + rearrangeDom(); + + // Check localStorage for existing color scheme preference + var prefersDark = localStorage.getItem(LS_COLOR_SCHEME) == DARK; + // Check link for search param "color"... it may be "light" or "dark" + var urlParams = new URLSearchParams(window.location.search); + if (urlParams.size > 0) { + // This is used for color mode continuity between the main Solidity Lang site and the docs + var colorSchemeParam = urlParams.get("color"); + // If present, overwrite prefersDark accordingly + if (colorSchemeParam) { + prefersDark = colorSchemeParam == DARK; + } + + // Remove "color" search param from URL + const { location, title } = document; + const { pathname, origin, search, hash } = location; + const newSearchParams = new URLSearchParams(search); + newSearchParams.delete("color"); + const sanitizedSearch = + newSearchParams.size < 1 ? "" : "?" + newSearchParams.toString(); + window.history.replaceState( + origin, + title, + pathname + sanitizedSearch + hash + ); + } + + // In case none existed, establish localStorage color scheme preference + var mode = prefersDark ? DARK : LIGHT; + localStorage.setItem(LS_COLOR_SCHEME, mode); + + // Select the root element and set the style attribute to denote color-scheme attribute + document + .querySelector(":root") + .setAttribute("style", `--color-scheme: ${mode}`); + + // Remove old input and RTD logo anchor element + document.querySelector("input[name=mode]").remove(); + document.querySelector("label[for=switch]").remove(); + document.querySelector(".wy-side-nav-search > a").remove(); + + // Add footer note + addFooterNote(); + + // Build header + buildHeader(); + + // Close menu + toggleMenu({ force: false }); + + // Update active nav link + updateActiveNavLink(); + + // Update GitHub edit path to direct to `develop` branch + updateGitHubEditPath(); +} + +document.addEventListener("DOMContentLoaded", initialize); + +const handleClick = (e) => { + if (e.target.closest(".backdrop")) { + toggleMenu({ force: false }); + } + + if (e.target.closest("a")) { + const target = e.target.closest("a"); + const href = target.getAttribute("href"); + if (href.includes(SOLIDITY_HOME_URL)) { + const url = new URL(href); + const params = new URLSearchParams(url.search); + params.set("color", localStorage.getItem(LS_COLOR_SCHEME)); + url.search = params.toString(); + target.setAttribute("href", url.toString()); + } + } +}; +document.addEventListener("click", handleClick); + +const handleKeyDown = (e) => { + if (e.metaKey && e.key === "k") { + document.querySelector("#rtd-search-form input").focus(); + } else if (e.key === "Escape") { + toggleMenu({ force: false }); + } + if (e.metaKey && e.code === "Backslash") { + toggleColorMode(); + } +}; +document.addEventListener("keydown", handleKeyDown); diff --git a/docs/_static/js/toggle.js b/docs/_static/js/toggle.js index f46a3a6662..6ea2dd1f80 100644 --- a/docs/_static/js/toggle.js +++ b/docs/_static/js/toggle.js @@ -1,38 +1,47 @@ -document.addEventListener('DOMContentLoaded', function() { +function toggleColorMode() { + // Check localStorage for previous color scheme preference, assign the opposite + var newMode = localStorage.getItem(LS_COLOR_SCHEME) == DARK ? LIGHT : DARK; - function toggleCssMode(isDay) { - var mode = (isDay ? "Day" : "Night"); - localStorage.setItem("css-mode", mode); + // Update localStorage with new color scheme preference + localStorage.setItem(LS_COLOR_SCHEME, newMode); - var daysheet = $('link[href="_static/pygments.css"]')[0].sheet; - daysheet.disabled = !isDay; + // Update the root element with the new color scheme preference + document + .querySelector(":root") + .setAttribute("style", `--color-scheme: ${newMode}`); - var nightsheet = $('link[href="_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"); - document.getElementsByTagName("head")[0].appendChild(element); - return; - } - if (nightsheet !== undefined) { - nightsheet.sheet.disabled = isDay; - } - } - - var initial = localStorage.getItem("css-mode") != "Night"; - var checkbox = document.querySelector('input[name=mode]'); + // Update logo + document + .querySelector(`img.${SOLIDITY_LOGO_CLASS}`) + .setAttribute("src", newMode === LIGHT ? LIGHT_LOGO_PATH : DARK_LOGO_PATH); - toggleCssMode(initial); - checkbox.checked = initial; + // Update color mode toggle icon + document + .querySelector(`img.${COLOR_TOGGLE_ICON_CLASS}`) + .setAttribute("src", newMode === LIGHT ? MOON_ICON_PATH : SUN_ICON_PATH); - checkbox.addEventListener('change', function() { - document.documentElement.classList.add('transition'); - window.setTimeout(() => { - document.documentElement.classList.remove('transition'); - }, 1000) - toggleCssMode(this.checked); - }) + // Update hamburger menu icon color + document + .querySelector("button.mobile-menu-button img") + .setAttribute( + "src", + newMode === LIGHT ? LIGHT_HAMBURGER_PATH : DARK_HAMBURGER_PATH + ); +} -}); \ No newline at end of file +function toggleMenu(options = {}) { + const handleClassToggle = ({ classList }, className) => { + if (typeof options.force !== "undefined") { + classList.toggle(className, options.force); + } else { + classList.toggle(className); + } + }; + document + .querySelectorAll('[data-toggle="rst-versions"]') + .forEach((e) => handleClassToggle(e, MOBILE_MENU_TOGGLE_CLASS)); + document + .querySelectorAll('[data-toggle="wy-nav-shift"]') + .forEach((e) => handleClassToggle(e, MOBILE_MENU_TOGGLE_CLASS)); + handleClassToggle(document.querySelector(`.${WRAPPER_CLASS}`), "menu-open"); +} diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index 02e5f8b2a4..0d48b51dd7 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,21 @@ 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 ``bar`` with the argument ``["abc", "def"]``, we would pass 68 bytes total, broken down into: + +- ``0xfce353f6``: the Method ID. This is derived from the signature ``bar(bytes3[2])``. +- ``0x6162630000000000000000000000000000000000000000000000000000000000``: the first part of the first + parameter, a ``bytes3`` value ``"abc"`` (left-aligned). +- ``0x6465660000000000000000000000000000000000000000000000000000000000``: the second part of the first + parameter, a ``bytes3`` value ``"def"`` (left-aligned). + +In total: + +.. code-block:: none + + 0xfce353f661626300000000000000000000000000000000000000000000000000000000006465660000000000000000000000000000000000000000000000000000000000 + +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 @@ -271,20 +285,6 @@ In total: It returns a single ``bool``. If, for example, it were to return ``false``, its output would be the single byte array ``0x0000000000000000000000000000000000000000000000000000000000000000``, a single bool. -If we wanted to call ``bar`` with the argument ``["abc", "def"]``, we would pass 68 bytes total, broken down into: - -- ``0xfce353f6``: the Method ID. This is derived from the signature ``bar(bytes3[2])``. -- ``0x6162630000000000000000000000000000000000000000000000000000000000``: the first part of the first - parameter, a ``bytes3`` value ``"abc"`` (left-aligned). -- ``0x6465660000000000000000000000000000000000000000000000000000000000``: the second part of the first - parameter, a ``bytes3`` value ``"def"`` (left-aligned). - -In total: - -.. code-block:: none - - 0xfce353f661626300000000000000000000000000000000000000000000000000000000006465660000000000000000000000000000000000000000000000000000000000 - If we wanted to call ``sam`` with the arguments ``"dave"``, ``true`` and ``[1,2,3]``, we would pass 292 bytes total, broken down into: @@ -308,10 +308,10 @@ 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``. +We take the first four bytes of ``keccak("f(uint256,uint32[],bytes10,bytes)")``, i.e. ``0x8be65246``. Then we encode the head parts of all four arguments. For the static types ``uint256`` and ``bytes10``, these are directly the values we want to pass, whereas for the dynamic types ``uint32[]`` and ``bytes``, we use the offset in bytes to the start of their data area, measured from the start of the value @@ -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 ====== @@ -562,7 +563,7 @@ A function description is a JSON object with the fields: blockchain state `), ``view`` (:ref:`specified to not modify the blockchain state `), ``nonpayable`` (function does not accept Ether - the default) and ``payable`` (function accepts Ether). -Constructor and fallback function never have ``name`` or ``outputs``. Fallback function doesn't have ``inputs`` either. +Constructor, receive, and fallback never have ``name`` or ``outputs``. Receive and fallback do not have ``inputs`` either. .. note:: Sending non-zero Ether to non-payable function will revert the transaction. @@ -580,7 +581,7 @@ An event description is a JSON object with fairly similar fields: * ``name``: the name of the parameter. * ``type``: the canonical type of the parameter (more below). * ``components``: used for tuple types (more below). - * ``indexed``: ``true`` if the field is part of the log's topics, ``false`` if it one of the log's data segment. + * ``indexed``: ``true`` if the field is part of the log's topics, ``false`` if it is one of the log's data segments. - ``anonymous``: ``true`` if the event was declared as ``anonymous``. @@ -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/analysing-compilation-output.rst b/docs/analysing-compilation-output.rst index 892b18b957..183f773223 100644 --- a/docs/analysing-compilation-output.rst +++ b/docs/analysing-compilation-output.rst @@ -11,7 +11,7 @@ visual diff of the assembly before and after a change is often very enlightening Consider the following contract (named, say ``contract.sol``): -.. code-block:: Solidity +.. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.9.0; diff --git a/docs/assembly.rst b/docs/assembly.rst index c26a53e49a..e08ff9f627 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 behavior 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 +backward-compatibility with older compiler versions, prefer using the dialect string. diff --git a/docs/brand-guide.rst b/docs/brand-guide.rst index 5601b16a8e..cf471c5e3c 100644 --- a/docs/brand-guide.rst +++ b/docs/brand-guide.rst @@ -67,7 +67,7 @@ When using the Solidity logo, please respect the Solidity logo guidelines. Solidity Logo Guidelines ======================== -.. image:: logo.svg +.. image:: solidity_logo.svg :width: 256 *(Right click on the logo to download it.)* diff --git a/docs/bugs.json b/docs/bugs.json index 0b72c05c7d..c853f95edd 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,120 @@ [ + { + "uid": "SOL-2023-3", + "name": "VerbatimInvalidDeduplication", + "summary": "All ``verbatim`` blocks are considered identical by deduplicator and can incorrectly be unified when surrounded by identical opcodes.", + "description": "The block deduplicator is a step of the opcode-based optimizer which identifies equivalent assembly blocks and merges them into a single one. However, when blocks contained ``verbatim``, their comparison was performed incorrectly, leading to the collapse of assembly blocks which are identical except for the contents of the ``verbatim`` items. Since ``verbatim`` is only available in Yul, compilation of Solidity sources is not affected.", + "link": "https://blog.soliditylang.org/2023/11/08/verbatim-invalid-deduplication-bug/", + "introduced": "0.8.5", + "fixed": "0.8.23", + "severity": "low" + }, + { + "uid": "SOL-2023-2", + "name": "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "summary": "Optimizer sequences containing FullInliner do not preserve the evaluation order of arguments of inlined function calls in code that is not in expression-split form.", + "description": "Function call arguments in Yul are evaluated right to left. This order matters when the argument expressions have side-effects, and changing it may change contract behavior. FullInliner is an optimizer step that can replace a function call with the body of that function. The transformation involves assigning argument expressions to temporary variables, which imposes an explicit evaluation order. FullInliner was written with the assumption that this order does not necessarily have to match usual argument evaluation order because the argument expressions have no side-effects. In most circumstances this assumption is true because the default optimization step sequence contains the ExpressionSplitter step. ExpressionSplitter ensures that the code is in *expression-split form*, which means that function calls cannot appear nested inside expressions, and all function call arguments have to be variables. The assumption is, however, not guaranteed to be true in general. Version 0.6.7 introduced a setting allowing users to specify an arbitrary optimization step sequence, making it possible for the FullInliner to actually encounter argument expressions with side-effects, which can result in behavior differences between optimized and unoptimized bytecode. Contracts compiled without optimization or with the default optimization sequence are not affected. To trigger the bug the user has to explicitly choose compiler settings that contain a sequence with FullInliner step not preceded by ExpressionSplitter.", + "link": "https://blog.soliditylang.org/2023/07/19/full-inliner-non-expression-split-argument-evaluation-order-bug/", + "introduced": "0.6.7", + "fixed": "0.8.21", + "severity": "low", + "conditions": { + "yulOptimizer": true + } + }, + { + "uid": "SOL-2023-1", + "name": "MissingSideEffectsOnSelectorAccess", + "summary": "Accessing the ``.selector`` member on complex expressions leaves the expression unevaluated in the legacy code generation.", + "description": "When accessing the ``.selector`` member on an expression with side-effects, like an assignment, a function call or a conditional, the expression would not be evaluated in the legacy code generation. This would happen in expressions where the functions used in the expression were all known at compilation time, regardless of whether the whole expression could be evaluated at compilation time or not. Note that the code generated by the IR pipeline was unaffected and would behave as expected.", + "link": "https://blog.soliditylang.org/2023/07/19/missing-side-effects-on-selector-access-bug/", + "introduced": "0.6.2", + "fixed": "0.8.21", + "severity": "low", + "conditions": { + "viaIR": false + } + }, + { + "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": "NestedCalldataArrayAbiReencodingSizeValidation", + "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 +124,6 @@ "introduced": "0.8.8", "fixed": "0.8.9", "severity": "very low" - }, { "uid": "SOL-2021-3", diff --git a/docs/bugs.rst b/docs/bugs.rst index 75a23e4999..350b1e7a48 100644 --- a/docs/bugs.rst +++ b/docs/bugs.rst @@ -68,7 +68,7 @@ conditions If no conditions are given, assume that the bug is present. check This field contains different checks that report whether the smart contract - contains the bug or not. The first type of check are Javascript regular + contains the bug or not. The first type of check are JavaScript regular expressions that are to be matched against the source code ("source-regex") if the bug is present. If there is no match, then the bug is very likely not present. If there is a match, the bug might be present. For improved diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 608ba3dfda..156b846d01 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", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1051,6 +1101,9 @@ }, "0.5.11": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1065,6 +1118,9 @@ }, "0.5.12": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1079,6 +1135,9 @@ }, "0.5.13": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1093,6 +1152,9 @@ }, "0.5.14": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1109,6 +1171,9 @@ }, "0.5.15": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1124,6 +1189,9 @@ }, "0.5.16": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1138,6 +1206,9 @@ }, "0.5.17": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "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", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1287,6 +1367,9 @@ }, "0.5.9": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1304,6 +1387,9 @@ }, "0.6.0": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1319,6 +1405,9 @@ }, "0.6.1": { "bugs": [ + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1333,6 +1422,12 @@ }, "0.6.10": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1343,6 +1438,12 @@ }, "0.6.11": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1353,6 +1454,12 @@ }, "0.6.12": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1363,6 +1470,10 @@ }, "0.6.2": { "bugs": [ + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1377,6 +1488,10 @@ }, "0.6.3": { "bugs": [ + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1391,6 +1506,10 @@ }, "0.6.4": { "bugs": [ + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1405,6 +1524,10 @@ }, "0.6.5": { "bugs": [ + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1419,6 +1542,10 @@ }, "0.6.6": { "bugs": [ + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1432,6 +1559,11 @@ }, "0.6.7": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1445,6 +1577,11 @@ }, "0.6.8": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1455,6 +1592,12 @@ }, "0.6.9": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1466,6 +1609,12 @@ }, "0.7.0": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1476,6 +1625,12 @@ }, "0.7.1": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1487,6 +1642,12 @@ }, "0.7.2": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1497,6 +1658,12 @@ }, "0.7.3": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1506,6 +1673,12 @@ }, "0.7.4": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" @@ -1514,6 +1687,12 @@ }, "0.7.5": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" @@ -1522,6 +1701,12 @@ }, "0.7.6": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" @@ -1530,6 +1715,12 @@ }, "0.8.0": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" @@ -1538,6 +1729,12 @@ }, "0.8.1": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" @@ -1545,23 +1742,162 @@ "released": "2021-01-27" }, "0.8.10": { - "bugs": [], + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation" + ], "released": "2021-11-09" }, "0.8.11": { - "bugs": [], + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", + "AbiEncodeCallLiteralAsFixedBytesBug" + ], "released": "2021-12-20" }, + "0.8.12": { + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", + "AbiEncodeCallLiteralAsFixedBytesBug" + ], + "released": "2022-02-16" + }, + "0.8.13": { + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "StorageWriteRemovalBeforeConditionalTermination", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "InlineAssemblyMemorySideEffects", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation" + ], + "released": "2022-03-16" + }, + "0.8.14": { + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "StorageWriteRemovalBeforeConditionalTermination", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "InlineAssemblyMemorySideEffects" + ], + "released": "2022-05-17" + }, + "0.8.15": { + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "StorageWriteRemovalBeforeConditionalTermination", + "AbiReencodingHeadOverflowWithStaticArrayCleanup" + ], + "released": "2022-06-15" + }, + "0.8.16": { + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "StorageWriteRemovalBeforeConditionalTermination" + ], + "released": "2022-08-08" + }, + "0.8.17": { + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess" + ], + "released": "2022-09-08" + }, + "0.8.18": { + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess" + ], + "released": "2023-02-01" + }, + "0.8.19": { + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess" + ], + "released": "2023-02-22" + }, "0.8.2": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" ], "released": "2021-03-02" }, + "0.8.20": { + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess" + ], + "released": "2023-05-10" + }, + "0.8.21": { + "bugs": [ + "VerbatimInvalidDeduplication" + ], + "released": "2023-07-19" + }, + "0.8.22": { + "bugs": [ + "VerbatimInvalidDeduplication" + ], + "released": "2023-10-25" + }, + "0.8.23": { + "bugs": [], + "released": "2023-11-08" + }, + "0.8.24": { + "bugs": [], + "released": "2024-01-25" + }, "0.8.3": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory" ], @@ -1569,37 +1905,79 @@ }, "0.8.4": { "bugs": [ + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables" ], "released": "2021-04-21" }, "0.8.5": { "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables" ], "released": "2021-06-10" }, "0.8.6": { "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables" ], "released": "2021-06-22" }, "0.8.7": { "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "SignedImmutables" ], "released": "2021-08-11" }, "0.8.8": { "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation", "UserDefinedValueTypesBug", "SignedImmutables" ], "released": "2021-09-27" }, "0.8.9": { - "bugs": [], + "bugs": [ + "VerbatimInvalidDeduplication", + "FullInlinerNonExpressionSplitArgumentEvaluationOrder", + "MissingSideEffectsOnSelectorAccess", + "AbiReencodingHeadOverflowWithStaticArrayCleanup", + "DirtyBytesArrayToStorage", + "DataLocationChangeInInternalOverride", + "NestedCalldataArrayAbiReencodingSizeValidation" + ], "released": "2021-09-29" } } \ No newline at end of file diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst index eab1e3d52a..2b68d73119 100644 --- a/docs/cheatsheet.rst +++ b/docs/cheatsheet.rst @@ -2,75 +2,17 @@ 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 | ``,`` | -+------------+-------------------------------------+--------------------------------------------+ - -.. 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 - -Global Variables -================ +.. include:: types/operator-precedence-table.rst + +.. index:: abi;decode, abi;encode, abi;encodePacked, abi;encodeWithSelector, abi;encodeCall, abi;encodeWithSignature + +ABI Encoding and Decoding Functions +=================================== - ``abi.decode(bytes memory encodedData, (...)) returns (...)``: :ref:`ABI `-decodes the provided data. The types are given in parentheses as second argument. @@ -83,16 +25,56 @@ Global Variables - ``abi.encodeCall(function functionPointer, (...)) returns (bytes memory)``: ABI-encodes a call to ``functionPointer`` with the arguments found in the tuple. Performs a full type-check, ensuring the types match the function signature. Result equals ``abi.encodeWithSelector(functionPointer.selector, (...))`` - ``abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)``: Equivalent - to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature)), ...)`` + to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)`` + +.. index:: bytes;concat, string;concat + +Members of ``bytes`` and ``string`` +==================================== + - ``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` + +.. index:: address;balance, address;codehash, address;send, address;code, address;transfer + +Members of ``address`` +====================== + +- ``
.balance`` (``uint256``): balance of the :ref:`address` in Wei +- ``
.code`` (``bytes memory``): code at the :ref:`address` (can be empty) +- ``
.codehash`` (``bytes32``): the codehash of the :ref:`address` +- ``
.call(bytes memory) returns (bool, bytes memory)``: issue low-level ``CALL`` with the given payload, + returns success condition and return data +- ``
.delegatecall(bytes memory) returns (bool, bytes memory)``: issue low-level ``DELEGATECALL`` with the given payload, + returns success condition and return data +- ``
.staticcall(bytes memory) returns (bool, bytes memory)``: issue low-level ``STATICCALL`` with the given payload, + returns success condition and return data +- ``
.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`, + returns ``false`` on failure +- ``
.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure + +.. index:: blockhash, blobhash, block, block;basefee, block;blobbasefee, block;chainid, block;coinbase, block;difficulty, block;gaslimit, block;number, block;prevrandao, block;timestamp +.. index:: gasleft, msg;data, msg;sender, msg;sig, msg;value, tx;gasprice, tx;origin + +Block and Transaction Properties +================================ + +- ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent blocks +- ``blobhash(uint index) returns (bytes32)``: versioned hash of the ``index``-th blob associated with the current transaction. + A versioned hash consists of a single byte representing the version (currently ``0x01``), followed by the last 31 bytes + of the SHA256 hash of the KZG commitment (`EIP-4844 `_). - ``block.basefee`` (``uint``): current block's base fee (`EIP-3198 `_ and `EIP-1559 `_) +- ``block.blobbasefee`` (``uint``): current block's blob base fee (`EIP-7516 `_ and `EIP-4844 `_) - ``block.chainid`` (``uint``): current chain id - ``block.coinbase`` (``address payable``): current block miner's address -- ``block.difficulty`` (``uint``): current block difficulty +- ``block.difficulty`` (``uint``): current block difficulty (``EVM < Paris``). For other EVM versions it behaves as a deprecated alias for ``block.prevrandao`` that will be removed in the next breaking release - ``block.gaslimit`` (``uint``): current block gaslimit - ``block.number`` (``uint``): current block number -- ``block.timestamp`` (``uint``): current block timestamp +- ``block.prevrandao`` (``uint``): random number provided by the beacon chain (``EVM >= Paris``) (see `EIP-4399 `_ ) +- ``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) @@ -100,6 +82,12 @@ Global Variables - ``msg.value`` (``uint``): number of wei sent with the message - ``tx.gasprice`` (``uint``): gas price of the transaction - ``tx.origin`` (``address``): sender of the transaction (full call chain) + +.. index:: assert, require, revert + +Validations and Assertions +========================== + - ``assert(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for internal error) - ``require(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for malformed input or error in external component) @@ -107,7 +95,12 @@ Global Variables condition is ``false`` (use for malformed input or error in external component). Also provide error message. - ``revert()``: abort execution and revert state changes - ``revert(string memory message)``: abort execution and revert state changes providing an explanatory string -- ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent blocks + +.. index:: cryptography, keccak256, sha256, ripemd160, ecrecover, addmod, mulmod + +Mathematical and Cryptographic Functions +======================================== + - ``keccak256(bytes memory) returns (bytes32)``: compute the Keccak-256 hash of the input - ``sha256(bytes memory) returns (bytes32)``: compute the SHA-256 hash of the input - ``ripemd160(bytes memory) returns (bytes20)``: compute the RIPEMD-160 hash of the input @@ -117,15 +110,21 @@ Global Variables arbitrary precision and does not wrap around at ``2**256``. Assert that ``k != 0`` starting from version 0.5.0. - ``mulmod(uint x, uint y, uint k) returns (uint)``: compute ``(x * y) % k`` where the multiplication is performed with arbitrary precision and does not wrap around at ``2**256``. Assert that ``k != 0`` starting from version 0.5.0. + +.. index:: this, super, selfdestruct + +Contract-related +================ + - ``this`` (current contract's type): the current contract, explicitly convertible to ``address`` or ``address payable`` -- ``super``: the contract one level higher in the inheritance hierarchy +- ``super``: a contract one level higher in the inheritance hierarchy - ``selfdestruct(address payable recipient)``: destroy the current contract, sending its funds to the given address -- ``
.balance`` (``uint256``): balance of the :ref:`address` in Wei -- ``
.code`` (``bytes memory``): code at the :ref:`address` (can be empty) -- ``
.codehash`` (``bytes32``): the codehash of the :ref:`address` -- ``
.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`, - returns ``false`` on failure -- ``
.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure + +.. index:: type;name, type;creationCode, type;runtimeCode, type;interfaceId, type;min, type;max + +Type Information +================ + - ``type(C).name`` (``string``): the name of the contract - ``type(C).creationCode`` (``bytes memory``): creation bytecode of the given contract, see :ref:`Type Information`. - ``type(C).runtimeCode`` (``bytes memory``): runtime bytecode of the given contract, see :ref:`Type Information`. @@ -133,35 +132,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 @@ -190,21 +160,11 @@ Modifiers - ``view`` for functions: Disallows modification of state. - ``payable`` for functions: Allows them to receive Ether together with a call. - ``constant`` for state variables: Disallows assignment (except initialisation), does not occupy storage slot. -- ``immutable`` for state variables: Allows exactly one assignment at construction time and is constant afterwards. Is stored in code. +- ``immutable`` for state variables: Allows assignment at construction time and is constant when deployed. Is stored in code. - ``anonymous`` for events: Does not store event signature as topic. - ``indexed`` for event parameters: Stores the parameter as topic. - ``virtual`` for functions and modifiers: Allows the function's or modifier's - behaviour to be changed in derived contracts. + behavior to be changed in derived contracts. - ``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: + the behavior of a function or modifier in a base contract. -``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..cbc219b53b 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -18,7 +18,7 @@ introduces a potential security risk. You may read more about this on the :ref:`security_considerations` page. The following is an example of the withdrawal pattern in practice in -a contract where the goal is to send the most money to the +a contract where the goal is to send the most of some compensation, e.g. Ether, to the contract in order to become the "richest", inspired by `King of the Ether `_. @@ -34,7 +34,7 @@ you receive the funds of the person who is now the richest. address public richest; uint public mostSent; - mapping (address => uint) pendingWithdrawals; + mapping(address => uint) pendingWithdrawals; /// The amount of Ether sent was not higher than /// the currently highest amount. @@ -55,7 +55,7 @@ you receive the funds of the person who is now the richest. function withdraw() public { uint amount = pendingWithdrawals[msg.sender]; // Remember to zero the pending refund before - // sending to prevent re-entrancy attacks + // sending to prevent reentrancy attacks pendingWithdrawals[msg.sender] = 0; payable(msg.sender).transfer(amount); } @@ -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/conf.py b/docs/conf.py index 10aa406f28..ddc3ee81bb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,7 +31,10 @@ def setup(sphinx): sphinx.add_lexer('Solidity', SolidityLexer) sphinx.add_lexer('Yul', YulLexer) + sphinx.add_css_file('css/fonts.css') sphinx.add_css_file('css/custom.css') + sphinx.add_css_file('css/custom-dark.css') + sphinx.add_css_file('css/pygments.css') # -- General configuration ------------------------------------------------ @@ -45,6 +48,7 @@ def setup(sphinx): 'sphinx_a4doc', 'html_extra_template_renderer', 'remix_code_links', + 'sphinx.ext.imgconverter', ] a4_base_path = os.path.dirname(__file__) + '/grammar' @@ -63,7 +67,7 @@ def setup(sphinx): # General information about the project. project = 'Solidity' -project_copyright = '2016-2021, Ethereum' +project_copyright = '2016-2023, The Solidity Authors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -131,7 +135,6 @@ def setup(sphinx): # documentation. html_theme_options = { 'logo_only': True, - 'style_nav_header_background': '#65afff', 'display_version': True, } @@ -147,12 +150,12 @@ def setup(sphinx): # The name of an image file (relative to this directory) to place at the top # of the sidebar. -html_logo = "logo.svg" +# html_logo = "logo.svg" # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +html_favicon = "_static/img/favicon.ico" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -161,7 +164,7 @@ def setup(sphinx): html_css_files = ["css/toggle.css"] -html_js_files = ["js/toggle.js"] +html_js_files = ["js/constants.js", "js/initialize.js", "js/toggle.js"] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -209,7 +212,7 @@ def setup(sphinx): #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +html_show_sphinx = False # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True 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..a1bc24f50c 100644 --- a/docs/contracts/constant-state-variables.rst +++ b/docs/contracts/constant-state-variables.rst @@ -30,25 +30,29 @@ Not all types for constants and immutables are implemented at this time. The onl .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.7.4; + pragma solidity ^0.8.21; uint constant X = 32**22 + 8; contract C { string constant TEXT = "abc"; bytes32 constant MY_HASH = keccak256("abc"); - uint immutable decimals; + uint immutable decimals = 18; uint immutable maxBalance; address immutable owner = msg.sender; - constructor(uint _decimals, address _reference) { - decimals = _decimals; + constructor(uint decimals_, address ref) { + if (decimals_ != 0) + // Immutables are only immutable when deployed. + // At construction time they can be assigned to any number of times. + 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; } } @@ -74,25 +78,34 @@ Immutable ========= Variables declared as ``immutable`` are a bit less restricted than those -declared as ``constant``: Immutable variables can be assigned an arbitrary -value in the constructor of the contract or at the point of their declaration. -They can be assigned only once and can, from that point on, be read even during -construction time. +declared as ``constant``: Immutable variables can be assigned a +value at construction time. +The value can be changed at any time before deployment and then it becomes permanent. + +One additional restriction is that immutables can only be assigned to inside expressions for which +there is no possibility of being executed after creation. +This excludes all modifier definitions and functions other than constructors. + +There are no restrictions on reading immutable variables. +The read is even allowed to happen before the variable is written to for the first time because variables in +Solidity always have a well-defined initial value. +For this reason it is also allowed to never explicitly assign a value to an immutable. + +.. warning:: + When accessing immutables at construction time, please keep the :ref:`initialization order + ` in mind. + Even if you provide an explicit initializer, some expressions may end up being evaluated before + that initializer, especially when they are at a different level in inheritance hierarchy. + +.. note:: + Before Solidity 0.8.21 initialization of immutable variables was more restrictive. + Such variables had to be initialized exactly once at construction time and could not be read + before then. 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. - -.. note:: - Immutables that are assigned at their declaration are only considered - initialized once the constructor of the contract is executing. - This means you cannot initialize immutables inline with a value - that depends on another immutable. You can do this, however, - inside the constructor of the contract. - - 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 +blockchain. The compiler outputs where these immutables are located in the deployed bytecode +in the ``immutableReferences`` field of the :ref:`compiler JSON standard output `. diff --git a/docs/contracts/creating-contracts.rst b/docs/contracts/creating-contracts.rst index f1fd3b0b50..8eb4e5f56c 100644 --- a/docs/contracts/creating-contracts.rst +++ b/docs/contracts/creating-contracts.rst @@ -8,7 +8,7 @@ Contracts can be created "from outside" via Ethereum transactions or from within IDEs, such as `Remix `_, make the creation process seamless using UI elements. -One way to create contracts programmatically on Ethereum is via the JavaScript API `web3.js `_. +One way to create contracts programmatically on Ethereum is via the JavaScript API `web3.js `_. It has a function called `web3.eth.Contract `_ to facilitate contract creation. @@ -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..8c73c31603 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: @@ -9,12 +9,13 @@ Events Solidity events give an abstraction on top of the EVM's logging functionality. Applications can subscribe and listen to these events through the RPC interface of an Ethereum client. -Events are inheritable members of contracts. When you call them, they cause the +Events can be defined at file level or as inheritable members of contracts (including interfaces and libraries). +When you call them, they cause the arguments to be stored in the transaction's log - a special data structure -in the blockchain. These logs are associated with the address of the contract, +in the blockchain. These logs are associated with the address of the contract that emitted them, are incorporated into the blockchain, and stay there as long as a block is accessible (forever as of now, but this might -change with Serenity). The Log and its event data is not accessible from within +change in the future). The Log and its event data is not accessible from within contracts (not even from the contract that created them). It is possible to request a Merkle proof for logs, so if @@ -73,6 +74,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 +93,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 +139,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,8 +150,8 @@ The output of the above looks like the following (trimmed): } Additional Resources for Understanding Events -============================================== +============================================= -- `Javascript documentation `_ +- `JavaScript documentation `_ - `Example usage of events `_ - `How to access them in js `_ diff --git a/docs/contracts/function-modifiers.rst b/docs/contracts/function-modifiers.rst index 0d4c8e8c26..454e12ab65 100644 --- a/docs/contracts/function-modifiers.rst +++ b/docs/contracts/function-modifiers.rst @@ -6,7 +6,7 @@ Function Modifiers ****************** -Modifiers can be used to change the behaviour of functions in a declarative way. +Modifiers can be used to change the behavior of functions in a declarative way. For example, you can use a modifier to automatically check a condition prior to executing the function. @@ -19,6 +19,7 @@ if they are marked ``virtual``. For details, please see // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.1 <0.9.0; + // This will report a warning due to deprecated selfdestruct contract owned { constructor() { owner = payable(msg.sender); } @@ -60,7 +61,7 @@ if they are marked ``virtual``. For details, please see } contract Register is priced, destructible { - mapping (address => bool) registeredAddresses; + mapping(address => bool) registeredAddresses; uint price; constructor(uint initialPrice) { price = initialPrice; } @@ -72,8 +73,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 +112,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. @@ -125,7 +132,7 @@ variables are set to their :ref:`default values` just as if the f body. The ``_`` symbol can appear in the modifier multiple times. Each occurrence is replaced with -the function body. +the function body, and the function returns the return value of the final occurrence. Arbitrary expressions are allowed for modifier arguments and in this context, all symbols visible from the function are visible in the modifier. Symbols diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index ff49e4f281..5b82a93bcc 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -1,4 +1,4 @@ -.. index:: ! functions +.. index:: ! functions, ! function;free .. _functions: @@ -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: @@ -256,7 +250,7 @@ Reverting a state change is not considered a "state modification", as only chang state made previously in code that did not have the ``view`` or ``pure`` restriction are reverted and that code has the option to catch the ``revert`` and not pass it on. -This behaviour is also in line with the ``STATICCALL`` opcode. +This behavior is also in line with the ``STATICCALL`` opcode. .. warning:: It is not possible to prevent functions from reading the state at the level @@ -283,7 +277,7 @@ This behaviour is also in line with the ``STATICCALL`` opcode. Special Functions ================= -.. index:: ! receive ether function, function;receive ! receive +.. index:: ! receive ether function, function;receive, ! receive .. _receive-ether-function: @@ -303,7 +297,7 @@ on plain Ether transfers (e.g. via ``.send()`` or ``.transfer()``). If no such function exists, but a payable :ref:`fallback function ` exists, the fallback function will be called on a plain Ether transfer. If neither a receive Ether nor a payable fallback function is present, the -contract cannot receive Ether through regular transactions and throws an +contract cannot receive Ether through a transaction that does not represent a payable function call and throws an exception. In the worst case, the ``receive`` function can only rely on 2300 gas being @@ -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..c787c5af6a 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -40,7 +40,7 @@ Details are given in the following example. // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; - + // This will report a warning due to deprecated selfdestruct contract Owned { constructor() { owner = payable(msg.sender); } @@ -54,7 +54,7 @@ Details are given in the following example. // accessed externally via `this`, though. contract Destructible is Owned { // The keyword `virtual` means that the function can change - // its behaviour in derived classes ("overriding"). + // its behavior in derived classes ("overriding"). function destroy() virtual public { if (msg.sender == owner) selfdestruct(owner); } @@ -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); @@ -115,7 +115,7 @@ Details are given in the following example. // Here, we only specify `override` and not `virtual`. // This means that contracts deriving from `PriceFeed` - // cannot change the behaviour of `destroy` anymore. + // cannot change the behavior of `destroy` anymore. function destroy() public override(Destructible, Named) { Named.destroy(); } function get() public view returns(uint r) { return info; } @@ -130,6 +130,7 @@ seen in the following example: // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; + // This will report a warning due to deprecated selfdestruct contract owned { constructor() { owner = payable(msg.sender); } @@ -162,6 +163,7 @@ explicitly in the final override, but this function will bypass // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; + // This will report a warning due to deprecated selfdestruct contract owned { constructor() { owner = payable(msg.sender); } @@ -291,7 +293,7 @@ and ends at a contract mentioning a function with that signature that does not override. If you do not mark a function that overrides as ``virtual``, derived -contracts can no longer change the behaviour of that function. +contracts can no longer change the behavior of that function. .. note:: @@ -421,8 +423,8 @@ equivalent to ``constructor() {}``. For example: abstract contract A { uint public a; - constructor(uint _a) { - a = _a; + constructor(uint a_) { + a = a_; } } @@ -434,16 +436,16 @@ You can use internal parameters in a constructor (for example storage pointers). the contract has to be marked :ref:`abstract `, because these parameters cannot be assigned valid values from outside but only through the constructors of derived contracts. -.. warning :: +.. warning:: Prior to version 0.4.22, constructors were defined as functions with the same name as the contract. This syntax was deprecated and is not allowed anymore in version 0.5.0. -.. warning :: +.. warning:: Prior to version 0.7.0, you had to specify the visibility of constructors as either ``internal`` or ``public``. -.. index:: ! base;constructor +.. index:: ! base;constructor, inheritance list, contract;abstract, abstract contract Arguments for Base Constructors =============================== @@ -459,7 +461,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,16 +469,25 @@ 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 +constant and defines the behavior of the contract or describes it. The second way has to be used if the constructor arguments of the base depend on those of the derived contract. Arguments have to be given either in the @@ -484,7 +495,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 @@ -574,9 +590,11 @@ One area where inheritance linearization is especially important and perhaps not Inheriting Different Kinds of Members of the Same Name ====================================================== -It is an error when any of the following pairs in a contract have the same name due to inheritance: - - a function and a modifier - - a function and an event - - an event and a modifier +The only situations where, due to inheritance, a contract may contain multiple definitions sharing +the same name are: -As an exception, a state variable getter can override an external function. +- Overloading of functions. +- Overriding of virtual functions. +- Overriding of external virtual functions by state variable getters. +- Overriding of virtual modifiers. +- Overloading of events. diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst index a4581a15f9..a3085667b7 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. @@ -65,7 +65,7 @@ inheritance. Types defined inside interfaces and other contract-like structures can be accessed from other contracts: ``Token.TokenType`` or ``Token.Coin``. -.. warning: +.. warning:: Interfaces have supported ``enum`` types since :doc:`Solidity version 0.5.0 <050-breaking-changes>`, make sure the pragma version specifies this version as a minimum. 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..a05cb277c6 100644 --- a/docs/contracts/using-for.rst +++ b/docs/contracts/using-for.rst @@ -1,4 +1,4 @@ -.. index:: ! using for, library +.. index:: ! using for, library, ! operator;user-defined, function;free .. _using-for: @@ -6,71 +6,146 @@ 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. -These functions will receive the object they are called on +The directive ``using A for B`` can be used to attach +functions (``A``) as operators to user-defined value types +or as member functions to any type (``B``). +The member functions receive the object they are called on as their first parameter (like the ``self`` variable in Python). +The operator functions receive operands as parameters. -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 functions, optionally with an operator name assigned (e.g. + ``using {f, g as +, h, L.t} for uint``). + If no operator is specified, the function can be either a library function or a free function and + is attached to the type as a member function. + Otherwise it must be a free function and it becomes the definition of that operator on the type. +- The name of a library (e.g. ``using L for uint``) - + all non-private functions of the library are attached to the type + as member functions + +At file level, the second part, ``B``, has to be an explicit type (without data location specifier). +Inside contracts, you can also use ``*`` in place of the type (e.g. ``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* non-private functions in the library get 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 (e.g. ``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. +Note that private library functions can only be specified when ``using for`` is inside a library. + +If you define an operator (e.g. ``using {f as +} for T``), then the type (``T``) must be a +:ref:`user-defined value type ` and the definition must be a ``pure`` function. +Operator definitions must be global. +The following operators can be defined this way: + ++------------+----------+---------------------------------------------+ +| Category | Operator | Possible signatures | ++============+==========+=============================================+ +| Bitwise | ``&`` | ``function (T, T) pure returns (T)`` | +| +----------+---------------------------------------------+ +| | ``|`` | ``function (T, T) pure returns (T)`` | +| +----------+---------------------------------------------+ +| | ``^`` | ``function (T, T) pure returns (T)`` | +| +----------+---------------------------------------------+ +| | ``~`` | ``function (T) pure returns (T)`` | ++------------+----------+---------------------------------------------+ +| Arithmetic | ``+`` | ``function (T, T) pure returns (T)`` | +| +----------+---------------------------------------------+ +| | ``-`` | ``function (T, T) pure returns (T)`` | +| + +---------------------------------------------+ +| | | ``function (T) pure returns (T)`` | +| +----------+---------------------------------------------+ +| | ``*`` | ``function (T, T) pure returns (T)`` | +| +----------+---------------------------------------------+ +| | ``/`` | ``function (T, T) pure returns (T)`` | +| +----------+---------------------------------------------+ +| | ``%`` | ``function (T, T) pure returns (T)`` | ++------------+----------+---------------------------------------------+ +| Comparison | ``==`` | ``function (T, T) pure returns (bool)`` | +| +----------+---------------------------------------------+ +| | ``!=`` | ``function (T, T) pure returns (bool)`` | +| +----------+---------------------------------------------+ +| | ``<`` | ``function (T, T) pure returns (bool)`` | +| +----------+---------------------------------------------+ +| | ``<=`` | ``function (T, T) pure returns (bool)`` | +| +----------+---------------------------------------------+ +| | ``>`` | ``function (T, T) pure returns (bool)`` | +| +----------+---------------------------------------------+ +| | ``>=`` | ``function (T, T) pure returns (bool)`` | ++------------+----------+---------------------------------------------+ + +Note that unary and binary ``-`` need separate definitions. +The compiler will choose the right definition based on how the operator is invoked. + 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 and operators 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 +157,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 +176,61 @@ 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. + +Another example shows how to define a custom operator for a user-defined type: + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity ^0.8.19; + + type UFixed16x2 is uint16; + + using { + add as +, + div as / + } for UFixed16x2 global; + + uint32 constant SCALE = 100; + + function add(UFixed16x2 a, UFixed16x2 b) pure returns (UFixed16x2) { + return UFixed16x2.wrap(UFixed16x2.unwrap(a) + UFixed16x2.unwrap(b)); + } + + function div(UFixed16x2 a, UFixed16x2 b) pure returns (UFixed16x2) { + uint32 a32 = UFixed16x2.unwrap(a); + uint32 b32 = UFixed16x2.unwrap(b); + uint32 result32 = a32 * SCALE / b32; + require(result32 <= type(uint16).max, "Divide overflow"); + return UFixed16x2.wrap(uint16(a32 * SCALE / b32)); + } + + contract Math { + function avg(UFixed16x2 a, UFixed16x2 b) public pure returns (UFixed16x2) { + return (a + b) / UFixed16x2.wrap(200); + } + } diff --git a/docs/contracts/visibility-and-getters.rst b/docs/contracts/visibility-and-getters.rst index f04945cfdb..5bf46dea55 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. -Functions have to be specified as being ``external``, -``public``, ``internal`` or ``private``. -For state variables, ``external`` is not possible. +``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| + +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. + Private functions are like internal ones but they are not visible 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. +.. warning:: + |visibility-caveat| The visibility specifier is given after the type for state variables and between parameter list and @@ -187,12 +200,12 @@ The next example is more complex: struct Data { uint a; bytes3 b; - mapping (uint => uint) map; + mapping(uint => uint) map; uint[3] c; uint[] d; bytes e; } - mapping (uint => mapping(bool => Data[])) public data; + mapping(uint => mapping(bool => Data[])) public data; } It generates a function of the following form. The mapping and arrays (with the diff --git a/docs/contributing.rst b/docs/contributing.rst index aa871189f9..61f5b1cf52 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -2,10 +2,15 @@ 기여하기 ############ +<<<<<<< HEAD 도움은 항상 환영하며 Solidity에 기여하는 방법은 여러가지가 있습니다. +======= +Help is always welcome and there are plenty of options to contribute to Solidity. +>>>>>>> english/develop 특히 다음 분야에서 많은 도움을 기다리고 있습니다: +<<<<<<< HEAD * 이슈 리포트 * `Solidity의 깃허브 이슈 `_ 수정 및 대응, 특히 외부 컨트리뷰터의 입문용 이슈를 뜻하는 @@ -16,16 +21,34 @@ `_ 와 `Solidity Gitter Chat `_ 에서 다른 사용자들의 질문에 답변 * `Solidity forum `_ 언어 변경사항 혹은 새로운 피쳐를 제안하거나 피드백을 제공함으로써 언어 설계 과정에 참여 +======= +* Reporting issues. +* Fixing and responding to `Solidity's GitHub issues + `_, especially those tagged as + `"good first issue" `_ which are + meant as introductory issues for external contributors. +* Improving the documentation. +* `Translating `_ the documentation into more languages. +* Responding to questions from other users on `StackExchange + `_ and the `Solidity Gitter Chat + `_. +* Getting involved in the language design process by proposing language changes or new features in the `Solidity forum `_ and providing feedback. +>>>>>>> english/develop 먼저 솔리디티의 컴포넌트와 빌드 프로세스에 익숙해지려면 :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. +>>>>>>> english/develop Team Calls ========== +<<<<<<< HEAD 논의가 필요한 이슈 또는 풀리퀘스트가 있거나, 혹은 팀 또는 컨트리뷰터들이 무엇을 하고 있는지 듣고 싶으면 다음 공개 팀 콜에 참여하실 수 있습니다: @@ -33,6 +56,14 @@ Team Calls - 수요일 2pm CET/CEST. 둘 다 `Jitsi `_ 에서 참여할 수 있습니다. +======= +If you have issues or pull requests to discuss, or are interested in hearing what +the team and contributors are working on, you can join our public team call: + +- Wednesdays at 3PM CET/CEST. + +The call takes place on `Jitsi `_. +>>>>>>> english/develop 이슈 리포팅 ==================== @@ -41,6 +72,7 @@ Team Calls `GitHub issues tracker `_ 를 사용하십시오. 이슈 리포팅 시 다음과 같은 세부사항들을 알려주십시오: +<<<<<<< HEAD * 솔리디티 버전 * 소스코드 (가능한 경우) * 운영체제 @@ -49,6 +81,19 @@ Team Calls 이슈를 발생시킨 소스코드를 최소한으로 줄이는 것 항상 많은 도움이 되며 때로는 오해를 해결하기도 합니다. +======= +* Solidity version. +* Source code (if applicable). +* Operating system. +* Steps to reproduce the issue. +* Actual vs. expected behavior. + +Reducing the source code that caused the issue to a bare minimum is always +very helpful, and sometimes even clarifies a misunderstanding. + +For technical discussions about language design, a post in the +`Solidity forum `_ is the correct place (see :ref:`solidity_language_design`). +>>>>>>> english/develop 풀리퀘스트 워크플로우 ========================== @@ -62,8 +107,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. +>>>>>>> english/develop 새로운 피쳐와 버그픽스 내역는 ``Changelog.md`` 파일에 추가되어야 합니다. 해당하는 경우 이전 엔트리의 스타일을 따르십시오. @@ -72,7 +123,14 @@ Team Calls `_ 을 존중해주십시오. 또한, CI 테스팅을 하고 있지만, 풀리퀘스트를 제출하기 전에 코드를 테스트하고 로컬에서 빌드되는 지 확인하십시오. +<<<<<<< HEAD 도움을 주셔서 감사합니다! +======= +We highly recommend going through our `review checklist `_ before submitting the pull request. +We thoroughly review every PR and will help you get it right, but there are many common problems that can be easily avoided, making the review much smoother. + +Thank you for your help! +>>>>>>> english/develop Running the Compiler Tests ========================== @@ -80,12 +138,28 @@ Running the Compiler Tests Prerequisites ------------- +<<<<<<< HEAD 모든 컴파일러 테스트를 실행하기 위해서는 몇몇 의존성을 선택적으로 설치할 수 있습니다. (`evmone `_, `libz3 `_, `libhera `_). MacOS의 경우 일부 테스트 스크립트는 GNU coreutils가 설치되어야 합니다. 이는 Homebrew를 사용하는게 가장 쉬울 수 있습니다: ``brew install coreutils``. +======= +For running all compiler tests you may want to optionally install a few +dependencies (`evmone `_, +`libz3 `_). + +On macOS systems, some of the testing scripts expect GNU coreutils to be installed. +This can be easiest accomplished using Homebrew: ``brew install coreutils``. +>>>>>>> english/develop + +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 ----------------- @@ -94,25 +168,43 @@ Solidity는 여러 종류의 테스트가 있으며, 대부분은 `Boost C++ Tes `_ 어플리케이션 ``soltest`` 에 번들로 제공됩니다. 대부분의 변경의 경우 ``build/test/soltest`` 또는 이의 wrapper인 ``scripts/soltest.sh`` 를 실행하면 충분합니다. +<<<<<<< HEAD ``./scripts/tests.sh`` 스크립트는 `Boost C++ Test Framework `_ 어플리케이션 ``soltest`` (또는 wrapper ``scripts/soltest.sh``)에 번들된 테스트, 그리고 커멘드라인 테스트와 컴파일 테스트를 포함해서 대부분의 Solidity 테스트를 자동으로 실행합니다. +======= +The ``./scripts/tests.sh`` script executes most Solidity tests automatically, +including those bundled into the `Boost C++ Test Framework `_ +application ``soltest`` (or its wrapper ``scripts/soltest.sh``), as well as command-line tests and +compilation tests. +>>>>>>> english/develop 테스트 시스템은 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. +>>>>>>> english/develop ``evmone`` 주로 semantic 과 가스 테스트 실행에 필요합니다. 설치하지 않은 경우, ``scripts/soltest.sh`` 에 ``--no-semantic-tests`` 플래그를 추가해 해당하는 테스트를 건너뛸 수 있습니다. +<<<<<<< HEAD Ewasm 테스트는 기본적으로 비활성화되어 있으며, ``./scripts/soltest.sh --ewasm`` 를 사용해 명시적으로 허용할 수 있고 ``soltest`` 가 이를 찾기 위해 `hera `_ 를 요구합니다. ``hera`` 라이브러리를 위치시키는 방법은 명시적 위치 지정을 위한 변수 이름이 ``ETH_HERA`` 것을 제외하고 ``evmone`` 과 동일합니다. ``evmone`` 과 ``hera`` 라이브러리는 둘다 리눅스에서 ``.so``, 윈도우에서는 ``.dll``, MacOS에서는 ``.dylib`` 확장자로 끝나야 합니다. +======= +The ``evmone`` library should both end with the file name +extension ``.so`` on Linux, ``.dll`` on Windows systems and ``.dylib`` on macOS. +>>>>>>> english/develop SMT 테스트를 실행하려면 ``libz3`` 라이브러리가 설치되어 있어야 하며 컴파일러의 configure 단계에서 ``cmake`` 로 찾을 수 있어야 합니다. @@ -121,7 +213,7 @@ SMT 테스트를 실행하려면 ``libz3`` 라이브러리가 설치되어 있 SMT 테스트를 비활성화하거나 ``./scripts/soltest.sh --no-smt`` 를 실행하십시오. SMT 테스트는 ``libsolidity/smtCheckerTests`` 과 ``libsolidity/smtCheckerTestsJSON`` 입니다. -.. note :: +.. note:: Soltest가 실행하는 모든 단위테스트 목록을 보기 위해서는 ``./build/test/soltest --list_content=HRF`` 를 실행하십시오. @@ -142,7 +234,7 @@ SMT 테스트는 ``libsolidity/smtCheckerTests`` 과 ``libsolidity/smtCheckerTes - 특정 테스트 케이스 실행을 위해서는 `run_test (-t) `_ - 더 자세한 결과 리포트를 위해서는 `report-level (-r) `_ -.. note :: +.. note:: 윈도우 환경에서 위 기본 세트를 libz3 없이 실행하고 싶은 경우 다음을 참고하십시오. Git Bash를 사용하는 경우, ``./build/test/Release/soltest.exe -- --no-smt`` 를 사용하십시오. @@ -151,6 +243,12 @@ SMT 테스트는 ``libsolidity/smtCheckerTests`` 과 ``libsolidity/smtCheckerTes GDB를 사용해서 디버깅하려는 경우 "일반적인 경우"와 다르게 빌드해야 합니다. 예를 들어, 다음 명령어를 ``build`` 폴더에서 실행시킵니다: +<<<<<<< HEAD +======= +If you want to debug using GDB, make sure you build differently than the "usual". +For example, you could run the following command in your ``build`` folder: + +>>>>>>> english/develop .. code-block:: bash cmake -DCMAKE_BUILD_TYPE=Debug .. @@ -219,6 +317,7 @@ Writing and Running Syntax Tests 실패하는 테스트에 대해 몇가지 옵션을 제공합니다: +<<<<<<< HEAD - ``edit``: ``isoltest`` 가 수정할 수 있도록 에디터에 컨트랙트를 열려고 시도합니다. 이는 커멘드 라인 (``isoltest --editor /path/to/editor``), ``EDITOR`` 환경변수, 또는 ``/usr/bin/editor`` 를 순서대로 참고해서 에디터를 선택합니다. - ``update``: 테스트 중인 컨트랙트의 예상 결과값을 업데이트합니다. 이는 충족하지 않은 결과값을 지우고 누락된 결과값을 추가하는 방식으로 주석을 @@ -227,6 +326,14 @@ Writing and Running Syntax Tests - ``quit``: ``isoltest`` 를 종료합니다. 테스트 프로세스를 종료하는 ``quit`` 를 제외하고 위 모든 옵션들은 현재 컨트랙트에 적용됩니다. +======= +- ``edit``: ``isoltest`` tries to open the contract in an editor so you can adjust it. It either uses the editor given on the command-line (as ``isoltest --editor /path/to/editor``), in the environment variable ``EDITOR`` or just ``/usr/bin/editor`` (in that order). +- ``update``: Updates the expectations for contract under test. This updates the annotations by removing unmet expectations and adding missing expectations. The test is then run again. +- ``skip``: Skips the execution of this particular test. +- ``quit``: Quits ``isoltest``. + +All of these options apply to the current contract, except ``quit`` which stops the entire testing process. +>>>>>>> english/develop 위 테스트를 자동으로 업데이트하면 다음과 같이 바뀝니다. @@ -251,6 +358,62 @@ Writing and Running Syntax Tests 상속이나 cross-contract call을 테스트하는 경우가 아니라면 하나의 파일에 둘 이상의 컨트랙트를 포함하지 마십시오. 각 파일은 새로운 기능의 한 측면을 테스트해야 합니다. +Command-line Tests +------------------ + +Our suite of end-to-end command-line tests checks the behaviour of the compiler binary as a whole +in various scenarios. +These tests are located in `test/cmdlineTests/ `_, +one per subdirectory, and can be executed using the ``cmdlineTests.sh`` script. + +By default the script runs all available tests. +You can also provide one or more `file name patterns `_, +in which case only the tests matching at least one pattern will be executed. +It is also possible to exclude files matching a specific pattern by prefixing it with ``--exclude``. + +By default the script assumes that a ``solc`` binary is available inside the ``build/`` subdirectory +inside the working copy. +If you build the compiler outside of the source tree, you can use the ``SOLIDITY_BUILD_DIR`` environment +variable to specify a different location for the build directory. + +Example: + +.. code-block:: bash + + export SOLIDITY_BUILD_DIR=~/solidity/build/ + test/cmdlineTests.sh "standard_*" "*_yul_*" --exclude "standard_yul_*" + +The commands above will run tests from directories starting with ``test/cmdlineTests/standard_`` and +subdirectories of ``test/cmdlineTests/`` that have ``_yul_`` somewhere in the name, +but no test whose name starts with ``standard_yul_`` will be executed. +It will also assume that the file ``solidity/build/solc/solc`` inside your home directory is the +compiler binary (unless you are on Windows -- then ``solidity/build/solc/Release/solc.exe``). + +There are several kinds of command-line tests: + +- *Standard JSON test*: contains at least an ``input.json`` file. + In general may contain: + + - ``input.json``: input file to be passed to the ``--standard-json`` option on the command line. + - ``output.json``: expected Standard JSON output. + - ``args``: extra command-line arguments passed to ``solc``. + +- *CLI test*: contains at least an ``input.*`` file (other than ``input.json``). + In general may contain: + + - ``input.*``: a single input file, whose name will be supplied to ``solc`` on the command line. + Usually ``input.sol`` or ``input.yul``. + - ``args``: extra command-line arguments passed to ``solc``. + - ``stdin``: content to be passed to ``solc`` via standard input. + - ``output``: expected content of the standard output. + - ``err``: expected content of the standard error output. + - ``exit``: expected exit code. If not provided, zero is expected. + +- *Script test*: contains a ``test.*`` file. + In general may contain: + + - ``test.*``: a single script to run, usually ``test.sh`` or ``test.py``. + The script must be executable. Running the Fuzzer via AFL ========================== @@ -273,7 +436,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 @@ -332,7 +495,7 @@ The AFL documentation states that the corpus (the initial input files) should no too large. The files themselves should not be larger than 1 kB and there should be at most one input file per functionality, so better start with a small number of. There is also a tool called ``afl-cmin`` that can trim input files -that result in similar behaviour of the binary. +that result in similar behavior of the binary. Now run the fuzzer (the ``-m`` extends the size of memory to 60 MB): @@ -379,18 +542,17 @@ contributions to Solidity. English Language ---------------- -Use English, with British English spelling preferred, unless using project or brand names. Try to reduce the usage of -local slang and references, making your language as clear to all readers as possible. Below are some references to help: +Use International English, unless using project or brand names. Try to reduce the usage of +local slang and references, making your language as clear to all readers as possible. +Below are some references to help: * `Simplified technical English `_ * `International English `_ -* `British English spelling `_ - .. note:: While the official Solidity documentation is written in English, there are community contributed :ref:`translations` - in other languages available. Please refer to the `translation guide `_ + in other languages available. Please refer to the `translation guide `_ for information on how to contribute to the community translations. Title Case for Headings @@ -456,13 +618,15 @@ 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: + 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 +645,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..ea8a9c569d 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 @@ -173,14 +173,15 @@ parameters from the function declaration, but can be in arbitrary order. function set(uint key, uint value) public { data[key] = value; } - } -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 +284,7 @@ which only need to be created if there is a dispute. salt, keccak256(abi.encodePacked( type(D).creationCode, - arg + abi.encode(arg) )) ))))); @@ -364,13 +365,13 @@ i.e. the following is not valid: ``(x, uint y) = (1, 2);`` .. warning:: Be careful when assigning to multiple variables at the same time when reference types are involved, because it could lead to unexpected - copying behaviour. + copying behavior. Complications for Arrays and Structs ------------------------------------ The semantics of assignments are more complicated for non-value types like arrays and structs, -including ``bytes`` and ``string``, see :ref:`Data location and assignment behaviour ` for details. +including ``bytes`` and ``string``, see :ref:`Data location and assignment behavior ` for details. In the example below the call to ``g(x)`` has no effect on ``x`` because it creates an independent copy of the storage value in memory. However, ``h(x)`` successfully modifies ``x`` @@ -509,7 +510,7 @@ additional checks. Since Solidity 0.8.0, all arithmetic operations revert on over- and underflow by default, thus making the use of these libraries unnecessary. -To obtain the previous behaviour, an ``unchecked`` block can be used: +To obtain the previous behavior, an ``unchecked`` block can be used: .. code-block:: solidity @@ -649,7 +650,7 @@ in the following situations: For the following cases, the error data from the external call (if provided) is forwarded. This means that it can either cause -an `Error` or a `Panic` (or whatever else was given): +an ``Error`` or a ``Panic`` (or whatever else was given): #. If a ``.transfer()`` fails. #. If you call a function via a message call but it does not finish @@ -684,7 +685,7 @@ and ``assert`` for internal error checking. addr.transfer(msg.value / 2); // Since transfer throws an exception on failure and // cannot call back here, there should be no way for us to - // still have half of the money. + // still have half of the Ether. assert(address(this).balance == balanceBeforeTransfer - msg.value / 2); return address(this).balance; } @@ -718,7 +719,7 @@ The ``revert`` statement takes a custom error as direct argument without parenth revert CustomError(arg1, arg2); -For backwards-compatibility reasons, there is also the ``revert()`` function, which uses parentheses +For backward-compatibility reasons, there is also the ``revert()`` function, which uses parentheses and accepts a string: revert(); 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/blind-auction.rst b/docs/examples/blind-auction.rst index 70aafb3e10..369316fcdc 100644 --- a/docs/examples/blind-auction.rst +++ b/docs/examples/blind-auction.rst @@ -12,10 +12,19 @@ 간단한 공개 입찰 =================== +<<<<<<< HEAD 아래 간단한 공개 입찰 컨트랙트의 핵심은 입찰 기간 동안엔 누구든지 입찰가를 제시할 수 있다는 점입니다. 입찰에는 입찰자가 본인이 제시한 입찰가에 종속하게끔 하도록 돈이나 Ether를 보내는 것을 이미 포함하고 있습니다. 만일 제일 높은 입찰가가 제시될 경우, 직전의 제일 높은 가격으로 부른 입찰자에게 돈이 들어갑니다. 입찰 기간이 종료된 이후 수혜자가 돈을 받기 위해선 컨트랙트는 수동적으로 호출되어야 하며 컨트랙트 스스로 활성화될 수 없습니다. +======= +The general idea of the following simple auction contract is that everyone can +send their bids during a bidding period. The bids already include sending some compensation, +e.g. Ether, in order to bind the bidders to their bid. If the highest bid is +raised, the previous highest bidder gets their Ether back. After the end of +the bidding period, the contract has to be called manually for the beneficiary +to receive their Ether - contracts cannot activate themselves. +>>>>>>> english/develop .. code-block:: solidity @@ -80,18 +89,34 @@ if (block.timestamp > auctionEndTime) revert AuctionAlreadyEnded(); +<<<<<<< HEAD // 만일 입찰가가 높지 않다면, 돈을 다시 보내줍니다. // (취소에 대한 명령문은 여태까지 받았던 돈들을 포함하여 // 해당 함수에서 실행하는 모든 변동 사항들을 무효화합니다.) +======= + // If the bid is not higher, send the + // Ether back (the revert statement + // will revert all changes in this + // function execution including + // it having received the Ether). +>>>>>>> english/develop if (msg.value <= highestBid) revert BidNotHighEnough(highestBid); if (highestBid != 0) { +<<<<<<< HEAD // highestBidder.send(highestBid)를 이용하여 단순히 // 돈을 환불시키는 것에는 보안상 위험이 있습니다. // 왜냐하면 신뢰할 수 없는 컨트랙트를 실행시킬 수도 있기 때문입니다. // 그렇기 때문에 항상 수혜자들이 본인의 돈을 직접 // 인출하게끔 하는 것이 안전합니다. +======= + // Sending back the Ether by simply using + // highestBidder.send(highestBid) is a security risk + // because it could execute an untrusted contract. + // It is always safer to let the recipients + // withdraw their Ether themselves. +>>>>>>> english/develop pendingReturns[highestBidder] += highestBid; } highestBidder = msg.sender; @@ -162,19 +187,19 @@ During the **bidding period**, a bidder does not actually send their bid, but only a hashed version of it. Since it is currently considered practically impossible to find two (sufficiently long) values whose hash values are equal, the bidder commits to the bid by that. After the end of the bidding period, -the bidders have to reveal their bids: They send their values unencrypted and +the bidders have to reveal their bids: They send their values unencrypted, and the contract checks that the hash value is the same as the one provided during the bidding period. Another challenge is how to make the auction **binding and blind** at the same -time: The only way to prevent the bidder from just not sending the money after +time: The only way to prevent the bidder from just not sending the Ether after they won the auction is to make them send it together with the bid. Since value transfers cannot be blinded in Ethereum, anyone can see the value. The following contract solves this problem by accepting any value that is larger than the highest bid. Since this can of course only be checked during the reveal phase, some bids might be **invalid**, and this is on purpose (it -even provides an explicit flag to place invalid bids with high value +even provides an explicit flag to place invalid bids with high-value transfers): Bidders can confuse competition by placing several high or low invalid bids. diff --git a/docs/examples/micropayment.rst b/docs/examples/micropayment.rst index c95d7c5e41..50f28005bf 100644 --- a/docs/examples/micropayment.rst +++ b/docs/examples/micropayment.rst @@ -2,7 +2,7 @@ Micropayment Channel ******************** -In this section we will learn how to build an example implementation +In this section, we will learn how to build an example implementation of a payment channel. It uses cryptographic signatures to make repeated transfers of Ether between the same parties secure, instantaneous, and without transaction fees. For the example, we need to understand how to @@ -17,14 +17,14 @@ Alice is the sender and Bob is the recipient. Alice only needs to send cryptographically signed messages off-chain (e.g. via email) to Bob and it is similar to writing checks. -Alice and Bob use signatures to authorise transactions, which is possible with smart contracts on Ethereum. +Alice and Bob use signatures to authorize transactions, which is possible with smart contracts on Ethereum. Alice will build a simple smart contract that lets her transmit Ether, but instead of calling a function herself to initiate a payment, she will let Bob do that, and therefore pay the transaction fee. The contract will work as follows: 1. Alice deploys the ``ReceiverPays`` contract, attaching enough Ether to cover the payments that will be made. - 2. Alice authorises a payment by signing a message with her private key. + 2. Alice authorizes a payment by signing a message with her private key. 3. Alice sends the cryptographically signed message to Bob. The message does not need to be kept secret (explained later), and the mechanism for sending it does not matter. 4. Bob claims his payment by presenting the signed message to the smart contract, it verifies the @@ -36,7 +36,7 @@ Creating the signature Alice does not need to interact with the Ethereum network to sign the transaction, the process is completely offline. In this tutorial, we will sign messages in the browser -using `web3.js `_ and +using `web3.js `_ and `MetaMask `_, using the method described in `EIP-712 `_, as it provides a number of other security benefits. @@ -86,7 +86,7 @@ Packing arguments Now that we have identified what information to include in the signed message, we are ready to put the message together, hash it, and sign it. For simplicity, we concatenate the data. The `ethereumjs-abi `_ -library provides a function called ``soliditySHA3`` that mimics the behaviour of +library provides a function called ``soliditySHA3`` that mimics the behavior of Solidity's ``keccak256`` function applied to arguments encoded using ``abi.encodePacked``. Here is a JavaScript function that creates the proper signature for the ``ReceiverPays`` example: @@ -144,6 +144,7 @@ The full contract // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; + // This will report a warning due to deprecated selfdestruct contract ReceiverPays { address owner = msg.sender; @@ -259,7 +260,7 @@ Messages are cryptographically signed by the sender and then transmitted directl Each message includes the following information: * The smart contract's address, used to prevent cross-contract replay attacks. - * The total amount of Ether that is owed the recipient so far. + * The total amount of Ether that is owed to the recipient so far. A payment channel is closed just once, at the end of a series of transfers. Because of this, only one of the messages sent is redeemed. This is why @@ -341,6 +342,7 @@ The full contract // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; + // This will report a warning due to deprecated selfdestruct contract SimplePaymentChannel { address payable public sender; // The account sending payments. address payable public recipient; // The account receiving the payments. diff --git a/docs/examples/modular.rst b/docs/examples/modular.rst index 7903ae27fd..9ae2849cb4 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 behavior 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 @@ -34,7 +34,7 @@ and the sum of all balances is an invariant across the lifetime of the contract. contract Token { mapping(address => uint256) balances; using Balances for *; - mapping(address => mapping (address => uint256)) allowed; + mapping(address => mapping(address => uint256)) allowed; event Transfer(address from, address to, uint amount); event Approval(address owner, address spender, uint amount); diff --git a/docs/examples/safe-remote.rst b/docs/examples/safe-remote.rst index e42b017fb6..a2651af238 100644 --- a/docs/examples/safe-remote.rst +++ b/docs/examples/safe-remote.rst @@ -6,18 +6,18 @@ Safe Remote Purchase Purchasing goods remotely currently requires multiple parties that need to trust each other. The simplest configuration involves a seller and a buyer. The buyer would like to receive -an item from the seller and the seller would like to get money (or an equivalent) +an item from the seller and the seller would like to get some compensation, e.g. Ether, in return. The problematic part is the shipment here: There is no way to determine for sure that the item arrived at the buyer. There are multiple ways to solve this problem, but all fall short in one or the other way. In the following example, both parties have to put twice the value of the item into the -contract as escrow. As soon as this happened, the money will stay locked inside +contract as escrow. As soon as this happened, the Ether will stay locked inside the contract until the buyer confirms that they received the item. After that, the buyer is returned the value (half of their deposit) and the seller gets three times the value (their deposit plus the value). The idea behind this is that both parties have an incentive to resolve the situation or otherwise -their money is locked forever. +their Ether is locked forever. This contract of course does not solve the problem, but gives an overview of how you can use state machine-like constructs inside a contract. diff --git a/docs/examples/voting.rst b/docs/examples/voting.rst index 0c57165a97..7dba3c4a26 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]`. +>>>>>>> english/develop 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? +>>>>>>> english/develop diff --git a/docs/ext/remix_code_links.py b/docs/ext/remix_code_links.py index 2fc15ddda0..55fc0ef5c2 100644 --- a/docs/ext/remix_code_links.py +++ b/docs/ext/remix_code_links.py @@ -22,23 +22,16 @@ def remix_code_url(source_code, language, solidity_version): # NOTE: base64 encoded data may contain +, = and / characters. Remix seems to handle them just # fine without any escaping. base64_encoded_source = base64.b64encode(source_code.encode('utf-8')).decode('ascii') - return f"https://remix.ethereum.org/?language={language}&version={solidity_version}&code={base64_encoded_source}" + return f"https://remix.ethereum.org/?#language={language}&version={solidity_version}&code={base64_encoded_source}" def build_remix_link_node(url): - link_icon_node = docutils.nodes.inline() - link_icon_node.set_class('link-icon') - - link_text_node = docutils.nodes.inline(text="open in Remix") - link_text_node.set_class('link-text') - - reference_node = docutils.nodes.reference('', '', internal=False, refuri=url) - reference_node.set_class('remix-link') - reference_node += [link_icon_node, link_text_node] + reference_node = docutils.nodes.reference('', 'open in Remix', internal=False, refuri=url, target='_blank') + reference_node['classes'].append('remix-link') paragraph_node = docutils.nodes.paragraph() - paragraph_node.set_class('remix-link-container') - paragraph_node += reference_node + paragraph_node['classes'].append('remix-link-container') + paragraph_node.append(reference_node) return paragraph_node @@ -49,22 +42,24 @@ def insert_remix_link(app, doctree, solidity_version): for literal_block_node in doctree.traverse(docutils.nodes.literal_block): assert 'language' in literal_block_node.attributes language = literal_block_node.attributes['language'].lower() - if language in ['solidity', 'yul']: - text_nodes = list(literal_block_node.traverse(docutils.nodes.Text)) - assert len(text_nodes) == 1 - - remix_url = remix_code_url(text_nodes[0], language, solidity_version) - url_length = len(remix_url.encode('utf-8')) - if url_length > MAX_SAFE_URL_LENGTH: - logger.warning( - "Remix URL generated from the code snippet exceeds the maximum safe URL length " - " (%d > %d bytes).", - url_length, - MAX_SAFE_URL_LENGTH, - location=(literal_block_node.source, literal_block_node.line), - ) - - insert_node_before(literal_block_node, build_remix_link_node(remix_url)) + if language not in ['solidity', 'yul']: + continue + + text_nodes = list(literal_block_node.traverse(docutils.nodes.Text)) + assert len(text_nodes) == 1 + + remix_url = remix_code_url(text_nodes[0], language, solidity_version) + url_length = len(remix_url.encode('utf-8')) + if url_length > MAX_SAFE_URL_LENGTH: + logger.warning( + "Remix URL generated from the code snippet exceeds the maximum safe URL length " + " (%d > %d bytes).", + url_length, + MAX_SAFE_URL_LENGTH, + location=(literal_block_node.source, literal_block_node.line), + ) + + insert_node_before(literal_block_node, build_remix_link_node(remix_url)) def setup(app): diff --git a/docs/grammar/SolidityLexer.g4 b/docs/grammar/SolidityLexer.g4 index 5a73be85fd..43648ceb5d 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'; @@ -63,15 +62,17 @@ New: 'new'; /** * Unit denomination for numbers. */ -NumberUnit: 'wei' | 'gwei' | 'ether' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years'; +SubDenomination: '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. @@ -89,6 +90,7 @@ Try: 'try'; Type: 'type'; Ufixed: 'ufixed' | ('ufixed' [1-9][0-9]+ 'x' [1-9][0-9]+); Unchecked: 'unchecked'; +Unicode: 'unicode'; /** * Sized unsigned integer types. * uint is an alias of uint256. @@ -197,9 +199,7 @@ fragment EscapeSequence: /** * A single quoted string literal allowing arbitrary unicode characters. */ -UnicodeStringLiteral: - 'unicode"' DoubleQuotedUnicodeStringCharacter* '"' - | 'unicode\'' SingleQuotedUnicodeStringCharacter* '\''; +UnicodeStringLiteral: 'unicode' (('"' DoubleQuotedUnicodeStringCharacter* '"') | ('\'' SingleQuotedUnicodeStringCharacter* '\'')); //@doc:inline fragment DoubleQuotedUnicodeStringCharacter: ~["\r\n\\] | EscapeSequence; //@doc:inline @@ -221,6 +221,14 @@ fragment EvenHexDigits: HexCharacter HexCharacter ('_'? HexCharacter HexCharacte //@doc:inline fragment HexCharacter: [0-9A-Fa-f]; +/** + * Scanned but not used by any rule, i.e, disallowed. + * solc parser considers number starting with '0', not immediately followed by '.' or 'x' as + * octal, even if non octal digits '8' and '9' are present. + */ +OctalNumber: '0' DecimalDigits ('.' DecimalDigits)?; + + /** * A decimal number literal consists of decimal digits that may be delimited by underscores and * an optional positive or negative exponent. @@ -231,6 +239,12 @@ DecimalNumber: (DecimalDigits | (DecimalDigits? '.' DecimalDigits)) ([eE] '-'? D fragment DecimalDigits: [0-9] ('_'? [0-9])* ; +/** + * This is needed to avoid successfully parsing a number followed by a string with no whitespace between. + */ +DecimalNumberFollowedByIdentifier: DecimalNumber Identifier; + + /** * An identifier in solidity has to start with a letter, a dollar-sign or an underscore and * may additionally contain numbers after the first symbol. @@ -251,6 +265,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) ; @@ -278,14 +298,14 @@ YulEVMBuiltin: 'stop' | 'add' | 'sub' | 'mul' | 'div' | 'sdiv' | 'mod' | 'smod' | 'exp' | 'not' | 'lt' | 'gt' | 'slt' | 'sgt' | 'eq' | 'iszero' | 'and' | 'or' | 'xor' | 'byte' | 'shl' | 'shr' | 'sar' | 'addmod' | 'mulmod' | 'signextend' | 'keccak256' - | 'pop' | 'mload' | 'mstore' | 'mstore8' | 'sload' | 'sstore' | 'msize' | 'gas' + | 'pop' | 'mload' | 'mstore' | 'mstore8' | 'sload' | 'sstore' | 'tload' | 'tstore'| 'msize' | 'gas' | 'address' | 'balance' | 'selfbalance' | 'caller' | 'callvalue' | 'calldataload' | 'calldatasize' | 'calldatacopy' | 'extcodesize' | 'extcodecopy' | 'returndatasize' - | 'returndatacopy' | 'extcodehash' | 'create' | 'create2' | 'call' | 'callcode' + | 'returndatacopy' | 'mcopy' | 'extcodehash' | 'create' | 'create2' | 'call' | 'callcode' | 'delegatecall' | 'staticcall' | 'return' | 'revert' | 'selfdestruct' | 'invalid' | 'log0' | 'log1' | 'log2' | 'log3' | 'log4' | 'chainid' | 'origin' | 'gasprice' - | 'blockhash' | 'coinbase' | 'timestamp' | 'number' | 'difficulty' | 'gaslimit' - | 'basefee'; + | 'blockhash' | 'blobhash' | 'coinbase' | 'timestamp' | 'number' | 'difficulty' + | 'prevrandao' | 'gaslimit' | 'basefee' | 'blobbasefee'; YulLBrace: '{' -> pushMode(YulMode); YulRBrace: '}' -> popMode; diff --git a/docs/grammar/SolidityParser.g4 b/docs/grammar/SolidityParser.g4 index 110773fede..c46cefd2fa 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 @@ -21,6 +22,7 @@ sourceUnit: ( | enumDefinition | userDefinedValueTypeDefinition | errorDefinition + | eventDefinition )* EOF; //@doc: inline @@ -151,7 +153,7 @@ stateMutability: Pure | View | Payable; */ overrideSpecifier: Override (LParen overrides+=identifierPath (Comma overrides+=identifierPath)* RParen)?; /** - * The definition of contract, library and interface functions. + * The definition of contract, library, interface or free functions. * Depending on the context in which the function is defined, further restrictions may apply, * e.g. functions in interfaces have to be unimplemented, i.e. may not contain a body block. */ @@ -160,7 +162,7 @@ locals[ boolean visibilitySet = false, boolean mutabilitySet = false, boolean virtualSet = false, - boolean overrideSpecifierSet = false + boolean overrideSpecifierSet = false, ] : Function (identifier | Fallback | Receive) @@ -174,6 +176,7 @@ locals[ )* (Returns LParen returnParameters=parameterList RParen)? (Semicolon | body=block); + /** * The definition of a modifier. * Note that within the body block of a modifier, the underscore cannot be used as identifier, @@ -311,10 +314,37 @@ errorDefinition: Semicolon; /** - * Using directive to bind library functions to types. - * Can occur within contracts and libraries. + * Operators that users are allowed to implement for some types with `using for`. */ -usingDirective: Using identifierPath For (Mul | typeName) Semicolon; +userDefinableOperator: + BitAnd + | BitNot + | BitOr + | BitXor + | Add + | Div + | Mod + | Mul + | Sub + | Equal + | GreaterThan + | GreaterThanOrEqual + | LessThan + | LessThanOrEqual + | NotEqual; + +/** + * Using directive to attach library functions and free functions to types. + * Can occur within contracts and libraries and at the file level. + */ +usingDirective: + Using ( + identifierPath + | (LBrace usingAliases (Comma usingAliases)* RBrace) + ) For (Mul | typeName) Global? Semicolon; + +usingAliases: identifierPath (As userDefinableOperator)?; + /** * 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. @@ -346,7 +376,7 @@ dataLocation: Memory | Storage | Calldata; */ expression: expression LBrack index=expression? RBrack # IndexAccess - | expression LBrack start=expression? Colon end=expression? RBrack # IndexRangeAccess + | expression LBrack startIndex=expression? Colon endIndex=expression? RBrack # IndexRangeAccess | expression Period (identifier | Address) # MemberAccess | expression LBrace (namedArgument (Comma namedArgument)*)? RBrace # FunctionCallOptions | expression callArgumentList # FunctionCall @@ -367,12 +397,13 @@ expression: | expression Or expression # OrOperation | expression Conditional expression Colon expression # Conditional | expression assignOp expression # Assignment - | New typeName # NewExpression + | New typeName # NewExpr | tupleExpression # Tuple | inlineArrayExpression # InlineArray | ( identifier | literal + | literalWithSubDenomination | elementaryTypeName[false] ) # PrimaryExpression ; @@ -388,9 +419,12 @@ 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; + +literalWithSubDenomination: numberLiteral SubDenomination; + booleanLiteral: True | False; /** * A full string literal consists of either one or several consecutive quoted strings. @@ -408,7 +442,8 @@ unicodeStringLiteral: UnicodeStringLiteral+; /** * Number literals can be decimal or hexadecimal numbers with an optional unit. */ -numberLiteral: (DecimalNumber | HexNumber) NumberUnit?; +numberLiteral: DecimalNumber | HexNumber; + /** * A curly-braced block of statements. Opens its own scope. */ @@ -476,7 +511,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)*; @@ -497,7 +538,7 @@ variableDeclarationTuple: variableDeclarationStatement: ((variableDeclaration (Assign expression)?) | (variableDeclarationTuple Assign expression)) Semicolon; expressionStatement: expression Semicolon; -mappingType: Mapping LParen key=mappingKeyType DoubleArrow value=typeName RParen; +mappingType: Mapping LParen key=mappingKeyType name=identifier? DoubleArrow value=typeName name=identifier? RParen; /** * Only elementary types or user defined types are viable as mapping keys. */ diff --git a/docs/index.rst b/docs/index.rst index 689228c298..84bec67beb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,6 +1,7 @@ 솔리디티 ======== +<<<<<<< HEAD 솔리디티는 스마트 컨트랙트를 시도하기 위한 객체지향적인 고급 프로그래밍 언어입니다. 여기서 스마트 컨트랙트란 이더리움 상태 내부에 있는 여러 계정들의 행동들을 통제할 수 있는 프로그램을 의미합니다. @@ -14,18 +15,46 @@ C++, 파이썬 및 자바스크립트의 영향을 받았으며 이더리움 가 컨트랙트를 배포할 시, 반드시 최신 버전의 솔리디티를 사용하시기 바랍니다. 예외적인 경우를 제외하곤 오로지 최신 버전만이 `security fixes `_ 를 인정하기 때문입니다. 또한, 주기적으로 새로운 기능들이나 확연히 달라진 점들 소개될 예정입니다. `빠르게 업데이트 되고 있음을 명시 `_ 하기 위하여 현재 저희 솔리디티 팀은 0.y.z 형식의 버전 넘버링 규칙을 사용하고 있습니다. +======= +Solidity is an object-oriented, high-level language for implementing smart contracts. +Smart contracts are programs that govern the behavior of accounts within the Ethereum state. + +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. + +Solidity is statically typed, supports inheritance, libraries, and complex user-defined types, among other features. + +With Solidity, you can create contracts for uses such as voting, crowdfunding, blind auctions, and multi-signature wallets. + +When deploying contracts, you should use the latest released version of Solidity. +Apart from exceptional cases, only the latest version receives +`security fixes `_. +Furthermore, breaking changes, as well as new features, are introduced regularly. +We currently use a 0.y.z version number `to indicate this fast pace of change `_. +>>>>>>> english/develop .. 주의:: +<<<<<<< HEAD 최근 솔리디티는 0.8.x 버전을 출시하면서 굉장히 많은 변동이 있었습니다. 반드시 :doc:`전체 리스트 <080-breaking-changes>` 를 확인하시기 바랍니다. +======= + Solidity recently released the 0.8.x version that introduced a lot of breaking changes. + Make sure you read :doc:`the full list <080-breaking-changes>`. +>>>>>>> english/develop 솔리디티 혹은 공식 문서의 보다 나은 발전은 언제든지 환영합니다. 자세한 사항은 :doc:`contributors guide ` 를 확인해 주십시오. .. 힌트:: +<<<<<<< HEAD 해당 공식 문서는 좌측 하단에 있는 버전 드롭다운 메뉴를 클릭하여 PDF, HTML 혹은 Epub와 같이 원하는 다운로드 형식으로 다운로드 하실 수 있습니다. +======= + You can download this documentation as PDF, HTML or Epub + by clicking on the versions flyout menu in the bottom-left corner and selecting the preferred download format. +>>>>>>> english/develop 시작하기 @@ -33,7 +62,11 @@ C++, 파이썬 및 자바스크립트의 영향을 받았으며 이더리움 가 **1. 스마트 컨트랙트의 기초 이해하기** +<<<<<<< HEAD 스마트 컨트랙트가 처음이시라면 "스마트 컨트랙트 개요" 섹션부터 시작하는 것을 추천드립니다. 해당 섹션은 다음 파트들을 다루고 있습니다. +======= +If you are new to the concept of smart contracts, we recommend you to get started by digging into the "Introduction to Smart Contracts" section, which covers the following: +>>>>>>> english/develop * 솔리디티로 구성된 :ref:`간단한 스마트 컨트랙트의 예시 ` * :ref:`블록체인의 기초 `. @@ -47,6 +80,7 @@ C++, 파이썬 및 자바스크립트의 영향을 받았으며 이더리움 가 Solidity 컴파일러를 설치하는 방법은 다양합니다. 원하는 옵션을 선택하신 후 :ref:`installation page ` 에 설명된 단계를 따르십시오. +<<<<<<< HEAD .. 힌트:: `Remix IDE `_ 를 통해 예시 코드를 브라우저에서 직접 살펴볼 수도 있습니다. Remix는 Solidity를 로컬에서 설치할 필요 없이 Solidity 스마트 컨트랙트를 작성, 배포 및 관리할 수 있도록 도와주는 브라우저 기반의 IDE입니다. @@ -57,24 +91,69 @@ Solidity 컴파일러를 설치하는 방법은 다양합니다. 원하는 옵 코드 리뷰, 테스팅, 코드 감사 그리고 변경 내역 표기 등이 대표적인 예입니다. 스마트 컨트랙트 사용자는 종종 작성자보다 코드에 대해 더욱 자신있어 합니다. 또한 블록체인과 스마트 컨트랙트 모두 고유의 이슈가 있을 수 있으므로 배포 코드를 작성하기 전에 :ref:`security_considerations` 섹션을 읽어보시기 바랍니다. +======= +.. hint:: + You can try out code examples directly in your browser with the + `Remix IDE `_. + Remix is a web browser-based IDE that allows you to write, deploy and administer Solidity smart contracts, + without the need to install Solidity locally. + +.. warning:: + As humans write software, it can have bugs. + Therefore, you should follow established software development best practices when writing your smart contracts. + This includes code review, testing, audits, and correctness proofs. + Smart contract users are sometimes more confident with code than their authors, + and blockchains and smart contracts have their own unique issues to watch out for, + so before working on production code, make sure you read the :ref:`security_considerations` section. +>>>>>>> english/develop **4. 더 알아보기** +<<<<<<< HEAD Ethereum 상에서 동작하는 탈중앙화 어플리케이션 제작과 관련하여 더 알고 싶으시다면 `Ethereum Developer Resources `_ 를 참조해 주시기 바랍니다. Ethereum에 대한 더 많은 문서, 다양한 튜토리얼, 툴, 그리고 개발 프레임워크에 대한 내용이 포함되어 있습니다. 궁금한 점이 있으시다면 검색, `Ethereum StackExchange `_ 혹은 저희 `Gitter channel `_ 에 질문을 남겨주시기 바랍니다. +======= +If you want to learn more about building decentralized applications on Ethereum, +the `Ethereum Developer Resources `_ can help you with further general documentation around Ethereum, +and a wide selection of tutorials, tools, and development frameworks. + +If you have any questions, you can try searching for answers or asking on the +`Ethereum StackExchange `_, +or our `Gitter channel `_. +>>>>>>> english/develop .. _translations: 번역 ------------ +<<<<<<< HEAD 현재 커뮤니티 자원자분들께서 본 공식 문서를 몇몇 언어로 번역하고 계십니다. 완성도 및 업데이트 상황은 언어별로 상이하며, 영문이 원본입니다. +======= +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. + +* `Chinese `_ +* `French `_ +* `Indonesian `_ +* `Japanese `_ +* `Korean `_ +* `Persian `_ +* `Russian `_ +* `Spanish `_ +* `Turkish `_ +>>>>>>> english/develop .. 참조:: +<<<<<<< HEAD 번역 작업을 보다 수월하게 진행되도록 하기 위하여 저희 팀은 최근에 새로운 Github organization을 새로 생성하였습니다. 관심 있으신 분들은 `번역 가이드 `_ 부분을 참조하시어 어떻게 참여하실 수 있는지 알아보시기 바랍니다. @@ -86,6 +165,11 @@ Ethereum에 대한 더 많은 문서, 다양한 튜토리얼, 툴, 그리고 개 * `중국어(간체) `_ (진행 중) * `스페인어 `_ * `터키어 `_ (부분적으로 진행) +======= + We set up a GitHub organization and translation workflow to help streamline the community efforts. + Please refer to the translation guide in the `solidity-docs org `_ + for information on how to start a new language or contribute to the community translations. +>>>>>>> english/develop 차례 ======== @@ -97,8 +181,8 @@ Ethereum에 대한 더 많은 문서, 다양한 튜토리얼, 툴, 그리고 개 :caption: 기초 introduction-to-smart-contracts.rst - installing-solidity.rst solidity-by-example.rst + installing-solidity.rst .. toctree:: :maxdepth: 2 @@ -137,21 +221,31 @@ Ethereum에 대한 더 많은 문서, 다양한 튜토리얼, 툴, 그리고 개 .. toctree:: :maxdepth: 2 - :caption: Additional Material + :caption: Advisory content + security-considerations.rst + bugs.rst 050-breaking-changes.rst 060-breaking-changes.rst 070-breaking-changes.rst 080-breaking-changes.rst + +.. toctree:: + :maxdepth: 2 + :caption: Additional Material + natspec-format.rst - security-considerations.rst smtchecker.rst - resources.rst - path-resolution.rst yul.rst + path-resolution.rst + +.. toctree:: + :maxdepth: 2 + :caption: Resources + style-guide.rst common-patterns.rst - bugs.rst + resources.rst contributing.rst - brand-guide.rst language-influences.rst + brand-guide.rst diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index 90786a0eb0..a989aa8872 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -9,24 +9,55 @@ 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** to make +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 `_. +>>>>>>> english/develop Remix ===== *규모가 작은 컨트랙트를 작성하거나 Solidity를 보다 빠르게 배우기 위해 Remix를 사용할 것을 추천드립니다.* +<<<<<<< HEAD `Remix online에 접속하면 `_, 어떤 것도 설치하실 필요가 없어집니다. 인터넷 연결 없이 사용하고 싶으시다면, https://github.com/ethereum/remix-live/tree/gh-pages 페이지에 접속하신 후 ``.zip`` 파일을 다운로드 하십시오. Remix는 여러 버전의 Solidity를 설치하지 않고도 nightly 빌드를 테스트해볼 수 있는 편리한 옵션이기도 합니다. 이 페이지에선 여러분의 컴퓨터에 Solidity 컴파일러 소프트웨어 커맨드라인을 설치하기 위한 자세한 옵션들을 다뤄볼 예정입니다. 규모가 큰 컨트랙트나 더 많은 컴파일 옵션이 필요하실 경우 커맨드라인 컴파일러를 사용해 보십시오. +======= +`Access Remix online `_, you do not need to install anything. +If you want to use it without connection to the Internet, go to +https://github.com/ethereum/remix-live/tree/gh-pages#readme and follow the instructions on that page. +Remix is also a convenient option for testing nightly builds +without installing multiple Solidity versions. + +Further options on this page detail installing command-line Solidity compiler software +on your computer. Choose a command-line compiler if you are working on a larger contract +or if you require more compilation options. +>>>>>>> english/develop .. _solcjs: @@ -38,9 +69,16 @@ npm / Node.js :ref:`commandline-compiler` 문서는 여러분들이 모든 기능을 포함하고 있는 컴파일러인 ``solc``를 사용하고 있다고 가정합니다. 이 `레포지토리 `_ 안에 ``solcjs`` 에 대한 자세한 설명이 있습니다. +<<<<<<< HEAD 참고: solc-js 프로젝트는 Emscripten, 즉 같은 컴파일러 소스 코드를 사용하는 C++ `solc` 에서 유래됐습니다. `solc-js` 는 Remix처럼 JavaScript 프로젝트에 사용될 수 있습니다. 자세한 사항은 solc-js 레포지토리를 참고해주십시오. +======= +Note: The solc-js project is derived from the C++ +`solc` by using Emscripten, which means that both use the same compiler source code. +`solc-js` can be used in JavaScript projects directly (such as Remix). +Please refer to the solc-js repository for instructions. +>>>>>>> english/develop .. code-block:: bash @@ -48,39 +86,71 @@ npm / Node.js .. 참고:: +<<<<<<< HEAD commandline executable은 ``solcjs`` 라 불립니다. ``solcjs`` 커맨드라인 옵션은 ``solc`` 및 툴들(예: ``geth``)과 호환되지 않습니다. 따라서 ``solc`` 에서의 행동은 ``solcjs`` 에선 작동되지 않습니다. +======= + The command-line executable is named ``solcjs``. + + The command-line options of ``solcjs`` are not compatible with ``solc`` and tools (such as ``geth``) + expecting the behavior of ``solc`` will not work with ``solcjs``. +>>>>>>> english/develop Docker ====== +<<<<<<< HEAD Solidity 빌드의 Docker 이미지들은 ``ethereum`` 단체의 ``solc`` 이미지를 통해 가능합니다. 가장 최신 버전은 ``stable`` 태그를, 잠재적으로 불안정한 변동은 develop 브랜치에 있는 ``nightly`` 를 사용하십시오. Docker 이미지는 compiler executable를 실행하기 때문에 모든 컴파일러 인수를 전달할 수 있습니다. 예를 들어, (만약 여러분이 가지고 있지 않다면) 아래 명령어가 안정된 버전의 ``solc`` 이미지를 ``--help`` 인수를 전달한 후 pull하여 새로운 컨테이너에서 작동시키게 합니다. +======= +Docker images of Solidity builds are available using the ``solc`` image from the ``ethereum`` organization. +Use the ``stable`` tag for the latest released version, and ``nightly`` for potentially unstable changes in the ``develop`` branch. + +The Docker image runs the compiler executable so that you can pass all compiler arguments to it. +For example, the command below pulls the stable version of the ``solc`` image (if you do not have it already), +and runs it in a new container, passing the ``--help`` argument. +>>>>>>> english/develop .. code-block:: bash docker run ethereum/solc:stable --help +<<<<<<< HEAD 0.5.4 버전처럼 여러분들이 원하는 빌드 버전을 태그를 명시할 수도 있습니다. +======= +For example, You can specify release build versions in the tag for the 0.5.4 release. +>>>>>>> english/develop .. code-block:: bash docker run ethereum/solc:0.5.4 --help +<<<<<<< HEAD Docker 이미지를 호스트 머신에서 Solidity 파일들을 컴파일하려면 입력과 출력을 위한 로컬 폴더를 불러온 뒤 컴파일 하고자 하는 컨트랙트를 지정합니다. 예를 들자면, +======= +To use the Docker image to compile Solidity files on the host machine, mount a +local folder for input and output, and specify the contract to compile. For example. +>>>>>>> english/develop .. code-block:: bash docker run -v /local/path:/sources ethereum/solc:stable -o /sources/output --abi --bin /sources/Contract.sol +<<<<<<< HEAD 툴링과 함께 컴파일러를 사용할 때 추천드리는 표준 JSON 인터페이스를 사용하실 수도 있습니다. 이 인터페이스를 사용할 땐 JSON 입력이 self-contained되어 있을 경우 어떤 경로도 불러오실 필요가 없습니다. :ref:`import callback에 의해 로드되어야 하는 ` 어떠한 외부 파일을 참조할 필요가 없습니다. +======= +You can also use the standard JSON interface (which is recommended when using the compiler with tooling). +When using this interface, it is not necessary to mount any directories as long as the JSON input is +self-contained (i.e. it does not refer to any external files that would have to be +:ref:`loaded by the import callback `). +>>>>>>> english/develop .. code-block:: bash @@ -108,14 +178,23 @@ Nightly 버전의 경우 다음 명령어를 통해 설치됩니다. sudo apt-get update sudo apt-get install solc +<<<<<<< HEAD 또한, 몇몇 리눅스 버전은 독자적인 패키지를 제공합니다. 이러한 패키지들은 저희가 직접 유지 보수를 하고 있진 않습니다만, 패키지를 유지 보수하는 사람들에 의해 계속해서 업데이트 되고 있습니다. 예를 들어, Arch 리눅스는 최신 개발 버전의 패키지를 가지고 있습니다. +======= +Furthermore, some Linux distributions provide their own packages. These packages are not directly +maintained by us but usually kept up-to-date by the respective package maintainers. -.. code-block:: bash +For example, Arch Linux has packages for the latest development version as AUR packages: `solidity `_ +and `solidity-bin `_. +>>>>>>> english/develop + +.. note:: - pacman -S solidity + Please be aware that `AUR `_ packages + are user-produced content and unofficial packages. Exercise caution when using them. `snap package `_ 라는 것도 있지만 **현재는 유지 보수가 되고 있지 않습니다**. 모든 `supported Linux distros `_ 내에서 설치가 가능합니다. @@ -181,6 +260,7 @@ Static Binaries 이 레포지토리는 사용자들이 사용할 수 있는 바이너리들을 찾는 쉽고 빠른 방법일 뿐만이 아니라 다른 3자 툴과도 호환이 가능합니다. +<<<<<<< HEAD - 해당 콘텐츠는 https://binaries.soliditylang.org에 미러링되어 있으며 HTTPS, 인증, rate limiting 혹은 git을 사용하지 않고도 쉽게 다운로드 가능합니다. - 콘텐트는 올바른 `Content-Type` 헤더를 통해 제공되며 CORS 설정에 비교적 업격하지 않아 브라우저에서 작동되는 툴에 의해 바로 로드될 수 있습니다. - 바이너리들은 (필수 DLL과 함께 번들링된 오래된 Windows 빌드의 예외와 함께) 설치나 언팩킹이 필요 없습니다. @@ -188,14 +268,35 @@ Static Binaries 파일들은 또한 절대 변경되지 않으며 반드시 원본 검사합과 항상 합치해야 합니다. 발생될 수 있는 유일한 예외는 깨졌거나 사용 불가능한 파일들이 가져올 수 있는 잠정적인 해입니다. - 파일들은 HTTP와 HTTPS를 통해 서브가 됩니다. 여러분들께서 파일 리스트를 (git, HTTPS, IPFS 혹은 로컬에서 캐싱함으로서) 안전한 방법으로 보관하고 파일 다운로드 후 바이너리들의 해시를 인증하실 수만 있다면, HTTPS를 사용하실 필요가 없습니다. +======= +- The content is mirrored to https://binaries.soliditylang.org where it can be easily downloaded over + HTTPS without any authentication, rate limiting or the need to use git. +- Content is served with correct `Content-Type` headers and lenient CORS configuration so that it + can be directly loaded by tools running in the browser. +- Binaries do not require installation or unpacking (exception for older Windows builds + bundled with necessary DLLs). +- We strive for a high level of backward-compatibility. Files, once added, are not removed or moved + without providing a symlink/redirect at the old location. They are also never modified + in place and should always match the original checksum. The only exception would be broken or + unusable files with the potential to cause more harm than good if left as is. +- Files are served over both HTTP and HTTPS. As long as you obtain the file list in a secure way + (via git, HTTPS, IPFS or just have it cached locally) and verify hashes of the binaries + after downloading them, you do not have to use HTTPS for the binaries themselves. +>>>>>>> english/develop 동일한 바이너리들은 대부분 `Solidity release page on Github`_ 상에서 가능합니다. 차이점은 저희가 Github 배포 페이지에서는 오래된 버전이 릴리즈에 대해서 업데이트를 하지 않는다는 점입니다. 이는 네이밍 컨벤션이 바뀔 경우 재명명하지 않고 릴리즈 당시 호환되지 않는 플랫폼들에 대한 빌드를 추가하지 않는다는 뜻입니다. 이는 오직 ``solc-bin`` 에서만 이루어집니다. +<<<<<<< HEAD ``solc-bin`` 레포지토리는 몇 가지 상위 디렉토리를 가지고 있으며 각각의 디렉토리는 단일 플랫폼을 대표하고 있습니다. 각각의 디렉토리들은 사용 가능한 바이너리들의 리스트인 ``list.json`` 파일을 가지고 있습니다. 예를 들어 ``emscripten-wasm32/list.json`` 파일의 경우 버전 0.7.4에서 다음과 같은 정보를 확인하실 수 있습니다. +======= +The ``solc-bin`` repository contains several top-level directories, each representing a single platform. +Each one includes a ``list.json`` file listing the available binaries. For example in +``emscripten-wasm32/list.json`` you will find the following information about version 0.7.4: +>>>>>>> english/develop .. code-block:: json @@ -214,6 +315,7 @@ Static Binaries 이는 다음을 의미합니다. +<<<<<<< HEAD - `solc-emscripten-wasm32-v0.7.4+commit.3f05b770.js `_ 에서 여러분은 동일한 디렉토리에 있는 바이너리를 찾아보실 수 있습니다. 파일은 symlink일 수 있기 때문에 git을 통해 다운로드하지 않을 경우 스스로 해결하셔야 하며 그렇지 않을 경우 파일은 symlink와 호환되지 않습니다. - 바이너리는 또한 https://binaries.soliditylang.org/emscripten-wasm32/solc-emscripten-wasm32-v0.7.4+commit.3f05b770.js에 미러링되어 있습니다. @@ -223,6 +325,23 @@ Static Binaries - 바이너리 무결성을 keccak256 해시와 ``0x300330ecd127756b824aa13e843cb1f43c473cb22eaf3750d5fb9c99279af8c3`` 와의 대조를 통해 인증할 수 있습니다. 해시는 커맨드 라인에서 `sha3sum`_ 혹은 자바스크립트의 `keccak256() function from ethereumjs-util`_ 에 의해 제공되는 ``keccak256sum`` 유틸리티를 통해 연산될 수 있습니다. - 바이너리 무결성을 sha256 해시와 ``0x2b55ed5fec4d9625b6c7b3ab1abd2b7fb7dd2a9c68543bf0323db2c7e2d55af2`` 를 통해서도 인증할 수 있습니다. +======= +- You can find the binary in the same directory under the name + `solc-emscripten-wasm32-v0.7.4+commit.3f05b770.js `_. + Note that the file might be a symlink, and you will need to resolve it yourself if you are not using + git to download it or your file system does not support symlinks. +- The binary is also mirrored at https://binaries.soliditylang.org/emscripten-wasm32/solc-emscripten-wasm32-v0.7.4+commit.3f05b770.js. + In this case git is not necessary and symlinks are resolved transparently, either by serving a copy + of the file or returning a HTTP redirect. +- The file is also available on IPFS at `QmTLs5MuLEWXQkths41HiACoXDiH8zxyqBHGFDRSzVE5CS`_. +- The file might in future be available on Swarm at `16c5f09109c793db99fe35f037c6092b061bd39260ee7a677c8a97f18c955ab1`_. +- You can verify the integrity of the binary by comparing its keccak256 hash to + ``0x300330ecd127756b824aa13e843cb1f43c473cb22eaf3750d5fb9c99279af8c3``. The hash can be computed + on the command-line using ``keccak256sum`` utility provided by `sha3sum`_ or `keccak256() function + from ethereumjs-util`_ in JavaScript. +- You can also verify the integrity of the binary by comparing its sha256 hash to + ``0x2b55ed5fec4d9625b6c7b3ab1abd2b7fb7dd2a9c68543bf0323db2c7e2d55af2``. +>>>>>>> english/develop .. 주의:: @@ -264,8 +383,12 @@ Static Binaries 소스에서 빌드해보기 ==================== +<<<<<<< HEAD 전제 조건 - 모든 운영체제 +======= +Prerequisites - All Operating Systems +>>>>>>> english/develop ------------------------------------- 다음은 Solidity의 모든 빌드에 대한 의존성들을 보여줍니다. @@ -273,14 +396,23 @@ Static Binaries +-----------------------------------+-------------------------------------------------------+ | 소프트웨어 | 비고 | +===================================+=======================================================+ +<<<<<<< HEAD | `CMake`_ (version 3.13+) | 크로스플랫폼 빌드 파일 생성기 | +======= +| `CMake`_ (version 3.21.3+ on | Cross-platform build file generator. | +| Windows, 3.13+ otherwise) | | +>>>>>>> english/develop +-----------------------------------+-------------------------------------------------------+ | `Boost`_ (version 1.77+ on | C++ 라이브러리 . | | Windows, 1.65+ otherwise) | | +-----------------------------------+-------------------------------------------------------+ | `Git`_ | 소스 코드를 불러오기 위한 커맨드 라인 툴 | +-----------------------------------+-------------------------------------------------------+ +<<<<<<< HEAD | `z3`_ (version 4.8+, Optional) | SMT checker와의 사용을 위함 | +======= +| `z3`_ (version 4.8.16+, Optional) | For use with SMT checker. | +>>>>>>> english/develop +-----------------------------------+-------------------------------------------------------+ | `cvc4`_ (Optional) | SMT checker와의 사용을 위함 | +-----------------------------------+-------------------------------------------------------+ @@ -291,9 +423,16 @@ Static Binaries .. _CMake: https://cmake.org/download/ .. _z3: https://github.com/Z3Prover/z3 +<<<<<<< HEAD .. 참고:: 0.5.10 버전 이전의 Solidity의 경우 Boost 버전 1.70+과 올바르게 연결하는데 실패할 수 있습니다. 해결책으로는 Solidity를 설정하기 위해 cmake 커맨드를 실행하기 전에 ``/lib/cmake/Boost-1.70.0`` 를 임시로 이름을 바꾸는 것입니다. +======= +.. note:: + Solidity versions prior to 0.5.10 can fail to correctly link against Boost versions 1.70+. + A possible workaround is to temporarily rename ``/lib/cmake/Boost-1.70.0`` + prior to running the cmake command to configure Solidity. +>>>>>>> english/develop 0.5.10 버전 이후부터는 Boost 1.70+와의 연결은 수동적인 간섭 없이도 잘 동작합니다. @@ -305,7 +444,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 +>>>>>>> english/develop ^^^^^^^^^^^^^^^^^^^^^^^^^ 다음 C++ 컴파일러와 최소 사양들은 Solidity codebase를 빌드할 수 있습니다. @@ -317,10 +471,21 @@ Static Binaries 선결 조건 - macOS --------------------- +<<<<<<< HEAD macOS 빌드의 경우, 최신 버전의 `Xcode를 설치하십시오 `_ . 이는 OS X 상의 C++ 어플리케이션을 빌드하기 위해 필요한 `Clang C++ 컴파일러 `_ , `Xcode IDE `_ 그리고 기타 Apple 개발툴들을 포함하고 있습니다. 만일 Xcode를 처음으로 설치하시거나 새로운 버전을 막 설치하셨을 경우, 커맨드 라인 빌드를 하시기 전에 라이선스에 동의하셔야 합니다. +======= +For macOS builds, ensure that you have the latest version of +`Xcode installed `_. +This contains the `Clang C++ compiler `_, the +`Xcode IDE `_ and other Apple development +tools that are required for building C++ applications on OS X. +If you are installing Xcode for the first time, or have just installed a new +version then you will need to agree to the license before you can do +command-line builds: +>>>>>>> english/develop .. code-block:: bash @@ -359,7 +524,7 @@ Visual Studio 2019는 IDE와 필요한 컴파일러 및 라이브러리들을 * C++/CLI support .. _Visual Studio 2019: https://www.visualstudio.com/vs/ -.. _Visual Studio 2019 Build Tools: https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2019 +.. _Visual Studio 2019 Build Tools: https://visualstudio.microsoft.com/vs/older-downloads/#visual-studio-2019-and-other-products 모든 필수 외부 의존성을 설치하기 위한 도우미 스크립트 또한 사용하실 수 있습니다. @@ -379,15 +544,28 @@ Visual Studio 2019는 IDE와 필요한 컴파일러 및 라이브러리들을 git clone --recursive https://github.com/ethereum/solidity.git cd solidity +<<<<<<< HEAD 저희 Solidity 개발에 도움을 주고 싶으실 경우, Solidity를 fork한 후 두번째 remote로서 개인 fork를 추가하시기 바랍니다. +======= +If you want to help develop Solidity, +you should fork Solidity and add your personal fork as a second remote: +>>>>>>> english/develop .. code-block:: bash git remote add personal git@github.com:[username]/solidity.git +<<<<<<< HEAD .. 참고:: 이 방법은 컴파일러에 의해 만들어진 각각의 바이트코드에 설정된 flag를 야기하는 릴리즈 전 빌드를 생성합니다. 릴리즈된 Solidity 컴파일러를 재빌드하고 싶으실 경우, github 릴리즈 페이지에 있는 소스 코드를 사용하십시오. +======= +.. note:: + This method will result in a pre-release build leading to e.g. a flag + being set in each bytecode produced by such a compiler. + If you want to re-build a released Solidity compiler, then + please use the source tarball on the github release page: +>>>>>>> english/develop https://github.com/ethereum/solidity/releases/download/v0.X.Y/solidity_0.X.Y.tar.gz @@ -451,8 +629,13 @@ CMake 옵션 SMT Solvers ----------- +<<<<<<< HEAD Solidity는 (시스템 상에 존재할 경우) SMT solver에 의해 기본적으로 빌드됩니다. 각각의 solver는 `cmake` 옵션에 의해 비활성화 시킬 수 있습니다. +======= +Solidity can be built against SMT solvers and will do so by default if +they are found in the system. Each solver can be disabled by a ``cmake`` option. +>>>>>>> english/develop *참고: 몇몇의 케이스들의 경우 빌드하는데 실패할 수도 있습니다.* @@ -498,6 +681,7 @@ Solidity 커밋과 결합된 플랫폼이 SemVer 빌드의 메타데이터를 예시: +<<<<<<< HEAD 1. 0.4.0 버전이 만들어집니다. 2. nightly 빌드는 현 시점부터 0.4.1의 버전을 가지게 됩니다. 3. 충돌이 없는 변경점이 새로 발견되었습니다 --> 현 버전에 변경점이 없습니다. @@ -505,3 +689,12 @@ Solidity 커밋과 결합된 플랫폼이 SemVer 빌드의 메타데이터를 5. 0.5.0 릴리즈가 만들어집니다. 이러한 패턴은 :ref:`version pragma ` 와 잘 작동합니다. +======= +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. + +This behavior works well with the :ref:`version pragma `. +>>>>>>> english/develop diff --git a/docs/internals/layout_in_storage.rst b/docs/internals/layout_in_storage.rst index b1b89a6a3c..7afcfc2ac5 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", @@ -208,7 +208,7 @@ of types), arrays have its ``base`` type, and structs list their ``members`` in the same format as the top-level ``storage`` (see :ref:`above `). -.. note :: +.. note:: The JSON output format of a contract's storage layout is still considered experimental and is subject to change in non-breaking releases of Solidity. @@ -232,13 +232,13 @@ value and reference types, types that are encoded packed, and nested types. uint y; S s; address addr; - mapping (uint => mapping (address => bool)) map; + mapping(uint => mapping(address => bool)) map; uint[] array; string s1; bytes b1; } -.. code:: json +.. code-block:: json { "storage": [ diff --git a/docs/internals/optimizer.rst b/docs/internals/optimizer.rst index a7eff7346b..70896333c2 100644 --- a/docs/internals/optimizer.rst +++ b/docs/internals/optimizer.rst @@ -5,8 +5,11 @@ The Optimizer ************* -The Solidity compiler uses two different optimizer modules: The "old" optimizer -that operates at the opcode level and the "new" optimizer that operates on Yul IR code. +The Solidity compiler involves optimizations at three different levels (in order of execution): + +- Optimizations during code generation based on a direct analysis of Solidity code. +- Optimizing transformations on the Yul IR code. +- Optimizations at the opcode level. The opcode-based optimizer applies a set of `simplification rules `_ to opcodes. It also combines equal code sets and removes unused code. @@ -20,12 +23,33 @@ the function calls. Similarly, if a function is side-effect free and its result is multiplied by zero, you can remove the function call completely. +The codegen-based optimizer affects the initial low-level code produced from the Solidity input. +In the legacy pipeline, the bytecode is generated immediately and most of the optimizations of this +kind are implicit and not configurable, the only exception being an optimization which changes the +order of literals in binary operations. +The IR-based pipeline takes a different approach and produces Yul IR closely matching the structure +of the Solidity code, with nearly all optimizations deferred to the Yul optimizer module. +In that case codegen-level optimization is done only in very limited cases which are difficult to +handle in Yul IR, but are straightforward with the high-level information from analysis phase at hand. +An example of such an optimization is the bypass of checked arithmetic when incrementing the counter +in certain idiomatic ``for`` loops. + 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:: + Some optimizer steps, such as, for example, the `peephole optimizer `_ + and the :ref:`unchecked loop increment optimizer ` are always + enabled by default and can only be turned off via the :ref:`Standard JSON `. + +.. note:: + An empty optimizer sequence is accepted even without ``--optimize`` in order to fully disable + the user-supplied portion of the Yul :ref:`optimizer sequence `, as by default, + even when the optimizer is not turned on, the :ref:`unused pruner ` step will be run. + You can find more details on both optimizer modules and their optimization steps below. Benefits of Optimizing Solidity Code @@ -277,60 +301,82 @@ 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` +``m`` :ref:`rematerialiser` +``V`` :ref:`SSA-reverser` +``a`` :ref:`SSA-transform` +``t`` :ref:`structural-simplifier` +``p`` :ref:`unused-function-parameter-pruner` +``S`` :ref:`unused-store-eliminator` +``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. + +.. _selecting-optimizations: 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:fDnTOcmu' + +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 ------------- @@ -545,7 +591,7 @@ It is not applied to loop iteration-condition, because the loop control flow doe this "outlining" of the inner expressions in all cases. We can sidestep this limitation by applying :ref:`for-loop-condition-into-body` to move the iteration condition into loop body. -The final program should be in a form such that (with the exception of loop conditions) +The final program should be in an *expression-split form*, where (with the exception of loop conditions) function calls cannot appear nested inside expressions and all function call arguments have to be variables. @@ -683,7 +729,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. @@ -796,10 +842,10 @@ if the common subexpression eliminator was run right before it. .. _expression-simplifier: -Expression Simplifier -^^^^^^^^^^^^^^^^^^^^^ +ExpressionSimplifier +^^^^^^^^^^^^^^^^^^^^ -The Expression Simplifier uses the Dataflow Analyzer and makes use +The ExpressionSimplifier uses the Dataflow Analyzer and makes use of a list of equivalence transforms on expressions like ``X + 0 -> X`` to simplify the code. @@ -833,22 +879,6 @@ Works best if the code is in SSA form. Prerequisite: Disambiguator, ForLoopInitRewriter. -.. _reasoning-based-simplifier: - -ReasoningBasedSimplifier -^^^^^^^^^^^^^^^^^^^^^^^^ - -This optimizer uses SMT solvers to check whether ``if`` conditions are constant. - -- If ``constraints AND condition`` is UNSAT, the condition is never true and the whole body can be removed. -- If ``constraints AND NOT condition`` is UNSAT, the condition is always true and can be replaced by ``1``. - -The simplifications above can only be applied if the condition is movable. - -It is only effective on the EVM dialect, but safe to use on other dialects. - -Prerequisite: Disambiguator, SSATransform. - Statement-Scale Simplifications ------------------------------- @@ -929,7 +959,7 @@ DeadCodeEliminator This optimization stage removes unreachable code. Unreachable code is any code within a block which is preceded by a -leave, return, invalid, break, continue, selfdestruct or revert. +leave, return, invalid, break, continue, selfdestruct, revert or by a call to a user-defined function that recurses infinitely. Function definitions are retained as they might be called by earlier code and thus are considered reachable. @@ -1092,6 +1122,52 @@ The step LiteralRematerialiser is not required for correctness. It helps deal wi ``function f(x) -> y { revert(y, y} }`` where the literal ``y`` will be replaced by its value ``0``, allowing us to rewrite the function. +.. index:: ! unused store eliminator +.. _unused-store-eliminator: + +UnusedStoreEliminator +^^^^^^^^^^^^^^^^^^^^^ + +Optimizer component that removes redundant ``sstore`` and memory store statements. +In case of an ``sstore``, if all outgoing code paths revert (due to an explicit ``revert()``, ``invalid()``, or infinite recursion) or +lead to another ``sstore`` for which the optimizer can tell that it will overwrite the first store, the statement will be removed. +However, if there is a read operation between the initial ``sstore`` and the revert, or the overwriting ``sstore``, the statement +will not be removed. +Such read operations include: external calls, user-defined functions with any storage access, and ``sload`` of a slot that cannot be +proven to differ from the slot written by the initial ``sstore``. + +For example, the following code + +.. code-block:: yul + + { + let c := calldataload(0) + sstore(c, 1) + if c { + sstore(c, 2) + } + sstore(c, 3) + } + +will be transformed into the code below after the Unused Store Eliminator step is run + +.. code-block:: yul + + { + let c := calldataload(0) + if c { } + sstore(c, 3) + } + +For memory store operations, things are generally simpler, at least in the outermost yul block as all such +statements will be removed if they are never read from in any code path. +At function analysis level, however, the approach is similar to ``sstore``, as we do not know whether the memory location will +be read once we leave the function's scope, so the statement will be removed only if all code paths lead to a memory overwrite. + +Best run in SSA form. + +Prerequisites: Disambiguator, ForLoopInitRewriter. + .. _equivalent-function-combiner: EquivalentFunctionCombiner @@ -1137,7 +1213,7 @@ This component can only be used on sources with unique names. FullInliner ^^^^^^^^^^^ -The Full Inliner replaces certain calls of certain functions +The FullInliner replaces certain calls of certain functions by the function's body. This is not very helpful in most cases, because it just increases the code size but does not have a benefit. Furthermore, code is usually very expensive and we would often rather have shorter @@ -1161,6 +1237,11 @@ we can run the optimizer on this specialized function. If it results in heavy gains, the specialized function is kept, otherwise the original function is used instead. +FunctionHoister and ExpressionSplitter are recommended as prerequisites since they make the step +more efficient, but are not required for correctness. +In particular, function calls with other function calls as arguments are not inlined, but running +ExpressionSplitter beforehand ensures that there are no such calls in the input. + Cleanup ------- @@ -1203,8 +1284,8 @@ This is a tiny step that helps in reversing the effects of the SSA transform if it is combined with the Common Subexpression Eliminator and the Unused Pruner. -The SSA form we generate is detrimental to code generation on the EVM and -WebAssembly alike because it generates many local variables. It would +The SSA form we generate is detrimental to code generation +because it produces many local variables. It would be better to just re-use existing variables with assignments instead of fresh variable declarations. @@ -1323,14 +1404,62 @@ into The LiteralRematerialiser should be run before this step. +Codegen-Based Optimizer Module +============================== -WebAssembly specific --------------------- +Currently, the codegen-based optimizer module provides two optimizations. -MainFunction -^^^^^^^^^^^^ +The first one, available in the legacy code generator, moves literals to the right side of +commutative binary operators, which helps exploit their associativity. + +The other one, available in the IR-based code generator, enables the use of unchecked arithmetic +when generating code for incrementing the counter variable of certain idiomatic ``for`` loops. +This avoids wasting gas by identifying some conditions that guarantee that the counter variable +cannot overflow. +This eliminates the need to use a verbose unchecked arithmetic block inside the loop body to +increment the counter variable. -Changes the topmost block to be a function with a specific name ("main") which has no -inputs nor outputs. +.. _unchecked-loop-optimizer: + +Unchecked Loop Increment +------------------------ + +Introduced in Solidity ``0.8.22``, the overflow check optimization step is concerned with identifying +the conditions under which the ``for`` loop counter can be safely incremented +without overflow checks. + +This optimization is **only** applied to ``for`` loops of the general form: + +.. code-block:: solidity + + for (uint i = X; i < Y; ++i) { + // variable i is not modified in the loop body + } + +The condition and the fact that the counter variable is only ever incremented +guarantee that it never overflows. +The precise requirements for the loop to be eligible for the optimization are as follows: + +- The loop condition is a comparison of the form ``i < Y``, for a local counter variable ``i`` + (called the "loop counter" hereon) and an expression ``Y``. +- The built-in operator ``<`` is necessarily used in the loop condition and is the only operator + that triggers the optimization. ``<=`` and the like are intentionally excluded. Additionally, + user-defined operators are **not** eligible. +- The loop expression is a prefix or postfix increment of the counter variable, i.e, ``i++`` or ``++i``. +- The loop counter is a local variable of a built-in integer type. +- The loop counter is **not** modified by the loop body or by the expression used as the loop condition. +- The comparison is performed on the same type as the loop counter, meaning that the type of the + right-hand-side expression is implicitly convertible to the type of the counter, such that the latter + is not implicitly widened before the comparison. + +To clarify the last condition, consider the following example: + +.. code-block:: solidity + + for (uint8 i = 0; i < uint16(1000); i++) { + // ... + } -Depends on the Function Grouper. +In this case, the counter ``i`` has its type implicitly converted from ``uint8`` +to ``uint16`` before the comparison and the condition is in fact never false, so +the overflow check for the increment cannot be removed. diff --git a/docs/internals/source_mappings.rst b/docs/internals/source_mappings.rst index 11027b8aca..68c29d955e 100644 --- a/docs/internals/source_mappings.rst +++ b/docs/internals/source_mappings.rst @@ -26,7 +26,7 @@ that are not part of the original input but are referenced from the source mappings. These source files together with their identifiers can be obtained via ``output['contracts'][sourceName][contractName]['evm']['bytecode']['generatedSources']``. -.. note :: +.. note:: In the case of instructions that are not associated with any particular source file, the source mapping assigns an integer identifier of ``-1``. This may happen for bytecode sections stemming from compiler-generated inline assembly statements. diff --git a/docs/internals/variable_cleanup.rst b/docs/internals/variable_cleanup.rst index 9fec6929f6..bab3c8bef2 100644 --- a/docs/internals/variable_cleanup.rst +++ b/docs/internals/variable_cleanup.rst @@ -4,9 +4,10 @@ Cleaning Up Variables ********************* -When a value is shorter than 256 bit, in some cases the remaining bits -must be cleaned. -The Solidity compiler is designed to clean such remaining bits before any operations +Ultimately, all values in the EVM are stored in 256 bit words. +Thus, in some cases, when the type of a value has less than 256 bits, +it is necessary to clean the remaining bits. +The Solidity compiler is designed to do such cleaning before any operations that might be adversely affected by the potential garbage in the remaining bits. For example, before writing a value to memory, the remaining bits need to be cleared because the memory contents can be used for computing @@ -28,25 +29,83 @@ the boolean values before they are used as the condition for In addition to the design principle above, the Solidity compiler cleans input data when it is loaded onto the stack. -Different types have different rules for cleaning up invalid values: - -+---------------+---------------+-------------------+ -|Type |Valid Values |Invalid Values Mean| -+===============+===============+===================+ -|enum of n |0 until n - 1 |exception | -|members | | | -+---------------+---------------+-------------------+ -|bool |0 or 1 |1 | -+---------------+---------------+-------------------+ -|signed integers|sign-extended |currently silently | -| |word |wraps; in the | -| | |future exceptions | -| | |will be thrown | -| | | | -| | | | -+---------------+---------------+-------------------+ -|unsigned |higher bits |currently silently | -|integers |zeroed |wraps; in the | -| | |future exceptions | -| | |will be thrown | -+---------------+---------------+-------------------+ +The following table describes the cleaning rules applied to different types, +where ``higher bits`` refers to the remaining bits in case the type has less than 256 bits. + ++---------------+---------------+-------------------------+ +|Type |Valid Values |Cleanup of Invalid Values| ++===============+===============+=========================+ +|enum of n |0 until n - 1 |throws exception | +|members | | | ++---------------+---------------+-------------------------+ +|bool |0 or 1 |results in 1 | ++---------------+---------------+-------------------------+ +|signed integers|higher bits |currently silently | +| |set to the |signextends to a valid | +| |sign bit |value, i.e. all higher | +| | |bits are set to the sign | +| | |bit; may throw an | +| | |exception in the future | ++---------------+---------------+-------------------------+ +|unsigned |higher bits |currently silently masks | +|integers |zeroed |to a valid value, i.e. | +| | |all higher bits are set | +| | |to zero; may throw an | +| | |exception in the future | ++---------------+---------------+-------------------------+ + +Note that valid and invalid values are dependent on their type size. +Consider ``uint8``, the unsigned 8-bit type, which has the following valid values: + +.. code-block:: none + + 0000...0000 0000 0000 + 0000...0000 0000 0001 + 0000...0000 0000 0010 + .... + 0000...0000 1111 1111 + +Any invalid value will have the higher bits set to zero: + +.. code-block:: none + + 0101...1101 0010 1010 invalid value + 0000...0000 0010 1010 cleaned value + +For ``int8``, the signed 8-bit type, the valid values are: + +Negative + +.. code-block:: none + + 1111...1111 1111 1111 + 1111...1111 1111 1110 + .... + 1111...1111 1000 0000 + +Positive + +.. code-block:: none + + 0000...0000 0000 0000 + 0000...0000 0000 0001 + 0000...0000 0000 0010 + .... + 0000...0000 1111 1111 + +The compiler will ``signextend`` the sign bit, which is 1 for negative and 0 for +positive values, overwriting the higher bits: + +Negative + +.. code-block:: none + + 0010...1010 1111 1111 invalid value + 1111...1111 1111 1111 cleaned value + +Positive + +.. code-block:: none + + 1101...0101 0000 0100 invalid value + 0000...0000 0000 0100 cleaned value diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 4f3fea17c5..d521897376 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. +>>>>>>> english/develop Storage 예제 =============== @@ -76,7 +82,7 @@ Subcurrency 예제 // "public" 키워드는 변수를 // 다른 컨트랙트로부터 접근 가능하게 하도록 해줍니다. address public minter; - mapping (address => uint) public balances; + mapping(address => uint) public balances; // Event는 클라이언트에게 여러분이 선언한 // 특정 컨트랙트의 변화에 반응할 수 있도록 해줍니다. @@ -133,8 +139,14 @@ Subcurrency 예제 .. index:: mapping +<<<<<<< HEAD 다음 줄의 ``mapping (address => uint) public balances;`` 또한 public 상태 변수를 생성하지만 이번에는 더욱 복잡한 데이터 타입입니다. :ref:`mapping ` 타입은 :ref:`무부호 정수 ` 로 주소를 매핑합니다. +======= +The next line, ``mapping(address => uint) public balances;`` also +creates a public state variable, but it is a more complex datatype. +The :ref:`mapping ` type maps addresses to :ref:`unsigned integers `. +>>>>>>> english/develop 매핑은 `해시 테이블 `_ 과 같이 가상으로 초기화되어 더욱 많은 모든 키들이 시작부터 존재하며 모두 0의 바이트로 표시된 값으로 매핑됩니다. @@ -146,8 +158,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 +170,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 +>>>>>>> english/develop Coin.Sent().watch({}, '', function(error, result) { if (!error) { @@ -186,11 +206,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. +>>>>>>> english/develop ``send`` 함수는 (가지고 있는 코인을) 어느 누구에게든지 보내고자 하는 모든 사람들에 의해 사용될 수 있습니다. 만일 전송자가 전송하고자 하는 코인의 양이 충분치 않을 경우, ``if`` 조건은 참으로 판별하게 됩니다. @@ -228,9 +258,16 @@ Transactions 한 계좌에서 다른 계좌로의 이체 요청이 발생하면, 데이터베이스의 기본적인 거래 성질에 따라 한 계좌에서 특정 양이 감소가 되면 다른 한 쪽은 항상 그마만큼 추가가 된다는 것을 의미합니다. 어떠한 이유든지 간에 만일 상대방 계좌 상에서 해당 양만큼 증가가 이루어지지 않는다면 이는 원래 계좌에서 또한 감소가 이루어지지 않게 됩니다. +<<<<<<< HEAD 또한, 트랜잭션은 항상 전송자(생성자)에 의해 암호화된 서명을 받게 됩니다. 이렇게 함으로서 데이터베이스의 특정 변경에 대한 접근을 직접적으로 보호할 수 있게 됩니다. 전자 통화 예제에서 볼 수 있듯이, 계좌의 키를 가지고 있는 오직 한 사람만이 돈을 이체할 수 있습니다. +======= +Furthermore, a transaction is always cryptographically signed by the sender (creator). +This makes it straightforward to guard access to specific modifications of the +database. In the example of the electronic currency, a simple check ensures that +only the person holding the keys to the account can transfer some compensation, e.g. Ether, from it. +>>>>>>> english/develop .. index:: ! block @@ -245,8 +282,14 @@ Transactions 트랜잭션은 "블록"이라는 것으로 묶여지며 참가하는 모든 노드에게 전파되고 실행됩니다. 만일 두 개의 서로 다른 트랜잭션이 충돌을 일으킬 경우, 두 번째로 오는 트랜잭션은 거절되며 블록의 한 부분이 되지 못합니다. +<<<<<<< HEAD 이 블록들은 시간의 선형 시퀀스를 형성하며, 이것이 바로 "블록체인"이라는 용어가 탄생하게 된 계기입니다. 블록들은 일정한 간격으로 체인에 추가가되며, Ethereum의 경우 대략 매 17초가 걸립니다. +======= +These blocks form a linear sequence in time, and that is where the word "blockchain" derives from. +Blocks are added to the chain at regular intervals, although these intervals may be subject to change in the future. +For the most up-to-date information, it is recommended to monitor the network, for example, on `Etherscan `_. +>>>>>>> english/develop 순서 선택 메카니즘("채굴"이라고도 부릅니다)의 한 부분으로써 블록들은 시간에 따라 회귀하지만 오직 체인의 끝부분에서만 일어납니다. 특정 블록의 상단에 블록들이 추가되면 될수록 회귀되는 확률은 적어집니다. 따라서, 여러분의 트랜잭션들이 회귀될 수 있으며 블록체인에서 제거된다 하더라도 더욱 오래 기다릴수록 그럴 확률이 적어지게 됩니다. @@ -316,6 +359,7 @@ Ethereum에는 동일한 주소를 공유하고 있는 두 가지 종류의 계 가스 === +<<<<<<< HEAD 생성이 되고 난 후, 각 트랜잭션은 일정량의 **가스**를 지불하게 됩니다. 이는 트랜잭션을 실행하기 위해 필요한 작업량을 제한함과 동시에 작업을 수행하기 위하여 지불하기 위함입니다. EVM이 트랜잭션을 실행하는 동안, 가스는 특정 규칙에 따라 점차적으로 고갈됩니다. @@ -324,14 +368,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. +>>>>>>> english/develop + +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. +>>>>>>> english/develop 각 계정은 **스토리지**라는 데이터 공간이 있는데 함수의 호출과 트랜잭션 사이에서 지속적으로 존재합니다. 스토리지는 256 비트 단어를 256 비트의 단어로 매핑해주는 키-값 저장소입니다. @@ -385,14 +456,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. +>>>>>>> english/develop 이는 컨트랙트가 런타임에서 다른 주소로부터 코드를 동적으로 로드할 수 있음을 의미합니다. 스토리지, 현 주소 그리고 잔고는 여전히 호출 중인 컨트랙트를 참조하며 오직 코드만이 호출된 주소로부터 가져와집니다. @@ -421,7 +499,7 @@ Create 이렇게 **create call**과 일반 message call 간의 유일한 차이는 payload 데이터가 실행되고 코드로 결과가 저장되며 호출자 혹은 생성자가 스택 상에 새로운 컨트랙트의 주소를 받는다는 점입니다. -.. index:: selfdestruct, self-destruct, deactivate +.. index:: ! selfdestruct, deactivate Deactivate and Self-destruct ============================ @@ -431,10 +509,22 @@ Deactivate and Self-destruct 이론적으로 봤을 때 컨트랙트를 제거하는 것은 좋은 아이디어처럼 들릴 수도 있지만, 누군가가 제거된 컨트랙트에 Ether를 전송하고 Ether가 영원히 없어질 수 있는 것처럼 잠재적으로는 위험합니다. +<<<<<<< HEAD .. 경고:: ``selfdestruct`` 로 인해 컨트랙트가 제거가 되었어도 여전히 블록체인의 히스토리의 한 부분이며 대부분의 Ethereum 노드에 의해 아마도 보유되고 있을 수 있습니다. 따라서, ``selfdestruct`` 방식을 사용하는 것은 하드디스크에서 데이터를 지우는 것과는 다릅니다. +======= +.. warning:: + From version 0.8.18 and up, the use of ``selfdestruct`` in both Solidity and Yul will trigger a + deprecation warning, since the ``SELFDESTRUCT`` opcode will eventually undergo breaking changes in behavior + as stated in `EIP-6049 `_. + +.. warning:: + Even if a contract is removed by ``selfdestruct``, it is still part of the + history of the blockchain and probably retained by most Ethereum nodes. + So using ``selfdestruct`` is not the same as deleting data from a hard disk. +>>>>>>> english/develop .. 참고:: 컨트랙트의 코드에서 ``selfdestruct`` 로의 호출 부분이 없다 하더라도 ``delegatecall`` 혹은 ``callcode`` 를 통해 해당 작업을 실행할 수 있습니다. @@ -450,10 +540,19 @@ Deactivate and Self-destruct Precompiled Contracts ===================== +<<<<<<< HEAD "precompiled contracts"라 하는 특별한 작은 세트의 컨트랙트 주소가 있습니다. 이 주소는 ``1`` 에서 ``8`` (포함)까지의 범위를 가지고 있으며 기타 컨트랙트처럼 호출될 수 있지만 행동과 가스 소비는 특정 주소에 저장되는 EVM 코드에 의해 정의되지 않습니다 (코드를 포함하고 있지 않습니다). 다만, EVM의 실행 환경 자체에서 시행될 뿐입니다. +======= +There is a small set of contract addresses that are special: +The address range between ``1`` and (including) ``8`` contains +"precompiled contracts" that can be called as any other contract +but their behavior (and their gas consumption) is not defined +by EVM code stored at that address (they do not contain code) +but instead is implemented in the EVM execution environment itself. +>>>>>>> english/develop 다양한 EVM 호환적인 체인들은 다른 세트의 precompiled contract를 사용할 수 있습니다. 새 precompiled contracts가 미래에 Ethereum의 메인 체인에 추가될 수도 있지만 diff --git a/docs/ir-breaking-changes.rst b/docs/ir-breaking-changes.rst index c1f6deb57f..4917cfc715 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,17 +15,13 @@ 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! For several reasons, there are tiny semantic differences between the old and the IR-based code generator, mostly in areas where we would not -expect people to rely on this behaviour anyway. +expect people to rely on this behavior anyway. This section highlights the main differences between the old and the IR-based codegen. Semantic Only Changes @@ -32,6 +30,50 @@ Semantic Only Changes This section lists the changes that are semantic-only, thus potentially hiding new and different behavior in existing code. +.. _state-variable-initialization-order: + +- 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,14 +118,14 @@ 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() { _; _; } } - If you execute ``f(0)`` in the old code generator, it will return ``2``, while - it will return ``1`` when using the new code generator. + If you execute ``f(0)`` in the old code generator, it will return ``1``, while + it will return ``0`` when using the new code generator. .. code-block:: solidity @@ -114,78 +156,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,15 +169,15 @@ 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; } } The function ``preincr_u8(1)`` returns the following values: - - Old code generator: 3 (``1 + 2``) but the return value is unspecified in general - - New code generator: 4 (``2 + 2``) but the return value is not guaranteed + - Old code generator: ``3`` (``1 + 2``) but the return value is unspecified in general + - New code generator: ``4`` (``2 + 2``) but the return value is not guaranteed .. index:: ! evaluation order; function arguments @@ -220,11 +190,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); } } @@ -279,7 +249,7 @@ This causes differences in some contracts, for example: } } - The function `f()` behaves as follows: + The function ``f()`` behaves as follows: - Old code generator: runs out of gas while zeroing the array contents after the large memory allocation - New code generator: reverts due to free memory pointer overflow (does not run out of gas) @@ -323,13 +293,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 +308,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..600f2ed0f4 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 @@ -37,7 +40,7 @@ The comment is recognized by the compiler anywhere in the file at the file level, but it is recommended to put it at the top of the file. More information about how to use SPDX license identifiers -can be found at the `SPDX website `_. +can be found at the `SPDX website `_. .. index:: ! pragma @@ -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 `_. +a `default export `_. At a global level, you can use import statements of the following form: diff --git a/docs/logo.svg b/docs/logo.svg index 86b9f4995b..19391843b4 100644 --- a/docs/logo.svg +++ b/docs/logo.svg @@ -1,27 +1,8 @@ - - - - -Vector 1 -Created with Sketch. - - - - - - - - - - - - + + + + + + + diff --git a/docs/make.bat b/docs/make.bat index bc06e706e0..d11deb3ffc 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -28,6 +28,7 @@ if "%1" == "help" ( echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. latexpdf to make LaTeX files and run them through pdflatex echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files @@ -155,16 +156,6 @@ if "%1" == "latexpdf" ( goto end ) -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 diff --git a/docs/metadata.rst b/docs/metadata.rst index 1220f7822b..ede16a73fd 100644 --- a/docs/metadata.rst +++ b/docs/metadata.rst @@ -6,122 +6,194 @@ Contract Metadata .. index:: metadata, contract verification -The Solidity compiler automatically generates a JSON file, the contract -metadata, that contains information about the compiled contract. You can use -this file to query the compiler version, the sources used, the ABI and NatSpec -documentation to more safely interact with the contract and verify its source -code. +The Solidity compiler automatically generates a JSON file. +The file contains two kinds of information about the compiled contract: + +- How to interact with the contract: ABI, and NatSpec documentation. +- How to reproduce the compilation and verify a deployed contract: + compiler version, compiler settings, and source files used. The compiler appends by default the IPFS hash of the metadata file to the end -of the bytecode (for details, see below) of each contract, so that you can -retrieve the file in an authenticated way without having to resort to a -centralized data provider. The other available options are the Swarm hash and -not appending the metadata hash to the bytecode. These can be configured via -the :ref:`Standard JSON Interface`. +of the runtime bytecode (not necessarily the creation bytecode) of each contract, +so that, if published, you can retrieve the file in an authenticated way without +having to resort to a centralized data provider. The other available options are +the Swarm hash and not appending the metadata hash to the bytecode. These can be +configured via the :ref:`Standard JSON Interface`. 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, -reduce whitespace to a minimum and sort the keys of all objects to arrive at a -unique formatting. Comments are not permitted and used here only for +reduce whitespace to a minimum, and sort the keys of all objects in alphabetical order +to arrive at a canonical formatting. Comments are not permitted and are used here only for explanatory purposes. .. code-block:: javascript { - // Required: The version of the metadata format - "version": "1", - // Required: Source code language, basically selects a "sub-version" - // of the specification - "language": "Solidity", // Required: Details about the compiler, contents are specific // to the language. "compiler": { - // Required for Solidity: Version of the compiler - "version": "0.4.6+commit.2dabbdf0.Emscripten.clang", // Optional: Hash of the compiler binary which produced this output - "keccak256": "0x123..." + "keccak256": "0x123...", + // Required for Solidity: Version of the compiler + "version": "0.8.2+commit.661d1103" }, - // Required: Compilation source files/source units, keys are file names - "sources": - { - "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..." ], - // Optional: SPDX license identifier as given in the source file - "license": "MIT" + // Required: Source code language, basically selects a "sub-version" + // of the specification + "language": "Solidity", + // Required: Generated information about the contract. + "output": { + // Required: ABI definition of the contract. See "Contract ABI Specification" + "abi": [/* ... */], + // Required: NatSpec developer documentation of the contract. See https://docs.soliditylang.org/en/latest/natspec-format.html for details. + "devdoc": { + // Contents of the @author NatSpec field of the contract + "author": "John Doe", + // 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", + "errors": { + "MintToZeroAddress()" : { + "details": "Cannot mint to zero address" + } + }, + "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" + } + } + }, + "kind": "dev", + "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" + } + }, + // Contents of the @title NatSpec field of the contract + "title": "MyERC20: an example ERC20", + "version": 1 // NatSpec version }, - "destructible": { - // Required: keccak256 hash of the source file - "keccak256": "0x234...", - // Required (unless "url" is used): literal contents of the source file - "content": "contract destructible is owned { function destroy() { if (msg.sender == owner) selfdestruct(owner); } }" + // Required: NatSpec user documentation of the contract. See "NatSpec Format" + "userdoc": { + "errors": { + "ApprovalCallerNotOwnerNorApproved()": [ + { + "notice": "The caller must own the token or be an approved operator." + } + ] + }, + "events": { + "Transfer(address,address,uint256)": { + "notice": "`_value` tokens have been moved from `from` to `to`" + } + }, + "kind": "user", + "methods": { + "transfer(address,uint256)": { + "notice": "Transfers `_value` tokens to address `_to`" + } + }, + "version": 1 // NatSpec version } }, - // Required: Compiler settings - "settings": - { - // Required for Solidity: Sorted list of remappings - "remappings": [ ":g=/dir" ], + // Required: Compiler settings. Reflects the settings in the JSON input during compilation. + // Check the documentation of standard JSON input's "settings" field + "settings": { + // Required for Solidity: File path and the name of the contract or library this + // metadata is created for. + "compilationTarget": { + "myDirectory/myFile.sol": "MyContract" + }, + // Required for Solidity. + "evmVersion": "london", + // Required for Solidity: Addresses for libraries used. + "libraries": { + "MyLib": "0x123123..." + }, + "metadata": { + // Reflects the setting used in the input json, defaults to "true" + "appendCBOR": true, + // Reflects the setting used in the input json, defaults to "ipfs" + "bytecodeHash": "ipfs", + // Reflects the setting used in the input json, defaults to "false" + "useLiteralContent": true + }, // Optional: Optimizer settings. The fields "enabled" and "runs" are deprecated - // and are only given for backwards-compatibility. + // and are only given for backward-compatibility. "optimizer": { - "enabled": true, - "runs": 500, "details": { - // peephole defaults to "true" - "peephole": true, - // inliner defaults to "true" - "inliner": true, + "constantOptimizer": false, + "cse": false, + "deduplicate": false, + // inliner defaults to "false" + "inliner": false, // jumpdestRemover defaults to "true" "jumpdestRemover": true, "orderLiterals": false, - "deduplicate": false, - "cse": false, - "constantOptimizer": false, + // peephole defaults to "true" + "peephole": true, "yul": true, // Optional: Only present if "yul" is "true" "yulDetails": { - "stackAllocation": false, - "optimizerSteps": "dhfoDgvulfnTUtnIf..." + "optimizerSteps": "dhfoDgvulfnTUtnIf...", + "stackAllocation": false } - } - }, - "metadata": { - // 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" + }, + "enabled": true, + "runs": 500 }, - // Required for Solidity: File and name of the contract or library this - // metadata is created for. - "compilationTarget": { - "myFile.sol": "MyContract" + // Required for Solidity: Sorted list of import remappings. + "remappings": [ ":g=/dir" ] + }, + // Required: Compilation source files/source units, keys are file paths + "sources": { + "destructible": { + // Required (unless "url" is used): literal contents of the source file + "content": "contract destructible is owned { function destroy() { if (msg.sender == owner) selfdestruct(owner); } }", + // Required: keccak256 hash of the source file + "keccak256": "0x234..." }, - // Required for Solidity: Addresses for libraries used - "libraries": { - "MyLib": "0x123123..." + "myDirectory/myFile.sol": { + // Required: keccak256 hash of the source file + "keccak256": "0x123...", + // Optional: SPDX license identifier as given in the source file + "license": "MIT", + // Required (unless "content" is used, see above): Sorted URL(s) + // to the source file, protocol is more or less arbitrary, but an + // IPFS URL is recommended + "urls": [ "bzz-raw://7d7a...", "dweb:/ipfs/QmN..." ] } }, - // Required: Generated information about the contract. - "output": - { - // Required: ABI definition of the contract - "abi": [/* ... */], - // Required: NatSpec user documentation of the contract - "userdoc": [/* ... */], - // Required: NatSpec developer documentation of the contract - "devdoc": [/* ... */] - } + // Required: The version of the metadata format + "version": 1 } .. warning:: @@ -141,71 +213,80 @@ explanatory purposes. Encoding of the Metadata Hash in the Bytecode ============================================= -Because we might support other ways to retrieve the metadata file in the future, -the mapping ``{"ipfs": , "solc": }`` is stored -`CBOR `_-encoded. Since the mapping might -contain more keys (see below) and the beginning of that -encoding is not easy to find, its length is added in a two-byte big-endian -encoding. The current version of the Solidity compiler usually adds the following -to the end of the deployed bytecode +The compiler currently by default appends the +`IPFS hash (in CID v0) `_ +of the canonical metadata file and the compiler version to the end of the bytecode. +Optionally, a Swarm hash instead of the IPFS, or an experimental flag is used. +Below are all the possible fields: + +.. code-block:: javascript -.. code-block:: text + { + "ipfs": "", + // If "bytecodeHash" was "bzzr1" in compiler settings not "ipfs" but "bzzr1" + "bzzr1": "", + // Previous versions were using "bzzr0" instead of "bzzr1" + "bzzr0": "", + // If any experimental features that affect code generation are used + "experimental": true, + "solc": "" + } - 0xa2 - 0x64 'i' 'p' 'f' 's' 0x58 0x22 <34 bytes IPFS hash> - 0x64 's' 'o' 'l' 'c' 0x43 <3 byte version encoding> - 0x00 0x33 +Because we might support other ways to retrieve the +metadata file in the future, this information is stored +`CBOR `_-encoded. The last two bytes in the bytecode +indicate the length of the CBOR encoded information. By looking at this length, the +relevant part of the bytecode can be decoded with a CBOR decoder. -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. +Check the `Metadata Playground `_ to see it in action. 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 +above (one byte each for major, minor and patch version number), pre-release builds will instead use a complete version string including commit hash and build date. -.. note:: - The CBOR mapping can also contain other keys, so it is better to fully - decode the data instead of relying on it starting with ``0xa264``. - For example, if any experimental features that affect code generation - are used, the mapping will also contain ``"experimental": true``. +The commandline flag ``--no-cbor-metadata`` can be used to skip metadata +from getting appended at the end of the deployed bytecode. Equivalently, the +boolean field ``settings.metadata.appendCBOR`` in Standard JSON input can be set to false. .. note:: - The compiler currently uses the IPFS hash of the metadata by default, but - it may also use the bzzr1 hash or some other hash in the future, so do - not rely on this sequence to start with ``0xa2 0x64 'i' 'p' 'f' 's'``. We - might also add additional data to this CBOR structure, so the best option - is to use a proper CBOR parser. - + The CBOR mapping can also contain other keys, so it is better to fully + decode the data by looking at the end of the bytecode for the CBOR length, + and to use a proper CBOR parser. Do not rely on it starting with ``0xa264`` + or ``0xa2 0x64 'i' 'p' 'f' 's'``. 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 -whenever they interact with the contract, together with requesting -authorization for the transaction signature. +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. For additional information, read :doc:`Ethereum Natural Language Specification (NatSpec) format `. Usage for Source Code Verification ================================== -In order to verify the compilation, sources can be retrieved from IPFS/Swarm -via the link in the metadata file. -The compiler of the correct version (which is checked to be part of the "official" compilers) -is invoked on that input with the specified settings. The resulting -bytecode is compared to the data of the creation transaction or ``CREATE`` opcode data. -This automatically verifies the metadata since its hash is part of the bytecode. -Excess data corresponds to the constructor input data, which should be decoded -according to the interface and presented to the user. - -In the repository `sourcify `_ -(`npm package `_) you can see -example code that shows how to use this feature. +If pinned/published, it is possible to retrieve the metadata of the contract from IPFS/Swarm. +The metadata file also contains the URLs or the IPFS hashes of the source files, as well as +the compilation settings, i.e. everything needed to reproduce a compilation. + +With this information it is then possible to verify the source code of a contract by +reproducing the compilation, and comparing the bytecode from the compilation with +the bytecode of the deployed contract. + +This automatically verifies the metadata since its hash is part of the bytecode, as well +as the source codes, because their hashes are part of the metadata. Any change in the files +or settings would result in a different metadata hash. The metadata here serves +as a fingerprint of the whole compilation. + +`Sourcify `_ makes use of this feature for "full/perfect verification", +as well as pinning the files publicly on IPFS to be accessed with the metadata hash. diff --git a/docs/natspec-format.rst b/docs/natspec-format.rst index 297bbc8c62..0265fef3e6 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. @@ -46,7 +46,7 @@ for the purposes of NatSpec. - For Vyper, use ``"""`` indented to the inner contents with bare comments. See the `Vyper - documentation `__. + documentation `__. The following example shows a contract and a function using all available tags. @@ -58,7 +58,7 @@ The following example shows a contract and a function using all available tags. This may change in the future. -.. code-block:: Solidity +.. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.2 < 0.9.0; @@ -154,10 +154,6 @@ to the end-user as: if a function is being called and the input ``a`` is assigned a value of 10. -Specifying these dynamic expressions is outside the scope of the Solidity -documentation and you may read more at -`the radspec project `__. - .. _header-inheritance: Inheritance Notes @@ -183,7 +179,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 +198,7 @@ User Documentation The above documentation will produce the following user documentation JSON file as output: -.. code:: +.. code-block:: json { "version" : 1, @@ -230,7 +226,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/path-resolution.rst b/docs/path-resolution.rst index 40a727068b..ff4930bc9d 100644 --- a/docs/path-resolution.rst +++ b/docs/path-resolution.rst @@ -21,7 +21,7 @@ source unit is assigned a unique *source unit name* which is an opaque and unstr When you use the :ref:`import statement `, you specify an *import path* that references a source unit name. -.. index:: ! import callback, ! Host Filesystem Loader +.. index:: ! import callback, ! Host Filesystem Loader, ! --no-import-callback .. _import-callback: Import Callback @@ -36,11 +36,12 @@ An import callback is free to interpret source unit names in an arbitrary way, n If there is no callback available when one is needed or if it fails to locate the source code, compilation fails. -The command-line compiler provides the *Host Filesystem Loader* - a rudimentary callback +By default, the command-line compiler provides the *Host Filesystem Loader* - a rudimentary callback that interprets a source unit name as a path in the local filesystem. +This callback can be disabled using the ``--no-import-callback`` command-line option. The `JavaScript interface `_ does not provide any by default, but one can be provided by the user. -This mechanism can be used to obtain source code from locations other then the local filesystem +This mechanism can be used to obtain source code from locations other than the local filesystem (which may not even be accessible, e.g. when the compiler is running in a browser). For example the `Remix IDE `_ provides a versatile callback that lets you `import files from HTTP, IPFS and Swarm URLs or refer directly to packages in NPM registry @@ -139,7 +140,7 @@ The initial content of the VFS depends on how you invoke the compiler: #. **Standard input** - On the command line it is also possible to provide the source by sending it to compiler's + On the command-line it is also possible to provide the source by sending it to compiler's standard input: .. code-block:: bash @@ -197,7 +198,7 @@ source unit name. A source unit name is just an identifier and even if its value happens to look like a path, it is not subject to the normalization rules you would typically expect in a shell. - Any ``/./`` or ``/../`` seguments or sequences of multiple slashes remain a part of it. + Any ``/./`` or ``/../`` segments or sequences of multiple slashes remain a part of it. When the source is provided via Standard JSON interface it is entirely possible to associate different content with source unit names that would refer to the same file on disk. @@ -248,19 +249,15 @@ and is bounded by two path separators. A separator is a forward slash or the beginning/end of the string. For example in ``./abc/..//`` there are three path segments: ``.``, ``abc`` and ``..``. -The compiler computes a source unit name from the import path in the following way: +The compiler resolves the import into a source unit name based on the import path, in the following way: -1. First a prefix is computed +#. We start with the source unit name of the importing source unit. +#. The last path segment with preceding slashes is removed from the resolved name. +#. Then, for every segment in the import path, starting from the leftmost one: - - Prefix is initialized with the source unit name of the importing source unit. - - The last path segment with preceding slashes is removed from the prefix. - - Then, the leading part of the normalized import path, consisting only of ``/`` and ``.`` - characters is considered. - For every ``..`` segment found in this part the last path segment with preceding slashes is - removed from the prefix. - -2. Then the prefix is prepended to the normalized import path. - If the prefix is non-empty, a single slash is inserted between it and the import path. + - If the segment is ``.``, it is skipped. + - If the segment is ``..``, the last path segment with preceding slashes is removed from the resolved name. + - Otherwise, the segment (preceded by a single slash if the resolved name is not empty), is appended to the resolved name. The removal of the last path segment with preceding slashes is understood to work as follows: @@ -268,14 +265,10 @@ work as follows: 1. Everything past the last slash is removed (i.e. ``a/b//c.sol`` becomes ``a/b//``). 2. All trailing slashes are removed (i.e. ``a/b//`` becomes ``a/b``). -The normalization rules are the same as for UNIX paths, namely: - -- All the internal ``.`` segments are removed. -- Every internal ``..`` segment backtracks one level up in the hierarchy. -- Multiple slashes are squashed into a single one. - -Note that normalization is performed only on the import path. -The source unit name of the importing module that is used for the prefix remains unnormalized. +Note that the process normalizes the part of the resolved source unit name that comes from the import path according +to the usual rules for UNIX paths, i.e. all ``.`` and ``..`` are removed and multiple slashes are +squashed into a single one. +On the other hand, the part that comes from the source unit name of the importing module remains unnormalized. This ensures that the ``protocol://`` part does not turn into ``protocol:/`` if the importing file is identified with a URL. @@ -353,13 +346,13 @@ of the compiler. CLI Path Normalization and Stripping ------------------------------------ -On the command line the compiler behaves just as you would expect from any other program: +On the command-line the compiler behaves just as you would expect from any other program: it accepts paths in a format native to the platform and relative paths are relative to the current working directory. -The source unit names assigned to files whose paths are specified on the command line, however, +The source unit names assigned to files whose paths are specified on the command-line, however, should not change just because the project is being compiled on a different platform or because the compiler happens to have been invoked from a different directory. -To achieve this, paths to source files coming from the command line must be converted to a canonical +To achieve this, paths to source files coming from the command-line must be converted to a canonical form, and, if possible, made relative to the base path or one of the include paths. The normalization rules are as follows: @@ -416,7 +409,7 @@ The resulting file path becomes the source unit name. Prior to version 0.8.8, CLI path stripping was not performed and the only normalization applied was the conversion of path separators. When working with older versions of the compiler it is recommended to invoke the compiler from - the base path and to only use relative paths on the command line. + the base path and to only use relative paths on the command-line. .. index:: ! allowed paths, ! --allow-paths, remapping; target .. _allowed-paths: @@ -429,7 +422,7 @@ locations that are considered safe by default: - Outside of Standard JSON mode: - - The directories containing input files listed on the command line. + - The directories containing input files listed on the command-line. - The directories used as :ref:`remapping ` targets. If the target is not a directory (i.e does not end with ``/``, ``/.`` or ``/..``) the directory containing the target is used instead. @@ -523,7 +516,7 @@ you can use the following in your source file: The compiler will look for the file in the VFS under ``dapp-bin/library/math.sol``. If the file is not available there, the source unit name will be passed to the Host Filesystem -Loader, which will then look in ``/project/dapp-bin/library/iterable_mapping.sol``. +Loader, which will then look in ``/project/dapp-bin/library/math.sol``. .. warning:: @@ -559,7 +552,7 @@ you checked out to ``/project/dapp-bin_old``, then you can run: This means that all imports in ``module2`` point to the old version but imports in ``module1`` point to the new version. -Here are the detailed rules governing the behaviour of remappings: +Here are the detailed rules governing the behavior of remappings: #. **Remappings only affect the translation between import paths and source unit names.** diff --git a/docs/requirements.txt b/docs/requirements.txt index 23c8f90432..b1b21a8691 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -4,7 +4,7 @@ sphinx_rtd_theme>=0.5.2 pygments-lexer-solidity>=0.7.0 -sphinx-a4doc>=1.2.1 +sphinx-a4doc>=1.6.0 # Sphinx 2.1.0 is the oldest version that accepts a lexer class in add_lexer() -sphinx>=2.1.0 +sphinx>=2.1.0, <6.0 diff --git a/docs/resources.rst b/docs/resources.rst index 5b8d0013ab..85b3cf9a39 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 ============================================== @@ -23,10 +23,10 @@ Integrated (Ethereum) Development Environments Python-based development and testing framework for smart contracts targeting the Ethereum Virtual Machine. * `Dapp `_ - Tool for building, testing and deploying smart contracts from the command line. + Tool for building, testing and deploying smart contracts from the command-line. - * `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. @@ -34,26 +34,12 @@ Integrated (Ethereum) Development Environments * `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 `_ + * `Truffle `_ Ethereum development framework. Editor Integrations =================== -* Atom - - * `Etheratom `_ - Plugin for the Atom editor that features syntax highlighting, compilation and a runtime environment (Backend node & VM compatible). - - * `Atom Solidity Linter `_ - Plugin for the Atom editor that provides Solidity linting. - - * `Atom Solium Linter `_ - Configurable Solidity linter for Atom using Solium (now Ethlint) as a base. - * Emacs * `Emacs Solidity `_ @@ -61,27 +47,42 @@ Editor Integrations * IntelliJ - * `IntelliJ IDEA plugin `_ - Solidity plugin for IntelliJ IDEA (and all other JetBrains IDEs) + * `IntelliJ IDEA plugin `_ + Solidity plugin for IntelliJ IDEA (and all other JetBrains IDEs). -* Sublime +* Sublime Text * `Package for SublimeText - Solidity language syntax `_ Solidity syntax highlighting for SublimeText editor. * Vim - * `Vim Solidity `_ - Plugin for the Vim editor providing syntax highlighting. + * `Vim Solidity by Thesis `_ + Syntax highlighting for Solidity in Vim. + + * `Vim Solidity by TovarishFin `_ + Vim syntax file for Solidity. * `Vim Syntastic `_ Plugin for the Vim editor providing compile checking. -* Visual Studio Code +* Visual Studio Code (VS Code) + + * `Ethereum Remix Visual Studio Code extension `_ + Ethereum Remix extension pack for VS Code - * `Visual Studio Code extension `_ + * `Solidity Visual Studio Code extension, by Juan Blanco `_ Solidity plugin for Microsoft Visual Studio Code that includes syntax highlighting and the Solidity compiler. + * `Solidity Visual Studio Code extension, by Nomic Foundation `_ + Solidity and Hardhat support by the Hardhat team, including: syntax highlighting, jump to definition, renames, quick fixes and inline solc warnings and errors. + + * `Solidity Visual Auditor extension `_ + Adds security centric syntax and semantic highlighting to Visual Studio Code. + + * `Truffle for VS Code `_ + Build, debug and deploy smart contracts on Ethereum and EVM-compatible blockchains. + Solidity Tools ============== @@ -109,8 +110,8 @@ Solidity Tools * `leafleth `_ A documentation generator for Solidity smart-contracts. -* `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 +131,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..92d601043d 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -7,28 +7,28 @@ Security Considerations While it is usually quite easy to build software that works as expected, it is much harder to check that nobody can use it in a way that was **not** anticipated. -In Solidity, this is even more important because you can use smart contracts -to handle tokens or, possibly, even more valuable things. Furthermore, every -execution of a smart contract happens in public and, in addition to that, -the source code is often available. - -Of course you always have to consider how much is at stake: -You can compare a smart contract with a web service that is open to the -public (and thus, also to malicious actors) and perhaps even open source. -If you only store your grocery list on that web service, you might not have -to take too much care, but if you manage your bank account using that web service, -you should be more careful. - -This section will list some pitfalls and general security recommendations but -can, of course, never be complete. Also, keep in mind that even if your smart -contract code is bug-free, the compiler or the platform itself might have a -bug. A list of some publicly known security-relevant bugs of the compiler can -be found in the :ref:`list of known bugs`, which is also -machine-readable. Note that there is a bug bounty program that covers the code -generator of the Solidity compiler. - -As always, with open source documentation, please help us extend this section -(especially, some examples would not hurt)! +In Solidity, this is even more important because you can use smart contracts to handle tokens or, +possibly, even more valuable things. +Furthermore, every execution of a smart contract happens in public and, +in addition to that, the source code is often available. + +Of course, you always have to consider how much is at stake: +You can compare a smart contract with a web service that is open to the public +(and thus, also to malicious actors) and perhaps even open-source. +If you only store your grocery list on that web service, you might not have to take too much care, +but if you manage your bank account using that web service, you should be more careful. + +This section will list some pitfalls and general security recommendations +but can, of course, never be complete. +Also, keep in mind that even if your smart contract code is bug-free, +the compiler or the platform itself might have a bug. +A list of some publicly known security-relevant bugs of the compiler can be found +in the :ref:`list of known bugs`, which is also machine-readable. +Note that there is a `Bug Bounty Program `_ +that covers the code generator of the Solidity compiler. + +As always, with open-source documentation, +please help us extend this section (especially, some examples would not hurt)! NOTE: In addition to the list below, you can find more security recommendations and best practices `in Guy Lando's knowledge list `_ and @@ -41,20 +41,18 @@ Pitfalls Private Information and Randomness ================================== -Everything you use in a smart contract is publicly visible, even -local variables and state variables marked ``private``. +Everything you use in a smart contract is publicly visible, +even local variables and state variables marked ``private``. -Using random numbers in smart contracts is quite tricky if you do not want -miners to be able to cheat. +Using random numbers in smart contracts is quite tricky if you do not want block builders to be able to cheat. -Re-Entrancy -=========== +Reentrancy +========== -Any interaction from a contract (A) with another contract (B) and any transfer -of Ether hands over control to that contract (B). This makes it possible for B -to call back into A before this interaction is completed. To give an example, -the following code contains a bug (it is just a snippet and not a -complete contract): +Any interaction from a contract (A) with another contract (B) +and any transfer of Ether hands over control to that contract (B). +This makes it possible for B to call back into A before this interaction is completed. +To give an example, the following code contains a bug (it is just a snippet and not a complete contract): .. code-block:: solidity @@ -72,12 +70,12 @@ complete contract): } } -The problem is not too serious here because of the limited gas as part -of ``send``, but it still exposes a weakness: Ether transfer can always -include code execution, so the recipient could be a contract that calls -back into ``withdraw``. This would let it get multiple refunds and -basically retrieve all the Ether in the contract. In particular, the -following contract will allow an attacker to refund multiple times +The problem is not too serious here because of the limited gas as part of ``send``, +but it still exposes a weakness: +Ether transfer can always include code execution, +so the recipient could be a contract that calls back into ``withdraw``. +This would let it get multiple refunds and, basically, retrieve all the Ether in the contract. +In particular, the following contract will allow an attacker to refund multiple times as it uses ``call`` which forwards all remaining gas by default: .. code-block:: solidity @@ -97,8 +95,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: +To avoid reentrancy, you can use the Checks-Effects-Interactions pattern as demonstrated below: .. code-block:: solidity @@ -116,51 +113,58 @@ outlined further below: } } -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 -state of another contract you depend on. +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 *reentrancy attacks*, +where an externally called malicious contract can 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 reentrancy 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 state of another contract you depend on. Gas Limit and Loops =================== -Loops that do not have a fixed number of iterations, for example, loops that depend on storage values, have to be used carefully: -Due to the block gas limit, transactions can only consume a certain amount of gas. Either explicitly or just due to -normal operation, the number of iterations in a loop can grow beyond the block gas limit which can cause the complete -contract to be stalled at a certain point. This may not apply to ``view`` functions that are only executed -to read data from the blockchain. Still, such functions may be called by other contracts as part of on-chain operations -and stall those. Please be explicit about such cases in the documentation of your contracts. +Loops that do not have a fixed number of iterations, for example, +loops that depend on storage values, have to be used carefully: +Due to the block gas limit, transactions can only consume a certain amount of gas. +Either explicitly or just due to normal operation, +the number of iterations in a loop can grow beyond the block gas limit +which can cause the complete contract to be stalled at a certain point. +This may not apply to ``view`` functions that are only executed to read data from the blockchain. +Still, such functions may be called by other contracts as part of on-chain operations and stall those. +Please be explicit about such cases in the documentation of your contracts. Sending and Receiving Ether =========================== -- Neither contracts nor "external accounts" are currently able to prevent that someone sends them Ether. - Contracts can react on and reject a regular transfer, but there are ways - to move Ether without creating a message call. One way is to simply "mine to" - the contract address and the second way is using ``selfdestruct(x)``. +- Neither contracts nor "external accounts" are currently able to prevent someone from sending them Ether. + Contracts can react on and reject a regular transfer, but there are ways to move Ether without creating a message call. + One way is to simply "mine to" the contract address and the second way is using ``selfdestruct(x)``. -- If a contract receives Ether (without a function being called), - either the :ref:`receive Ether ` +- If a contract receives Ether (without a function being called), either the :ref:`receive Ether ` or the :ref:`fallback ` function is executed. - If it does not have a receive nor a fallback function, the Ether will be - rejected (by throwing an exception). During the execution of one of these - functions, the contract can only rely on the "gas stipend" it is passed (2300 - gas) being available to it at that time. This stipend is not enough to modify - storage (do not take this for granted though, the stipend might change with - future hard forks). To be sure that your contract can receive Ether in that - way, check the gas requirements of the receive and fallback functions + If it does not have a ``receive`` nor a ``fallback`` function, the Ether will be rejected (by throwing an exception). + During the execution of one of these functions, the contract can only rely on the "gas stipend" it is passed (2300 gas) + being available to it at that time. + This stipend is not enough to modify storage (do not take this for granted though, the stipend might change with future hard forks). + To be sure that your contract can receive Ether in that way, check the gas requirements of the receive and fallback functions (for example in the "details" section in Remix). -- There is a way to forward more gas to the receiving contract using - ``addr.call{value: x}("")``. This is essentially the same as ``addr.transfer(x)``, - only that it forwards all remaining gas and opens up the ability for the - recipient to perform more expensive actions (and it returns a failure code - instead of automatically propagating the error). This might include calling back - into the sending contract or other state changes you might not have thought of. +- There is a way to forward more gas to the receiving contract using ``addr.call{value: x}("")``. + This is essentially the same as ``addr.transfer(x)``, only that it forwards all remaining gas + and opens up the ability for the recipient to perform more expensive actions + (and it returns a failure code instead of automatically propagating the error). + This might include calling back into the sending contract or other state changes you might not have thought of. So it allows for great flexibility for honest users but also for malicious actors. -- Use the most precise units to represent the wei amount as possible, as you lose - any that is rounded due to a lack of precision. +- Use the most precise units to represent the Wei amount as possible, as you lose any that is rounded due to a lack of precision. - If you want to send Ether using ``address.transfer``, there are certain details to be aware of: @@ -184,24 +188,28 @@ Sending and Receiving Ether Call Stack Depth ================ -External function calls can fail any time because they exceed the maximum -call stack size limit of 1024. In such situations, Solidity throws an exception. +External function calls can fail at any time +because they exceed the maximum call stack size limit of 1024. +In such situations, Solidity throws an exception. Malicious actors might be able to force the call stack to a high value -before they interact with your contract. Note that, since `Tangerine Whistle `_ hardfork, the `63/64 rule `_ makes call stack depth attack impractical. Also note that the call stack and the expression stack are unrelated, even though both have a size limit of 1024 stack slots. +before they interact with your contract. +Note that, since `Tangerine Whistle `_ hardfork, +the `63/64 rule `_ makes call stack depth attack impractical. +Also note that the call stack and the expression stack are unrelated, +even though both have a size limit of 1024 stack slots. -Note that ``.send()`` does **not** throw an exception if the call stack is -depleted but rather returns ``false`` in that case. The low-level functions -``.call()``, ``.delegatecall()`` and ``.staticcall()`` behave in the same way. +Note that ``.send()`` does **not** throw an exception if the call stack is depleted +but rather returns ``false`` in that case. +The low-level functions ``.call()``, ``.delegatecall()`` and ``.staticcall()`` behave in the same way. Authorized Proxies ================== -If your contract can act as a proxy, i.e. if it can call arbitrary contracts -with user-supplied data, then the user can essentially assume the identity -of the proxy contract. Even if you have other protective measures in place, -it is best to build your contract system such that the proxy does not have -any permissions (not even for itself). If needed, you can accomplish that -using a second proxy: +If your contract can act as a proxy, i.e. if it can call arbitrary contracts with user-supplied data, +then the user can essentially assume the identity of the proxy contract. +Even if you have other protective measures in place, it is best to build your contract system such +that the proxy does not have any permissions (not even for itself). +If needed, you can accomplish that using a second proxy: .. code-block:: solidity @@ -210,9 +218,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,16 +228,17 @@ 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); } } tx.origin ========= -Never use tx.origin for authorization. Let's say you have a wallet contract like this: +Never use ``tx.origin`` for authorization. +Let's say you have a wallet contract like this: .. code-block:: solidity @@ -272,7 +281,11 @@ Now someone tricks you into sending Ether to the address of this attack wallet: } } -If your wallet had checked ``msg.sender`` for authorization, it would get the address of the attack wallet, instead of the owner address. But by checking ``tx.origin``, it gets the original address that kicked off the transaction, which is still the owner address. The attack wallet instantly drains all your funds. +If your wallet had checked ``msg.sender`` for authorization, it would get the address of the attack wallet, +instead of the owner's address. +But by checking ``tx.origin``, it gets the original address that kicked off the transaction, +which is still the owner's address. +The attack wallet instantly drains all your funds. .. _underflow-overflow: @@ -312,16 +325,14 @@ Try to use ``require`` to limit the size of inputs to a reasonable range and use Clearing Mappings ================= -The Solidity type ``mapping`` (see :ref:`mapping-types`) is a storage-only -key-value data structure that does not keep track of the keys that were -assigned a non-zero value. Because of that, cleaning a mapping without extra -information about the written keys is not possible. -If a ``mapping`` is used as the base type of a dynamic storage array, deleting -or popping the array will have no effect over the ``mapping`` elements. The -same happens, for example, if a ``mapping`` is used as the type of a member -field of a ``struct`` that is the base type of a dynamic storage array. The -``mapping`` is also ignored in assignments of structs or arrays containing a -``mapping``. +The Solidity type ``mapping`` (see :ref:`mapping-types`) is a storage-only key-value data structure +that does not keep track of the keys that were assigned a non-zero value. +Because of that, cleaning a mapping without extra information about the written keys is not possible. +If a ``mapping`` is used as the base type of a dynamic storage array, +deleting or popping the array will have no effect over the ``mapping`` elements. +The same happens, for example, if a ``mapping`` is used as the type of a member field of a ``struct`` +that is the base type of a dynamic storage array. +The ``mapping`` is also ignored in assignments of structs or arrays containing a ``mapping``. .. code-block:: solidity @@ -329,19 +340,19 @@ field of a ``struct`` that is the base type of a dynamic storage array. The pragma solidity >=0.6.0 <0.9.0; contract Map { - mapping (uint => uint)[] array; + 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 { @@ -349,15 +360,12 @@ field of a ``struct`` that is the base type of a dynamic storage array. The } } -Consider the example above and the following sequence of calls: ``allocate(10)``, -``writeMap(4, 128, 256)``. +Consider the example above and the following sequence of calls: ``allocate(10)``, ``writeMap(4, 128, 256)``. At this point, calling ``readMap(4, 128)`` returns 256. -If we call ``eraseMaps``, the length of state variable ``array`` is zeroed, but -since its ``mapping`` elements cannot be zeroed, their information stays alive -in the contract's storage. -After deleting ``array``, calling ``allocate(5)`` allows us to access -``array[4]`` again, and calling ``readMap(4, 128)`` returns 256 even without -another call to ``writeMap``. +If we call ``eraseMaps``, the length of the state variable ``array`` is zeroed, +but since its ``mapping`` elements cannot be zeroed, their information stays alive in the contract's storage. +After deleting ``array``, calling ``allocate(5)`` allows us to access ``array[4]`` again, +and calling ``readMap(4, 128)`` returns 256 even without another call to ``writeMap``. If your ``mapping`` information must be deleted, consider using a library similar to `iterable mapping `_, @@ -368,10 +376,11 @@ Minor Details - Types that do not occupy the full 32 bytes might contain "dirty higher order bits". This is especially important if you access ``msg.data`` - it poses a malleability risk: - You can craft transactions that call a function ``f(uint8 x)`` with a raw byte argument - of ``0xff000001`` and with ``0x00000001``. Both are fed to the contract and both will - look like the number ``1`` as far as ``x`` is concerned, but ``msg.data`` will - be different, so if you use ``keccak256(msg.data)`` for anything, you will get different results. + You can craft transactions that call a function ``f(uint8 x)`` + with a raw byte argument of ``0xff000001`` and with ``0x00000001``. + Both are fed to the contract and both will look like the number ``1`` as far as ``x`` is concerned, + but ``msg.data`` will be different, so if you use ``keccak256(msg.data)`` for anything, + you will get different results. *************** Recommendations @@ -381,48 +390,45 @@ Take Warnings Seriously ======================= If the compiler warns you about something, you should change it. -Even if you do not think that this particular warning has security -implications, there might be another issue buried beneath it. -Any compiler warning we issue can be silenced by slight changes to the -code. +Even if you do not think that this particular warning has security implications, +there might be another issue buried beneath it. +Any compiler warning we issue can be silenced by slight changes to the code. -Always use the latest version of the compiler to be notified about all recently -introduced warnings. +Always use the latest version of the compiler to be notified about all recently introduced warnings. -Messages of type ``info`` issued by the compiler are not dangerous, and simply -represent extra suggestions and optional information that the compiler thinks -might be useful to the user. +Messages of type ``info``, issued by the compiler, are not dangerous +and simply represent extra suggestions and optional information +that the compiler thinks might be useful to the user. Restrict the Amount of Ether ============================ -Restrict the amount of Ether (or other tokens) that can be stored in a smart -contract. If your source code, the compiler or the platform has a bug, these -funds may be lost. If you want to limit your loss, limit the amount of Ether. +Restrict the amount of Ether (or other tokens) that can be stored in a smart contract. +If your source code, the compiler or the platform has a bug, these funds may be lost. +If you want to limit your loss, limit the amount of Ether. Keep it Small and Modular ========================= -Keep your contracts small and easily understandable. Single out unrelated -functionality in other contracts or into libraries. General recommendations -about source code quality of course apply: Limit the amount of local variables, -the length of functions and so on. Document your functions so that others -can see what your intention was and whether it is different than what the code does. +Keep your contracts small and easily understandable. +Single out unrelated functionality in other contracts or into libraries. +General recommendations about the source code quality of course apply: +Limit the amount of local variables, the length of functions and so on. +Document your functions so that others can see what your intention was +and whether it is different than what the code does. Use the Checks-Effects-Interactions Pattern =========================================== -Most functions will first perform some checks (who called the function, -are the arguments in range, did they send enough Ether, does the person -have tokens, etc.). These checks should be done first. +Most functions will first perform some checks and they should be done first +(who called the function, are the arguments in range, did they send enough Ether, +does the person have tokens, etc.). -As the second step, if all checks passed, effects to the state variables -of the current contract should be made. Interaction with other contracts -should be the very last step in any function. +As the second step, if all checks passed, effects to the state variables of the current contract should be made. +Interaction with other contracts should be the very last step in any function. -Early contracts delayed some effects and waited for external function -calls to return in a non-error state. This is often a serious mistake -because of the re-entrancy problem explained above. +Early contracts delayed some effects and waited for external function calls to return in a non-error state. +This is often a serious mistake because of the reentrancy problem explained above. Note that, also, calls to known contracts might in turn cause calls to unknown contracts, so it is probably better to just always apply this pattern. @@ -430,24 +436,23 @@ unknown contracts, so it is probably better to just always apply this pattern. Include a Fail-Safe Mode ======================== -While making your system fully decentralised will remove any intermediary, -it might be a good idea, especially for new code, to include some kind -of fail-safe mechanism: +While making your system fully decentralized will remove any intermediary, +it might be a good idea, especially for new code, to include some kind of fail-safe mechanism: -You can add a function in your smart contract that performs some -self-checks like "Has any Ether leaked?", +You can add a function in your smart contract that performs some self-checks like "Has any Ether leaked?", "Is the sum of the tokens equal to the balance of the contract?" or similar things. -Keep in mind that you cannot use too much gas for that, so help through off-chain -computations might be needed there. +Keep in mind that you cannot use too much gas for that, +so help through off-chain computations might be needed there. -If the self-check fails, the contract automatically switches into some kind -of "failsafe" mode, which, for example, disables most of the features, hands over -control to a fixed and trusted third party or just converts the contract into -a simple "give me back my money" contract. +If the self-check fails, the contract automatically switches into some kind of "failsafe" mode, +which, for example, disables most of the features, +hands over control to a fixed and trusted third party +or just converts the contract into a simple "give me back my Ether" contract. Ask for Peer Review =================== The more people examine a piece of code, the more issues are found. -Asking people to review your code also helps as a cross-check to find out whether your code -is easy to understand - a very important criterion for good smart contracts. +Asking people to review your code also helps as a cross-check to find out +whether your code is easy to understand - +a very important criterion for good smart contracts. diff --git a/docs/smtchecker.rst b/docs/smtchecker.rst index 791659897e..f8085b63de 100644 --- a/docs/smtchecker.rst +++ b/docs/smtchecker.rst @@ -73,7 +73,7 @@ Tutorial Overflow ======== -.. code-block:: Solidity +.. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0; @@ -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) { @@ -97,7 +97,7 @@ Overflow The contract above shows an overflow check example. The SMTChecker does not check underflow and overflow by default for Solidity >=0.8.7, -so we need to use the command line option ``--model-checker-targets "underflow,overflow"`` +so we need to use the command-line option ``--model-checker-targets "underflow,overflow"`` or the JSON option ``settings.modelChecker.targets = ["underflow", "overflow"]``. See :ref:`this section for targets configuration`. Here, it reports the following: @@ -116,13 +116,13 @@ 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, the SMTChecker proves that no overflow is reachable (by not reporting warnings): -.. code-block:: Solidity +.. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0; @@ -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,25 +155,25 @@ 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! -.. code-block:: Solidity +.. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 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)); } } @@ -182,20 +182,20 @@ The following code searches for the maximum element of an unrestricted array of numbers, and asserts the property that the found element must be greater or equal every element in the array. -.. code-block:: Solidity +.. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 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; } @@ -216,21 +216,21 @@ All the properties are correctly proven safe. Feel free to change the properties and/or add restrictions on the array to see different results. For example, changing the code to -.. code-block:: Solidity +.. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 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 @@ -268,7 +268,7 @@ Let us place a robot at position (0, 0). The robot can only move diagonally, one and cannot move outside the grid. The robot's state machine can be represented by the smart contract below. -.. code-block:: Solidity +.. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0; @@ -319,7 +319,7 @@ We can also trick the SMTChecker into giving us a path to a certain position we think might be reachable. We can add the property that (2, 4) is *not* reachable, by adding the following function. -.. code-block:: Solidity +.. code-block:: solidity function reach_2_4() public view { assert(!(x == 2 && y == 4)); @@ -368,7 +368,7 @@ In some cases, it is possible to automatically infer properties over state variables that are still true even if the externally called code can do anything, including reenter the caller contract. -.. code-block:: Solidity +.. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.0; @@ -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 { @@ -412,7 +412,7 @@ is already "locked", so it would not be possible to change the value of ``x``, regardless of what the unknown called code does. If we "forget" to use the ``mutex`` modifier on function ``set``, the -SMTChecker is able to synthesize the behaviour of the externally called code so +SMTChecker is able to synthesize the behavior of the externally called code so that the assertion fails: .. code-block:: text @@ -483,6 +483,14 @@ All targets are checked by default, except underflow and overflow for Solidity > There is no precise heuristic on how and when to split verification targets, but it can be useful especially when dealing with large contracts. +Proved Targets +============== + +If there are any proved targets, the SMTChecker issues one warning per engine stating +how many targets were proved. If the user wishes to see all the specific +proved targets, the CLI option ``--model-checker-show-proved`` and +the JSON option ``settings.modelChecker.showProved = true`` can be used. + Unproved Targets ================ @@ -491,6 +499,23 @@ how many unproved targets there are. If the user wishes to see all the specific unproved targets, the CLI option ``--model-checker-show-unproved`` and the JSON option ``settings.modelChecker.showUnproved = true`` can be used. +Unsupported Language Features +============================= + +Certain Solidity language features are not completely supported by the SMT +encoding that the SMTChecker applies, for example assembly blocks. +The unsupported construct is abstracted via overapproximation to preserve +soundness, meaning any properties reported safe are safe even though this +feature is unsupported. +However such abstraction may cause false positives when the target properties +depend on the precise behavior of the unsupported feature. +If the encoder encounters such cases it will by default report a generic warning +stating how many unsupported features it has seen. +If the user wishes to see all the specific unsupported features, the CLI option +``--model-checker-show-unsupported`` and the JSON option +``settings.modelChecker.showUnsupported = true`` can be used, where their default +value is ``false``. + Verified Contracts ================== @@ -518,13 +543,196 @@ which has the following form: "source2.sol": ["contract2", "contract3"] } +Trusted External Calls +====================== + +By default, the SMTChecker does not assume that compile-time available code +is the same as the runtime code for external calls. Take the following contracts +as an example: + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.8.0; + + contract Ext { + uint public x; + function setX(uint _x) public { x = _x; } + } + contract MyContract { + function callExt(Ext _e) public { + _e.setX(42); + assert(_e.x() == 42); + } + } + +When ``MyContract.callExt`` is called, an address is given as the argument. +At deployment time, we cannot know for sure that address ``_e`` actually +contains a deployment of contract ``Ext``. +Therefore, the SMTChecker will warn that the assertion above can be violated, +which is true, if ``_e`` contains another contract than ``Ext``. + +However, it can be useful to treat these external calls as trusted, for example, +to test that different implementations of an interface conform to the same property. +This means assuming that address ``_e`` indeed was deployed as contract ``Ext``. +This mode can be enabled via the CLI option ``--model-checker-ext-calls=trusted`` +or the JSON field ``settings.modelChecker.extCalls: "trusted"``. + +Please be aware that enabling this mode can make the SMTChecker analysis much more +computationally costly. + +An important part of this mode is that it is applied to contract types and high +level external calls to contracts, and not low level calls such as ``call`` and +``delegatecall``. The storage of an address is stored per contract type, and +the SMTChecker assumes that an externally called contract has the type of the +caller expression. Therefore, casting an ``address`` or a contract to +different contract types will yield different storage values and can give +unsound results if the assumptions are inconsistent, such as the example below: + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.8.0; + + contract D { + constructor(uint _x) { x = _x; } + uint public x; + function setX(uint _x) public { x = _x; } + } + + contract E { + constructor() { x = 2; } + uint public x; + function setX(uint _x) public { x = _x; } + } + + contract C { + function f() public { + address d = address(new D(42)); + + // `d` was deployed as `D`, so its `x` should be 42 now. + assert(D(d).x() == 42); // should hold + assert(D(d).x() == 43); // should fail + + // E and D have the same interface, so the following + // call would also work at runtime. + // However, the change to `E(d)` is not reflected in `D(d)`. + E(d).setX(1024); + + // Reading from `D(d)` now will show old values. + // The assertion below should fail at runtime, + // but succeeds in this mode's analysis (unsound). + assert(D(d).x() == 42); + // The assertion below should succeed at runtime, + // but fails in this mode's analysis (false positive). + assert(D(d).x() == 1024); + } + } + +Due to the above, make sure that the trusted external calls to a certain +variable of ``address`` or ``contract`` type always have the same caller +expression type. + +It is also helpful to cast the called contract's variable as the type of the +most derived type in case of inheritance. + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.8.0; + + interface Token { + function balanceOf(address _a) external view returns (uint); + function transfer(address _to, uint _amt) external; + } + + contract TokenCorrect is Token { + mapping (address => uint) balance; + constructor(address _a, uint _b) { + balance[_a] = _b; + } + function balanceOf(address _a) public view override returns (uint) { + return balance[_a]; + } + function transfer(address _to, uint _amt) public override { + require(balance[msg.sender] >= _amt); + balance[msg.sender] -= _amt; + balance[_to] += _amt; + } + } + + contract Test { + function property_transfer(address _token, address _to, uint _amt) public { + require(_to != address(this)); + + TokenCorrect t = TokenCorrect(_token); + + uint xPre = t.balanceOf(address(this)); + require(xPre >= _amt); + uint yPre = t.balanceOf(_to); + + t.transfer(_to, _amt); + uint xPost = t.balanceOf(address(this)); + uint yPost = t.balanceOf(_to); + + assert(xPost == xPre - _amt); + assert(yPost == yPre + _amt); + } + } + +Note that in function ``property_transfer``, the external calls are +performed on variable ``t``. + +Another caveat of this mode are calls to state variables of contract type +outside the analyzed contract. In the code below, even though ``B`` deploys +``A``, it is also possible for the address stored in ``B.a`` to be called by +anyone outside of ``B`` in between transactions to ``B`` itself. To reflect the +possible changes to ``B.a``, the encoding allows an unbounded number of calls +to be made to ``B.a`` externally. The encoding will keep track of ``B.a``'s +storage, therefore assertion (2) should hold. However, currently the encoding +allows such calls to be made from ``B`` conceptually, therefore assertion (3) +fails. Making the encoding stronger logically is an extension of the trusted +mode and is under development. Note that the encoding does not keep track of +storage for ``address`` variables, therefore if ``B.a`` had type ``address`` +the encoding would assume that its storage does not change in between +transactions to ``B``. + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.8.0; + + contract A { + uint public x; + address immutable public owner; + constructor() { + owner = msg.sender; + } + function setX(uint _x) public { + require(msg.sender == owner); + x = _x; + } + } + + contract B { + A a; + constructor() { + a = new A(); + assert(a.x() == 0); // (1) should hold + } + function g() public view { + assert(a.owner() == address(this)); // (2) should hold + assert(a.x() == 0); // (3) should hold, but fails due to a false positive + } + } + Reported Inferred Inductive Invariants ====================================== For properties that were proved safe with the CHC engine, the SMTChecker can retrieve inductive invariants that were inferred by the Horn solver as part of the proof. -Currently two types of invariants can be reported to the user: +Currently only two types of invariants can be reported to the user: - Contract Invariants: these are properties over the contract's state variables that are true before and after every possible transaction that the contract may ever run. For example, ``x >= y``, where ``x`` and ``y`` are a contract's state variables. @@ -543,7 +751,7 @@ and modulo operations inside Horn rules. Because of that, by default the Solidity division and modulo operations are encoded using the constraint ``a = b * d + m`` where ``d = a / b`` and ``m = a % b``. However, other solvers, such as Eldarica, prefer the syntactically precise operations. -The command line flag ``--model-checker-div-mod-no-slacks`` and the JSON option +The command-line flag ``--model-checker-div-mod-no-slacks`` and the JSON option ``settings.modelChecker.divModNoSlacks`` can be used to toggle the encoding depending on the used solver preferences. @@ -614,20 +822,26 @@ which is primarily an SMT solver and makes `Spacer `_ which does both. The user can choose which solvers should be used, if available, via the CLI -option ``--model-checker-solvers {all,cvc4,smtlib2,z3}`` or the JSON option +option ``--model-checker-solvers {all,cvc4,eld,smtlib2,z3}`` or the JSON option ``settings.modelChecker.solvers=[smtlib2,z3]``, where: - ``cvc4`` is only available if the ``solc`` binary is compiled with it. Only BMC uses ``cvc4``. +- ``eld`` is used via its binary which must be installed in the system. Only CHC uses ``eld``, and only if ``z3`` is not enabled. - ``smtlib2`` outputs SMT/Horn queries in the `smtlib2 `_ format. These can be used together with the compiler's `callback mechanism `_ so that any solver binary from the system can be employed to synchronously return the results of the queries to the compiler. - This is currently the only way to use Eldarica, for example, since it does not have a C++ API. This can be used by both BMC and CHC depending on which solvers are called. - ``z3`` is available - if ``solc`` is compiled with it; - - 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. + - 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, and conversely, only use older z3 with older solc releases. + We also recommend using the latest z3 release which is what SMTChecker also does. 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 @@ -679,7 +893,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 +968,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/solidity_logo.svg b/docs/solidity_logo.svg new file mode 100644 index 0000000000..86b9f4995b --- /dev/null +++ b/docs/solidity_logo.svg @@ -0,0 +1,27 @@ + + + + +Vector 1 +Created with Sketch. + + + + + + + + + + + + + diff --git a/docs/structure-of-a-contract.rst b/docs/structure-of-a-contract.rst index 740cce861a..51d99a8036 100644 --- a/docs/structure-of-a-contract.rst +++ b/docs/structure-of-a-contract.rst @@ -112,11 +112,11 @@ Events are convenience interfaces with the EVM logging facilities. .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.4.21 <0.9.0; + pragma solidity ^0.8.22; - contract SimpleAuction { - event HighestBidIncreased(address bidder, uint amount); // Event + event HighestBidIncreased(address bidder, uint amount); // Event + contract SimpleAuction { function bid() public payable { // ... emit HighestBidIncreased(msg.sender, msg.value); // Triggering event diff --git a/docs/style-guide.rst b/docs/style-guide.rst index 177f4a7987..427ede5ee3 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. @@ -16,19 +16,19 @@ Many projects will implement their own style guides. In the event of conflicts, project specific style guides take precedence. The structure and many of the recommendations within this style guide were -taken from python's -`pep8 style guide `_. +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 -`pep8 `_ +Solidity code. The goal of this guide is *consistency*. A quote from Python's +`pep8 `_ captures this concept well. .. note:: 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 do not 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); @@ -234,7 +233,7 @@ Yes: bytes32[] options ); - LongAndLotsOfArgs( + emit LongAndLotsOfArgs( sender, recipient, publicKey, @@ -252,7 +251,7 @@ No: uint256 amount, bytes32[] options); - LongAndLotsOfArgs(sender, + emit LongAndLotsOfArgs(sender, recipient, publicKey, amount, @@ -281,6 +280,7 @@ Yes: // ... } + contract B is Owned { // ... } @@ -438,17 +438,17 @@ 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: +Do not include a whitespace in the receive and fallback functions: Yes: @@ -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: @@ -1040,27 +1045,55 @@ No: Order of Layout *************** -Layout contract elements in the following order: +Contract elements should be laid out in the following order: 1. Pragma statements 2. Import statements -3. Interfaces -4. Libraries -5. Contracts +3. Events +4. Errors +5. Interfaces +6. Libraries +7. Contracts Inside each contract, library or interface, use the following order: 1. Type declarations 2. State variables 3. Events -4. Modifiers -5. Functions +4. Errors +5. Modifiers +6. Functions .. note:: It might be clearer to declare types close to their use in events or state variables. +Yes: + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.8.4 <0.9.0; + + abstract contract Math { + error DivideByZero(); + function divide(int256 numerator, int256 denominator) public virtual returns (uint256); + } + +No: + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.8.4 <0.9.0; + + abstract contract Math { + function divide(int256 numerator, int256 denominator) public virtual returns (uint256); + error DivideByZero(); + } + + ****************** Naming Conventions ****************** @@ -1086,12 +1119,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. @@ -1127,15 +1158,15 @@ Yes: contract Owned { address public owner; - constructor() { - owner = msg.sender; - } - modifier onlyOwner { require(msg.sender == owner); _; } + constructor() { + owner = msg.sender; + } + function transferOwnership(address newOwner) public onlyOwner { owner = newOwner; } @@ -1166,15 +1197,15 @@ No: contract owned { address public owner; - constructor() { - owner = msg.sender; - } - modifier onlyOwner { require(msg.sender == owner); _; } + constructor() { + owner = msg.sender; + } + function transferOwnership(address newOwner) public onlyOwner { owner = newOwner; } @@ -1250,10 +1281,25 @@ 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 +an existing state variable, function, built-in or otherwise reserved name. + +Underscore Prefix for Non-external Functions and Variables +========================================================== + +* ``_singleLeadingUnderscore`` + +This convention is suggested for non-external functions and state variables (``private`` or ``internal``). State variables without a specified visibility are ``internal`` by default. -This convention is suggested when the desired name collides with that of a -built-in or otherwise reserved name. +When designing a smart contract, the public-facing API (functions that can be called by any account) +is an important consideration. +Leading underscores allow you to immediately recognize the intent of such functions, +but more importantly, if you change a function from non-external to external (including ``public``) +and rename it accordingly, this forces you to review every call site while renaming. +This can be an important manual check against unintended external functions +and a common source of security vulnerabilities (avoid find-replace-all tooling for this change). .. _style_guide_natspec: diff --git a/docs/types/conversion.rst b/docs/types/conversion.rst index 7e266d1bd4..dafb336bd0 100644 --- a/docs/types/conversion.rst +++ b/docs/types/conversion.rst @@ -44,7 +44,7 @@ Explicit Conversions If the compiler does not allow implicit conversion but you are confident a conversion will work, an explicit type conversion is sometimes possible. This may -result in unexpected behaviour and allows you to bypass some security +result in unexpected behavior and allows you to bypass some security features of the compiler, so be sure to test that the result is what you want and expect! @@ -130,6 +130,7 @@ If the array is shorter than the target type, it will be padded with zeros at th } } +.. index:: ! literal;conversion, literal;rational, literal;hexadecimal number .. _types-conversion-literals: Conversions between Literals and Elementary Types @@ -152,6 +153,8 @@ that is large enough to represent it without truncation: converted to an integer type. From 0.8.0, such explicit conversions are as strict as implicit conversions, i.e., they are only allowed if the literal fits in the resulting range. +.. index:: literal;string, literal;hexadecimal + Fixed-Size Byte Arrays ---------------------- @@ -182,12 +185,18 @@ if their number of characters matches the size of the bytes type: bytes2 e = "x"; // not allowed bytes2 f = "xyz"; // not allowed +.. index:: literal;address + 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..454caaf05d 100644 --- a/docs/types/mapping-types.rst +++ b/docs/types/mapping-types.rst @@ -4,12 +4,13 @@ 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 -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. +Mapping types use the syntax ``mapping(KeyType KeyName? => ValueType ValueName?)`` and variables of +mapping type are declared using the syntax ``mapping(KeyType KeyName? => ValueType ValueName?) +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. ``KeyName`` +and ``ValueName`` are optional (so ``mapping(KeyType => ValueType)`` works as well) and can be any +valid identifier that is not a type. 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 +30,12 @@ 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 +with name ``KeyName`` (if specified) for the getter. +If ``ValueType`` is a value type or a struct, the getter returns ``ValueType`` with +name ``ValueName`` (if specified). +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 @@ -64,6 +67,25 @@ contract that returns the value at the specified address. The example below is a simplified version of an `ERC20 token `_. ``_allowances`` is an example of a mapping type inside another mapping type. + +In the example below, the optional ``KeyName`` and ``ValueName`` are provided for the mapping. +It does not affect any contract functionality or bytecode, it only sets the ``name`` field +for the inputs and outputs in the ABI for the mapping's getter. + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity ^0.8.18; + + contract MappingExampleWithNames { + mapping(address user => uint balance) public balances; + + function update(uint newBalance) public { + balances[msg.sender] = newBalance; + } + } + + The example below uses ``_allowances`` to record the amount someone else is allowed to withdraw from your account. .. code-block:: solidity @@ -73,8 +95,8 @@ The example below uses ``_allowances`` to record the amount someone else is allo contract MappingExample { - mapping (address => uint256) private _balances; - mapping (address => mapping (address => uint256)) private _allowances; + mapping(address => uint256) private _balances; + mapping(address => mapping(address => uint256)) private _allowances; event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); @@ -119,14 +141,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 +159,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 +190,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 +234,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..d2e9300e64 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -47,8 +47,8 @@ non-persistent area where function arguments are stored, and behaves mostly like .. _data-location-assignment: -Data location and assignment behaviour -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Data location and assignment behavior +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data locations are not only relevant for persistency of data, but also for the semantics of assignments: @@ -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 @@ -131,9 +133,13 @@ It is possible to mark state variable arrays ``public`` and have Solidity create The numeric index becomes a required parameter for the getter. Accessing an array past its end causes a failing assertion. Methods ``.push()`` and ``.push(value)`` can be used -to append a new element at the end of the array, where ``.push()`` appends a zero-initialized element and returns +to append a new element at the end of a dynamically-sized array, where ``.push()`` appends a zero-initialized element and returns a reference to it. +.. note:: + Dynamically-sized arrays can only be resized in storage. + In memory, such arrays can be of arbitrary size but the size cannot be changed once an array is allocated. + .. index:: ! string, ! bytes .. _strings: @@ -150,7 +156,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 +171,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: + +The functions ``bytes.concat`` and ``string.concat`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``bytes.concat`` function -^^^^^^^^^^^^^^^^^^^^^^^^^ +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. -You can concatenate a variable number of ``bytes`` or ``bytes1 ... bytes32`` using ``bytes.concat``. +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 @@ -220,7 +235,7 @@ with the :ref:`default value`. } } -.. index:: ! array;literals, ! inline;arrays +.. index:: ! literal;array, ! inline;arrays Array Literals ^^^^^^^^^^^^^^ @@ -337,10 +352,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()`` @@ -357,7 +372,7 @@ Array Members .. note:: In EVM versions before Byzantium, it was not possible to access - dynamic arrays return from function calls. If you call functions + dynamic arrays returned from function calls. If you call functions that return dynamic arrays, make sure to use an EVM that is set to Byzantium mode. @@ -367,20 +382,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 +419,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 +476,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 behavior of dangling storage references in the +current version of the compiler, any code with dangling references should be +considered to have *undefined behavior*. In particular, this means that +any future version of the compiler may change the behavior of code that +involves dangling references. + +Be sure to avoid dangling references in your code! + .. index:: ! array;slice .. _array-slices: @@ -502,21 +633,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 behavior, 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."); } } @@ -555,11 +686,11 @@ shown in the following example: uint fundingGoal; uint numFunders; uint amount; - mapping (uint => Funder) funders; + mapping(uint => Funder) funders; } uint numCampaigns; - mapping (uint => Campaign) campaigns; + mapping(uint => Campaign) campaigns; function newCampaign(address payable beneficiary, uint goal) public returns (uint campaignID) { campaignID = numCampaigns++; // campaignID is return variable diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 215a18ceec..12fcb0b171 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -4,8 +4,7 @@ Value Types =========== -The following types are also called value types because variables of these -types will always be passed by value, i.e. they are always copied when they +The following are called value types because their variables will always be passed by value, i.e. they are always copied when they are used as function arguments or in assignments. .. index:: ! bool, ! true, ! false @@ -47,7 +46,7 @@ access the minimum and maximum value representable by the type. Integers in Solidity are restricted to a certain range. For example, with ``uint32``, this is ``0`` up to ``2**32 - 1``. There are two modes in which arithmetic is performed on these types: The "wrapping" or "unchecked" mode and the "checked" mode. - By default, arithmetic is always "checked", which mean that if the result of an operation falls outside the value range + By default, arithmetic is always "checked", meaning that if an operation's result falls outside the value range of the type, the call is reverted through a :ref:`failing assertion`. You can switch to "unchecked" mode using ``unchecked { ... }``. More details can be found in the section about :ref:`unchecked `. @@ -141,7 +140,7 @@ Exponentiation Exponentiation is only available for unsigned types in the exponent. The resulting type of an exponentiation is always equal to the type of the base. Please take care that it is -large enough to hold the result and prepare for potential assertion failures or wrapping behaviour. +large enough to hold the result and prepare for potential assertion failures or wrapping behavior. .. note:: In checked mode, exponentiation only uses the comparatively cheap ``exp`` opcode for small bases. @@ -182,13 +181,14 @@ Operators: Address ------- -The address type comes in two flavours, which are largely identical: +The address type comes in two largely identical flavors: - ``address``: Holds a 20 byte value (size of an Ethereum address). - ``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 +209,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: @@ -254,13 +257,13 @@ reverts on failure. * ``send`` -Send is the low-level counterpart of ``transfer``. If the execution fails, the current contract will not stop with an exception, but ``send`` will return ``false``. +``send`` is the low-level counterpart of ``transfer``. If the execution fails, the current contract will not stop with an exception, but ``send`` will return ``false``. .. warning:: There are some dangers in using ``send``: The transfer fails if the call stack depth is at 1024 (this can always be forced by the caller) and it also fails if the recipient runs out of gas. So in order to make safe Ether transfers, always check the return value of ``send``, use ``transfer`` or even better: - use a pattern where the recipient withdraws the money. + use a pattern where the recipient withdraws the Ether. * ``call``, ``delegatecall`` and ``staticcall`` @@ -331,7 +334,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 @@ -410,15 +415,7 @@ Members: .. note:: Prior to version 0.8.0, ``byte`` used to be an alias for ``bytes1``. -Dynamically-sized byte array ----------------------------- - -``bytes``: - Dynamically-sized byte array, see :ref:`arrays`. Not a value-type! -``string``: - Dynamically-sized UTF-8-encoded string, see :ref:`arrays`. Not a value-type! - -.. index:: address, literal;address +.. index:: address, ! literal;address .. _address_literals: @@ -434,7 +431,7 @@ an error. You can prepend (for integer types) or append (for bytesNN types) zero .. note:: The mixed-case address checksum format is defined in `EIP-55 `_. -.. index:: literal, literal;rational +.. index:: integer, rational number, ! literal;rational .. _rational_literals: @@ -445,8 +442,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 +457,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 +465,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 @@ -503,7 +509,7 @@ regardless of the type of the right (exponent) operand. uint128 a = 1; uint128 b = 2.5 + a + 0.5; -.. index:: literal, literal;string, string +.. index:: ! literal;string, string .. _string_literals: String Literals and Types @@ -550,6 +556,8 @@ character sequence ``abcdef``. Any Unicode line terminator which is not a newline (i.e. LF, VF, FF, CR, NEL, LS, PS) is considered to terminate the string literal. Newline only terminates the string literal if it is not preceded by a ``\``. +.. index:: ! literal;unicode + Unicode Literals ---------------- @@ -560,7 +568,7 @@ They also support the very same escape sequences as regular string literals. string memory a = unicode"Hello 😃"; -.. index:: literal, bytes +.. index:: ! literal;hexadecimal, bytes Hexadecimal Literals -------------------- @@ -574,7 +582,8 @@ of the hexadecimal sequence. Multiple hexadecimal literals separated by whitespace are concatenated into a single literal: ``hex"00112233" hex"44556677"`` is equivalent to ``hex"0011223344556677"`` -Hexadecimal literals behave like :ref:`string literals ` and have the same convertibility restrictions. +Hexadecimal literals in some ways behave like :ref:`string literals ` but are not +implicitly convertible to the ``string`` type. .. index:: enum @@ -638,18 +647,18 @@ smallest and respectively largest value of the given enum. .. _user-defined-value-types: -User Defined Value Types +User-defined Value Types ------------------------ -A user defined value type allows creating a zero cost abstraction over an elementary value type. +A user-defined value type allows creating a zero cost abstraction over an elementary value type. This is similar to an alias, but with stricter type requirements. -A user defined value type is defined using ``type C is V``, where ``C`` is the name of the newly +A user-defined value type is defined using ``type C is V``, where ``C`` is the name of the newly introduced type and ``V`` has to be a built-in value type (the "underlying type"). The function ``C.wrap`` is used to convert from the underlying type to the custom type. Similarly, the function ``C.unwrap`` is used to convert from the custom type to the underlying type. -The type ``C`` does not have any operators or bound member functions. In particular, even the +The type ``C`` does not have any operators or attached member functions. In particular, even the operator ``==`` is not defined. Explicit and implicit conversions to and from other types are disallowed. @@ -665,7 +674,7 @@ type with 18 decimals and a minimal library to do arithmetic operations on the t // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.8; - // Represent a 18 decimal, 256 bit wide fixed point type using a user defined value type. + // Represent a 18 decimal, 256 bit wide fixed point type using a user-defined value type. type UFixed256x18 is uint256; /// A minimal library to do fixed point operations on UFixed256x18. @@ -755,6 +764,16 @@ confusing, but in essence, if a function is ``payable``, this means that it also accepts a payment of zero Ether, so it also is ``non-payable``. On the other hand, a ``non-payable`` function will reject Ether sent to it, so ``non-payable`` functions cannot be converted to ``payable`` functions. +To clarify, rejecting ether is more restrictive than not rejecting ether. +This means you can override a payable function with a non-payable but not the +other way around. + +Additionally, When you define a ``non-payable`` function pointer, +the compiler does not enforce that the pointed function will actually reject ether. +Instead, it enforces that the function pointer is never used to send ether. +Which makes it possible to assign a ``payable`` function pointer to a ``non-payable`` +function pointer ensuring both types behave the same way, i.e, both cannot be used +to send ether. If a function type variable is not initialised, calling it results in a :ref:`Panic error`. The same happens if you call a function after using ``delete`` @@ -774,6 +793,24 @@ This includes private, internal and public functions of both contracts and libra functions. External function types, on the other hand, are only compatible with public and external contract functions. + +.. note:: + External functions with ``calldata`` parameters are incompatible with external function types with ``calldata`` parameters. + They are compatible with the corresponding types with ``memory`` parameters instead. + For example, there is no function that can be pointed at by a value of type ``function (string calldata) external`` while + ``function (string memory) external`` can point at both ``function f(string memory) external {}`` and + ``function g(string calldata) external {}``. + This is because for both locations the arguments are passed to the function in the same way. + The caller cannot pass its calldata directly to an external function and always ABI-encodes the arguments into memory. + Marking the parameters as ``calldata`` only affects the implementation of the external function and is + meaningless in a function pointer on the caller's side. + +.. warning:: + Comparison of internal function pointers can have unexpected results in the legacy pipeline with the optimizer enabled, + as it can collapse identical functions into one, which will then lead to said function pointers comparing as equal instead of not. + Such comparisons are not advised, and will lead to the compiler issuing a warning, until the next breaking release (0.9.0), + when the warning will be upgraded to an error, thereby making such comparisons disallowed. + Libraries are excluded because they require a ``delegatecall`` and use :ref:`a different ABI convention for their selectors `. Functions declared in interfaces do not have definitions so pointing at them does not make sense either. diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 70125636c2..a0422c32df 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -1,8 +1,10 @@ +.. index:: ! denomination + ************************************** Units and Globally Available Variables ************************************** -.. index:: wei, finney, szabo, gwei, ether +.. index:: ! wei, ! finney, ! szabo, ! gwei, ! ether, ! denomination;ether Ether Units =========== @@ -21,7 +23,7 @@ The only effect of the subdenomination suffix is a multiplication by a power of .. note:: The denominations ``finney`` and ``szabo`` have been removed in version 0.7.0. -.. index:: time, seconds, minutes, hours, days, weeks, years +.. index:: ! seconds, ! minutes, ! hours, ! days, ! weeks, ! years, ! denomination;time Time Units ========== @@ -52,7 +54,7 @@ interpret a function parameter in days, you can in the following way: function f(uint start, uint daysAfter) public { if (block.timestamp >= start + daysAfter * 1 days) { - // ... + // ... } } @@ -65,19 +67,24 @@ There are special variables and functions which always exist in the global namespace and are mainly used to provide information about the blockchain or are general-use utility functions. -.. index:: abi, block, coinbase, difficulty, encode, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, gas price, origin +.. index:: abi, block, coinbase, difficulty, prevrandao, encode, number, block;number, timestamp, block;timestamp, block;basefee, block;blobbasefee, msg, data, gas, sender, value, gas price, origin Block and Transaction Properties -------------------------------- - ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block when ``blocknumber`` is one of the 256 most recent blocks; otherwise returns zero +- ``blobhash(uint index) returns (bytes32)``: versioned hash of the ``index``-th blob associated with the current transaction. + A versioned hash consists of a single byte representing the version (currently ``0x01``), followed by the last 31 bytes + of the SHA256 hash of the KZG commitment (`EIP-4844 `_). - ``block.basefee`` (``uint``): current block's base fee (`EIP-3198 `_ and `EIP-1559 `_) +- ``block.blobbasefee`` (``uint``): current block's blob base fee (`EIP-7516 `_ and `EIP-4844 `_) - ``block.chainid`` (``uint``): current chain id - ``block.coinbase`` (``address payable``): current block miner's address -- ``block.difficulty`` (``uint``): current block difficulty +- ``block.difficulty`` (``uint``): current block difficulty (``EVM < Paris``). For other EVM versions it behaves as a deprecated alias for ``block.prevrandao`` (`EIP-4399 `_ ) - ``block.gaslimit`` (``uint``): current block gaslimit - ``block.number`` (``uint``): current block number +- ``block.prevrandao`` (``uint``): random number provided by the beacon chain (``EVM >= Paris``) - ``block.timestamp`` (``uint``): current block timestamp as seconds since unix epoch - ``gasleft() returns (uint256)``: remaining gas - ``msg.data`` (``bytes calldata``): complete calldata @@ -104,7 +111,7 @@ Block and Transaction Properties 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. + and just retry a different hash if they did not receive any compensation, e.g. Ether. 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 @@ -154,6 +161,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 @@ -223,8 +238,8 @@ Mathematical and Cryptographic Functions for _transaction_ signatures (see `EIP-2 `_), but the ecrecover function remained unchanged. - This is usually not a problem unless you require signatures to be unique or - use them to identify items. OpenZeppelin have a `ECDSA helper library `_ that you can use as a wrapper for ``ecrecover`` without this issue. + This is usually not a problem unless you require signatures to be unique or use them to identify items. + OpenZeppelin has an `ECDSA helper library `_ that you can use as a wrapper for ``ecrecover`` without this issue. .. note:: @@ -271,7 +286,7 @@ For more information, see the section on :ref:`address`. There are some dangers in using ``send``: The transfer fails if the call stack depth is at 1024 (this can always be forced by the caller) and it also fails if the recipient runs out of gas. So in order to make safe Ether transfers, always check the return value of ``send``, use ``transfer`` or even better: - Use a pattern where the recipient withdraws the money. + Use a pattern where the recipient withdraws the Ether. .. warning:: Due to the fact that the EVM considers a call to a non-existing contract to always succeed, @@ -302,13 +317,16 @@ For more information, see the section on :ref:`address`. semantics than ``delegatecall``. -.. index:: this, selfdestruct +.. index:: this, selfdestruct, super -Contract Related +Contract-related ---------------- ``this`` (current contract's type) - the current contract, explicitly convertible to :ref:`address` + The current contract, explicitly convertible to :ref:`address` + +``super`` + A contract one level higher in the inheritance hierarchy ``selfdestruct(address payable recipient)`` Destroy the current contract, sending its funds to the given :ref:`address` @@ -318,11 +336,13 @@ Contract Related - the receiving contract's receive function is not executed. - the contract is only really destroyed at the end of the transaction and ``revert`` s might "undo" the destruction. - - - Furthermore, all functions of the current contract are callable directly including the current function. +.. warning:: + From version 0.8.18 and up, the use of ``selfdestruct`` in both Solidity and Yul will trigger a + deprecation warning, since the ``SELFDESTRUCT`` opcode will eventually undergo breaking changes in behavior + as stated in `EIP-6049 `_. + .. note:: Prior to version 0.5.0, there was a function called ``suicide`` with the same semantics as ``selfdestruct``. @@ -364,7 +384,7 @@ The following properties are available for a contract type ``C``: In addition to the properties above, the following properties are available for an interface type ``I``: -``type(I).interfaceId``: +``type(I).interfaceId`` A ``bytes4`` value containing the `EIP-165 `_ interface identifier of the given interface ``I``. This identifier is defined as the ``XOR`` of all function selectors defined within the interface itself - excluding all inherited functions. @@ -376,3 +396,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``. diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index c6c40cacc0..97abbdba9d 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -15,7 +15,7 @@ Using the Commandline Compiler Basic Usage ----------- -One of the build targets of the Solidity repository is ``solc``, the solidity commandline compiler. +One of the build targets of the Solidity repository is ``solc``, the Solidity commandline compiler. Using ``solc --help`` provides you with an explanation of all options. The compiler can produce various outputs, ranging from simple binaries and assembly over an abstract syntax tree (parse tree) to estimations of gas usage. If you only want to compile a single file, you run it as ``solc --bin sourceFile.sol`` and it will print the binary. If you want to get some of the more advanced output variants of ``solc``, it is probably better to tell it to output everything to separate files using ``solc -o outputDirectory --bin --ast-compact-json --asm sourceFile.sol``. @@ -54,7 +54,7 @@ or ../ ` are treated as relative to the directories specified us Furthermore, the part of the path added via these options will not appear in the contract metadata. For security reasons the compiler has :ref:`restrictions on what directories it can access `. -Directories of source files specified on the command line and target paths of +Directories of source files specified on the command-line and target paths of remappings are automatically allowed to be accessed by the file reader, but everything else is rejected by default. Additional paths (and their subdirectories) can be allowed via the @@ -114,15 +114,15 @@ Setting the EVM Version to Target ********************************* When you compile your contract code you can specify the Ethereum virtual machine -version to compile for to avoid particular features or behaviours. +version to compile for to avoid particular features or behaviors. .. warning:: Compiling for the wrong EVM version can result in wrong, strange and failing - behaviour. Please ensure, especially if running a private chain, that you + behavior. Please ensure, especially if running a private chain, that you use matching EVM versions. -On the command line, you can select the EVM version as follows: +On the command-line, you can select the EVM version as follows: .. code-block:: shell @@ -147,20 +147,20 @@ Target Options Below is a list of target EVM versions and the compiler-relevant changes introduced at each version. Backward compatibility is not guaranteed between each version. -- ``homestead`` +- ``homestead`` (*support deprecated*) - (oldest version) -- ``tangerineWhistle`` +- ``tangerineWhistle`` (*support deprecated*) - Gas cost for access to other accounts increased, relevant for gas estimation and the optimizer. - All gas sent by default for external calls, previously a certain amount had to be retained. -- ``spuriousDragon`` +- ``spuriousDragon`` (*support deprecated*) - Gas cost for the ``exp`` opcode increased, relevant for gas estimation and the optimizer. -- ``byzantium`` +- ``byzantium`` (*support deprecated*) - Opcodes ``returndatacopy``, ``returndatasize`` and ``staticcall`` are available in assembly. - The ``staticcall`` opcode is used when calling non-library view or pure functions, which prevents the functions from modifying state at the EVM level, i.e., even applies when you use invalid type conversions. - It is possible to access dynamic data returned from function calls. - ``revert`` opcode introduced, which means that ``revert()`` will not waste gas. - ``constantinople`` - - Opcodes ``create2`, ``extcodehash``, ``shl``, ``shr`` and ``sar`` are available in assembly. + - Opcodes ``create2``, ``extcodehash``, ``shl``, ``shr`` and ``sar`` are available in assembly. - Shifting operators use shifting opcodes and thus need less gas. - ``petersburg`` - The compiler behaves the same way as with constantinople. @@ -170,9 +170,17 @@ at each version. Backward compatibility is not guaranteed between each version. - Gas costs for ``SLOAD``, ``*CALL``, ``BALANCE``, ``EXT*`` and ``SELFDESTRUCT`` increased. The compiler assumes cold gas costs for such operations. This is relevant for gas estimation and the optimizer. -- ``london`` (**default**) +- ``london`` - The block's base fee (`EIP-3198 `_ and `EIP-1559 `_) can be accessed via the global ``block.basefee`` or ``basefee()`` in inline assembly. - +- ``paris`` + - Introduces ``prevrandao()`` and ``block.prevrandao``, and changes the semantics of the now deprecated ``block.difficulty``, disallowing ``difficulty()`` in inline assembly (see `EIP-4399 `_). +- ``shanghai`` (**default**) + - Smaller code size and gas savings due to the introduction of ``push0`` (see `EIP-3855 `_). +- ``cancun`` + - The block's blob base fee (`EIP-7516 `_ and `EIP-4844 `_) can be accessed via the global ``block.blobbasefee`` or ``blobbasefee()`` in inline assembly. + - Introduces ``blobhash()`` in inline assembly and a corresponding global function to retrieve versioned hashes of blobs associated with the transaction (see `EIP-4844 `_). + - Opcode ``mcopy`` is available in assembly (see `EIP-5656 `_). + - Opcodes ``tstore`` and ``tload`` are available in assembly (see `EIP-1153 `_). .. index:: ! standard JSON, ! --standard-json .. _compiler-api: @@ -200,7 +208,7 @@ Input Description .. code-block:: javascript { - // Required: Source code language. Currently supported are "Solidity" and "Yul". + // Required: Source code language. Currently supported are "Solidity", "Yul", "SolidityAST" (experimental), "EVMAssembly" (experimental). "language": "Solidity", // Required "sources": @@ -224,7 +232,7 @@ Input Description "bzzr://56ab...", "ipfs://Qma...", "/tmp/path/to/file.sol" - // If files are used, their directories should be added to the command line via + // If files are used, their directories should be added to the command-line via // `--allow-paths `. ] }, @@ -234,6 +242,33 @@ Input Description "keccak256": "0x234...", // Required (unless "urls" is used): literal contents of the source file "content": "contract destructible is owned { function shutdown() { if (msg.sender == owner) selfdestruct(owner); } }" + }, + "myFile.sol_json.ast": + { + // If language is set to "SolidityAST", an AST needs to be supplied under the "ast" key + // and there can be only one source file present. + // The format is the same as used by the `ast` output. + // Note that importing ASTs is experimental and in particular that: + // - importing invalid ASTs can produce undefined results and + // - no proper error reporting is available on invalid ASTs. + // Furthermore, note that the AST import only consumes the fields of the AST as + // produced by the compiler in "stopAfter": "parsing" mode and then re-performs + // analysis, so any analysis-based annotations of the AST are ignored upon import. + "ast": { ... } + }, + "myFile_evm.json": + { + // If language is set to "EVMAssembly", an EVM Assembly JSON object needs to be supplied + // under the "assemblyJson" key and there can be only one source file present. + // The format is the same as used by the `evm.legacyAssembly` output or `--asm-json` + // output on the command line. + // Note that importing EVM assembly is experimental. + "assemblyJson": + { + ".code": [ ... ], + ".data": { ... }, // optional + "sourceList": [ ... ] // optional (if no `source` node was defined in any `.code` object) + } } }, // Optional @@ -261,9 +296,9 @@ Input Description // The peephole optimizer is always on if no details are given, // use details to switch it off. "peephole": true, - // The inliner is always on if no details are given, - // use details to switch it off. - "inliner": true, + // The inliner is always off if no details are given, + // use details to switch it on. + "inliner": false, // The unused jumpdest remover is always on if no details are given, // use details to switch it off. "jumpdestRemover": true, @@ -276,6 +311,9 @@ Input Description "cse": false, // Optimize representation of literal numbers and strings in code. "constantOptimizer": false, + // Use unchecked arithmetic when incrementing the counter of for loops + // under certain circumstances. It is always on if no details are given. + "simpleCounterForLoopUncheckedIncrement": true, // The new Yul optimizer. Mostly operates on the code of ABI coder v2 // and inline assembly. // It is activated together with the global optimizer setting @@ -287,18 +325,29 @@ Input Description // Improve allocation of stack slots for variables, can free up stack slots early. // Activated by default if the Yul optimizer is activated. "stackAllocation": true, - // Select optimization steps to be applied. - // Optional, the optimizer will use the default sequence if omitted. + // Select optimization steps to be applied. It is also possible to modify both the + // optimization sequence and the clean-up sequence. Instructions for each sequence + // are separated with the ":" delimiter and the values are provided in the form of + // optimization-sequence:clean-up-sequence. For more information see + // "The Optimizer > Selecting Optimizations". + // This field is optional, and if not provided, the default sequences for both + // optimization and clean-up are used. If only one of the sequences is provided + // the other will not be run. + // If only the delimiter ":" is provided then neither the optimization nor the clean-up + // sequence will be run. + // If set to an empty value, only the default clean-up sequence is used and + // no optimization steps are applied. "optimizerSteps": "dhfoDgvulfnTUtnIf..." } } }, // Version of the EVM to compile for. // Affects type checking and code generation. Can be homestead, - // tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul or berlin - "evmVersion": "byzantium", + // tangerineWhistle, spuriousDragon, byzantium, constantinople, + // petersburg, istanbul, berlin, london, paris or shanghai (default) + "evmVersion": "shanghai", // 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": { @@ -323,6 +372,9 @@ Input Description }, // Metadata settings (optional) "metadata": { + // The CBOR metadata is appended at the end of the bytecode by default. + // Setting this to false omits the metadata from the runtime and deploy time code. + "appendCBOR": true, // Use only literal content and not URLs (false by default) "useLiteralContent": true, // Use the given hash method for the metadata hash that is appended to the bytecode. @@ -334,7 +386,7 @@ Input Description // Addresses of the libraries. If not all libraries are given here, // it can result in unlinked objects whose output data is different. "libraries": { - // The top level key is the the name of the source file where the library is used. + // The top level key is the name of the source file where the library is used. // If remappings are used, this source file should match the global path // after remappings were applied. // If this key is an empty string, that refers to a global level. @@ -366,7 +418,9 @@ Input Description // userdoc - User documentation (natspec) // metadata - Metadata // ir - Yul intermediate representation of the code before optimization + // irAst - AST of Yul intermediate representation of the code before optimization // irOptimized - Intermediate representation after optimization + // irOptimizedAst - AST of intermediate representation after optimization // storageLayout - Slots, offsets and types of the contract's state variables. // evm.assembly - New assembly format // evm.legacyAssembly - Old-style assembly format in JSON @@ -380,10 +434,8 @@ Input Description // evm.deployedBytecode.immutableReferences - Map from AST ids to bytecode ranges that reference immutables // evm.methodIdentifiers - The list of function hashes // evm.gasEstimates - Function gas estimates - // ewasm.wast - Ewasm in WebAssembly S-expressions format - // ewasm.wasm - Ewasm in WebAssembly binary format // - // Note that using a using `evm`, `evm.bytecode`, `ewasm`, etc. will select every + // Note that using `evm`, `evm.bytecode`, etc. will select every // target part of that output. Additionally, `*` can be used as a wildcard to request everything. // "outputSelection": { @@ -410,18 +462,27 @@ 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 whether external calls should be considered trusted in case the + // code of the called function is available at compile-time. + // For details see the SMTChecker section. + "extCalls": "trusted", // Choose which types of invariants should be reported to the user: contract, reentrancy. "invariants": ["contract", "reentrancy"], + // Choose whether to output all proved targets. The default is `false`. + "showProved": true, // Choose whether to output all unproved targets. The default is `false`. "showUnproved": true, + // Choose whether to output all unsupported language features. The default is `false`. + "showUnsupported": true, // Choose which solvers should be used, if available. // See the Formal Verification section for the solvers description. "solvers": ["cvc4", "smtlib2", "z3"], @@ -468,7 +529,7 @@ Output Description // Mandatory: Error type, such as "TypeError", "InternalCompilerError", "Exception", etc. // See below for complete list of types. "type": "TypeError", - // Mandatory: Component where the error originated, such as "general", "ewasm", etc. + // Mandatory: Component where the error originated, such as "general" etc. "component": "general", // Mandatory ("error", "warning" or "info", but please note that this may be extended in the future) "severity": "error", @@ -505,8 +566,14 @@ Output Description "userdoc": {}, // Developer documentation (natspec) "devdoc": {}, - // Intermediate representation (string) + // Intermediate representation before optimization (string) "ir": "", + // AST of intermediate representation before optimization + "irAst": {/* ... */}, + // Intermediate representation after optimization (string) + "irOptimized": "", + // AST of intermediate representation after optimization + "irOptimizedAst": {/* ... */}, // See the Storage Layout documentation. "storageLayout": {"storage": [/* ... */], "types": {/* ... */} }, // EVM-related outputs @@ -584,13 +651,6 @@ Output Description "heavyLifting()": "infinite" } } - }, - // Ewasm related outputs - "ewasm": { - // S-expressions format - "wast": "", - // Binary format (hex string) - "wasm": "" } } } @@ -613,230 +673,6 @@ 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. - - -.. _compiler-tools: - -Compiler Tools -************** - -solidity-upgrade ----------------- - -``solidity-upgrade`` can help you to semi-automatically upgrade your contracts -to breaking language changes. While it does not and cannot implement all -required changes for every breaking release, it still supports the ones, that -would need plenty of repetitive manual adjustments otherwise. - -.. note:: - - ``solidity-upgrade`` carries out a large part of the work, but your - contracts will most likely need further manual adjustments. We recommend - using a version control system for your files. This helps reviewing and - eventually rolling back the changes made. - -.. warning:: - - ``solidity-upgrade`` is not considered to be complete or free from bugs, so - please use with care. - -How it Works -~~~~~~~~~~~~ - -You can pass (a) Solidity source file(s) to ``solidity-upgrade [files]``. If -these make use of ``import`` statement which refer to files outside the -current source file's directory, you need to specify directories that -are allowed to read and import files from, by passing -``--allow-paths [directory]``. You can ignore missing files by passing -``--ignore-missing``. - -``solidity-upgrade`` is based on ``libsolidity`` and can parse, compile and -analyse your source files, and might find applicable source upgrades in them. - -Source upgrades are considered to be small textual changes to your source code. -They are applied to an in-memory representation of the source files -given. The corresponding source file is updated by default, but you can pass -``--dry-run`` to simulate to whole upgrade process without writing to any file. - -The upgrade process itself has two phases. In the first phase source files are -parsed, and since it is not possible to upgrade source code on that level, -errors are collected and can be logged by passing ``--verbose``. No source -upgrades available at this point. - -In the second phase, all sources are compiled and all activated upgrade analysis -modules are run alongside compilation. By default, all available modules are -activated. Please read the documentation on -:ref:`available modules ` for further details. - - -This can result in compilation errors that may -be fixed by source upgrades. If no errors occur, no source upgrades are being -reported and you're done. -If errors occur and some upgrade module reported a source upgrade, the first -reported one gets applied and compilation is triggered again for all given -source files. The previous step is repeated as long as source upgrades are -reported. If errors still occur, you can log them by passing ``--verbose``. -If no errors occur, your contracts are up to date and can be compiled with -the latest version of the compiler. - -.. _upgrade-modules: - -Available Upgrade Modules -~~~~~~~~~~~~~~~~~~~~~~~~~ - -+----------------------------+---------+--------------------------------------------------+ -| Module | Version | Description | -+============================+=========+==================================================+ -| ``constructor`` | 0.5.0 | Constructors must now be defined using the | -| | | ``constructor`` keyword. | -+----------------------------+---------+--------------------------------------------------+ -| ``visibility`` | 0.5.0 | Explicit function visibility is now mandatory, | -| | | defaults to ``public``. | -+----------------------------+---------+--------------------------------------------------+ -| ``abstract`` | 0.6.0 | The keyword ``abstract`` has to be used if a | -| | | contract does not implement all its functions. | -+----------------------------+---------+--------------------------------------------------+ -| ``virtual`` | 0.6.0 | Functions without implementation outside an | -| | | interface have to be marked ``virtual``. | -+----------------------------+---------+--------------------------------------------------+ -| ``override`` | 0.6.0 | When overriding a function or modifier, the new | -| | | keyword ``override`` must be used. | -+----------------------------+---------+--------------------------------------------------+ -| ``dotsyntax`` | 0.7.0 | The following syntax is deprecated: | -| | | ``f.gas(...)()``, ``f.value(...)()`` and | -| | | ``(new C).value(...)()``. Replace these calls by | -| | | ``f{gas: ..., value: ...}()`` and | -| | | ``(new C){value: ...}()``. | -+----------------------------+---------+--------------------------------------------------+ -| ``now`` | 0.7.0 | The ``now`` keyword is deprecated. Use | -| | | ``block.timestamp`` instead. | -+----------------------------+---------+--------------------------------------------------+ -| ``constructor-visibility`` | 0.7.0 | Removes visibility of constructors. | -| | | | -+----------------------------+---------+--------------------------------------------------+ - -Please read :doc:`0.5.0 release notes <050-breaking-changes>`, -:doc:`0.6.0 release notes <060-breaking-changes>`, -:doc:`0.7.0 release notes <070-breaking-changes>` and :doc:`0.8.0 release notes <080-breaking-changes>` for further details. - -Synopsis -~~~~~~~~ - -.. code-block:: none - - Usage: solidity-upgrade [options] contract.sol - - Allowed options: - --help Show help message and exit. - --version Show version and exit. - --allow-paths path(s) - Allow a given path for imports. A list of paths can be - supplied by separating them with a comma. - --ignore-missing Ignore missing files. - --modules module(s) Only activate a specific upgrade module. A list of - modules can be supplied by separating them with a comma. - --dry-run Apply changes in-memory only and don't write to input - file. - --verbose Print logs, errors and changes. Shortens output of - upgrade patches. - --unsafe Accept *unsafe* changes. - - - -Bug Reports / Feature Requests -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you found a bug or if you have a feature request, please -`file an issue `_ on Github. - - -Example -~~~~~~~ - -Assume that you have the following contract in ``Source.sol``: - -.. code-block:: Solidity - - pragma solidity >=0.6.0 <0.6.4; - // This will not compile after 0.7.0 - // SPDX-License-Identifier: GPL-3.0 - contract C { - // FIXME: remove constructor visibility and make the contract abstract - constructor() internal {} - } - - contract D { - uint time; - - function f() public payable { - // FIXME: change now to block.timestamp - time = now; - } - } - - contract E { - D d; - - // FIXME: remove constructor visibility - constructor() public {} - - function g() public { - // FIXME: change .value(5) => {value: 5} - d.f.value(5)(); - } - } - - - -Required Changes -^^^^^^^^^^^^^^^^ - -The above contract will not compile starting from 0.7.0. To bring the contract up to date with the -current Solidity version, the following upgrade modules have to be executed: -``constructor-visibility``, ``now`` and ``dotsyntax``. Please read the documentation on -:ref:`available modules ` for further details. - - -Running the Upgrade -^^^^^^^^^^^^^^^^^^^ - -It is recommended to explicitly specify the upgrade modules by using ``--modules`` argument. - -.. code-block:: bash - - solidity-upgrade --modules constructor-visibility,now,dotsyntax Source.sol - -The command above applies all changes as shown below. Please review them carefully (the pragmas will -have to be updated manually.) - -.. code-block:: Solidity - - // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.7.0 <0.9.0; - abstract contract C { - // FIXME: remove constructor visibility and make the contract abstract - constructor() {} - } - - contract D { - uint time; - - function f() public payable { - // FIXME: change now to block.timestamp - time = block.timestamp; - } - } - - contract E { - D d; - - // FIXME: remove constructor visibility - constructor() {} - - function g() public { - // FIXME: change .value(5) => {value: 5} - d.f{value: 5}(); - } - } +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. diff --git a/docs/yul.rst b/docs/yul.rst index 60a2da5b94..3cf2785fc4 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -9,13 +9,9 @@ Yul Yul (previously also called JULIA or IULIA) is an intermediate language that can be compiled to bytecode for different backends. -Support for EVM 1.0, EVM 1.5 and Ewasm is planned, and it is designed to -be a usable common denominator of all three -platforms. It can already be used in stand-alone mode and -for "inline assembly" inside Solidity -and there is an experimental implementation of the Solidity compiler -that uses Yul as an intermediate language. Yul is a good target for -high-level optimisation stages that can benefit all target platforms equally. +It can be used in stand-alone mode and for "inline assembly" inside Solidity. +The compiler uses Yul as an intermediate language in the IR-based code generator ("new codegen" or "IR-based codegen"). +Yul is a good target for high-level optimisation stages that can benefit all target platforms equally. Motivation and High-level Description ===================================== @@ -89,7 +85,6 @@ It can be compiled using ``solc --strict-assembly``. The builtin functions It is also possible to implement the same function using a for-loop instead of with recursion. Here, ``lt(a, b)`` computes whether ``a`` is less than ``b``. -less-than comparison. .. code-block:: yul @@ -157,7 +152,7 @@ where an object is expected. Inside a code block, the following elements can be used (see the later sections for more details): -- literals, i.e. ``0x123``, ``42`` or ``"abc"`` (strings up to 32 characters) +- literals, e.g. ``0x123``, ``42`` or ``"abc"`` (strings up to 32 characters) - calls to builtin functions, e.g. ``add(1, mload(0))`` - variable declarations, e.g. ``let x := 7``, ``let x := add(y, 3)`` or ``let x`` (initial value of 0 is assigned) - identifiers (variables), e.g. ``add(3, x)`` @@ -171,6 +166,8 @@ Inside a code block, the following elements can be used Multiple syntactical elements can follow each other simply separated by whitespace, i.e. there is no terminating ``;`` or newline required. +.. index:: ! literal;in Yul + Literals -------- @@ -243,7 +240,7 @@ they have to be assigned to local variables. For built-in functions of the EVM, functional expressions can be directly translated to a stream of opcodes: You just read the expression from right to left to obtain the -opcodes. In the case of the first line in the example, this +opcodes. In the case of the second line in the example, this is ``PUSH1 3 PUSH1 0x80 MLOAD ADD PUSH1 0x80 MSTORE``. For calls to user-defined functions, the arguments are also @@ -663,10 +660,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 +683,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) = @@ -744,7 +741,7 @@ EVM Dialect ----------- The default dialect of Yul currently is the EVM dialect for the currently selected version of the EVM. -with a version of the EVM. The only type available in this dialect +The only type available in this dialect is ``u256``, the 256-bit native type of the Ethereum Virtual Machine. Since it is the default type of this dialect, it can be omitted. @@ -755,11 +752,12 @@ This document does not want to be a full description of the Ethereum virtual mac Please refer to a different document if you are interested in the precise semantics. Opcodes marked with ``-`` do not return a result and all others return exactly one value. -Opcodes marked with ``F``, ``H``, ``B``, ``C``, ``I`` and ``L`` are present since Frontier, Homestead, -Byzantium, Constantinople, Istanbul or London respectively. +Opcodes marked with ``F``, ``H``, ``B``, ``C``, ``I``, ``L``, ``P`` and ``N`` are present since Frontier, +Homestead, Byzantium, Constantinople, Istanbul, London, Paris or Cancun respectively. In the following, ``mem[a...b)`` signifies the bytes of memory starting at position ``a`` up to -but not including position ``b`` and ``storage[p]`` signifies the storage contents at slot ``p``. +but not including position ``b``, ``storage[p]`` signifies the storage contents at slot ``p``, and +similarly, ``transientStorage[p]`` signifies the transient storage contents at slot ``p``. Since Yul manages local variables and control-flow, opcodes that interfere with these features are not available. This includes @@ -768,7 +766,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 | +-------------------------+-----+---+-----------------------------------------------------------------+ @@ -836,6 +834,10 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a +-------------------------+-----+---+-----------------------------------------------------------------+ | sstore(p, v) | `-` | F | storage[p] := v | +-------------------------+-----+---+-----------------------------------------------------------------+ +| tload(p) | | N | transientStorage[p] | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| tstore(p, v) | `-` | N | transientStorage[p] := v | ++-------------------------+-----+---+-----------------------------------------------------------------+ | msize() | | F | size of memory, i.e. largest accessed memory index | +-------------------------+-----+---+-----------------------------------------------------------------+ | gas() | | F | gas still available to execution | @@ -868,6 +870,8 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a +-------------------------+-----+---+-----------------------------------------------------------------+ | returndatacopy(t, f, s) | `-` | B | copy s bytes from returndata at position f to mem at position t | +-------------------------+-----+---+-----------------------------------------------------------------+ +| mcopy(t, f, s) | `-` | N | copy s bytes from mem at position f to mem at position t | ++-------------------------+-----+---+-----------------------------------------------------------------+ | extcodehash(a) | | C | code hash of address a | +-------------------------+-----+---+-----------------------------------------------------------------+ | create(v, p, n) | | F | create new contract with code mem[p...(p+n)) and send v wei | @@ -903,37 +907,44 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a | revert(p, s) | `-` | B | end execution, revert state changes, return data mem[p...(p+s)) | +-------------------------+-----+---+-----------------------------------------------------------------+ | selfdestruct(a) | `-` | F | end execution, destroy current contract and send funds to a | +| | | | (deprecated) | +-------------------------+-----+---+-----------------------------------------------------------------+ | invalid() | `-` | F | end execution with invalid instruction | +-------------------------+-----+---+-----------------------------------------------------------------+ -| log0(p, s) | `-` | F | log without topics and data mem[p...(p+s)) | +| log0(p, s) | `-` | F | log data mem[p...(p+s)) | +-------------------------+-----+---+-----------------------------------------------------------------+ -| log1(p, s, t1) | `-` | F | log with topic t1 and data mem[p...(p+s)) | +| log1(p, s, t1) | `-` | F | log data mem[p...(p+s)) with topic t1 | +-------------------------+-----+---+-----------------------------------------------------------------+ -| log2(p, s, t1, t2) | `-` | F | log with topics t1, t2 and data mem[p...(p+s)) | +| log2(p, s, t1, t2) | `-` | F | log data mem[p...(p+s)) with topics t1, t2 | +-------------------------+-----+---+-----------------------------------------------------------------+ -| log3(p, s, t1, t2, t3) | `-` | F | log with topics t1, t2, t3 and data mem[p...(p+s)) | +| log3(p, s, t1, t2, t3) | `-` | F | log data mem[p...(p+s)) with topics t1, t2, t3 | +-------------------------+-----+---+-----------------------------------------------------------------+ -| log4(p, s, t1, t2, t3, | `-` | F | log with topics t1, t2, t3, t4 and data mem[p...(p+s)) | +| log4(p, s, t1, t2, t3, | `-` | F | log data mem[p...(p+s)) with topics t1, t2, t3, t4 | | t4) | | | | +-------------------------+-----+---+-----------------------------------------------------------------+ | chainid() | | I | ID of the executing chain (EIP-1344) | +-------------------------+-----+---+-----------------------------------------------------------------+ | basefee() | | L | current block's base fee (EIP-3198 and EIP-1559) | +-------------------------+-----+---+-----------------------------------------------------------------+ +| blobbasefee() | | N | current block's blob base fee (EIP-7516 and EIP-4844) | ++-------------------------+-----+---+-----------------------------------------------------------------+ | origin() | | F | transaction sender | +-------------------------+-----+---+-----------------------------------------------------------------+ | gasprice() | | F | gas price of the transaction | +-------------------------+-----+---+-----------------------------------------------------------------+ | blockhash(b) | | F | hash of block nr b - only for last 256 blocks excluding current | +-------------------------+-----+---+-----------------------------------------------------------------+ +| blobhash(i) | | N | versioned hash of transaction's i-th blob | ++-------------------------+-----+---+-----------------------------------------------------------------+ | coinbase() | | F | current mining beneficiary | +-------------------------+-----+---+-----------------------------------------------------------------+ | timestamp() | | F | timestamp of the current block in seconds since the epoch | +-------------------------+-----+---+-----------------------------------------------------------------+ | number() | | F | current block number | +-------------------------+-----+---+-----------------------------------------------------------------+ -| difficulty() | | F | difficulty of the current block | +| difficulty() | | F | difficulty of the current block (see note below) | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| prevrandao() | | P | randomness provided by the beacon chain (see note below) | +-------------------------+-----+---+-----------------------------------------------------------------+ | gaslimit() | | F | block gas limit of the current block | +-------------------------+-----+---+-----------------------------------------------------------------+ @@ -948,6 +959,20 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a You need to use the ``returndatasize`` opcode to check which part of this memory area contains the return data. The remaining bytes will retain their values as of before the call. +.. note:: + The ``difficulty()`` instruction is disallowed in EVM version >= Paris. + With the Paris network upgrade the semantics of the instruction that was previously called + ``difficulty`` have been changed and the instruction was renamed to ``prevrandao``. + It can now return arbitrary values in the full 256-bit range, whereas the highest recorded + difficulty value within Ethash was ~54 bits. + This change is described in `EIP-4399 `_. + Please note that irrelevant to which EVM version is selected in the compiler, the semantics of + instructions depend on the final chain of deployment. + +.. warning:: + From version 0.8.18 and up, the use of ``selfdestruct`` in both Solidity and Yul will trigger a + deprecation warning, since the ``SELFDESTRUCT`` opcode will eventually undergo breaking changes in behavior + as stated in `EIP-6049 `_. In some internal dialects, there are additional functions: @@ -981,7 +1006,7 @@ Its first and only argument must be a string literal and uniquely represents the Identifiers can be arbitrary but when the compiler produces Yul code from Solidity sources, it uses a library name qualified with the name of the source unit that defines that library. To link the code with a particular library address, the same identifier must be provided to the -``--libraries`` option on the command line. +``--libraries`` option on the command-line. For example this code @@ -1062,12 +1087,12 @@ or even opcodes unknown to the Solidity compiler, care has to be taken when using ``verbatim`` together with the optimizer. Even when the optimizer is switched off, the code generator has to determine the stack layout, which means that e.g. using ``verbatim`` to modify -the stack height can lead to undefined behaviour. +the stack height can lead to undefined behavior. The following is a non-exhaustive list of restrictions on verbatim bytecode that are not checked by the compiler. Violations of these restrictions can result in -undefined behaviour. +undefined behavior. - Control-flow should not jump into or out of verbatim blocks, but it can jump within the same verbatim block. @@ -1124,6 +1149,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 +1187,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)) } @@ -1168,24 +1199,24 @@ An example Yul Object is shown below: datacopy(offset, dataoffset("Contract2"), size) // constructor parameter is a single number 0x1234 mstore(add(offset, size), 0x1234) - pop(create(offset, add(size, 32), 0)) + pop(create(0, offset, add(size, 32))) // 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) + // This will turn into a codecopy for EVM + 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 +1235,7 @@ An example Yul Object is shown below: // code here ... } - object "runtime" { + object "Contract2_deployed" { code { // code here ... } @@ -1233,68 +1264,13 @@ and optionally specify the :ref:`expected number of contract executions `. .. _erc20yul: