diff --git a/CMakeLists.txt b/CMakeLists.txt index 73e7930b7222..836d2cccb79e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.8.22") +set(PROJECT_VERSION "0.8.29") # OSX target needed in order to support std::visit set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) @@ -34,19 +34,34 @@ 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(STRICT_Z3_VERSION "Require the exact version of Z3 solver expected by our test suite." 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) +option( + IGNORE_VENDORED_DEPENDENCIES + "Ignore libraries provided as submodules of the repository and allow CMake to look for \ +them in the typical locations, including system-wide dirs." + OFF +) +option( + ONLY_BUILD_SOLIDITY_LIBRARIES + "Only build library targets that can be statically linked against. Do not build executables or tests." + OFF +) +mark_as_advanced(PROFILE_OPTIMIZER_STEPS) +mark_as_advanced(IGNORE_VENDORED_DEPENDENCIES) +mark_as_advanced(ONLY_BUILD_SOLIDITY_LIBRARIES) # Setup cccache. include(EthCcache) # Let's find our dependencies include(EthDependencies) -include(fmtlib) -include(jsoncpp) -include(range-v3) -include_directories(SYSTEM ${JSONCPP_INCLUDE_DIR}) +if (NOT IGNORE_VENDORED_DEPENDENCIES) + include(fmtlib) + include(nlohmann-json) + include(range-v3) +endif() find_package(Threads) @@ -75,62 +90,31 @@ configure_file("${PROJECT_SOURCE_DIR}/cmake/templates/license.h.in" include/lice 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).") +if(EMSCRIPTEN) + set(TESTED_Z3_VERSION "4.12.1") + set(MINIMUM_Z3_VERSION "4.8.16") + find_package(Z3) + if (${Z3_FOUND}) + add_definitions(-DEMSCRIPTEN_BUILD) + if (${STRICT_Z3_VERSION}) + if (NOT ("${Z3_VERSION_STRING}" VERSION_EQUAL ${TESTED_Z3_VERSION})) + message( + FATAL_ERROR + "SMTChecker tests require Z3 ${TESTED_Z3_VERSION} for all tests to pass.\n" + ) + endif() + else() + if ("${Z3_VERSION_STRING}" VERSION_LESS ${MINIMUM_Z3_VERSION}) + message( + FATAL_ERROR + "Solidity requires Z3 ${MINIMUM_Z3_VERSION} or newer." + ) + endif() + endif() + else() + message(FATAL_ERROR "Solidity requires Z3 for emscripten build.") + endif() endif() add_subdirectory(libsolutil) @@ -141,12 +125,15 @@ add_subdirectory(libyul) add_subdirectory(libsolidity) add_subdirectory(libsolc) add_subdirectory(libstdlib) -add_subdirectory(tools) -if (NOT EMSCRIPTEN) - add_subdirectory(solc) -endif() +if (NOT ONLY_BUILD_SOLIDITY_LIBRARIES) + add_subdirectory(tools) -if (TESTS AND NOT EMSCRIPTEN) - add_subdirectory(test) + if (NOT EMSCRIPTEN) + add_subdirectory(solc) + endif() + + if (TESTS AND NOT EMSCRIPTEN) + add_subdirectory(test) + endif() endif() diff --git a/docs/080-breaking-changes.rst b/docs/080-breaking-changes.rst index 62e226149415..c35326ba5001 100644 --- a/docs/080-breaking-changes.rst +++ b/docs/080-breaking-changes.rst @@ -132,8 +132,13 @@ Solidity v0.8.0 突破性变化 * ``--combined-json`` 的输出已经改变。JSON字段 ``abi``, ``devdoc``, ``userdoc`` 和 ``storage-layout`` 现在是子对象。在0.8.0之前,它们曾被序列化为字符串。 +<<<<<<< HEAD * “传统AST“ 已被删除( ``--ast-json`` 在命令行界面, ``legacyAST`` 用于标准JSON)。 使用 “紧凑型AST”( ``--ast-compact-json`` 参数. ``AST``)作为替代。 +======= +* The "legacy AST" has been removed (``--ast-json`` on the commandline interface and ``legacyAST`` for standard JSON). + Use the "compact AST" (``--ast-compact-json`` resp. ``AST``) as replacement. +>>>>>>> english/develop * 旧的错误报告器( ``--old-reporter`` )已经被删除。 diff --git a/docs/_static/css/toggle.css b/docs/_static/css/toggle.css index 6f03e6fb6aba..d525ab62a78f 100644 --- a/docs/_static/css/toggle.css +++ b/docs/_static/css/toggle.css @@ -85,4 +85,9 @@ html.transition *:after { .wy-menu-vertical a:hover { background-color: #0002; +} + +body { + font-weight: 300; + letter-spacing: 0.5px; } \ No newline at end of file diff --git a/docs/_static/js/initialize.js b/docs/_static/js/initialize.js index a20d4fce7190..1c3be8aaddaa 100644 --- a/docs/_static/js/initialize.js +++ b/docs/_static/js/initialize.js @@ -23,18 +23,24 @@ function rearrangeDom() { document.body.prepend(wrapperDiv); const rstVersions = document.querySelector(".rst-versions"); - rstVersions.remove(); const wyNavSide = document.querySelector("nav.wy-nav-side"); - wyNavSide.appendChild(rstVersions); + // NOTE: Since RTD migration to addons, `.rst-versions` is no longer present in the DOM. + // The following code is kept for compatibility with older versions. + // See: https://github.com/readthedocs/readthedocs.org/issues/11474 + if (rstVersions && wyNavSide) { + rstVersions.remove(); + 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); + if (content) { + content.id = "content"; + document.querySelector("section.wy-nav-content-wrap")?.remove(); + document.querySelector(".wy-grid-for-nav")?.appendChild(content); + } } function buildHeader() { @@ -144,8 +150,15 @@ const updateActiveNavLink = () => { document.addEventListener("locationchange", updateActiveNavLink); function updateGitHubEditPath() { - // Replaces the version number in the GitHub edit path with "develop" + // Replaces the version number in the GitHub edit path with "develop" if it exists. + // This is to ensure that the edit path always points to the `develop` branch instead of the specific version branch. + // Note that it will fail silently if the anchor element is not found, i.e. the page is not editable or + // if the sphinx_rtd_theme is updated to a version that changes the anchor element. + // See: https://github.com/readthedocs/sphinx_rtd_theme/blob/a1c2147b17cbf0e57b7d7a6450ad4d9a5ff362cf/sphinx_rtd_theme/breadcrumbs.html#L35 + // TODO: We should consider a more robust way to handle this in the future. const gitHubEditAnchor = document.querySelector(".wy-breadcrumbs-aside > a"); + if (!gitHubEditAnchor) return; + const url = new URL(gitHubEditAnchor.href); const split = url.pathname.split("/"); const versionIndex = split.indexOf("blob") + 1; @@ -195,10 +208,12 @@ function initialize() { .querySelector(":root") .setAttribute("style", `--color-scheme: ${mode}`); + // NOTE: Since RTD migration to addons, the elements below are no longer present in the DOM. + // The following code is kept for compatibility with older versions. // 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(); + document.querySelector("input[name=mode]")?.remove(); + document.querySelector("label[for=switch]")?.remove(); + document.querySelector(".wy-side-nav-search > a")?.remove(); // Add footer note addFooterNote(); @@ -239,7 +254,7 @@ document.addEventListener("click", handleClick); const handleKeyDown = (e) => { if (e.metaKey && e.key === "k") { - document.querySelector("#rtd-search-form input").focus(); + document.querySelector("#rtd-search-form input")?.focus(); } else if (e.key === "Escape") { toggleMenu({ force: false }); } diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index 76ee2c66f852..66cbcb26d134 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -16,7 +16,11 @@ 我们假设合约的接口函数是强类型的,在编译时就知道,并且是静态的。 我们假设所有合约在编译时都有它们所调用的任何合约的接口定义。 +<<<<<<< HEAD 本规范不涉及其接口是动态的或其他只有在运行时才知道的合约。 +======= +This specification does not address contracts whose interface is dynamic or otherwise known only at run-time. Also, the ABI specification for libraries is :ref:`slightly different `. +>>>>>>> english/develop .. _abi_function_selector: .. index:: ! selector; of a function @@ -44,7 +48,13 @@ 类型 ===== +<<<<<<< HEAD 以下是基础类型: +======= +Note that the library ABIs can take types different than below e.g. for non-storage structs. See :ref:`library selectors ` for details. + +The following elementary types exist: +>>>>>>> english/develop - ``uint``: ``M`` 位的无符号整数, ``0 < M <= 256``, ``M % 8 == 0``。例如: ``uint32``, ``uint8``, ``uint256``。 @@ -238,8 +248,27 @@ Solidity 支持上面介绍的除了元祖之外的所有同名类型。 } +<<<<<<< HEAD 因此,对于我们的例子 ``Foo``,如果我们想用 ``69`` 和 ``true`` 做参数调用 ``baz``, 我们总共需要传送 68 字节,可以分解为: +======= +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: +>>>>>>> english/develop - ``0xcdcd77c0``: 方法ID。这源自ASCII格式的 ``baz(uint32,bool)`` 签名的 Keccak 哈希的前 4 字节。 - ``0x0000000000000000000000000000000000000000000000000000000000000045``: 第一个参数, @@ -257,6 +286,7 @@ Solidity 支持上面介绍的除了元祖之外的所有同名类型。 那么它的输出将是一个字节数组 ``0x0000000000000000000000000000000000000000000000000000000000000000``, 一个 ``bool`` 值。 +<<<<<<< HEAD 如果我们想用 ``["abc", "def"]`` 做参数调用 ``bar``,我们总共需要传送 68 字节,可以分解为: - ``0xfce353f6``: 方法ID。源自 ``bar(bytes3[2])`` 的签名。 @@ -273,6 +303,10 @@ Solidity 支持上面介绍的除了元祖之外的所有同名类型。 如果我们想用 ``"dave"``, ``true`` 和 ``[1,2,3]`` 作为参数调用 ``sam``, 我们总共需要传送 292 字节,可以分解为: +======= +If we wanted to call ``sam`` with the arguments ``"dave"``, ``true`` and ``[1,2,3]``, we would +pass 292 bytes total, broken down into: +>>>>>>> english/develop - ``0xa5643bf2``: 方法ID。这是从签名 ``sam(bytes,bool,uint256[])`` 中导出的。注意, ``uint`` 被替换为其典型代表 ``uint256``。 - ``0x0000000000000000000000000000000000000000000000000000000000000060``: 第一个参数(动态类型)的数据部分的位置,即从参数编码块开始位置算起的字节数。在这里,是 ``0x60`` 。 diff --git a/docs/assembly.rst b/docs/assembly.rst index f7c0f5b7da6c..6e9b33283f6f 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -7,8 +7,15 @@ .. index:: ! assembly, ! asm, ! evmasm +<<<<<<< HEAD 您可以用接近Ethereum虚拟机的语言,将Solidity语句与内联汇编交错使用。 这给了您更精细的控制,这在您通过编写库来增强语言时特别有用。 +======= +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, +which is especially useful when you are enhancing the language by writing libraries or +optimizing gas usage. +>>>>>>> english/develop 在 Solidity 中用于内联汇编的语言被称为 :ref:`Yul `,它在自己的章节中被记录。 本节将只涉及内联汇编代码如何在 Solidity 代码内交互。 @@ -150,6 +157,15 @@ 对于动态的calldata数组,您可以使用 ``x.offset`` 和 ``x.length`` 访问它们的calldata偏移量(字节)和长度(元素数)。 这两个表达式也可以被赋值,但是和静态情况一样,不会进行验证以确保产生的数据区域在 ``calldatasize()`` 的范围内。 +<<<<<<< HEAD +======= +For local storage variables or state variables (including transient storage) a single Yul identifier +is not sufficient, since they do not necessarily occupy a single full storage slot. +Therefore, their "address" is composed of a slot and a byte-offset +inside that slot. To retrieve the slot pointed to by the variable ``x``, you +use ``x.slot``, and to retrieve the byte-offset you use ``x.offset``. +Using ``x`` itself will result in an error. +>>>>>>> english/develop 对于本地存储变量或状态变量,一个Yul标识符是不够的,因为它们不一定占据一个完整的存储槽。 因此,它们的 "地址" 是由一个槽和槽内的字节偏移量组成。要检索变量 ``x`` 所指向的槽, @@ -166,14 +182,17 @@ :force: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.7.0 <0.9.0; + pragma solidity >=0.8.28 <0.9.0; + // This will report a warning contract C { + bool transient a; uint b; - function f(uint x) public view returns (uint r) { + function f(uint x) public returns (uint r) { assembly { // 我们忽略了存储槽的偏移量,我们知道在这种特殊情况下它是零。 r := mul(x, sload(b.slot)) + tstore(a.slot, true) } } } @@ -341,5 +360,31 @@ Solidity中内存数组中的元素总是占据32字节的倍数 ... } +<<<<<<< HEAD 请注意,我们将在未来的突破性版本中禁止通过注释的方式进行注解; 因此,如果您不关心与旧编译器版本的向后兼容问题,请优先使用这种代码字符串形式的写法。 +======= +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. + +Advanced Safe Use of Memory +--------------------------- + +Beyond the strict definition of memory-safety given above, there are cases in which you may want to use more than 64 bytes +of scratch space starting at memory offset ``0``. If you are careful, it can be admissible to use memory up to (and not +including) offset ``0x80`` and still safely declare the assembly block as ``memory-safe``. +This is admissible under either of the following conditions: + +- By the end of the assembly block, the free memory pointer at offset ``0x40`` is restored to a sane value (i.e. it is either + restored to its original value or an increment of it due to a manual memory allocation), and the memory word at offset ``0x60`` + is restored to a value of zero. + +- The assembly block terminates, i.e. execution can never return to high-level Solidity code. This is the case, for example, + if your assembly block unconditionally ends in calling the ``revert`` opcode. + +Furthermore, you need to be aware that the default-value of dynamic arrays in Solidity point to memory offset ``0x60``, so +for the duration of temporarily changing the value at memory offset ``0x60``, you can no longer rely on getting accurate +length values when reading dynamic arrays, until you restore the zero value at ``0x60``. To be more precise, we only guarantee +safety when overwriting the zero pointer, if the remainder of the assembly snippet does not interact with the memory of +high-level Solidity objects (including by reading from offsets previously stored in variables). +>>>>>>> english/develop diff --git a/docs/bugs.json b/docs/bugs.json index 6245bdeda5af..c853f95eddea 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,14 @@ [ + { + "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", diff --git a/docs/bugs.rst b/docs/bugs.rst index 0bb35682871e..75c527de4401 100644 --- a/docs/bugs.rst +++ b/docs/bugs.rst @@ -6,9 +6,17 @@ 已知bug列表 ################## +<<<<<<< HEAD 下面,您可以找到一个JSON格式的列表,其中包括Solidity编译器中一些已知的与安全有关的错误。 该文件本身托管在 `Github 仓库 `_。 该列表最早可以追溯到0.3.0版本,只有在此之前的版本中已知的错误没有列出。 +======= +Below, you can find a JSON-formatted list of some of the known security-relevant bugs in the +Solidity compiler. The file itself is hosted in the `GitHub repository +`_. +The list stretches back as far as version 0.3.0, bugs known to be present only +in versions preceding that are not listed. +>>>>>>> english/develop 还有一个文件叫 `bugs_by_version.json `_, diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index aa144f5928ad..e8a199dd8123 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1743,6 +1743,7 @@ }, "0.8.10": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1754,6 +1755,7 @@ }, "0.8.11": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1766,6 +1768,7 @@ }, "0.8.12": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1778,6 +1781,7 @@ }, "0.8.13": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "StorageWriteRemovalBeforeConditionalTermination", @@ -1791,6 +1795,7 @@ }, "0.8.14": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "StorageWriteRemovalBeforeConditionalTermination", @@ -1802,6 +1807,7 @@ }, "0.8.15": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "StorageWriteRemovalBeforeConditionalTermination", @@ -1811,6 +1817,7 @@ }, "0.8.16": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "StorageWriteRemovalBeforeConditionalTermination" @@ -1819,6 +1826,7 @@ }, "0.8.17": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess" ], @@ -1826,6 +1834,7 @@ }, "0.8.18": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess" ], @@ -1833,6 +1842,7 @@ }, "0.8.19": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess" ], @@ -1854,15 +1864,48 @@ }, "0.8.20": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess" ], "released": "2023-05-10" }, "0.8.21": { - "bugs": [], + "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.25": { + "bugs": [], + "released": "2024-03-14" + }, + "0.8.26": { + "bugs": [], + "released": "2024-05-21" + }, + "0.8.27": { + "bugs": [], + "released": "2024-09-04" + }, + "0.8.28": { + "bugs": [], + "released": "2024-10-09" + }, "0.8.3": { "bugs": [ "FullInlinerNonExpressionSplitArgumentEvaluationOrder", @@ -1890,6 +1933,7 @@ }, "0.8.5": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1902,6 +1946,7 @@ }, "0.8.6": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1914,6 +1959,7 @@ }, "0.8.7": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1926,6 +1972,7 @@ }, "0.8.8": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1939,6 +1986,7 @@ }, "0.8.9": { "bugs": [ + "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst index cbd49e2d4fec..2ebbb0f19793 100644 --- a/docs/cheatsheet.rst +++ b/docs/cheatsheet.rst @@ -14,6 +14,7 @@ ABI 编码和解码函数 =================================== +<<<<<<< HEAD - ``abi.decode(bytes memory encodedData, (...)) returns (...)``: :ref:`ABI ` - 对提供的数据进行解码。类型在括号中作为第二个参数给出。 示例: ``(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))`` - ``abi.encode(...) returns (bytes memory)``: :ref:`ABI ` - 对给定的参数进行编码。 @@ -25,6 +26,20 @@ ABI 编码和解码函数 参数在元组中找到。执行全面的类型检查,确保类型与函数签名相符。结果等于 ``abi.encodeWithSelector(functionPointer.selector(..))``。 - ``abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)``: 等价于 ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)`` +======= +- ``abi.decode(bytes memory encodedData, (...)) returns (...)``: :ref:`ABI `-decodes + the provided data. The types are given in parentheses as second argument. + Example: ``(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))`` +- ``abi.encode(...) returns (bytes memory)``: :ref:`ABI `-encodes the given arguments +- ``abi.encodePacked(...) returns (bytes memory)``: Performs :ref:`packed encoding ` of + the given arguments. Note that this encoding can be ambiguous! +- ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)``: :ref:`ABI `-encodes + the given arguments starting from the second and prepends the given four-byte selector +- ``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))), ...)`` +>>>>>>> english/develop .. index:: bytes;concat, string;concat @@ -41,18 +56,34 @@ ABI 编码和解码函数 ``address`` 的成员方法 ====================== +<<<<<<< HEAD - ``
.balance`` (``uint256``): :ref:`address` 的余额,以 Wei 为单位 - ``
.code`` (``bytes memory``): 在 :ref:`address` 的代码(可以是空的)。 - ``
.codehash`` (``bytes32``): :ref:`address` 的代码哈希值。 - ``
.send(uint256 amount) returns (bool)``: 向 :ref:`address` 发送给定数量的 Wei,失败时返回 ``false`` - ``
.transfer(uint256 amount)``: 向 :ref:`address` 发送给定数量的 Wei,失败时会把错误抛出(throw) - -.. index:: blockhash, block, block;basefree, block;chainid, block;coinbase, block;difficulty, block;gaslimit, block;number, block;prevrandao, block;timestamp +======= +- ``
.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 +>>>>>>> english/develop + +.. 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 区块和交易属性 ================================ +<<<<<<< HEAD - ``blockhash(uint blockNumber) returns (bytes32)``: 给定区块的哈希值 - 只对最近的256个区块有效 - ``block.basefee`` (``uint``): 当前区块的基本费用 ( `EIP-3198 `_ 和 `EIP-1559 `_ ) - ``block.chainid`` (``uint``): 当前链的ID @@ -69,6 +100,29 @@ ABI 编码和解码函数 - ``msg.value`` (``uint``): 随消息发送的 wei 的数量 - ``tx.gasprice`` (``uint``): 交易的 gas 价格 - ``tx.origin`` (``address``): 交易发送方(完整调用链上的原始发送方) +======= +- ``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 `_). + Returns zero if no blob with the given index exists. +- ``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 (``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.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) +- ``msg.sig`` (``bytes4``): first four bytes of the calldata (i.e. function identifier) +- ``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) +>>>>>>> english/develop .. index:: assert, require, revert @@ -100,10 +154,17 @@ ABI 编码和解码函数 合约相关方法 ================ +<<<<<<< HEAD - ``this`` (当前合约的类型): 当前合约,可明确转换为 ``address`` 或 ``address payable``。 - ``super``: 继承层次中高一级的合约 - ``selfdestruct(address payable recipient)``: 销毁当前合约,将其资金发送到给定的地址。 +======= +- ``this`` (current contract's type): the current contract, explicitly convertible to ``address`` or ``address payable`` +- ``super``: a contract one level higher in the inheritance hierarchy +- ``selfdestruct(address payable recipient)``: send all funds to the given address and (only on EVMs before Cancun or when invoked within the transaction creating the contract) destroy the contract. + +>>>>>>> english/develop .. index:: type;name, type;creationCode, type;runtimeCode, type;interfaceId, type;min, type;max 类型相关信息 @@ -140,6 +201,7 @@ ABI 编码和解码函数 修饰器 ========= +<<<<<<< HEAD - ``pure`` 修饰函数时:不允许修改或访问状态变量。 - ``view`` 修饰函数时:不允许修改状态变量。 - ``payable`` 修饰函数时:允许从调用中接收以太币。 @@ -149,4 +211,17 @@ ABI 编码和解码函数 - ``indexed`` 修饰事件参数时:将参数作为 topic 存储。 - ``virtual`` 修饰函数和修改时:允许在派生合约中改变函数或修改器的行为。 - ``override`` 表示该函数、修改器或公共状态变量改变了基类合约中的函数或修改器的行为。 +======= +- ``pure`` for functions: Disallows modification or access of state. +- ``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 initialization), does not occupy storage slot. +- ``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 + behavior to be changed in derived contracts. +- ``override``: States that this function, modifier or public state variable changes + the behavior of a function or modifier in a base contract. +>>>>>>> english/develop diff --git a/docs/conf.py b/docs/conf.py index 5f096a97eab6..5230cd0b61df 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -36,8 +36,55 @@ def setup(sphinx): sphinx.add_css_file('css/custom-dark.css') sphinx.add_css_file('css/pygments.css') -# -- General configuration ------------------------------------------------ +# -- RTD GitHub configuration --------------------------------------------- + +# Taken from: +# https://github.com/readthedocs/readthedocs.org/blob/e366e7fc8649fbcf1b6d06ecc12c5f7766144c46/readthedocs/projects/constants.py#L350 +GITHUB_REGEXS = [ + re.compile(r"github.com/(.+)/(.+)(?:\.git){1}$"), + # This must come before the one without a / to make sure we don't capture the / + re.compile(r"github.com/(.+)/(.+)/"), + re.compile(r"github.com/(.+)/(.+)"), + re.compile(r"github.com:(.+)/(.+)\.git$"), +] + +# Taken and adapted from: +# https://github.com/readthedocs/readthedocs.org/blob/e366e7fc8649fbcf1b6d06ecc12c5f7766144c46/readthedocs/builds/utils.py#L24 +def get_github_username_repo(url): + if "github" in url: + for regex in GITHUB_REGEXS: + match = regex.search(url) + if match: + return match.groups() + return (None, None) + +display_github = False +# NOTE: RTD_DISPLAY_GITHUB, RTD_GITHUB_USER and RTD_GITHUB_REPO are set in the RTD project settings +github_user = os.getenv("RTD_GITHUB_USER") +github_repo = os.getenv("RTD_GITHUB_REPO") + +if github_user and github_repo: + display_github = True +else: + git_clone_url = os.getenv("READTHEDOCS_GIT_CLONE_URL") + if git_clone_url: + github_user, github_repo = get_github_username_repo(git_clone_url) + if github_user and github_repo: + display_github = True + +display_github_env = os.getenv("RTD_DISPLAY_GITHUB") +if display_github_env: + display_github = display_github_env.lower() == "true" + +html_context = { + "display_github": display_github, + "github_user": github_user, + "github_repo": github_repo, + "github_version": os.getenv("READTHEDOCS_VERSION", "develop"), + "conf_py_path": "/docs/", +} +# -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' @@ -67,7 +114,7 @@ def setup(sphinx): # General information about the project. project = 'Solidity' -project_copyright = '2016-2023, The Solidity Authors' +project_copyright = '2016-2024, 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 diff --git a/docs/contracts.rst b/docs/contracts.rst index 3cf9e2c30fae..f79fa07a7f31 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -19,6 +19,8 @@ Solidity中的合约类似于面向对象语言中的类。 .. include:: contracts/function-modifiers.rst +.. include:: contracts/transient-storage.rst + .. include:: contracts/constant-state-variables.rst .. include:: contracts/functions.rst diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst index 19968261c071..c9d9b22cdd75 100644 --- a/docs/contracts/constant-state-variables.rst +++ b/docs/contracts/constant-state-variables.rst @@ -13,7 +13,13 @@ 也可以在文件级别定义 ``constant`` 变量。 +<<<<<<< HEAD 编译器并没有为这些变量预留存储,它们的每次出现都会被替换为相应的常量表达式。 +======= +Every occurrence of such a variable in the source is replaced by its underlying value +and the compiler does not reserve a storage slot for it. +It cannot be assigned a slot in transient storage using the ``transient`` keyword either. +>>>>>>> english/develop 与普通的状态变量相比,常量变量(constant)和不可改变的变量(immutable)的气体成本要低得多。 对于常量变量,分配给它的表达式被复制到所有访问它的地方,并且每次都要重新评估, diff --git a/docs/contracts/errors.rst b/docs/contracts/errors.rst index c7ba3355d2f1..2b078a4dd555 100644 --- a/docs/contracts/errors.rst +++ b/docs/contracts/errors.rst @@ -1,20 +1,36 @@ -.. index:: ! error, revert, ! selector; of an error +.. index:: ! error, revert, require, ! selector; of an error .. _errors: +<<<<<<< HEAD ******************************* 错误和恢复语句 ******************************* +======= +************* +Custom Errors +************* +>>>>>>> english/develop Solidity 中的错误提供了一种方便且省gas的方式来向用户解释为什么一个操作会失败。 它们可以被定义在合约内部和外部(包括接口合约和库合约)。 +<<<<<<< HEAD 它们必须与 :ref:`恢复语句 ` 一起使用, 它导致当前调用中的所有变化被恢复,并将错误数据传回给调用者。 +======= +They have to be used together with the :ref:`revert statement ` +or the :ref:`require function `. +In the case of ``revert`` statements, or ``require`` calls where the condition is evaluated to be false, +all changes in the current call are reverted, and the error data passed back to the caller. + +The example below shows custom error usage with the ``revert`` statement in function ``transferWithRevertError``, +as well as the newer approach with ``require`` in function ``transferWithRequireError``. +>>>>>>> english/develop .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 - pragma solidity ^0.8.4; + pragma solidity ^0.8.27; /// 转账的余额不足。需要 `required` 数量但只有 `available` 数量可用。 /// @param 可用的余额。 @@ -23,7 +39,7 @@ Solidity 中的错误提供了一种方便且省gas的方式来向用户解释 contract TestToken { mapping(address => uint) balance; - function transfer(address to, uint256 amount) public { + function transferWithRevertError(address to, uint256 amount) public { if (amount > balance[msg.sender]) revert InsufficientBalance({ available: balance[msg.sender], @@ -32,12 +48,28 @@ Solidity 中的错误提供了一种方便且省gas的方式来向用户解释 balance[msg.sender] -= amount; balance[to] += amount; } + function transferWithRequireError(address to, uint256 amount) public { + require(amount <= balance[msg.sender], InsufficientBalance(balance[msg.sender], amount)); + balance[msg.sender] -= amount; + balance[to] += amount; + } // ... } +<<<<<<< HEAD 错误不能被重载或覆盖,但是可以被继承。 只要作用域不同,同一个错误可以在多个地方定义。 错误的实例只能使用 ``revert`` 语句创建。 +======= +Another important detail to mention when it comes to using ``require`` with custom errors, is that memory +allocation for the error-based revert reason will only happen in the reverting case, which, along with +optimization of constants and string literals makes this about as gas-efficient as the +``if (!condition) revert CustomError(args)`` pattern. + +Errors cannot be overloaded or overridden but are inherited. +The same error can be defined in multiple places as long as the scopes are distinct. +Instances of errors can only be created using ``revert`` statements, or as the second argument to ``require`` functions. +>>>>>>> english/develop 错误会创建数据,然后通过还原操作传递给调用者, 使其返回到链下组件或在 :ref:`try/catch 语句 ` 中捕获它。 @@ -59,10 +91,16 @@ Solidity 中的错误提供了一种方便且省gas的方式来向用户解释 甚至因为在不同地方定义的错误而使调用者无法区分。 对于外部来说,即ABI,只有错误的名称是相关的,而不是定义它的合约或文件。 +<<<<<<< HEAD 如果您能定义 ``error Error(string)``, 那么语句 ``require(condition, "description");`` 将等同于 ``if (!condition) revert Error("description")``。 但是请注意, ``Error`` 是一个内置类型,不能在用户提供的代码中定义。 +======= +The statement ``require(condition, "description");`` would be equivalent to +``if (!condition) revert Error("description")`` if you could define ``error Error(string)``. +Note, however, that ``Error`` is a built-in type and cannot be defined in user-supplied code. +>>>>>>> english/develop 同样,一个失败的 ``assert`` 或类似的条件将以一个内置的 ``Panic(uint256)`` 类型的错误来恢复。 diff --git a/docs/contracts/function-modifiers.rst b/docs/contracts/function-modifiers.rst index a21a02b2026f..6733e4864452 100644 --- a/docs/contracts/function-modifiers.rst +++ b/docs/contracts/function-modifiers.rst @@ -17,7 +17,10 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.1 <0.9.0; +<<<<<<< HEAD // 这将报告一个由于废弃的 selfdestruct 而产生的警告 +======= +>>>>>>> english/develop contract owned { constructor() { owner = payable(msg.sender); } @@ -37,6 +40,7 @@ } } +<<<<<<< HEAD contract destructible is owned { // 这个合约从 `owned` 合约继承了 `onlyOwner` 修饰器, // 并将其应用于 `destroy` 函数, @@ -46,6 +50,8 @@ } } +======= +>>>>>>> english/develop contract priced { // 修饰器可以接受参数: modifier costs(uint price) { @@ -55,7 +61,7 @@ } } - contract Register is priced, destructible { + contract Register is priced, owned { mapping(address => bool) registeredAddresses; uint price; @@ -67,6 +73,9 @@ registeredAddresses[msg.sender] = true; } + // This contract inherits the `onlyOwner` modifier from + // the `owned` contract. As a result, calls to `changePrice` will + // only take effect if they are made by the stored owner. function changePrice(uint price_) public onlyOwner { price = price_; } diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index 71d913cbbfeb..c1667c321722 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -161,6 +161,7 @@ View 函数 以下声明被认为是修改状态: +<<<<<<< HEAD #. 修改状态变量。 #. :ref:`产生事件 `。 #. :ref:`创建其它合约 `。 @@ -169,6 +170,16 @@ View 函数 #. 调用任何没有标记为 ``view`` 或者 ``pure`` 的函数。 #. 使用低级调用。 #. 使用包含特定操作码的内联汇编。 +======= +#. Writing to state variables (storage and transient storage). +#. :ref:`Emitting events `. +#. :ref:`Creating other contracts `. +#. Using ``selfdestruct``. +#. Sending Ether via calls. +#. Calling any function not marked ``view`` or ``pure``. +#. Using low-level calls. +#. Using inline assembly that contains certain opcodes. +>>>>>>> english/develop .. code-block:: solidity @@ -209,11 +220,19 @@ Pure 函数 除了上面解释的状态修改语句列表外,以下内容被认为是从状态中读取的: +<<<<<<< HEAD #. 读取状态变量。 #. 访问 ``address(this).balance`` 或者 ``
.balance``。 #. 访问 ``block``, ``tx``, ``msg`` 中任意成员 (除 ``msg.sig`` 和 ``msg.data`` 之外)。 #. 调用任何未标记为 ``pure`` 的函数。 #. 使用包含某些操作码的内联汇编。 +======= +#. Reading from state variables (storage and transient storage). +#. Accessing ``address(this).balance`` or ``
.balance``. +#. Accessing any of the members of ``block``, ``tx``, ``msg`` (with the exception of ``msg.sig`` and ``msg.data``). +#. Calling any function not marked ``pure``. +#. Using inline assembly that contains certain opcodes. +>>>>>>> english/develop .. code-block:: solidity @@ -245,10 +264,18 @@ Pure 函数能够使用 ``revert()`` 和 ``require()`` 函数来恢复潜在的 通过对 ``pure`` 函数使用 ``STATICCALL``,在EVM层面防止了对状态的修改。 .. note:: +<<<<<<< HEAD 在0.4.17版本之前,编译器并没有强制要求 ``pure`` 不读取状态。 这是一个编译时的类型检查,可以规避在合约类型之间做无效的显式转换, 因为编译器可以验证合约的类型不做改变状态的操作, 但它不能检查将在运行时被调用的合约是否真的属于该类型。 +======= + Prior to version 0.4.17 the compiler did not enforce that ``pure`` is not reading the state. + It is a compile-time type check, which can be circumvented by doing invalid explicit conversions + between contract types, because the compiler can verify that the type of the contract does + not do state-changing operations, but it cannot check that the contract that will be called + at runtime is actually of that type. +>>>>>>> english/develop .. _special-functions: diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst index a4024e50fc02..c0a689020b44 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -33,14 +33,18 @@ Solidity支持多重继承,包括多态性。 // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; +<<<<<<< HEAD // 这将报告一个由于废弃的 selfdestruct 而产生的警告 +======= +>>>>>>> english/develop contract Owned { - constructor() { owner = payable(msg.sender); } address payable owner; + constructor() { owner = payable(msg.sender); } } +<<<<<<< HEAD // 使用 `is` 从另一个合约派生。派生合约可以访问所有非私有成员, // 包括内部函数和状态变量,但无法通过 `this` 来外部访问。 @@ -55,25 +59,53 @@ Solidity支持多重继承,包括多态性。 // 这些抽象合约仅用于给编译器提供接口。 // 注意函数没有函数体。 // 如果一个合约没有实现所有函数,则只能用作接口。 +======= + // Use `is` to derive from another contract. Derived + // contracts can access all non-private members including + // internal functions and state variables. These cannot be + // accessed externally via `this`, though. + contract Emittable is Owned { + event Emitted(); + + // The keyword `virtual` means that the function can change + // its behavior in derived classes ("overriding"). + function emitEvent() virtual public { + if (msg.sender == owner) + emit Emitted(); + } + } + + // These abstract contracts are only provided to make the + // interface known to the compiler. Note the function + // without body. If a contract does not implement all + // functions it can only be used as an interface. +>>>>>>> english/develop abstract contract Config { function lookup(uint id) public virtual returns (address adr); } - abstract contract NameReg { function register(bytes32 name) public virtual; function unregister() public virtual; } +<<<<<<< HEAD // 多重继承是可能的。请注意, `Owned` 也是 `Destructible` 的基类, // 但只有一个 `Owned` 实例(就像 C++ 中的虚拟继承)。 contract Named is Owned, Destructible { +======= + // Multiple inheritance is possible. Note that `Owned` is + // also a base class of `Emittable`, yet there is only a single + // instance of `Owned` (as for virtual inheritance in C++). + contract Named is Owned, Emittable { +>>>>>>> english/develop constructor(bytes32 name) { Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970); NameReg(config.lookup(1)).register(name); } +<<<<<<< HEAD // 函数可以被另一个具有相同名称和相同数量/类型输入的函数重载。 // 如果重载函数有不同类型的输出参数,会导致错误。 // 本地和基于消息的函数调用都会考虑这些重载。 @@ -85,79 +117,164 @@ Solidity支持多重继承,包括多态性。 NameReg(config.lookup(1)).unregister(); // 仍然可以调用特定的重载函数。 Destructible.destroy(); +======= + // Functions can be overridden by another function with the same name and + // the same number/types of inputs. If the overriding function has different + // types of output parameters, that causes an error. + // Both local and message-based function calls take these overrides + // into account. + // If you want the function to override, you need to use the + // `override` keyword. You need to specify the `virtual` keyword again + // if you want this function to be overridden again. + function emitEvent() public virtual override { + if (msg.sender == owner) { + Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970); + NameReg(config.lookup(1)).unregister(); + // It is still possible to call a specific + // overridden function. + Emittable.emitEvent(); +>>>>>>> english/develop } } } +<<<<<<< HEAD // 如果构造函数接受参数, // 则需要在声明(合约的构造函数)时提供, // 或在派生合约的构造函数位置以修饰器调用风格提供(见下文)。 contract PriceFeed is Owned, Destructible, Named("GoldFeed") { +======= + // If a constructor takes an argument, it needs to be + // provided in the header or modifier-invocation-style at + // the constructor of the derived contract (see below). + contract PriceFeed is Owned, Emittable, Named("GoldFeed") { + uint info; + +>>>>>>> english/develop function updateInfo(uint newInfo) public { if (msg.sender == owner) info = newInfo; } +<<<<<<< HEAD // 在这里,我们只指定了 `override` 而没有 `virtual`。 // 这意味着从 `PriceFeed` 派生出来的合约不能再改变 `destroy` 的行为。 function destroy() public override(Destructible, Named) { Named.destroy(); } +======= + // Here, we only specify `override` and not `virtual`. + // This means that contracts deriving from `PriceFeed` + // cannot change the behavior of `emitEvent` anymore. + function emitEvent() public override(Emittable, Named) { Named.emitEvent(); } +>>>>>>> english/develop function get() public view returns(uint r) { return info; } - - uint info; } +<<<<<<< HEAD 注意,在上面,我们调用 ``Destructible.destroy()`` 来 "转发" 销毁请求。 这样做的方式是有问题的,从下面的例子中可以看出: +======= +Note that above, we call ``Emittable.emitEvent()`` to "forward" the +emit event request. The way this is done is problematic, as +seen in the following example: +>>>>>>> english/develop .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; +<<<<<<< HEAD // 这将报告一个由于废弃的 selfdestruct 而产生的警告 +======= +>>>>>>> english/develop - contract owned { - constructor() { owner = payable(msg.sender); } + contract Owned { address payable owner; + constructor() { owner = payable(msg.sender); } } - contract Destructible is owned { - function destroy() public virtual { - if (msg.sender == owner) selfdestruct(owner); + contract Emittable is Owned { + event Emitted(); + + function emitEvent() virtual public { + if (msg.sender == owner) { + emit Emitted(); + } } } +<<<<<<< HEAD contract Base1 is Destructible { function destroy() public virtual override { /* 清除操作 1 */ Destructible.destroy(); } } contract Base2 is Destructible { function destroy() public virtual override { /* 清除操作 2 */ Destructible.destroy(); } +======= + contract Base1 is Emittable { + event Base1Emitted(); + function emitEvent() public virtual override { + /* Here, we emit an event to simulate some Base1 logic */ + emit Base1Emitted(); + Emittable.emitEvent(); + } + } + + contract Base2 is Emittable { + event Base2Emitted(); + function emitEvent() public virtual override { + /* Here, we emit an event to simulate some Base2 logic */ + emit Base2Emitted(); + Emittable.emitEvent(); + } +>>>>>>> english/develop } contract Final is Base1, Base2 { - function destroy() public override(Base1, Base2) { Base2.destroy(); } + event FinalEmitted(); + function emitEvent() public override(Base1, Base2) { + /* Here, we emit an event to simulate some Final logic */ + emit FinalEmitted(); + Base2.emitEvent(); + } } +<<<<<<< HEAD 调用 ``Final.destroy()`` 时会调用最后的派生重载函数 ``Base2.destroy``, 但是会绕过 ``Base1.destroy``, 解决这个问题的方法是使用 ``super``: +======= +A call to ``Final.emitEvent()`` will call ``Base2.emitEvent`` because we specify it +explicitly in the final override, but this function will bypass +``Base1.emitEvent``, resulting in the following sequence of events: +``FinalEmitted -> Base2Emitted -> Emitted``, instead of the expected sequence: +``FinalEmitted -> Base2Emitted -> Base1Emitted -> Emitted``. +The way around this is to use ``super``: +>>>>>>> english/develop .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; +<<<<<<< HEAD // 这将报告一个由于废弃的 selfdestruct 而产生的警告 +======= +>>>>>>> english/develop - contract owned { - constructor() { owner = payable(msg.sender); } + contract Owned { address payable owner; + constructor() { owner = payable(msg.sender); } } - contract Destructible is owned { - function destroy() virtual public { - if (msg.sender == owner) selfdestruct(owner); + contract Emittable is Owned { + event Emitted(); + + function emitEvent() virtual public { + if (msg.sender == owner) { + emit Emitted(); + } } } +<<<<<<< HEAD contract Base1 is Destructible { function destroy() public virtual override { /* 清除操作 1 */ super.destroy(); } } @@ -165,18 +282,55 @@ Solidity支持多重继承,包括多态性。 contract Base2 is Destructible { function destroy() public virtual override { /* 清除操作 2 */ super.destroy(); } +======= + contract Base1 is Emittable { + event Base1Emitted(); + function emitEvent() public virtual override { + /* Here, we emit an event to simulate some Base1 logic */ + emit Base1Emitted(); + super.emitEvent(); + } + } + + + contract Base2 is Emittable { + event Base2Emitted(); + function emitEvent() public virtual override { + /* Here, we emit an event to simulate some Base2 logic */ + emit Base2Emitted(); + super.emitEvent(); + } +>>>>>>> english/develop } contract Final is Base1, Base2 { - function destroy() public override(Base1, Base2) { super.destroy(); } + event FinalEmitted(); + function emitEvent() public override(Base1, Base2) { + /* Here, we emit an event to simulate some Final logic */ + emit FinalEmitted(); + super.emitEvent(); + } } +<<<<<<< HEAD 如果 ``Base2`` 调用 ``super`` 的函数,它不会简单在其基类合约上调用该函数。 相反,它在最终的继承关系图谱的上一个基类合约中调用这个函数, 所以它会调用 ``Base1.destroy()`` (注意最终的继承序列是——从最远派生合约开始:Final, Base2, Base1, Destructible, ownerd)。 在类中使用 super 调用的实际函数在当前类的上下文中是未知的,尽管它的类型是已知的。 这与普通的虚拟方法查找类似。 +======= +If ``Final`` calls a function of ``super``, it does not simply +call this function on one of its base contracts. Rather, it +calls this function on the next base contract in the final +inheritance graph, so it will call ``Base1.emitEvent()`` (note that +the final inheritance sequence is -- starting with the most +derived contract: Final, Base2, Base1, Emittable, Owned). +The actual function that is called when using super is +not known in the context of the class where it is used, +although its type is known. This is similar for ordinary +virtual method lookup. +>>>>>>> english/develop .. index:: ! overriding;function @@ -358,8 +512,14 @@ Solidity支持多重继承,包括多态性。 构造函数 ============ +<<<<<<< HEAD 构造函数是一个用 ``constructor`` 关键字声明的可选函数, 它在合约创建时被执行,您可以在这里运行合约初始化代码。 +======= +A constructor is an optional function declared with the ``constructor`` keyword +which is executed upon contract creation, and where you can run contract +initialization code. +>>>>>>> english/develop 在构造函数代码执行之前,如果您用内联编程的方式初始化状态变量,则将其初始化为指定的值; 如果您不用内联编程的方式来初始化,则将其初始化为 :ref:`默认值 `。 diff --git a/docs/contracts/libraries.rst b/docs/contracts/libraries.rst index 9afdb8dd69d4..fbb7dacedf84 100644 --- a/docs/contracts/libraries.rst +++ b/docs/contracts/libraries.rst @@ -170,6 +170,7 @@ 通过将库合约的类型转换为 ``address`` 类型,即使用 ``address(LibraryName)``,可以获得一个库的地址。 +<<<<<<< HEAD 由于编译器不知道库合约的部署地址, 编译后的十六进制代码将包含 ``__$30bbc0abd4d6364515865950d3e0d10953$__`` 形式的占位符。 占位符是完全等同于库合约名的keccak256哈希值的34个字符的前缀,例如 ``libraries/bigint.sol:BigInt``, @@ -177,6 +178,17 @@ 这样的字节码是不完整的,不应该被部署。占位符需要被替换成实际地址。 您可以在编译库的时候把它们传递给编译器,或者用链接器来更新已经编译好的二进制文件。 参见 :ref:`library-linking`,了解如何使用命令行编译器进行链接。 +======= +As the compiler does not know the address where the library will be deployed, the compiled hex code +will contain placeholders of the form ``__$30bbc0abd4d6364515865950d3e0d10953$__`` `(format was different `_. The placeholder +is a 34 character prefix of the hex encoding of the keccak256 hash of the fully qualified library +name, which would be for example ``libraries/bigint.sol:BigInt`` if the library was stored in a file +called ``bigint.sol`` in a ``libraries/`` directory. Such bytecode is incomplete and should not be +deployed. Placeholders need to be replaced with actual addresses. You can do that by either passing +them to the compiler when the library is being compiled or by using the linker to update an already +compiled binary. See :ref:`library-linking` for information on how to use the commandline compiler +for linking. +>>>>>>> english/develop 与合约相比,库在以下方面受到限制: diff --git a/docs/contracts/transient-storage.rst b/docs/contracts/transient-storage.rst new file mode 100644 index 000000000000..b2d0be292204 --- /dev/null +++ b/docs/contracts/transient-storage.rst @@ -0,0 +1,172 @@ +.. index:: ! transient storage, ! transient, tstore, tload + +.. _transient-storage: + +***************** +Transient Storage +***************** + +Transient storage is another data location besides memory, storage, calldata +(and return-data and code) which was introduced alongside its respective opcodes +``TSTORE`` and ``TLOAD`` by `EIP-1153 `_. +This new data location behaves as a key-value store similar to storage with the main +difference being that data in transient storage is not permanent, but is scoped to +the current transaction only, after which it will be reset to zero. +Since the content of transient storage has very limited lifetime and size, +it does not need to be stored permanently as a part of state +and the associated gas costs are much lower than in case of storage. +EVM version ``cancun`` or newer is required for transient storage to be available. + +Transient storage variables cannot be initialized in place, i.e., they cannot be assigned +to upon declaration, since the value would be cleared at the end of the creation transaction, +rendering the initialization ineffective. +Transient variables will be :ref:`default value` initialized depending on +their underlying type. +``constant`` and ``immutable`` variables conflict with transient storage, since +their values are either inlined or directly stored in code. + +Transient storage variables have completely independent address space from storage, +so that the order of transient state variables does not affect the layout of storage +state variables and vice-versa. +They do need distinct names though because all state variables share the same namespace. +It is also important to note that the values in transient storage are packed in the +same fashion as those in persistent storage. +See :ref:`Storage Layout ` for more information. + +Besides that, transient variables can have visibility as well and ``public`` ones will +have a getter function generated automatically as usual. + +Note that, currently, such use of ``transient`` as a data location is only allowed for +:ref:`value type ` state variable declarations. +Reference types, such as arrays, mappings and structs, as well as local or parameter +variables are not yet supported. + +An expected canonical use case for transient storage is cheaper reentrancy locks, +which can be readily implemented with the opcodes as showcased next. + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity ^0.8.28; + + contract Generosity { + mapping(address => bool) sentGifts; + bool transient locked; + + modifier nonReentrant { + require(!locked, "Reentrancy attempt"); + locked = true; + _; + // Unlocks the guard, making the pattern composable. + // After the function exits, it can be called again, even in the same transaction. + locked = false; + } + + function claimGift() nonReentrant public { + require(address(this).balance >= 1 ether); + require(!sentGifts[msg.sender]); + (bool success, ) = msg.sender.call{value: 1 ether}(""); + require(success); + + // In a reentrant function, doing this last would open up the vulnerability + sentGifts[msg.sender] = true; + } + } + +Transient storage is private to the contract that owns it, in the same way as persistent storage. +Only owning contract frames may access their transient storage, and when they do, all the frames access the same transient store. + +Transient storage is part of the EVM state and is subject to the same mutability enforcements +as persistent storage. As such, any read access to it is not ``pure`` and writing access is not ``view``. + +If the ``TSTORE`` opcode is called within the context of a ``STATICCALL``, +it will result in an exception instead of performing the modification. +``TLOAD`` is allowed within the context of a ``STATICCALL``. + +When transient storage is used in the context of ``DELEGATECALL`` or ``CALLCODE``, +then the owning contract of the transient storage is the contract that issued ``DELEGATECALL`` +or ``CALLCODE`` instruction (the caller) as with persistent storage. +When transient storage is used in the context of ``CALL`` or ``STATICCALL``, +then the owning contract of the transient storage is the contract that is the target +of the ``CALL`` or ``STATICCALL`` instruction (the callee). + +.. note:: + In the case of ``DELEGATECALL``, since references to transient storage variables + are currently not supported, it is not possible to pass those into library calls. + In libraries, access to transient storage is only possible using inline assembly. + +If a frame reverts, all writes to transient storage that took place between entry +to the frame and the return are reverted, including those that took place in inner calls. +The caller of an external call may employ a ``try ... catch`` block to prevent reverts +bubbling up from the inner calls. + +********************************************************************* +Composability of Smart Contracts and the Caveats of Transient Storage +********************************************************************* + +Given the caveats mentioned in the specification of EIP-1153, +in order to preserve the composability of your smart contract, +utmost care is recommended for more advanced use cases of transient storage. + +For smart contracts, composability is a very important design principle to achieve self-contained behaviour, +such that multiple calls into individual smart contracts can be composed to more complex applications. +So far the EVM largely guaranteed composable behaviour, since multiple calls into a smart contract +within a complex transaction are virtually indistinguishable from multiple calls to the contract +stretched over several transactions. However, transient storage allows a violation of this principle, +and incorrect use may lead to complex bugs that only surface when used across several calls. + +Let's illustrate the problem with a simple example: + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity ^0.8.28; + + contract MulService { + uint transient multiplier; + function setMultiplier(uint mul) external { + multiplier = mul; + } + + function multiply(uint value) external view returns (uint) { + return value * multiplier; + } + } + +and a sequence of external calls: + +.. code-block:: solidity + + setMultiplier(42); + multiply(1); + multiply(2); + +If the example used memory or storage to store the multiplier, it would be fully composable. +It would not matter whether you split the sequence into separate transactions or grouped them in some way. +You would always get the same result: after ``multiplier`` is set to ``42``, the subsequent calls +would return ``42`` and ``84`` respectively. +This enables use cases such as batching calls from multiple transactions +together to reduce gas costs. +Transient storage potentially breaks such use cases since composability can no longer be taken for granted. +In the example, if the calls are not executed in the same transaction, then ``multiplier`` +is reset and the next calls to function ``multiply`` would always return ``0``. + +As another example, since transient storage is constructed as a relatively cheap key-value store, +a smart contract author may be tempted to use transient storage as a replacement for in-memory mappings +without keeping track of the modified keys in the mapping and thereby without clearing the mapping +at the end of the call. +This, however, can easily lead to unexpected behaviour in complex transactions, +in which values set by a previous call into the contract within the same transaction remain. + +The use of transient storage for reentrancy locks that are cleared at the end of the call frame +into the contract, is safe. +However, be sure to resist the temptation to save the 100 gas used for resetting the +reentrancy lock, since failing to do so, will restrict your contract to only one call +within a transaction, preventing its use in complex composed transactions, +which have been a cornerstone for complex applications on chain. + +It is recommend to generally always clear transient storage completely at the end of a call +into your smart contract to avoid these kinds of issues and to simplify +the analysis of the behaviour of your contract within complex transactions. +Check the `Security Considerations section of EIP-1153 `_ +for further details. \ No newline at end of file diff --git a/docs/contributing.rst b/docs/contributing.rst index 86838fd05b7b..e7ef093b1774 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -29,7 +29,11 @@ - 每周三下午3点,中欧标准时间/中欧夏令时间。 +<<<<<<< HEAD 会议在 `Jitsi `_ 举行。 +======= +The call takes place on `Jitsi `_. +>>>>>>> english/develop 如何报告问题 ==================== @@ -82,9 +86,16 @@ 先决条件 ------------- +<<<<<<< HEAD 为了运行所有的编译器测试,您可能想选择性地安装一些依赖项 ( `evmone `_, `libz3 `_)。 +======= +For running all compiler tests you may want to optionally install a few +dependencies (`evmone `_, +`z3 `_, `Eldarica `_, +`cvc5 `). +>>>>>>> english/develop 在 macOS 系统上,一些测试脚本需要安装 GNU 核心工具。 可以使用 Homebrew 很简单地完成安装: ``brew install coreutils``。 @@ -115,6 +126,7 @@ Solidity包括不同类型的测试,其中大部分捆绑在 ``evmone`` 主要用于运行语义和gas测试。 如果您没有安装它,您可以通过向 ``scripts/soltest.sh`` 传递 ``--no-semantic-tests`` 标志来跳过这些测试。 +<<<<<<< HEAD ``evmone`` 库的文件名后缀应该 是Linux上的 ``.so``,Windows系统上的 ``.dll``,MacOS上的 ``.dylib``。 @@ -123,6 +135,20 @@ Solidity包括不同类型的测试,其中大部分捆绑在 如果您的系统没有安装 ``libz3`` 库,您应该在运行 ``./scripts/tests.sh`` 或 ``./scripts/soltest.sh --no-smt`` 之前, 通过导出 ``SMT_FLAGS=--no-smt`` 来禁用SMT测试。 这些测试是 ``libsolidity/smtCheckerTests`` 和 ``libsolidity/smtCheckerTestsJSON``。 +======= +The ``evmone`` library should end with the file name +extension ``.so`` on Linux, ``.dll`` on Windows systems and ``.dylib`` on macOS. + +For running SMT tests, the ``z3`` executable must be present in ``PATH``. +A few SMT tests use ``Eldarica`` instead of ``z3``. +These requry its executable (``eld``) to be present in ``PATH`` for the tests to pass. +However, if ``Eldarica`` is not found, these tests will be automatically skipped. + +If ``z3`` is not present on your system, you should disable the +SMT tests by exporting ``SMT_FLAGS=--no-smt`` before running ``./scripts/tests.sh`` or +running ``./scripts/soltest.sh --no-smt``. +These tests are ``libsolidity/smtCheckerTests``. +>>>>>>> english/develop .. note:: @@ -147,9 +173,15 @@ Solidity包括不同类型的测试,其中大部分捆绑在 .. note:: +<<<<<<< HEAD 那些在Windows环境下使用的人,想在没有libz3的情况下运行上述基本集,可以使用Git Bash, 使用命令为: ``./build/test/Release/soltest.exe -- --no-smt``。 如果您在普通的命令提示符下运行,使用 ``.\build\test\Release\soltest.exe -- --no-smt``。 +======= + Those working in a Windows environment wanting to run the above basic sets + without z3. Using Git Bash, you use: ``./build/test/Release/soltest.exe -- --no-smt``. + If you are running this in plain Command Prompt, use ``.\build\test\Release\soltest.exe -- --no-smt``. +>>>>>>> english/develop 如果您想使用GDB进行调试,确保您的构建方式与 “通常” 不同。 例如,您可以在您的 ``build`` 文件夹中运行以下命令: @@ -523,11 +555,17 @@ Solidity论坛作为提出和讨论新的语言功能及其在早期构思阶段 我们也在论坛中分享反馈调查和其他与语言设计相关的内容。 +<<<<<<< HEAD 如果您想知道团队在实施新功能方面的情况, 您可以在 `Solidity Github项目 `_ 中关注实施状况。 设计积压中的问题需要进一步规范,将在语言设计电话会议或常规团队电话会议中讨论。 您可以通过从默认分支( `develop` )到 `breaking 分支 `_ 来查看下一个突破性版本即将发生的变化。 +======= +If you want to know where the team is standing in terms of implementing new features, you can follow the implementation status in the `Solidity GitHub project `_. +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 `_. +>>>>>>> english/develop 对于特殊情况和问题,您可以通过 `Solidity-dev Gitter 频道 `_ 与我们联系, - 这是一个专门用于围绕 Solidity 编译器和语言开发的聊天室。 diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 8bdd8003ab73..34abfd431993 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -539,8 +539,15 @@ Solidity 使用状态恢复异常来处理错误。 内置的错误 ``Error(string)`` 和 ``Panic(uint256)`` 被特殊函数使用, 解释如下。 ``Error`` 用于 "常规" 错误条件,而 ``Panic`` 用于在无错误代码中不应该出现的错误。 +<<<<<<< HEAD 通过 ``assert`` 引起Panic异常和通过 ``require`` 引起Error异常 ------------------------------------------------------------- +======= +.. _assert-and-require-statements: + +Panic via ``assert`` and Error via ``require`` +---------------------------------------------- +>>>>>>> english/develop 快捷函数 ``assert`` 和 ``require`` 可以用来检查条件,如果不符合条件就抛出一个异常。 @@ -566,6 +573,7 @@ Assert应该只用于测试内部错误,以及检查不变量。 #. 0x41: 如果您分配了太多的内存空间或创建了一个太大的数组。 #. 0x51: 如果您调用一个零初始化的内部函数类型的变量。 +<<<<<<< HEAD ``require`` 函数要么创造一个没有任何数据的错误, 要么创造一个 ``Error(string)`` 类型的错误。 它应该被用来确保在执行之前无法检测到的有效条件。 @@ -577,6 +585,22 @@ Assert应该只用于测试内部错误,以及检查不变量。 请使用 ``if (!condition) revert CustomError();`` 代替。 在下列情况下,编译器会产生一个 ``Error(string)`` 异常(或者没有数据的异常)。 +======= +The ``require`` function provides three overloads: + +1. ``require(bool)`` which will revert without any data (not even an error selector). +2. ``require(bool, string)`` which will revert with an ``Error(string)``. +3. ``require(bool, error)`` which will revert with the custom, user supplied error provided as the second argument. + +.. note:: + ``require`` arguments are evaluated unconditionally, so take special care to make sure that + they are not expressions with unexpected side-effects. + For example, in ``require(condition, CustomError(f()));`` and ``require(condition, f());``, + function ``f()`` will be called regardless of whether the supplied condition is ``true`` or ``false``. + +An ``Error(string)`` exception (or an exception without data) is generated +by the compiler in the following situations: +>>>>>>> english/develop #. 调用 ``require(x)``,其中 ``x`` 的值为 ``false``。 #. 如果您使用 ``revert()`` 或 ``revert("错误描述")``。 @@ -595,11 +619,19 @@ Assert应该只用于测试内部错误,以及检查不变量。 #. 如果您使用 ``new`` 关键字创建一个合约, 但合约创建 :ref:`没有正常完成 `。 +<<<<<<< HEAD 您可以选择为 ``require`` 提供一个信息字符串,但不能为 ``assert`` 提供。 .. note:: 如果您没有给 ``require`` 提供一个字符串参数,它将以空的错误数据进行还原, 甚至不包括错误选择器。 +======= +You can optionally provide a message string or a custom error to ``require``, but not to ``assert``. + +.. note:: + If you do not provide a string or custom error argument to ``require``, it will revert + with empty error data, not even including the error selector. +>>>>>>> english/develop 下面的例子显示了如何使用 ``require`` 来检查输入的条件 diff --git a/docs/docs.sh b/docs/docs.sh index f2c566761228..abe4921e306c 100755 --- a/docs/docs.sh +++ b/docs/docs.sh @@ -31,5 +31,8 @@ set -euo pipefail script_dir="$(dirname "$0")" cd "${script_dir}" -pip3 install -r requirements.txt --upgrade --upgrade-strategy eager +# TODO `--ignore-installed` now fixes an issue where pip tries to uninstall a Debian installed package, but is unable to +# TODO since Debian has decided to not use the RECORD file, which then breaks pip. +# TODO https://github.com/pypa/pip/issues/11631 and https://bugs.launchpad.net/ubuntu/+source/wheel/+bug/2063151 +pip3 install -r requirements.txt --ignore-installed --upgrade --upgrade-strategy eager sphinx-build -nW -b html -d _build/doctrees . _build/html diff --git a/docs/examples/micropayment.rst b/docs/examples/micropayment.rst index 0e3dea03c8e7..9e997932ca8d 100644 --- a/docs/examples/micropayment.rst +++ b/docs/examples/micropayment.rst @@ -49,7 +49,11 @@ Alice不需要与以太坊网络交互来签署交易,这个过程是完全离 签署内容 ------------ +<<<<<<< HEAD 对于履行付款的合约,签署的信息必须包括: +======= +For a contract that fulfills payments, the signed message must include: +>>>>>>> english/develop 1. 收件人的钱包地址。 2. 要转移的金额。 @@ -69,8 +73,17 @@ Alice可以通过在消息中包含合约的地址来防止这种攻击, 并且只有包含合约地址本身的消息才会被接受。 您可以在本节末尾的完整合约的 ``claimPayment()`` 函数的前两行找到这个例子。 +<<<<<<< HEAD 组装参数 --------- +======= +Furthermore, instead of destroying the contract by calling ``selfdestruct``, +which is currently deprecated, we will disable the contract's functionalities by freezing it, +resulting in the reversion of any call after it being frozen. + +Packing arguments +----------------- +>>>>>>> english/develop 既然我们已经确定了要在签名信息中包含哪些信息, 我们准备把信息放在一起,进行哈希运算,然后签名。 @@ -130,30 +143,65 @@ web3.js 产生的签名是 ``r``, ``s`` 和 ``v`` 的拼接的, // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; +<<<<<<< HEAD // 这将报告一个由于废弃的 selfdestruct 而产生的警告 contract ReceiverPays { address owner = msg.sender; +======= +>>>>>>> english/develop + + contract Owned { + address payable owner; + constructor() { + owner = payable(msg.sender); + } + } + + contract Freezable is Owned { + bool private _frozen = false; + + modifier notFrozen() { + require(!_frozen, "Inactive Contract."); + _; + } + function freeze() internal { + if (msg.sender == owner) + _frozen = true; + } + } + + contract ReceiverPays is Freezable { mapping(uint256 => bool) usedNonces; constructor() payable {} - function claimPayment(uint256 amount, uint256 nonce, bytes memory signature) external { + function claimPayment(uint256 amount, uint256 nonce, bytes memory signature) + external + notFrozen + { require(!usedNonces[nonce]); usedNonces[nonce] = true; // 这将重新创建在客户端上签名的信息。 bytes32 message = prefixed(keccak256(abi.encodePacked(msg.sender, amount, nonce, this))); - require(recoverSigner(message, signature) == owner); - payable(msg.sender).transfer(amount); } +<<<<<<< HEAD /// 销毁合约并收回剩余的资金。 function shutdown() external { +======= + /// freeze the contract and reclaim the leftover funds. + function shutdown() + external + notFrozen + { +>>>>>>> english/develop require(msg.sender == owner); - selfdestruct(payable(msg.sender)); + freeze(); + payable(msg.sender).transfer(address(this).balance); } /// 签名方法。 @@ -182,7 +230,6 @@ web3.js 产生的签名是 ``r``, ``s`` 和 ``v`` 的拼接的, returns (address) { (uint8 v, bytes32 r, bytes32 s) = splitSignature(sig); - return ecrecover(message, v, r, s); } @@ -282,11 +329,19 @@ Alice通过向Bob发送签名信息进行支付。 关闭支付通道 ------------ +<<<<<<< HEAD 当Bob准备好接收他的资金时, 是时候通过调用智能合约上的 ``close`` 函数关闭支付通道了。 关闭通道会向接收者支付欠他们的以太币,并销毁合约, 将任何剩余的以太币送回给Alice。 为了关闭通道,Bob需要提供一个由Alice签名的信息。 +======= +When Bob is ready to receive his funds, it is time to +close the payment channel by calling a ``close`` function on the smart contract. +Closing the channel pays the recipient the Ether they are owed and +deactivates the contract by freezing it, sending any remaining Ether back to Alice. To +close the channel, Bob needs to provide a message signed by Alice. +>>>>>>> english/develop 智能合约必须验证该消息是否包含发送者的有效签名。 进行这种验证的过程与接收者使用签名的过程相同。 @@ -298,10 +353,17 @@ Solidity函数 ``isValidSignature`` 和 ``recoverSigner`` 的工作方式 如果允许发送者调用这个函数,他们可以提供一个金额较低的签名消息, 骗取接收者的欠款。 +<<<<<<< HEAD 该函数会验证签名的信息与给定的参数是否相符。 如果一切正常,接收者就会收到他们的那部分以太币, 而剩下的以太币将通过 ``selfdestruct`` 发送给发送者。 您可以在完整的合约中看到 ``close`` 函数。 +======= +The function verifies the signed message matches the given parameters. +If everything checks out, the recipient is sent their portion of the Ether, +and the sender is sent the remaining funds via a ``transfer``. +You can see the ``close`` function in the full contract. +>>>>>>> english/develop 通道到期 -------- @@ -322,11 +384,32 @@ Alice需要一个方法来收回她的托管资金。在合约部署的时候, // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; +<<<<<<< HEAD // 这将报告一个由于废弃的 selfdestruct 而产生的警告 contract SimplePaymentChannel { address payable public sender; // 发送付款的账户。 address payable public recipient; // 接收付款的账户。 uint256 public expiration; // 超时时间,以防接收者永不关闭支付通道。 +======= + + contract Frozeable { + bool private _frozen = false; + + modifier notFrozen() { + require(!_frozen, "Inactive Contract."); + _; + } + + function freeze() internal { + _frozen = true; + } + } + + contract SimplePaymentChannel is Frozeable { + address payable public sender; // The account sending payments. + address payable public recipient; // The account receiving the payments. + uint256 public expiration; // Timeout in case the recipient never closes. +>>>>>>> english/develop constructor (address payable recipientAddress, uint256 duration) payable @@ -336,29 +419,58 @@ Alice需要一个方法来收回她的托管资金。在合约部署的时候, expiration = block.timestamp + duration; } +<<<<<<< HEAD /// 接收者可以在任何时候通过提供发送者签名的金额来关闭通道, /// 接收者将获得该金额,其余部分将返回发送者。 function close(uint256 amount, bytes memory signature) external { +======= + /// the recipient can close the channel at any time by presenting a + /// signed amount from the sender. the recipient will be sent that amount, + /// and the remainder will go back to the sender + function close(uint256 amount, bytes memory signature) + external + notFrozen + { +>>>>>>> english/develop require(msg.sender == recipient); require(isValidSignature(amount, signature)); recipient.transfer(amount); - selfdestruct(sender); + freeze(); + sender.transfer(address(this).balance); } +<<<<<<< HEAD /// 发送者可以在任何时候延长到期时间。 function extend(uint256 newExpiration) external { +======= + /// the sender can extend the expiration at any time + function extend(uint256 newExpiration) + external + notFrozen + { +>>>>>>> english/develop require(msg.sender == sender); require(newExpiration > expiration); expiration = newExpiration; } +<<<<<<< HEAD /// 如果达到超时时间而接收者没有关闭通道, /// 那么以太就会被释放回给发送者。 function claimTimeout() external { +======= + /// if the timeout is reached without the recipient closing the channel, + /// then the Ether is released back to the sender. + function claimTimeout() + external + notFrozen + { +>>>>>>> english/develop require(block.timestamp >= expiration); - selfdestruct(sender); + freeze(); + sender.transfer(address(this).balance); } function isValidSignature(uint256 amount, bytes memory signature) @@ -367,6 +479,7 @@ Alice需要一个方法来收回她的托管资金。在合约部署的时候, returns (bool) { bytes32 message = prefixed(keccak256(abi.encodePacked(this, amount))); +<<<<<<< HEAD // 检查签名是否来自付款方。 return recoverSigner(message, signature) == sender; @@ -374,6 +487,14 @@ Alice需要一个方法来收回她的托管资金。在合约部署的时候, /// 下面的所有功能是取自 '创建和验证签名' 的章节。 +======= + // check that the signature is from the payment sender + return recoverSigner(message, signature) == sender; + } + + /// All functions below this are just taken from the chapter + /// 'creating and verifying signatures' chapter. +>>>>>>> english/develop function splitSignature(bytes memory sig) internal pure @@ -389,7 +510,6 @@ Alice需要一个方法来收回她的托管资金。在合约部署的时候, // 最后一个字节(下一个32字节的第一个字节)。 v := byte(0, mload(add(sig, 96))) } - return (v, r, s); } @@ -399,7 +519,6 @@ Alice需要一个方法来收回她的托管资金。在合约部署的时候, returns (address) { (uint8 v, bytes32 r, bytes32 s) = splitSignature(sig); - return ecrecover(message, v, r, s); } @@ -411,10 +530,16 @@ Alice需要一个方法来收回她的托管资金。在合约部署的时候, .. note:: +<<<<<<< HEAD 函数 ``splitSignature`` 并没有使用所有的安全检查。 真正的实现应该使用更严格的测试库,例如openzepplin的 `这个版本 `_ 的这个代码。 +======= + The function ``splitSignature`` does not use all security + checks. A real implementation should use a more rigorously tested library, + such as openzeppelin's `version `_ of this code. +>>>>>>> english/develop 验证付款 -------- diff --git a/docs/grammar/SolidityLexer.g4 b/docs/grammar/SolidityLexer.g4 index 620d0a6d3e3c..296a5d2fea70 100644 --- a/docs/grammar/SolidityLexer.g4 +++ b/docs/grammar/SolidityLexer.g4 @@ -85,6 +85,7 @@ SignedIntegerType: Storage: 'storage'; String: 'string'; Struct: 'struct'; +Transient: 'transient'; // not a real keyword True: 'true'; Try: 'try'; Type: 'type'; @@ -296,14 +297,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' | 'prevrandao' - | '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 8c8c37210d4d..41b6d0610bcf 100644 --- a/docs/grammar/SolidityParser.g4 +++ b/docs/grammar/SolidityParser.g4 @@ -250,7 +250,7 @@ structMember: type=typeName name=identifier Semicolon; /** * 一个枚举的定义。可以出现在源代码单元的顶层,也可以出现在合约,库或接口中。 */ -enumDefinition: Enum name=identifier LBrace enumValues+=identifier (Comma enumValues+=identifier)* RBrace; +enumDefinition: Enum name=identifier LBrace enumValues+=identifier (Comma enumValues+=identifier)* RBrace; /** * 用户自定义的值类型的定义。可以出现在源代码单元的顶层,也可以出现在合约,库或接口中。 */ @@ -261,7 +261,7 @@ userDefinedValueTypeDefinition: * 一个状态变量的声明。 */ stateVariableDeclaration -locals [boolean constantnessSet = false, boolean visibilitySet = false, boolean overrideSpecifierSet = false] +locals [boolean constantnessSet = false, boolean visibilitySet = false, boolean overrideSpecifierSet = false, boolean locationSet = false] : type=typeName ( @@ -271,6 +271,7 @@ locals [boolean constantnessSet = false, boolean visibilitySet = false, boolean | {!$constantnessSet}? Constant {$constantnessSet = true;} | {!$overrideSpecifierSet}? overrideSpecifier {$overrideSpecifierSet = true;} | {!$constantnessSet}? Immutable {$constantnessSet = true;} + | {!$locationSet}? Transient {$locationSet = true;} )* name=identifier (Assign initialValue=expression)? @@ -336,7 +337,14 @@ userDefinableOperator: * 使用指令将库函数和自由函数附加到类型上。 * 可以在合约、库和文件级别中出现。 */ -usingDirective: Using (identifierPath | (LBrace identifierPath (As userDefinableOperator)? (Comma identifierPath (As userDefinableOperator)?)* RBrace)) For (Mul | typeName) Global? Semicolon; +usingDirective: + Using ( + identifierPath + | (LBrace usingAliases (Comma usingAliases)* RBrace) + ) For (Mul | typeName) Global? Semicolon; + +usingAliases: identifierPath (As userDefinableOperator)?; + /** * 使用指令将库函数和自由函数附加到类型上。 * 可以在合约和库中以及文件层面中出现。 @@ -397,7 +405,7 @@ expression: | New typeName # NewExpr | tupleExpression # Tuple | inlineArrayExpression # InlineArray - | ( + | ( identifier | literal | literalWithSubDenomination @@ -416,7 +424,7 @@ inlineArrayExpression: LBrack (expression ( Comma expression)* ) RBrack; /** * 除了常规的非关键字标识符,一些关键字如 ‘from‘ 和 ‘error‘ 也可以作为标识符。 */ -identifier: Identifier | From | Error | Revert | Global; +identifier: Identifier | From | Error | Revert | Global | Transient; literal: stringLiteral | numberLiteral | booleanLiteral | hexStringLiteral | unicodeStringLiteral; diff --git a/docs/index.rst b/docs/index.rst index 7be9276d2ce4..9056287176d3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,11 +3,17 @@ Solidity .. warning:: +<<<<<<< HEAD You are reading a community translation of the Solidity documentation. The Solidity team can give no guarantees on the quality and accuracy of the translations provided. The English reference version is and will remain the only officially supported version by the Solidity team and will always be the most accurate and most up-to-date one. When in doubt, please always refer to the `English (original) documentation `_. +======= +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. +>>>>>>> english/develop Solidity是一门为实现智能合约而创建的面向对象的高级编程语言。 智能合约是管理以太坊中账户行为的程序。 diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index e4e67ade25e2..74c81b7add8b 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -69,8 +69,13 @@ npm / Node.js Docker ====== +<<<<<<< HEAD Solidity构建的Docker镜像可以使用从 ``ethereum`` 组织获得的 ``solc`` 镜像。 使用 ``stable`` 标签获取最新发布的版本,使用 ``nightly`` 标签获取开发分支中潜在的不稳定变更的版本。 +======= +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. +>>>>>>> english/develop Docker镜像会运行编译器可执行文件,以便您可以将所有编译器参数传递给它。 例如,下面的命令提取了稳定版的 ``solc`` 镜像(如果您还没有), @@ -80,14 +85,29 @@ Docker镜像会运行编译器可执行文件,以便您可以将所有编译 docker run ethereum/solc:stable --help +<<<<<<< HEAD 例如,您可以在0.5.4版本的标签中指定发布的构建版本。 +======= +You can specify release build versions in the tag. For example: +>>>>>>> english/develop .. code-block:: bash - docker run ethereum/solc:0.5.4 --help + docker run ethereum/solc:stable --help + +Note + +Specific compiler versions are supported as the Docker image tag such as `ethereum/solc:0.8.23`. We will be passing the +`stable` tag here instead of specific version tag to ensure that users get the latest version by default and avoid the issue of +an out-of-date version. +<<<<<<< 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 @@ -172,8 +192,13 @@ macOS 软件包 如果您需要特定版本的 Solidity,您可以直接从 Github 上安装一个 Homebrew 列表。 +<<<<<<< HEAD 参见 `solidity.rb 在 Github 上的提交情况 `_. +======= +View +`solidity.rb commits on GitHub `_. +>>>>>>> english/develop 复制您想要的版本的提交哈希值,然后在您的机器上检出该分支。 @@ -212,9 +237,16 @@ macOS 软件包 (通过 git、HTTPS、IPFS 或者只是在本地的缓存),并在下载后验证二进制文件的哈希值, 您就不必通过HTTPS获得二进制文件。 +<<<<<<< HEAD 在大多数情况下,同样的二进制文件可以在 `Github 上的 Solidity 发布页 `_ 中找到。 不同的是,我们一般不更新Github已发布的旧版本。这意味着如果命名规则改变,我们不会重新命名, 也不会为发布时不支持的平台添加构建。这只发生在 ``solc-bin`` 资源库里。 +======= +The same binaries are in most cases available on the `Solidity release page on GitHub`_. The +difference is that we do not generally update old releases on the GitHub release page. This means +that we do not rename them if the naming convention changes and we do not add builds for platforms +that were not supported at the time of release. This only happens in ``solc-bin``. +>>>>>>> english/develop ``solc-bin`` 资源库包含几个顶级目录,每个目录代表一个平台。 每个目录都包含一个 ``list.json`` 文件,列出可用的二进制文件。 @@ -230,7 +262,6 @@ macOS 软件包 "keccak256": "0x300330ecd127756b824aa13e843cb1f43c473cb22eaf3750d5fb9c99279af8c3", "sha256": "0x2b55ed5fec4d9625b6c7b3ab1abd2b7fb7dd2a9c68543bf0323db2c7e2d55af2", "urls": [ - "bzzr://16c5f09109c793db99fe35f037c6092b061bd39260ee7a677c8a97f18c955ab1", "dweb:/ipfs/QmTLs5MuLEWXQkths41HiACoXDiH8zxyqBHGFDRSzVE5CS" ] } @@ -239,6 +270,7 @@ macOS 软件包 - 您可以在同一目录下找到二进制文件,名称为 `solc-emscripten-wasm32-v0.7.4+commit.3f05b770.js `_. +<<<<<<< HEAD 注意,该文件可能是一个软链接,如果您没有使用 git 下载,或者您的文件系统不支持软链接,您需要自己解决。 - 该二进制文件也被镜像在 https://binaries.soliditylang.org/emscripten-wasm32/solc-emscripten-wasm32-v0.7.4+commit.3f05b770.js. 在这种情况下,不需要 git,软链接的解决方式是显而易见的,要么提供一个文件的副本,要么返回一个 HTTP 重定向。 @@ -251,6 +283,21 @@ macOS 软件包 或在 JavaScript 中使用 `ethereumjs-util 的 keccak256() 函数`_ - 您也可以通过比较二进制文件的sha256哈希值来验证它的完整性 ``0x2b55ed5fec4d9625b6c7b3ab1abd2b7fb7dd2a9c68543bf0323db2c7e2d55af2``。 +======= + 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`_. + Please, be aware that the order of items in the ``urls`` array is not predetermined or guaranteed and users should not rely on it. +- 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 .. warning:: @@ -279,14 +326,12 @@ macOS 软件包 ``binaries.soliditylang.org`` 可以保证长期运行并保持相同的URL结构。 .. _IPFS: https://ipfs.io -.. _Swarm: https://swarm-gateways.net/bzz:/swarm.eth .. _solc-bin: https://github.com/ethereum/solc-bin/ -.. _Solidity release page on github: https://github.com/ethereum/solidity/releases +.. _Solidity release page on GitHub: https://github.com/ethereum/solidity/releases .. _sha3sum: https://github.com/maandree/sha3sum .. _ethereumjs-util 的 keccak256() 函数: https://github.com/ethereumjs/ethereumjs-util/blob/master/docs/modules/_hash_.md#const-keccak256 .. _WebAssembly 构建: https://emscripten.org/docs/compiling/WebAssembly.html .. _QmTLs5MuLEWXQkths41HiACoXDiH8zxyqBHGFDRSzVE5CS: https://gateway.ipfs.io/ipfs/QmTLs5MuLEWXQkths41HiACoXDiH8zxyqBHGFDRSzVE5CS -.. _16c5f09109c793db99fe35f037c6092b061bd39260ee7a677c8a97f18c955ab1: https://swarm-gateways.net/bzz:/16c5f09109c793db99fe35f037c6092b061bd39260ee7a677c8a97f18c955ab1/ .. _building-from-source: @@ -297,6 +342,7 @@ macOS 软件包 以下是 Solidity 构建的所有依赖性: +<<<<<<< HEAD +------------------------------------------+------------------------------+ | 软件 | 备注 | @@ -313,8 +359,22 @@ macOS 软件包 +------------------------------------------+------------------------------+ | `cvc4`_ (可选) | 与SMT检查器一起使用。 | +------------------------------------------+------------------------------+ +======= ++-----------------------------------+-------------------------------------------------------+ +| Software | Notes | ++===================================+=======================================================+ +| `CMake`_ (version 3.21.3+ on | Cross-platform build file generator. | +| Windows, 3.13+ otherwise) | | ++-----------------------------------+-------------------------------------------------------+ +| `Boost`_ (version 1.77+ on | C++ libraries. | +| Windows, 1.67+ otherwise) | | ++-----------------------------------+-------------------------------------------------------+ +| `Git`_ | Command-line tool for retrieving source code. | ++-----------------------------------+-------------------------------------------------------+ +| `z3`_ (version 4.8.16+, Optional) | For use with SMT checker. | ++-----------------------------------+-------------------------------------------------------+ +>>>>>>> english/develop -.. _cvc4: https://cvc4.cs.stanford.edu/web/ .. _Git: https://git-scm.com/download .. _Boost: https://www.boost.org .. _CMake: https://cmake.org/download/ @@ -429,6 +489,7 @@ Visual Studio 2019 同时提供IDE和必要的编译器和库。 git remote add personal git@github.com:[username]/solidity.git +<<<<<<< HEAD .. note:: 这种方法将导致一个预发布版本的构建,例如,在这种编译器产生的每个字节码中设置一个标志。 如果您想重新构建一个已发布的 Solidity 编译器,那么请使用 github 发布页上的源压缩包: @@ -436,6 +497,17 @@ Visual Studio 2019 同时提供IDE和必要的编译器和库。 https://github.com/ethereum/solidity/releases/download/v0.X.Y/solidity_0.X.Y.tar.gz (而不是由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: + + https://github.com/ethereum/solidity/releases/download/v0.X.Y/solidity_0.X.Y.tar.gz + + (not the "Source code" provided by GitHub). +>>>>>>> english/develop 命令行构建 ------------------ @@ -496,6 +568,7 @@ CMake 选项 SMT 解算器 ----------- +<<<<<<< HEAD Solidity 可以针对 SMT 解算器进行构建,如果它们在系统中被发现, 将默认为是这样做的。每个解算器都可以通过 ``cmake`` 选项禁用。 @@ -514,6 +587,14 @@ Solidity 可以针对 SMT 解算器进行构建,如果它们在系统中被发 # 同时禁用Z3和CVC4 cmake .. -DUSE_CVC4=OFF -DUSE_Z3=OFF +======= +Solidity can optionally use SMT solvers, namely ``z3``, ``cvc5`` and ``Eldarica``, +but their presence is checked only at runtime, they are not needed for the build to succeed. + +.. note:: + + The emscripten builds require Z3 and will statically link against it instead. +>>>>>>> english/develop 版本号字符串详解 ============================ diff --git a/docs/internals/layout_in_storage.rst b/docs/internals/layout_in_storage.rst index 7fbe291a7033..3b045f25ee9e 100644 --- a/docs/internals/layout_in_storage.rst +++ b/docs/internals/layout_in_storage.rst @@ -1,5 +1,6 @@ -.. index:: storage, state variable, mapping +.. index:: storage, state variable, mapping, transient storage +<<<<<<< HEAD ************************************ 存储中的状态变量储存结构 ************************************ @@ -13,6 +14,28 @@ 它被存储在槽 ``0`` 中。对于每个变量, 根据它的类型确定一个字节的大小。如果可能的话,需要少于32字节的多个连续项目被打包到一个存储槽中, 根据以下规则: +======= +********************************************************** +Layout of State Variables in Storage and Transient Storage +********************************************************** + +.. _storage-inplace-encoding: + +.. note:: + The rules described in this section apply for both storage and transient storage data locations. + The layouts are completely independent and don't interfere with each other's variable locations. + Thus storage and transient storage state variables can be safely interleaved without any side effects. + Only value types are supported for transient storage. + +State variables of contracts are stored in storage in a compact way such +that multiple values sometimes use the same storage slot. +Except for dynamically-sized arrays and mappings (see below), data is stored +contiguously item after item starting with the first state variable, +which is stored in slot ``0``. For each variable, +a size in bytes is determined according to its type. +Multiple, contiguous items that need less than 32 bytes are packed into a single +storage slot if possible, according to the following rules: +>>>>>>> english/develop - 存储插槽的第一项会以低位对齐(即右对齐)的方式储存。 - 值类型只使用存储它们所需的字节数。 @@ -135,9 +158,16 @@ JSON输出 .. _storage-layout-top-level: +<<<<<<< HEAD 合约的存储结构可以通过 :ref:`标准的JSON接口 ` 请求获得。 输出的是一个JSON对象,包含两个键, ``storage`` 和 ``types``。 ``storage`` 对象是一个数组,每个元素都有以下形式: +======= +The storage (or transient storage) layout of a contract can be requested via +the :ref:`standard JSON interface `. The output is a JSON object containing two keys, +``storage`` and ``types``. The ``storage`` object is an array where each +element has the following form: +>>>>>>> english/develop .. code-block:: json @@ -193,13 +223,18 @@ JSON输出 .. note:: 合约的存储结构的JSON输出格式仍被认为是实验性的,并且在Solidity的非重大版本中会有变化。 +<<<<<<< HEAD 下面的例子显示了一个合约及其存储结构,包含值类型和引用类型,被编码打包的类型,以及嵌套的类型。 +======= +The following example shows a contract and both its storage and transient storage layout, +containing value and reference types, types that are encoded packed, and nested types. +>>>>>>> english/develop .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.4.0 <0.9.0; + pragma solidity ^0.8.28; contract A { struct S { uint128 a; @@ -209,15 +244,22 @@ JSON输出 } uint x; - uint y; + uint transient y; + uint w; + uint transient z; + S s; address addr; + address transient taddr; mapping(uint => mapping(address => bool)) map; uint[] array; string s1; bytes b1; } +Storage Layout +-------------- + .. code-block:: json { @@ -231,15 +273,15 @@ JSON输出 "type": "t_uint256" }, { - "astId": 17, + "astId": 19, "contract": "fileA:A", - "label": "y", + "label": "w", "offset": 0, "slot": "1", "type": "t_uint256" }, { - "astId": 20, + "astId": 24, "contract": "fileA:A", "label": "s", "offset": 0, @@ -247,7 +289,7 @@ JSON输出 "type": "t_struct(S)13_storage" }, { - "astId": 22, + "astId": 26, "contract": "fileA:A", "label": "addr", "offset": 0, @@ -255,7 +297,7 @@ JSON输出 "type": "t_address" }, { - "astId": 28, + "astId": 34, "contract": "fileA:A", "label": "map", "offset": 0, @@ -263,7 +305,7 @@ JSON输出 "type": "t_mapping(t_uint256,t_mapping(t_address,t_bool))" }, { - "astId": 31, + "astId": 37, "contract": "fileA:A", "label": "array", "offset": 0, @@ -271,7 +313,7 @@ JSON输出 "type": "t_array(t_uint256)dyn_storage" }, { - "astId": 33, + "astId": 39, "contract": "fileA:A", "label": "s1", "offset": 0, @@ -279,7 +321,7 @@ JSON输出 "type": "t_string_storage" }, { - "astId": 35, + "astId": 41, "contract": "fileA:A", "label": "b1", "offset": 0, @@ -385,3 +427,49 @@ JSON输出 } } } + +Transient Storage Layout +------------------------ + +.. code-block:: json + + { + "storage": [ + { + "astId": 17, + "contract": "fileA:A", + "label": "y", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 21, + "contract": "fileA:A", + "label": "z", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 28, + "contract": "fileA:A", + "label": "taddr", + "offset": 0, + "slot": "2", + "type": "t_address" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } \ No newline at end of file diff --git a/docs/internals/optimizer.rst b/docs/internals/optimizer.rst index cd5af563e4b8..3a4649433a82 100644 --- a/docs/internals/optimizer.rst +++ b/docs/internals/optimizer.rst @@ -5,8 +5,16 @@ 优化器 ************* +<<<<<<< HEAD Solidity编译器使用两种不同的优化器模块。在操作码水平上操作的 “旧” 优化器 和在 Yul IR 代码上操作的 “新” 优化器。 +======= +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. +>>>>>>> english/develop 基于操作码的优化器对操作码应用一套 `简化规则 `_。 它还结合了相等的代码集并删除了未使用的代码。 @@ -18,6 +26,7 @@ Solidity编译器使用两种不同的优化器模块。在操作码水平上操 如果它们的参数和返回值不相互依赖,我们就可以对函数调用重新排序。 同样地,如果一个函数是没有副作用的,而且其结果是乘以0的,就可以完全删除该函数调用。 +<<<<<<< HEAD 目前,参数 ``--optimize`` 会为生成的字节码激活基于操作码的优化器, 并为内部生成的 Yul 代码激活 Yul 优化器,例如当使用 ABI coder v2 时。 您可以使用 ``solc --ir optimized --optimize`` 来为 Solidity 源码产生一个优化的 Yul IR。 @@ -28,6 +37,36 @@ Solidity编译器使用两种不同的优化器模块。在操作码水平上操 总是默认启用的,只能通过 :ref:`标准 JSON 文件配置 ` 关闭。 您可以在下面找到关于这两个优化器模块及其优化步骤的更多细节。 +======= +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 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, i.e ``:``, 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. +>>>>>>> english/develop 优化Solidity代码的好处 ==================================== @@ -247,11 +286,19 @@ Solidity编译器使用两种不同的优化器模块。在操作码水平上操 下面将解释基于Yul的优化器模块的所有组件。 以下的转换步骤是主要的组成部分: +<<<<<<< HEAD - SSA转换 - 通用子表达式消除器 - 表达式简化器 - 冗余赋值消除器 - 完全内联 +======= +- SSATransform +- CommonSubexpressionEliminator +- ExpressionSimplifier +- UnusedAssignEliminator +- FullInliner +>>>>>>> english/develop .. _optimizer-steps: @@ -265,7 +312,7 @@ Solidity编译器使用两种不同的优化器模块。在操作码水平上操 缩略语 全称 ============ =============================== ``f`` :ref:`block-flattener` -``l`` :ref:`circular-reference-pruner` +``l`` :ref:`circular-references-pruner` ``c`` :ref:`common-subexpression-eliminator` ``C`` :ref:`conditional-simplifier` ``U`` :ref:`conditional-unsimplifier` @@ -287,11 +334,11 @@ Solidity编译器使用两种不同的优化器模块。在操作码水平上操 ``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` +``V`` :ref:`ssa-reverser` +``a`` :ref:`ssa-transform` ``t`` :ref:`structural-simplifier` +``r`` :ref:`unused-assign-eliminator` ``p`` :ref:`unused-function-parameter-pruner` ``S`` :ref:`unused-store-eliminator` ``u`` :ref:`unused-pruner` @@ -301,6 +348,7 @@ Solidity编译器使用两种不同的优化器模块。在操作码水平上操 一些步骤依赖于 ``块展平器``, ``函数分组器``, ``循环初始重写器`` 所保证的属性。 由于这个原因,Yul 优化器总是在应用用户提供的任何步骤之前应用它们。 +.. _selecting-optimizations: 选择优化方案 ----------------------- @@ -365,9 +413,15 @@ Solidity编译器使用两种不同的优化器模块。在操作码水平上操 函数分组器 ^^^^^^^^^^^^^^^ +<<<<<<< HEAD 函数分组器必须在消歧义器和函数提升器之后应用。 它的作用是将所有不是函数定义的最上面的元素移到一个单一的块中, 这个块是根块的第一个语句。 +======= +The function grouper has to be applied after the Disambiguator and the FunctionHoister. +Its effect is that all topmost elements that are not function definitions are moved +into a single block which is the first statement of the root block. +>>>>>>> english/develop 在这一步之后,一个程序具有以下正常形式: @@ -378,15 +432,25 @@ Solidity编译器使用两种不同的优化器模块。在操作码水平上操 其中 ``I`` 是一个(可能是空的)区块,不包含任何函数定义(甚至是递归的), ``F`` 是一个函数定义的列表,使得没有一个函数包含函数定义。 +<<<<<<< HEAD 这个阶段的好处是,我们总是知道功能列表的开始位置。 +======= +The benefit of this stage is that we always know where the list of functions begins. +>>>>>>> english/develop .. _for-loop-condition-into-body: 循环条件进入正文 ^^^^^^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 这种转换将for循环的循环迭代条件移动到循环体中。 我们需要这种转换,因为 :ref:`expression-splitter` 将不适用于迭代条件表达式(以下示例中的 ``C``)。 +======= +This transformation moves the loop-iteration condition of a ``for`` loop into loop body. +We need this transformation because :ref:`expression-splitter` will not +apply to iteration condition expressions (the ``C`` in the following example). +>>>>>>> english/develop .. code-block:: text @@ -403,15 +467,25 @@ Solidity编译器使用两种不同的优化器模块。在操作码水平上操 Body... } +<<<<<<< HEAD 当与 ``循环不变代码模式`` 搭配时,这种转换也是有用的,因为循环不变条件中的不变量可以在循环之外进行。 +======= +This transformation can also be useful when paired with LoopInvariantCodeMotion, since +invariants in the loop-invariant conditions can then be taken outside the loop. +>>>>>>> english/develop .. _for-loop-init-rewriter: 循环初始重写器 ^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 这种转换将for-loop的初始化部分移到循环之前: +======= +This transformation moves the initialization part of a ``for`` loop to before +the loop: +>>>>>>> english/develop .. code-block:: text @@ -428,8 +502,13 @@ Solidity编译器使用两种不同的优化器模块。在操作码水平上操 Body... } +<<<<<<< HEAD 这简化了其余的优化过程, 因为我们可以忽略for循环初始化块的复杂范围规则。 +======= +This eases the rest of the optimization process because we can ignore +the complicated scoping rules of the ``for`` loop initialization block. +>>>>>>> english/develop .. _var-decl-initializer: @@ -541,7 +620,7 @@ Solidity编译器使用两种不同的优化器模块。在操作码水平上操 也更简单地替换表达式的各个部分或重新组织“表达式树”。 缺点是这样的代码对我们来说更难阅读。 -.. _SSA-transform: +.. _ssa-transform: SSA转换 ^^^^^^^^^^^^ @@ -579,6 +658,7 @@ SSA转换 - 将 ``let a := v`` 替换为 ``let a_i := v let a := a_i`` - 将 ``a := v`` 替换为 ``let a_i := v a := a_i``, 其中 ``i`` 是一个数字,使得 ``a_i`` 尚未使用。 +<<<<<<< HEAD 此外,总是记录用于 ``a`` 的 ``i`` 的当前值,并用 ``a_i`` 替换对 ``a`` 的每次引用。 变量 ``a`` 的当前值映射在每个分配给它的块结束时被清除, 如果它被分配在for循环体或post块内,则在for循环初始块结束时被清除。 @@ -590,11 +670,35 @@ SSA转换 如果在这个阶段之前运行表达式拆分器和通用子表达式消除器, 那么这个阶段会提供最好的结果,因为这样就不会产生过多的变量。 另一方面,如果在SSA转换之后运行通用子表达式消除器,则效率更高。 - -.. _redundant-assign-eliminator: - +======= +Furthermore, always record the current value of ``i`` used for ``a`` and replace each +reference to ``a`` by ``a_i``. +The current value mapping is cleared for a variable ``a`` at the end of each block +in which it was assigned to and at the end of the ``for`` loop init block if it is assigned +inside the ``for`` loop body or post block. +If a variable's value is cleared according to the rule above and the variable is declared outside +the block, a new SSA variable will be created at the location where control flow joins, +this includes the beginning of loop post/body block and the location right after +``if``/``switch``/``for``/block statement. + +After this stage, the UnusedAssignEliminator is recommended to remove the unnecessary +intermediate assignments. + +This stage provides best results if the ExpressionSplitter and the CommonSubexpressionEliminator +are run right before it, because then it does not generate excessive amounts of variables. +On the other hand, the CommonSubexpressionEliminator could be more efficient if run after the +SSA transform. +>>>>>>> english/develop + +.. _unused-assign-eliminator: + +<<<<<<< HEAD 冗余赋值消除器 ^^^^^^^^^^^^^^^^^^^^^^^^^ +======= +UnusedAssignEliminator +^^^^^^^^^^^^^^^^^^^^^^ +>>>>>>> english/develop SSA转换总是生成 ``a := a_i`` 形式的赋值, 尽管这些赋值在许多情况下可能是不必要的,比如下面的例子: @@ -622,8 +726,14 @@ SSA转换将这个片段转换为以下内容: sstore(a_3, 1) } +<<<<<<< HEAD 冗余赋值消除器将删除对 ``a`` 的所有三个赋值,因为未使用 ``a`` 的值, 因此将此代码段转换为严格的SSA形式为: +======= +The UnusedAssignEliminator removes all the three assignments to ``a``, because +the value of ``a`` is not used and thus turn this +snippet into strict SSA form: +>>>>>>> english/develop .. code-block:: yul @@ -634,7 +744,12 @@ SSA转换将这个片段转换为以下内容: sstore(a_3, 1) } +<<<<<<< HEAD 当然,确定分配是否多余的错综复杂的部分与加入控制流有关。 +======= +Of course the intricate parts of determining whether an assignment is unused or not +are connected to joining control flow. +>>>>>>> english/develop 该组件的详细工作情况如下: @@ -642,9 +757,17 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 在信息收集过程中,我们维护了一个从赋值语句到 “未使用(unused)”,“未决定(undecided)” 和 “已使用(used)” 三种状态的映射, 这标志着分配的值是否会在以后被变量的引用使用。 +<<<<<<< HEAD 当一个赋值被访问时,它被添加到处于 “未决定” 状态的映射中 (见下面关于for循环的注释),而其他每个仍处于 “未决定” 状态的对同一变量的赋值被改为 “未使用”。 当一个变量被引用时,任何对该变量的赋值仍处于 “未决定” 状态,其状态被改变为 “已使用”。 +======= +When an assignment is visited, it is added to the mapping in the "undecided" state +(see remark about ``for`` loops below) and every other assignment to the same variable +that is still in the "undecided" state is changed to "unused". +When a variable is referenced, the state of any assignment to that variable still +in the "undecided" state is changed to "used". +>>>>>>> english/develop 在控制流分叉的地方,映射的拷贝被移交给每个分支。 在控制流汇合的地方,来自两个分支的两个映射以下列方式合并: @@ -655,8 +778,15 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 - “未使用”, “已使用” -> “已使用” - “未决定”, “已使用” -> “已使用” +<<<<<<< HEAD 对于For循环,考虑到条件下的连接控制流,将对条件、主体和后部进行两次访问。 换句话说,我们创建了三条控制流路径:循环的零次运行、一次运行和两次运行,然后在最后合并它们。 +======= +For ``for`` loops, the condition, body and post-part are visited twice, taking +the joining control-flow at the condition into account. +In other words, we create three control flow paths: Zero runs of the loop, +one run and two runs and then combine them at the end. +>>>>>>> english/develop 不需要模拟第三次甚至更多的运行,这可以如下所示: @@ -678,11 +808,16 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 .. code-block:: none - max(s, f(s), f(f(s))) = max(s, f(s), f(f(s)), f(f(f(s))), ...). + max(s, f(s), f(f(s))) = max(s, f(s), f(f(s)), f(f(f(s))), ...) 总之,最多运行两次循环就足够了,因为只有三种不同的状态。 +<<<<<<< HEAD 对于有 “默认”情况的switch语句,没有跳过switch的控制流部分。 +======= +For ``switch`` statements that have a default case, there is no control-flow +part that skips the ``switch``. +>>>>>>> english/develop 当一个变量超出范围时,所有仍处于“未决定”状态的语句都被改为“未使用”, 除非该变量是一个函数的返回参数--如何是这样,状态变为“已使用”。 @@ -709,6 +844,7 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 数据流分析器 ^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 数据流分析器本身不是一个优化步骤,而是被其他组件作为工具使用。 在遍历AST时,它跟踪每个变量的当前值, 只要该值是一个可移动的表达式。 @@ -719,6 +855,21 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 在控制流连接处,如果变量在任何控制流路径中已经或将要被分配, 那么关于这些变量的记忆就会被清除。例如,在进入for循环时,所有将在主体或后块中分配的变量都被清除。 +======= +The DataflowAnalyzer is not an optimizer step itself but is used as a tool +by other components. While traversing the AST, it tracks the current value of +each variable, as long as that value is a movable expression. +It records the variables that are part of the expression +that is currently assigned to each other variable. Upon each assignment to +a variable ``a``, the current stored value of ``a`` is updated and +all stored values of all variables ``b`` are cleared whenever ``a`` is part +of the currently stored expression for ``b``. + +At control-flow joins, knowledge about variables is cleared if they have or would be assigned +in any of the control-flow paths. For instance, upon entering a +``for`` loop, all variables are cleared that will be assigned during the +body or the post block. +>>>>>>> english/develop 表达式的简化 -------------------------------- @@ -730,11 +881,19 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 通用子表达式消除器 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 这一步使用数据流分析器,用对某一变量的引用来替换语法上与该变量当前值相匹配的子表达式。 这是一个等价转换,因为这种子表达式必须是可移动的。 +======= +This step uses the DataflowAnalyzer and replaces subexpressions that +syntactically match the current value of a variable by a reference to +that variable. This is an equivalence transform because such subexpressions have +to be movable. +>>>>>>> english/develop 如果值是一个标识符,所有本身是标识符的子表达式都被其当前值替换。 +<<<<<<< HEAD 上述两条规则的结合允许计算出一个局部值的编号, 这意味着如果两个变量有相同的值,其中一个将永远是未使用的。 然后,未使用过的处理器或冗余赋值消除器将能够完全消除此类变量。 @@ -744,24 +903,53 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 如果通用子表达式消除器在它之前运行, 表达式简化器将能够进行更好的替换。 +======= +The combination of the two rules above allow to compute a local value +numbering, which means that if two variables have the same +value, one of them will always be unused. The UnusedPruner or the +UnusedAssignEliminator will then be able to fully eliminate such +variables. + +This step is especially efficient if the ExpressionSplitter is run +before. If the code is in pseudo-SSA form, +the values of variables are available for a longer time and thus we +have a higher chance of expressions to be replaceable. + +The ExpressionSimplifier will be able to perform better replacements +if the CommonSubexpressionEliminator was run right before it. +>>>>>>> english/develop .. _expression-simplifier: 表达式简化器 ^^^^^^^^^^^^ +<<<<<<< HEAD 表达式简化器使用数据流分析器, 并利用表达式的等价变换列表,如 ``X + 0 -> X`` 来简化代码。 +======= +The ExpressionSimplifier uses the DataflowAnalyzer and makes use +of a list of equivalence transforms on expressions like ``X + 0 -> X`` +to simplify the code. +>>>>>>> english/develop 它试图在每个子表达式上匹配诸如 ``X + 0`` 的模式。 在匹配过程中,它将变量解析为当前分配的表达式, 以便能够匹配更深入的嵌套模式, 即使代码是伪SSA形式。 +<<<<<<< HEAD 一些模式如 ``X - X -> 0`` 只能在表达式 ``X`` 是可移动的情况下应用, 否则会删除其潜在的副作用。 由于变量引用总是可移动的,即使它们的当前值可能不是, 表达式简化器在拆分或伪SSA形式下又更加强大。 +======= +Some of the patterns like ``X - X -> 0`` can only be applied as long +as the expression ``X`` is movable, because otherwise it would remove its potential side-effects. +Since variable references are always movable, even if their current +value might not be, the ExpressionSimplifier is again more powerful +in split or pseudo-SSA form. +>>>>>>> english/develop .. _literal-rematerialiser: @@ -779,12 +967,16 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 如果代码是SSA形式的,效果最好。 +<<<<<<< HEAD 先决条件:消歧器,循环初始重写器。 +======= +Prerequisites: Disambiguator, ForLoopInitRewriter. +>>>>>>> english/develop 声明规模的简化 ------------------------------- -.. _circular-reference-pruner: +.. _circular-references-pruner: 循环引用程序 ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -796,7 +988,12 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 条件简化器 ^^^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 如果可以从控制流中确定数值,条件简化器就会插入对条件变量的赋值。 +======= +The ConditionalSimplifier inserts assignments to condition variables if the value can be determined +from the control-flow. +>>>>>>> english/develop 销毁SSA表格。 @@ -805,13 +1002,23 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 当前的特性: +<<<<<<< HEAD - 切换条件:插入 “<条件> := <条件标签>” - 在带有终止控制流的if语句后,插入“<条件> : =0” +======= +- ``switch`` cases: insert `` := `` +- after ``if`` statement with terminating control-flow, insert `` := 0`` +>>>>>>> english/develop 未来的特性: +<<<<<<< HEAD - 允许用“1”替换 - 考虑到用户定义的终止函数 +======= +- allow replacements by ``1`` +- take termination of user-defined functions into account +>>>>>>> english/develop 如果之前已经运行过死代码的删除,那么使用SSA表单效果最好。 @@ -822,7 +1029,11 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 有条件的非对称性放大器 ^^^^^^^^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 条件简化器的反面。 +======= +Reverse of ConditionalSimplifier. +>>>>>>> english/develop .. _control-flow-simplifier: @@ -831,6 +1042,7 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 简化了几个控制流结构: +<<<<<<< HEAD - 用pop(条件)代替if,用空的程序体代替if - 移除空的默认switch情况 - 如果不存在默认情况,则删除空的switch情况 @@ -840,13 +1052,30 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 - 用匹配的条件程序体的常量表达式替换switch - 将 ``for`` 替换为终止控制流,在没有其他 break/continue 的情况下替换为 ``if`` - 移除函数末尾的 ``leave`` +======= +- replace ``if`` with empty body with ``pop(condition)`` +- remove empty default ``switch`` case +- remove empty ``switch`` case if no default case exists +- replace ``switch`` with no cases with ``pop(expression)`` +- turn ``switch`` with single case into ``if`` +- replace ``switch`` with only default case with ``pop(expression)`` and body +- replace ``switch`` with const expr with matching case body +- replace ``for`` with terminating control flow and without other ``break``/``continue`` by ``if`` +- remove ``leave`` at the end of a function. +>>>>>>> english/develop 这些操作都不依赖于数据流。然而结构简化器执行类似的任务,确实依赖于数据流。 控制流简化器在其遍历过程中确实记录了是否存在 ``break`` 和 ``continue`` 语句。 +<<<<<<< HEAD 先决条件:消歧器,函数提升器, 循环初始重写器。 重要提示:引入了EVM操作代码,因此目前只能用于EVM代码。 +======= +Prerequisite: Disambiguator, FunctionHoister, ForLoopInitRewriter. + +Important: Introduces EVM opcodes and thus can only be used on EVM code for now. +>>>>>>> english/develop .. _dead-code-eliminator: @@ -855,15 +1084,28 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 这个优化阶段删除了不可到达的代码。 +<<<<<<< HEAD 无法访问的代码是指在一个区块内的任何代码, 其前面有 leave,return,invalid,break,continue,selfdestruct,revert 或调用用户定义的函数,并无限地递归。 +======= +Unreachable code is any code within a block which is preceded by a +``leave``, ``return``, ``invalid``, ``break``, ``continue``, ``selfdestruct``, ``revert`` or by +a call to a user-defined function that recurses infinitely. +>>>>>>> english/develop 函数定义被保留下来,因为它们可能被早期的代码调用,因此被认为是可访问的。 +<<<<<<< HEAD 因为在for循环的init块中声明的变量,其范围会扩展到循环体, 所以我们要求 循环初始重写器 在此步骤之前运行。 先决条件: 循环初始重写器, 函数提升器, 函数分组器 +======= +Because variables declared in a ``for`` loop's init block have their scope extended to the loop body, +we require ForLoopInitRewriter to run before this step. + +Prerequisites: ForLoopInitRewriter, FunctionHoister, FunctionGrouper. +>>>>>>> english/develop .. _equal-store-eliminator: @@ -874,10 +1116,19 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 但中间没有其他存储,并且 ``k`` 和 ``v`` 的值没有变化, 则该步骤将删除 ``mstore(k, v)`` 和 ``sstore(k, v)`` 的调用。 +<<<<<<< HEAD 如果在SSA转换和通用子表达式消除器之后运行,这个简单的步骤是有效的, 因为SSA将确保变量不会改变,而通用子表达式消除器在已知值相同的情况下会重新使用完全相同的变量。 先决条件: 消歧器, 循环初始重写器 +======= +This simple step is effective if run after the SSATransform and the +CommonSubexpressionEliminator, because SSA will make sure that the variables +will not change and the CommonSubexpressionEliminator re-uses exactly the same +variable if the value is known to be the same. + +Prerequisites: Disambiguator, ForLoopInitRewriter. +>>>>>>> english/develop .. _unused-pruner: @@ -886,8 +1137,14 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 这一步删除了所有从未被引用的函数的定义。 +<<<<<<< HEAD 它还删除了从未被引用的变量的声明。如果声明指定了一个不可移动的值, 表达式将被保留,但其值将被丢弃。 +======= +It also removes declarations of variables that are never referenced. +If a declaration assigns a value that is not movable, the expression is retained, +but its value is discarded. +>>>>>>> english/develop 所有可移动的表达式语句(未被赋值的表达式)都被删除。 @@ -898,6 +1155,7 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 这是一个一般的步骤,在结构层面上进行各种简化: +<<<<<<< HEAD - 用 ``pop(条件)`` 代替 if 语句的空程序体。 - 用其主体替换带有真实条件的if语句 - 删除带有错误条件的if语句 @@ -907,14 +1165,32 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 - 用其初始化部分取代带有错误条件的for循环 该组件使用数据流分析器。 +======= +- replace ``if`` statement with empty body by ``pop(condition)`` +- replace ``if`` statement with true condition by its body +- remove ``if`` statement with false condition +- turn ``switch`` with single case into ``if`` +- replace ``switch`` with only default case by ``pop(expression)`` and body +- replace ``switch`` with literal expression by matching case body +- replace ``for`` loop with false condition by its initialization part + +This component uses the DataflowAnalyzer. +>>>>>>> english/develop .. _block-flattener: 块展平器 ^^^^^^^^^^^^^^ +<<<<<<< HEAD 这个阶段通过在外部块的适当位置插入内部块的语句来消除嵌套块。 它依赖于函数分组器,并不对最外层的块进行展平,以保持函数分组器产生的形式。 +======= +This stage eliminates nested blocks by inserting the statements in the +inner block at the appropriate place in the outer block. It depends on the +FunctionGrouper and does not flatten the outermost block to keep the form +produced by the FunctionGrouper. +>>>>>>> english/develop .. code-block:: yul @@ -951,10 +1227,16 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 只有在循环体或后块中的最高级别的语句被考虑, 即条件分支内的变量声明不会被移出循环。 +<<<<<<< HEAD 要求: - 消歧器, 循环初始重写器和函数提升器必须提前运行。 - 表达式拆分器和SSA转换应在前期运行以获得更好的结果。 +======= +ExpressionSplitter and SSATransform should be run upfront to obtain better results. + +Prerequisites: Disambiguator, ForLoopInitRewriter, FunctionHoister. +>>>>>>> english/develop 函数级的优化 @@ -981,7 +1263,11 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 其他优化步骤将能够对函数进行更多的简化。 优化步骤主要对那些不会被内联的函数有用。 +<<<<<<< HEAD 先决条件: 消歧器, 函数提升器 +======= +Prerequisites: Disambiguator, FunctionHoister. +>>>>>>> english/develop 建议将字面意义上的再物质化器(LiteralRematerialiser)作为先决条件,尽管它不是正确性的必要条件。 @@ -1011,7 +1297,7 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 ``function f(x) -> y { revert(y, y} }`` 其中字面意思 ``y`` 将被其值 ``0`` 取代, 使我们能够重写该函数。 -.. index:: ! unused store eliminator +.. index:: ! UnusedStoreEliminator .. _unused-store-eliminator: 未使用的存储清除器 @@ -1037,7 +1323,11 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 sstore(c, 3) } +<<<<<<< HEAD 在运行未使用的存储消除器步骤后,将被转化为以下代码 +======= +will be transformed into the code below after the UnusedStoreEliminator step is run +>>>>>>> english/develop .. code-block:: yul @@ -1047,10 +1337,17 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 sstore(c, 3) } +<<<<<<< HEAD 对于内存存储操作,事情一般比较简单,至少在最外层的yul块中是这样, 因为如果在任何代码路径中从未被读取,所有这样的语句都将被删除。 然而,在函数分析层面,其方法与 ``sstore`` 类似,因为我们不知道一旦离开函数的范围,内存位置是否会被读取, 所以只有当所有的代码路径都导致内存被覆写时,语句才会被删除。 +======= +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. +>>>>>>> english/develop 最好以SSA形式运行。 @@ -1065,8 +1362,12 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 同时允许变量重命名,但不允许任何重新排序, 那么对其中一个函数的任何引用都会被另一个函数取代。 +<<<<<<< HEAD 实际删除的功能是由未使用过的处理器执行的。 +======= +>>>>>>> english/develop +The actual removal of the function is performed by the UnusedPruner. 函数内联 ----------------- @@ -1084,9 +1385,15 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 此外,对于所有的参数,以下各项都需要为真: +<<<<<<< HEAD - 参数是可移动的。 - 该参数在函数体中被引用不到两次,或者该参数相当便宜 ( “成本”最多为1,就像一个0xff以下的常数)。 +======= +- The argument is movable. +- The parameter is either referenced less than twice in the function body, or the argument is rather cheap + ("cost" of at most 1, like a constant up to ``0xff``). +>>>>>>> english/develop 例如:要被内联的函数的形式是: ``function f(...) -> r { r := E }`` 其中 ``E`` 是一个不引用 ``r`` 的表达式,函数调用中的所有参数都是可移动表达式。 @@ -1100,11 +1407,21 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 完全内联 ^^^^^^^^^^^ +<<<<<<< HEAD 完全内联用函数的主体取代了某些函数的调用。 这在大多数情况下是没有什么帮助的,因为它只是增加了代码的大小,但并没有什么好处。 此外,代码通常是非常昂贵的,我们往往宁愿要更短的代码而不是更有效的代码。 不过,在相同的情况下,内联一个函数可以对后续的优化步骤产生积极的影响。 例如,如果一个函数参数是一个常数,就会出现这种情况。 +======= +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 +code than more efficient code. In some cases, though, inlining a function +can have positive effects on subsequent optimizer steps. This is the case +if one of the function arguments is a constant, for example. +>>>>>>> english/develop 在内联过程中,一个启发式方法被用来判断函数调用是否应该被内联。 目前的启发式方法是不内联到“大”函数,除非被调用的函数很小。 @@ -1134,9 +1451,18 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 表达式连接器 ^^^^^^^^^^^^^^^^ +<<<<<<< HEAD 这是与表达式分割器相反的操作。它把正好有一个引用的变量声明序列变成一个复杂的表达式。 这个阶段完全保留了函数调用和操作码执行的顺序。它不使用任何关于操作码的互换性的信息; 如果将一个变量的值移到它的使用位置会改变任何函数调用或操作码执行的顺序,则不执行转换。 +======= +This is the opposite operation of the ExpressionSplitter. It turns a sequence of +variable declarations that have exactly one reference into a complex expression. +This stage fully preserves the order of function calls and opcode executions. +It does not make use of any information concerning the commutativity of the opcodes; +if moving the value of a variable to its place of use would change the order +of any function call or opcode execution, the transformation is not performed. +>>>>>>> english/develop 注意,组件不会移动变量赋值或被多次引用的变量的赋值。 @@ -1148,19 +1474,29 @@ AST被遍历了两次:分别在在信息收集步骤和实际删除步骤中 因此,片段 ``let x := add(0, 2) let y := mul(x, 3)`` 被转换为 ``let y := mul(add(0, 2), 3)``,尽管 ``add`` 操作码将在计算字面意义 ``3`` 后执行。 -.. _SSA-reverser: +.. _ssa-reverser: SSA反转器 ^^^^^^^^^^^ +<<<<<<< HEAD 这是一个微小的步骤,如果它与通用子表达式消除器和未使用过的处理器相结合, 则有助于扭转SSA转换的影响。 +======= +This is a tiny step that helps in reversing the effects of the SSATransform +if it is combined with the CommonSubexpressionEliminator and the +UnusedPruner. +>>>>>>> english/develop 我们生成的SSA形式对代码生成是不利的, 因为它生成了许多局部变量。最好的办法是用赋值重新使用现有的变量, 而不是用新的变量声明。 +<<<<<<< HEAD SSA转换改写 +======= +The SSATransform rewrites +>>>>>>> english/develop .. code-block:: yul @@ -1177,9 +1513,16 @@ SSA转换改写 let a_2 := calldataload(0x20) a := a_2 +<<<<<<< HEAD 问题是在引用 ``a`` 时使用了变量 ``a_1``,而不是 ``a``。 SSA转换改变了这种形式的语句,只需将声明和赋值互换。 上面的片段被转化为 +======= +The problem is that instead of ``a``, the variable ``a_1`` is used +whenever ``a`` was referenced. The SSATransform changes statements +of this form by just swapping out the declaration and the assignment. The above +snippet is turned into +>>>>>>> english/develop .. code-block:: yul @@ -1189,9 +1532,17 @@ SSA转换改变了这种形式的语句,只需将声明和赋值互换。 a := calldataload(0x20) let a_2 := a +<<<<<<< HEAD 这是一个非常简单的等价转换,但是当我们现在运行通用子表达式消除器时, 它将用 ``a`` 替换所有出现的 ``a_1`` (直到 ``a`` 被重新赋值)。 然后,未使用过的处理器将完全消除变量 ``a_1``,从而完全逆转SSA的转换。 +======= +This is a very simple equivalence transform, but when we now run the +CommonSubexpressionEliminator, it will replace all occurrences of ``a_1`` +by ``a`` (until ``a`` is re-assigned). The UnusedPruner will then +eliminate the variable ``a_1`` altogether and thus fully reverse the +SSATransform. +>>>>>>> english/develop .. _stack-compressor: @@ -1214,6 +1565,7 @@ SSA转换改变了这种形式的语句,只需将声明和赋值互换。 再物质化 ^^^^^^^^^^^^^^ +<<<<<<< HEAD 再物质化阶段试图用最后分配给变量的表达式来替换变量引用。 当然,这只有在这个表达式的评估费用相对较低的情况下才是有益的。 此外,只有当表达式的值在赋值点和使用点之间没有变化时, @@ -1225,6 +1577,20 @@ SSA转换改变了这种形式的语句,只需将声明和赋值互换。 这些变量总是可移动的。 如果数值非常便宜或者变量被明确要求消除, 那么变量的引用就会被其当前值所取代。 +======= +The rematerialisation stage tries to replace variable references by the expression that +was last assigned to the variable. This is of course only beneficial if this expression +is comparatively cheap to evaluate. Furthermore, it is only semantically equivalent if +the value of the expression did not change between the point of assignment and the +point of use. The main benefit of this stage is that it can save stack slots if it +leads to a variable being eliminated completely (see below), but it can also +save a ``DUP`` opcode on the EVM if the expression is very cheap. + +The Rematerialiser uses the DataflowAnalyzer to track the current values of variables, +which are always movable. +If the value is very cheap or the variable was explicitly requested to be eliminated, +the variable reference is replaced by its current value. +>>>>>>> english/develop .. _for-loop-condition-out-of-body: @@ -1267,4 +1633,68 @@ SSA转换改变了这种形式的语句,只需将声明和赋值互换。 ... } +<<<<<<< HEAD 这一步骤之前应该运行文本重组器。 +======= +The LiteralRematerialiser should be run before this step. + +Codegen-Based Optimizer Module +============================== + +Currently, the codegen-based optimizer module provides two optimizations. + +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. + +.. _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++) { + // ... + } + +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. +>>>>>>> english/develop diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 643a26a8b437..e46c0f36e9af 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -78,8 +78,9 @@ Solidity意义上的合约是代码(其 *函数*)和数据(其 *状态*) .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 - pragma solidity ^0.8.4; + pragma solidity ^0.8.26; + // This will only compile via IR contract Coin { // 关键字 "public" 使变量可以从其他合约中访问。 address public minter; @@ -106,12 +107,7 @@ Solidity意义上的合约是代码(其 *函数*)和数据(其 *状态*) // 从任何调用者那里发送一定数量的代币到一个地址 function send(address receiver, uint amount) public { - if (amount > balances[msg.sender]) - revert InsufficientBalance({ - requested: amount, - available: balances[msg.sender] - }); - + require(amount <= balances[msg.sender], InsufficientBalance(amount, balances[msg.sender])); balances[msg.sender] -= amount; balances[receiver] += amount; emit Sent(msg.sender, receiver, amount); @@ -141,11 +137,20 @@ Solidity意义上的合约是代码(其 *函数*)和数据(其 *状态*) 但它是一个更复杂的数据类型。 :ref:`映射 ` 类型将地址映射到 :ref:`无符号整数 `。 +<<<<<<< HEAD 映射可以被看作是 `哈希表 `_, 它实际上是被初始化的,因此每一个可能的键从一开始就存在,并被映射到一个值,其字节表示为全零的值。 然而,它既不可能获得一个映射的所有键的列表,也不可能获得所有值的列表。 因此,要么记住您添加到映射中的内容,要么在不需要的情况下使用它。 甚至更好的是,保留一个列表,或者使用一个更合适的数据类型。 +======= +Mappings can be seen as `hash tables `_ which are +virtually initialized such that every possible key exists from the start and is mapped to a +value whose byte-representation is all zeros. However, it is neither possible to obtain a list of all keys of +a mapping, nor a list of all values. Record what you +added to the mapping, or use it in a context where this is not needed. Or +even better, keep a list, or use a more suitable data type. +>>>>>>> english/develop 而由 ``public`` 关键字创建的 :ref:`getter 函数 ` 则是更复杂一些的情况, 它大致如下所示: @@ -198,10 +203,20 @@ Solidity意义上的合约是代码(其 *函数*)和数据(其 *状态*) 即当任意精度算术中的 ``balances[receiver] + amount`` 大于 ``uint`` 的最大值( ``2**256 - 1``)时, 交易将被恢复。对于函数 ``send`` 中的语句 ``balances[receiver] += amount;`` 也是如此。 +<<<<<<< HEAD :ref:`错误(Errors) ` 允许您向调用者提供更多关于一个条件或操作失败原因的信息。 错误与 :ref:`恢复状态 ` 一起使用。 ``revert`` 语句无条件地中止和恢复所有的变化, 类似于 ``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, much like the :ref:`require function `. +Both approaches allow 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`` 条件就会为真。 @@ -265,11 +280,19 @@ Solidity意义上的合约是代码(其 *函数*)和数据(其 *状态*) 区块以固定的时间间隔添加到链上,尽管这些间隔在未来可能会有所改变。 为了获取最新的信息,建议监控网络,例如在 `Etherscan `_ 上进行监测。 +<<<<<<< HEAD 作为 “顺序选择机制”(也就是所谓的“挖矿”)的一部分, 可能有时会发生块(blocks)被回滚的情况,但仅在链的“末端”。 末端增加的块越多,其发生回滚的概率越小。 因此您的交易被回滚甚至从区块链中抹除,这是可能的, 但等待的时间越长,这种情况发生的概率就越小。 +======= +As part of the "order selection mechanism", which is called `attestation `_, it may happen that +blocks are reverted from time to time, but only at the "tip" of the chain. The more +blocks are added on top of a particular block, the less likely this block will be reverted. So it might be that your transactions +are reverted and even removed from the blockchain, but the longer you wait, the less +likely it will be. +>>>>>>> english/develop .. note:: 交易不保证被包括在下一个区块或任何特定的未来区块中, @@ -362,12 +385,22 @@ Solidity意义上的合约是代码(其 *函数*)和数据(其 *状态*) 由于EVM执行器可以选择包含一笔交易, 因此交易发送者无法通过设置低燃料价格滥用系统。 -.. index:: ! storage, ! memory, ! stack +.. index:: ! storage, ! memory, ! stack, ! transient storage +<<<<<<< HEAD 存储,内存和栈 ============================= 以太坊虚拟机有三个存储数据的区域:存储器,内存和堆栈。 +======= +.. _locations: + +Storage, Transient Storage, Memory and the Stack +================================================ + +The Ethereum Virtual Machine has different areas where it can store data with the most +prominent being storage, transient storage, memory and the stack. +>>>>>>> english/develop 每个账户都有一个称为 **存储** 的数据区,在函数调用和交易之间是持久的。 存储是一个键值存储,将256位的字映射到256位的字。 @@ -375,11 +408,29 @@ Solidity意义上的合约是代码(其 *函数*)和数据(其 *状态*) 由于这种成本,您应该把您存储在持久性存储中的内容减少到合约运行所需的程度。 在合约之外存储像派生计算,缓存和聚合的数据。合约既不能读也不能写到除其自身以外的任何存储。 +<<<<<<< HEAD 第二个数据区被称为 **内存**,合约在每次消息调用时都会获得一个新清除的实例。 内存是线性的,可以在字节级寻址,但读的宽度限制在256位, 而写的宽度可以是8位或256位。当访问(无论是读还是写)一个先前未触及的内存字(即一个字内的任何偏移)时, 内存被扩展一个字(256位)。在扩展的时候,必须支付燃料成本。 内存越大,成本就越高(它以平方级别扩展)。 +======= +Similar to storage, there is another data area called **transient storage**, +where the main difference is that it is reset at the end of each transaction. +The values stored in this data location persist only across function calls originating +from the first call of the transaction. +When the transaction ends, the transient storage is reset and the values stored there +become unavailable to calls in subsequent transactions. +Despite this, the cost of reading and writing to transient storage is significantly lower than for storage. + +The third data area is called **memory**, of which a contract obtains +a freshly cleared instance for each message call. Memory is linear and can be +addressed at byte level, but reads are limited to a width of 256 bits, while writes +can be either 8 bits or 256 bits wide. Memory is expanded by a word (256-bit), when +accessing (either reading or writing) a previously untouched memory word (i.e. any offset +within a word). At the time of expansion, the cost in gas must be paid. Memory is more +costly the larger it grows (it scales quadratically). +>>>>>>> english/develop EVM 不是基于寄存器的,而是基于栈的,因此所有的计算都在一个被称为 **栈(stack)** 的区域执行。 栈最大有1024个元素,每个元素长度是一个字(256位)。对栈的访问只限于其顶端,限制方式为: @@ -388,6 +439,31 @@ EVM 不是基于寄存器的,而是基于栈的,因此所有的计算都在 运算后,把结果压入栈顶。当然可以把栈上的元素放到存储或内存中。 但是无法只访问栈上指定深度的那个元素,除非先从栈顶移除其他元素。 +Calldata, Returndata and Code +============================= + +There are also other data areas which are not as apparent as those discussed previously. +However, they are routinely used during the execution of smart contract transactions. + +The calldata region is the data sent to a transaction as part of a smart contract transaction. +For example, when creating a contract, calldata would be the constructor code of the new contract. +The parameters of external functions are always initially stored in calldata in an ABI-encoded form +and only then decoded into the location specified in their declaration. +If declared as ``memory``, the compiler will eagerly decode them into memory at the beginning of the function, +while marking them as ``calldata`` means that this will be done lazily, only when accessed. +Value types and ``storage`` pointers are decoded directly onto the stack. + +The returndata is the way a smart contract can return a value after a call. +In general, external Solidity functions use the ``return`` keyword to ABI-encode values into the returndata area. + +The code is the region where the EVM instructions of a smart contract are stored. +Code is the bytes read, interpreted, and executed by the EVM during smart contract execution. +Instruction data stored in the code is persistent as part of a contract account state field. +Immutable and constant variables are stored in the code region. +All references to immutables are replaced with the values assigned to them. +A similar process is performed for constants which have their expressions inlined +in the places where they are referenced in the smart contract code. + .. index:: ! instruction 指令集 @@ -469,9 +545,29 @@ EVM的指令集应尽量保持最小,以避免不正确或不一致的实现 因为如果有人向被删除的合约发送以太币,以太币就会永远丢失。 .. warning:: +<<<<<<< HEAD 从0.8.18及更高版本开始,在 Solidity 和 Yul 中使用 ``selfdestruct`` 将触发弃用警告, 因为 ``SELFDESTRUCT`` 操作码最终将经历 `EIP-6049 `_ 中所述的行为的重大变化。 +======= + From ``EVM >= Cancun`` onwards, ``selfdestruct`` will **only** send all Ether in the account to the given recipient and not destroy the contract. + However, when ``selfdestruct`` is called in the same transaction that creates the contract calling it, + the behaviour of ``selfdestruct`` before Cancun hardfork (i.e., ``EVM <= Shanghai``) is preserved and will destroy the current contract, + deleting any data, including storage keys, code and the account itself. + See `EIP-6780 `_ for more details. + + The new behaviour is the result of a network-wide change that affects all contracts present on + the Ethereum mainnet and testnets. + It is important to note that this change is dependent on the EVM version of the chain on which + the contract is deployed. + The ``--evm-version`` setting used when compiling the contract has no bearing on it. + + Also, note that the ``selfdestruct`` opcode has been deprecated in Solidity version 0.8.18, + as recommended by `EIP-6049 `_. + The deprecation is still in effect and the compiler will still emit warnings on its use. + Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. + Future changes to the EVM might further reduce the functionality of the opcode. +>>>>>>> english/develop .. warning:: 即使一个合约通过 ``selfdestruct`` 删除,它仍然是区块链历史的一部分, @@ -493,10 +589,19 @@ EVM的指令集应尽量保持最小,以避免不正确或不一致的实现 预编译合约 ===================== +<<<<<<< HEAD 有一小群合约地址是特殊的。 ``1`` 和(包括) ``8`` 之间的地址范围包含 “预编译合约“, 可以像其他合约一样被调用,但它们的行为(和它们的燃料消耗) 不是由存储在该地址的EVM代码定义的(它们不包含代码), 而是由EVM执行环境本身实现。 +======= +There is a small set of contract addresses that are special: +The address range between ``1`` and (including) ``0x0a`` 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兼容链可能使用不同的预编译合约集。 未来也有可能在以太坊主链上添加新的预编译合约, diff --git a/docs/language-influences.rst b/docs/language-influences.rst index 9e6bf59b29ac..1be990c2b59c 100644 --- a/docs/language-influences.rst +++ b/docs/language-influences.rst @@ -2,8 +2,13 @@ 语言的影响因素 ################### +<<<<<<< HEAD Solidity是一种 `花括号语言 `_, 受到几种著名编程语言的影响和启发。 +======= +Solidity is a `curly-bracket language `_ +that has been influenced and inspired by several well-known programming languages. +>>>>>>> english/develop Solidity受C++的影响最深,但也借用了Python,JavaScript等语言的概念。 diff --git a/docs/metadata.rst b/docs/metadata.rst index 52dfc303a426..6f0571bd16cd 100644 --- a/docs/metadata.rst +++ b/docs/metadata.rst @@ -166,10 +166,17 @@ Solidity编译器会自动生成一个JSON文件。该文件包含关于编译 }, // 必选:编译源文件/源单元,键为文件路径 "sources": { +<<<<<<< HEAD "destructible": { // 必选(除非使用“url”):源文件的字面内容 "content": "contract destructible is owned { function destroy() { if (msg.sender == owner) selfdestruct(owner); } }", // 必选:源文件的keccak256哈希值 +======= + "settable": { + // Required (unless "url" is used): literal contents of the source file + "content": "contract settable is owned { uint256 private x = 0; function set(uint256 _x) public { if (msg.sender == owner) x = _x; } }", + // Required: keccak256 hash of the source file +>>>>>>> english/develop "keccak256": "0x234..." }, "myDirectory/myFile.sol": { diff --git a/docs/natspec-format.rst b/docs/natspec-format.rst index 4d2c7c65a297..c172e3d13e06 100644 --- a/docs/natspec-format.rst +++ b/docs/natspec-format.rst @@ -61,12 +61,22 @@ NatSpec 也可以包括第三方工具使用的注释。 /// @dev 目前所有的函数调用都是在没有副作用的情况下实现的 /// @custom:experimental 这是一个实验性的合约。 contract Tree { +<<<<<<< HEAD /// @notice 计算活体树木的树龄,按四舍五入计算 /// @dev Alexandr N. Tetearing 算法可以提高精确度 /// @param rings 树龄学样本的环数 /// @return 树龄(岁),部分年份四舍五入 function age(uint256 rings) external virtual pure returns (uint256) { return rings + 1; +======= + /// @notice Calculate tree age in years, rounded up, for live trees + /// @dev The Alexandr N. Tetearing algorithm could increase precision + /// @param rings The number of rings from dendrochronological sample + /// @return Age in years, rounded up for partial years + /// @return Name of the tree + function age(uint256 rings) external virtual pure returns (uint256, string memory) { + return (rings + 1, "tree"); +>>>>>>> english/develop } /// @notice 返回该树的叶子数量。 @@ -83,8 +93,8 @@ NatSpec 也可以包括第三方工具使用的注释。 } contract KumquatTree is Tree, Plant { - function age(uint256 rings) external override pure returns (uint256) { - return rings + 2; + function age(uint256 rings) external override pure returns (uint256, string memory) { + return (rings + 2, "Kumquat"); } /// 返回这种特定类型的树的叶子数量。 @@ -106,6 +116,7 @@ NatSpec 也可以包括第三方工具使用的注释。 =============== ====================================================================================== ============================= 标签 应用于 =============== ====================================================================================== ============================= +<<<<<<< HEAD ``@title`` 一个应该描述合约/接口的标题 contract, library, interface ``@author`` 作者的名字 contract, library, interface ``@notice`` 向终端用户解释这个东西的作用 contract, library, interface, function, public state variable, event @@ -114,6 +125,16 @@ NatSpec 也可以包括第三方工具使用的注释。 ``@return`` 记录一个合约的函数的返回变量 function, public state variable ``@inheritdoc`` 从基本函数中复制所有缺失的标签(必须在合约名称之后) function, public state variable ``@custom:...`` 自定义标签,语义由应用程序定义 everywhere +======= +``@title`` A title that should describe the contract/interface contract, library, interface, struct, enum +``@author`` The name of the author contract, library, interface, struct, enum +``@notice`` Explain to an end user what this does contract, library, interface, function, public state variable, event, struct, enum, error +``@dev`` Explain to a developer any extra details contract, library, interface, function, state variable, event, struct, enum, error +``@param`` Documents a parameter just like in Doxygen (must be followed by parameter name) function, event, error +``@return`` Documents the return variables of a contract's function function, public state variable +``@inheritdoc`` Copies all missing tags from the base function (must be followed by the contract name) function, public state variable +``@custom:...`` Custom tag, semantics is application-defined everywhere +>>>>>>> english/develop =============== ====================================================================================== ============================= 如果您的函数返回多个值,如 ``(int quotient, int remainder)`` @@ -181,7 +202,12 @@ Solidity 编译器将通过 NatSpec 文档从您的 Solidity 源代码传递到 用户文档 ------------------ +<<<<<<< HEAD 上述文档将产生以下用户文档 JSON 文件作为输出: +======= +The above documentation will produce the following user documentation +JSON file as output for the ``Tree`` contract: +>>>>>>> english/develop .. code-block:: json @@ -194,6 +220,10 @@ Solidity 编译器将通过 NatSpec 文档从您的 Solidity 源代码传递到 { "notice" : "计算活体树木的树龄,按四舍五入计算" } + "leaves()" : + { + "notice" : "Returns the amount of leaves the tree has." + } }, "notice" : "您只能将此合约用于最基本的模拟。" } @@ -225,7 +255,18 @@ Solidity 编译器将通过 NatSpec 文档从您的 Solidity 源代码传递到 { "rings" : "树龄学样本的环数" }, +<<<<<<< HEAD "return" : "树龄(岁),部分年份四舍五入" +======= + "returns" : { + "_0" : "Age in years, rounded up for partial years", + "_1" : "Name of the tree" + } + }, + "leaves()" : + { + "details" : "Returns only a fixed number." +>>>>>>> english/develop } }, "title" : "树的模拟器" diff --git a/docs/path-resolution.rst b/docs/path-resolution.rst index 6a7857e82e90..f9c04e739f7f 100644 --- a/docs/path-resolution.rst +++ b/docs/path-resolution.rst @@ -34,6 +34,7 @@ VFS最初只填充了编译器收到的输入文件。 一个导入回调可以自由地以任意方式解释源单元名称,而不仅仅是作为路径。 如果在需要回调时没有可用的回调,或者无法找到源代码,编译就会失败。 +<<<<<<< HEAD 默认情况下,命令行编译器提供了 *主机文件系统加载器* -- 一个基本的回调, 它将源单元名称解释为本地文件系统中的一个路径。 可以使用 ``--no-import-callback`` 命令行选项禁用此回调。 @@ -43,6 +44,18 @@ VFS最初只填充了编译器收到的输入文件。 (本地文件系统甚至可能无法访问,例如当编译器在浏览器中运行时)。 例如, `Remix IDE `_ 提供了一个多功能的回调, 让您 `从HTTP、IPFS和Swarm URLs导入文件,或直接引用NPM注册表中的包 `_。 +======= +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 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 +`_. +>>>>>>> english/develop .. note:: diff --git a/docs/resources.rst b/docs/resources.rst index 0d37034ea777..8196bcffc547 100644 --- a/docs/resources.rst +++ b/docs/resources.rst @@ -25,9 +25,12 @@ * `Dapp `_ 用于从命令行构建,测试和部署智能合约的工具。 +<<<<<<< HEAD * `Embark `_ 构建和部署去中心化应用程序的开发者平台。 +======= +>>>>>>> english/develop * `Foundry `_ 用Rust编写的用于Ethereum应用开发的快速,可移植和模块化的工具包。 @@ -113,8 +116,13 @@ Solidity 工具 * `leafleth `_ Solidity智能合约的文档生成器。 +<<<<<<< HEAD * `Scaffold-ETH `_ 专注于产品快速迭代的可分叉的以太坊开发堆栈。 +======= +* `Scaffold-ETH 2 `_ + Forkable Ethereum development stack focused on fast product iterations. +>>>>>>> english/develop * `sol2uml `_ Solidity合约的统一建模语言(UML)类图生成器。 diff --git a/docs/smtchecker.rst b/docs/smtchecker.rst index 2473fd100090..76f51aebf00c 100644 --- a/docs/smtchecker.rst +++ b/docs/smtchecker.rst @@ -459,10 +459,17 @@ SMT检查器创建的验证目标的类型也可以通过命令行界面选项 ` 已验证的目标 ============== +<<<<<<< HEAD 果有任何已证明的目标,SMT检查器会向每个引擎发出一个警告, 说明有多少目标已证明。如果用户希望查看所有已证明的具体目标, 可使用命令行选项 ``--model-checker-show-proved`` 和 JSON选项 ``settings.modelChecker.showProved = true``。 +======= +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-safe`` and +the JSON option ``settings.modelChecker.showProvedSafe = true`` can be used. +>>>>>>> english/develop 未验证的目标 ================ @@ -778,6 +785,7 @@ BMC使用一个SMT求解器,而CHC使用一个Horn求解器。 作为一个Horn求解器使用,而 `Eldarica `_ 则同时做这两种工作。 +<<<<<<< HEAD 如果求解器可用的话,用户可以通过命令行界面选项 ``--model-checker-solvers {all,cvc4,eld,smtlib2,z3}`` 或JSON选项 ``settings.modelChecker.solvers=[smtlib2,z3]`` 来选择应该使用哪个求解器, 其中: @@ -793,6 +801,19 @@ BMC使用一个SMT求解器,而CHC使用一个Horn求解器。 - 如果 ``solc`` 与它一起被编译的话; - 如果Linux系统中安装了4.8.x及其以上版本的动态 ``z3`` 库(从Solidity 0.7.6开始); - 在 ``soljson.js`` (从Solidity 0.6.9开始)中静态的,也就是编译器的JavaScript二进制。 +======= +The user can choose which solvers should be used, if available, via the CLI +option ``--model-checker-solvers {all,cvc5,eld,smtlib2,z3}`` or the JSON option +``settings.modelChecker.solvers=[smtlib2,z3]``, where: + +- ``cvc5`` is used via its binary which must be installed in the system. Only BMC uses ``cvc5``. +- ``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 can be used by both BMC and CHC depending on which solvers are called. +- ``z3`` is available statically in ``soljson.js`` (from Solidity 0.6.9), that is, the JavaScript binary of the compiler. Otherwise it is used via its binary which must be installed in the system. +>>>>>>> english/develop .. note:: z3 4.8.16 版本破坏了与以前版本的 ABI 兼容性, @@ -803,7 +824,12 @@ BMC使用一个SMT求解器,而CHC使用一个Horn求解器。 由于 BMC 和 CHC 都使用 ``z3``,而且 ``z3`` 可以在更多的环境中使用,包括在浏览器中, 大多数用户几乎不需要关心这个选项。更高级的用户可能会应用这个选项,在更复杂的问题上尝试其他求解器。 +<<<<<<< HEAD 请注意,所选择的引擎和求解器的某些组合将导致SMT检查器不做任何事情,例如选择CHC和 ``cvc4``。 +======= +Please note that certain combinations of chosen engine and solver will lead to +the SMTChecker doing nothing, for example choosing CHC and ``cvc5``. +>>>>>>> english/develop ******************************* 抽象和假阳性结果 @@ -845,6 +871,7 @@ CHC引擎创建了非线性的Horn选项,使用被调用函数的摘要来支 复杂的纯函数是由参数上的未转译函数(UF)抽象出来的。 +<<<<<<< HEAD +------------------------------------+------------------------------------------+ | 方法 | BMC/CHC 运行方式 | +====================================+==========================================+ @@ -883,6 +910,53 @@ CHC引擎创建了非线性的Horn选项,使用被调用函数的摘要来支 +------------------------------------+------------------------------------------+ | 其他调用 | 目前不支持 | +------------------------------------+------------------------------------------+ +======= ++-----------------------------------+--------------------------------------+ +|Functions |BMC/CHC behavior | ++===================================+======================================+ +|``assert`` |Verification target. | ++-----------------------------------+--------------------------------------+ +|``require`` |Assumption. | ++-----------------------------------+--------------------------------------+ +|internal call |BMC: Inline function call. | +| |CHC: Function summaries. | ++-----------------------------------+--------------------------------------+ +|external call to known code |BMC: Inline function call or | +| |erase knowledge about state variables | +| |and local storage references. | +| |CHC: Assume called code is unknown. | +| |Try to infer invariants that hold | +| |after the call returns. | ++-----------------------------------+--------------------------------------+ +|Storage array push/pop |Supported precisely. | +| |Checks whether it is popping an | +| |empty array. | ++-----------------------------------+--------------------------------------+ +|ABI functions |Abstracted with UF. | ++-----------------------------------+--------------------------------------+ +|``addmod``, ``mulmod`` |Supported precisely. | ++-----------------------------------+--------------------------------------+ +|``gasleft``, ``blockhash``, |Abstracted with UF. | +|``keccak256``, ``ecrecover`` | | +|``ripemd160`` | | ++-----------------------------------+--------------------------------------+ +|pure functions without |Abstracted with UF | +|implementation (external or | | +|complex) | | ++-----------------------------------+--------------------------------------+ +|external functions without |BMC: Erase state knowledge and assume | +|implementation |result is nondeterministic. | +| |CHC: Nondeterministic summary. | +| |Try to infer invariants that hold | +| |after the call returns. | ++-----------------------------------+--------------------------------------+ +|transfer |BMC: Checks whether the contract's | +| |balance is sufficient. | +| |CHC: does not yet perform the check. | ++-----------------------------------+--------------------------------------+ +|others |Currently unsupported | ++-----------------------------------+--------------------------------------+ +>>>>>>> english/develop 使用抽象意味着失去精确的知识,但在许多情况下,这并不意味着失去证明力。 diff --git a/docs/structure-of-a-contract.rst b/docs/structure-of-a-contract.rst index 0038f24c1cb5..240063217461 100644 --- a/docs/structure-of-a-contract.rst +++ b/docs/structure-of-a-contract.rst @@ -21,7 +21,14 @@ 状态变量 ========== +<<<<<<< HEAD 状态变量是指其值被永久地存储在合约存储中的变量。 +======= +State variables are variables whose values are either permanently stored in contract +storage or, alternatively, temporarily stored in transient storage which is cleaned at +the end of each transaction. +See :ref:`data locations ` for more details. +>>>>>>> english/develop .. code-block:: solidity diff --git a/docs/style-guide.rst b/docs/style-guide.rst index 6f04919b15fb..417736792eee 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -652,11 +652,16 @@ Import 语句应始终放在文件的顶部。 return balanceOf[from]; } - function shutdown() public onlyOwner { - selfdestruct(owner); + function increment(uint x) public pure onlyOwner returns (uint) { + return x + 1; } +<<<<<<< HEAD 错误写法: +======= + +No: +>>>>>>> english/develop .. code-block:: solidity @@ -664,8 +669,8 @@ Import 语句应始终放在文件的顶部。 return balanceOf[from]; } - function shutdown() onlyOwner public { - selfdestruct(owner); + function increment(uint x) onlyOwner public pure returns (uint) { + return x + 1; } 对于长的函数声明,建议将每个参数放在自己的行中,与函数主体的缩进程度相同。 diff --git a/docs/types/conversion.rst b/docs/types/conversion.rst index bbc1e38d262e..abc74d2843e3 100644 --- a/docs/types/conversion.rst +++ b/docs/types/conversion.rst @@ -159,6 +159,7 @@ bytes4 f = 0; // 可行 bytes4 g = 0x0; // 可行 +<<<<<<< HEAD 字符串和十六进制字符串字面常数可以被隐含地转换为固定大小的字节数组, 如果它们的字符数与字节类型的大小相匹配: @@ -170,6 +171,18 @@ bytes2 d = hex"123"; // 不允许 bytes2 e = "x"; // 不允许 bytes2 f = "xyz"; // 不允许 +======= +String literals and hex string literals can be implicitly converted to fixed-size byte arrays, +if their number of characters is less than or equal to the size of the bytes type: + +.. code-block:: solidity + + bytes2 a = hex"1234"; // fine + bytes2 b = "xy"; // fine + bytes2 c = hex"12"; // fine + bytes2 e = "x"; // fine + bytes2 f = "xyz"; // not allowed +>>>>>>> english/develop .. index:: literal;address @@ -184,5 +197,10 @@ ``address a`` 可以通过 ``payable(a)`` 显式转换为 ``address payable``。 .. note:: +<<<<<<< HEAD 在 0.8.0 版本之前,可以显式地从任何整数类型(任何大小,有符号或无符号)转换为 ``address`` 或 ``address payable`` 类型。 从 0.8.0 开始,只允许从 ``uint160`` 转换。 +======= + 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 0.8.0 only conversion from ``uint160`` is allowed. +>>>>>>> english/develop diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index b386c201e63d..32d5721a1b4f 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -26,9 +26,19 @@ Calldata是一个不可修改的、非持久性的区域,用于存储函数参数,其行为主要类似于memory。 .. note:: +<<<<<<< HEAD 如果可以的话,尽量使用 ``calldata`` 作为数据位置,因为这样可以避免复制, 也可以确保数据不能被修改。使用 ``calldata`` 数据位置的数组和结构也可以从函数中返回, 但不可能分配这种类型。 +======= + ``transient`` is not yet supported as a data location for reference types. + +.. note:: + If you can, try to use ``calldata`` as data location because it will avoid copies and + also makes sure that the data cannot be modified. Arrays and structs with ``calldata`` + data location can also be returned from functions, but it is not possible to + allocate such types. +>>>>>>> english/develop .. note:: 在0.6.9版本之前,引用型参数的数据位置被限制在外部函数中的 ``calldata``, @@ -353,7 +363,11 @@ Solidity没有字符串操作函数,但有第三方的字符串库。 // 所有状态变量的数据位置都是存储。 bool[2][] pairsOfFlags; +<<<<<<< HEAD // newPairs被存储在memory中--这是公开合约函数参数的唯一可能性。 +======= + // newPairs is stored in memory +>>>>>>> english/develop function setAllFlagPairs(bool[2][] memory newPairs) public { // 赋值到一个存储数组会执行 ``newPairs`` 的拷贝, // 并替换完整的数组 ``pairsOfFlags``。 diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 2b17410221fa..24abf14866cb 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -7,6 +7,12 @@ 以下类型之所以被称为值类型,是因为它们的变量总是通过值传递, 即在用作函数参数或赋值时总是被复制。 +Unlike :ref:`reference types `, value type declarations do not +specify a data location since they are small enough to be stored on the stack. +The only exception are :ref:`state variables `. +Those are by default located in storage, but can also be marked as +:ref:`transient `, :ref:`constant or immutable `. + .. index:: ! bool, ! true, ! false 布尔类型 @@ -333,6 +339,13 @@ 这可能是空的。使用 ``.codehash`` 获得该代码的Keccak-256哈希值(作为 ``bytes32``)。 注意,使用 ``addr.codehash`` 比 ``keccak256(addr.code)`` 更便宜。 +.. warning:: + The output of ``addr.codehash`` may be ``0`` if the account associated with ``addr`` is empty or non-existent + (i.e., it has no code, zero balance, and zero nonce as defined by `EIP-161 `_). + If the account has no code but a non-zero balance or nonce, then ``addr.codehash`` will output the Keccak-256 hash of empty data + (i.e., ``keccak256("")`` which is equal to ``c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470``), as defined by + `EIP-1052 `_. + .. note:: 所有的合约都可以转换为 ``address`` 类型,所以可以用 ``address(this).balance`` 查询当前合约的余额。 @@ -402,6 +415,7 @@ .. note:: 在 0.8.0 版本之前, ``byte`` 曾经是 ``bytes1`` 的别名。 +<<<<<<< HEAD 变长字节数组 ------------ @@ -410,6 +424,8 @@ ``string``: 变长 UTF-8 编码字符串类型,参见 :ref:`arrays`。并不是值类型! +======= +>>>>>>> english/develop .. index:: address, ! literal;address .. _address_literals: @@ -766,9 +782,21 @@ Unicode 字面量 调用者不能直接将其calldata传递给外部函数,总是ABI将参数编码到内存中。 将参数标记为 ``calldata`` 只影响到外部函数的实现,在调用者一方的函数指针中是没有意义的。 +<<<<<<< HEAD 库合约被排除在外,因为它们需要 ``delegatecall``, 并且 :ref:`对它们的选择器使用不同的 ABI 约定 `。 接口中声明的函数没有定义,所以指向它们也没有意义。 +======= +.. 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. +>>>>>>> english/develop 成员: 外部(或公共)函数有以下成员: diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index b9e38e7f030c..857d299be487 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -63,12 +63,13 @@ 有一些特殊的变量和函数总是存在于全局命名空间,主要用于提供区块链的信息,或者是通用的工具函数。 -.. index:: abi, block, coinbase, difficulty, prevrandao, 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 区块和交易属性 --------------- +<<<<<<< HEAD - ``blockhash(uint blockNumber) returns (bytes32)``: 当 ``blocknumber`` 是最近的256个区块之一时,给定区块的哈希值;否则返回0。 - ``block.basefee`` ( ``uint``): 当前区块的基本费用 ( `EIP-3198 `_ 和 `EIP-1559 `_) - ``block.chainid`` ( ``uint``): 当前链的ID @@ -84,6 +85,29 @@ - ``msg.value`` ( ``uint``): 随消息发送的 wei 的数量 - ``tx.gasprice`` ( ``uint``): 随消息发送的 wei 的数量 - ``tx.origin`` ( ``address``): 交易发起者(完全的调用链) +======= +- ``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 `_). + Returns zero if no blob with the given index exists. +- ``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 (``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 +- ``msg.sender`` (``address``): sender of the message (current call) +- ``msg.sig`` (``bytes4``): first four bytes of the calldata (i.e. function identifier) +- ``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) +>>>>>>> english/develop .. note:: 对于每一个 **外部(external)** 函数调用, @@ -319,8 +343,28 @@ ABI编码和解码函数 此外,当前合约的所有函数都可以直接调用,包括当前函数。 .. warning:: +<<<<<<< HEAD 从 0.8.18 及以上版本开始,在 Solidity 和 Yul 中使用 ``selfdestruct`` 将触发一个已废弃警告, 因为 ``SELFDESTRUCT`` 操作码最终会发生如 `EIP-6049 `_ 中所述的行为上的重大变化。 +======= + From ``EVM >= Cancun`` onwards, ``selfdestruct`` will **only** send all Ether in the account to the given recipient and not destroy the contract. + However, when ``selfdestruct`` is called in the same transaction that creates the contract calling it, + the behaviour of ``selfdestruct`` before Cancun hardfork (i.e., ``EVM <= Shanghai``) is preserved and will destroy the current contract, + deleting any data, including storage keys, code and the account itself. + See `EIP-6780 `_ for more details. + + The new behaviour is the result of a network-wide change that affects all contracts present on + the Ethereum mainnet and testnets. + It is important to note that this change is dependent on the EVM version of the chain on which + the contract is deployed. + The ``--evm-version`` setting used when compiling the contract has no bearing on it. + + Also, note that the ``selfdestruct`` opcode has been deprecated in Solidity version 0.8.18, + as recommended by `EIP-6049 `_. + The deprecation is still in effect and the compiler will still emit warnings on its use. + Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. + Future changes to the EVM might further reduce the functionality of the opcode. +>>>>>>> english/develop .. note:: 在 0.5.0 版本之前,有一个叫做 ``suicide`` 的函数,其语义与 ``selfdestruct`` 相同。 diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 74ccbcad3bd0..6c9266bdff8f 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -69,12 +69,21 @@ 库链接 --------------- +<<<<<<< HEAD 如果您的合约使用 :ref:`库合约 `, 您会注意到字节码中含有 ``__$53aea86b7d70b31448b230b20ae141a537$__`` 形式的字符串。 这些是实际库的地址的占位符。此占位符是完全限定库名的keccak256散列的十六进制编码的34个字符前缀。 字节码文件也将包含形式为 ``// -> `` 的代码行,以帮助识别占位符代表的库。 注意,完全限定的库名是其源文件的路径和用 ``:`` 分隔的库名。 您可以使用 ``solc`` 作为链接器,意味着您将在这些地方插入库的地址: +======= +If your contracts use :ref:`libraries `, you will notice that the bytecode contains substrings of the form ``__$53aea86b7d70b31448b230b20ae141a537$__`` `(format was different `_. These are placeholders for the actual library addresses. +The placeholder is a 34 character prefix of the hex encoding of the keccak256 hash of the fully qualified library name. +The bytecode file will also contain lines of the form ``// -> `` at the end to help +identify which libraries the placeholders represent. Note that the fully qualified library name +is the path of its source file and the library name separated by ``:``. +You can use ``solc`` as a linker meaning that it will insert the library addresses for you at those points: +>>>>>>> english/develop 要么在您的命令中加入 ``--libraries "file.sol:Math=0x1234567890123456789012345678901234567890 file.sol:Heap=0xabCD567890123456789012345678901234567890"``, @@ -166,6 +175,7 @@ EVM版本选项 - ``istanbul`` - 在汇编中可使用操作码 ``chainid`` 和 ``selfbalance``。 - ``berlin`` +<<<<<<< HEAD - ``SLOAD``, ``*CALL``, ``BALANCE``, ``EXT*`` 和 ``SELFDESTRUCT`` 的燃料成本增加。 编译器假设这类操作的燃料成本是固定的。这与燃料估算和优化器有关。 - ``london`` @@ -174,6 +184,23 @@ EVM版本选项 - 引入了 ``prevrandao()`` 和 ``block.prevrandao``,并改变了现在已经废弃的 ``block.difficulty`` 的语义,不允许在内联汇编中使用 ``difficulty()`` (见 `EIP-4399 `_ )。 - ``shanghai`` ( **默认项** ) - 由于引入了 ``push0``,代码量更小,并且节省了燃料(参见 `EIP-3855 `_)。 +======= + - 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`` + - 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`` + - Smaller code size and gas savings due to the introduction of ``push0`` (see `EIP-3855 `_). +- ``cancun`` (**default**) + - 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 `_). +- ``prague`` (**experimental**) +>>>>>>> english/develop .. index:: ! standard JSON, ! --standard-json .. _compiler-api: @@ -198,7 +225,11 @@ EVM版本选项 .. code-block:: javascript { +<<<<<<< HEAD // 必选:源代码语言。目前支持 “Solidity”, “Yul” 和 “SolidityAST”(试验性)。 +======= + // Required: Source code language. Currently supported are "Solidity", "Yul", "SolidityAST" (experimental), "EVMAssembly" (experimental). +>>>>>>> english/develop "language": "Solidity", // 必选 "sources": @@ -222,6 +253,7 @@ EVM版本选项 "/tmp/path/to/file.sol" // 如果使用文件,其目录应通过 `--allow-paths ` 添加到命令行中。 ] +<<<<<<< HEAD // 如果语言设置为 “SolididityAST”,则需要在“ast”键下提供AST。 // 请注意,AST的导入是试验性的,尤其是: // - 导入无效的AST可能会产生未定义的结果, @@ -230,13 +262,49 @@ EVM版本选项 // “解析” 模式下生成的AST字段,然后重新执行分析, // 因此AST中任何基于分析的注释在导入时都会被忽略。 "ast": { ... } // 格式化为json ast请求的“ast”输出选择。 +======= }, - "destructible": + "settable": { + // Optional: keccak256 hash of the source file + "keccak256": "0x234...", + // Required (unless "urls" is used): literal contents of the source file + "content": "contract settable is owned { uint256 private x = 0; function set(uint256 _x) public { if (msg.sender == owner) x = _x; } }" + }, + "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": { ... } +>>>>>>> english/develop + }, + "myFile_evm.json": + { +<<<<<<< HEAD // 可选:源文件的keccak256哈希值 "keccak256": "0x234...", // 必选:(除非使用 “urls“):源文件的字面内容 "content": "contract destructible is owned { function shutdown() { if (msg.sender == owner) selfdestruct(owner); } }" +======= + // 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) + } +>>>>>>> english/develop } }, // 可选 @@ -306,10 +374,17 @@ EVM版本选项 // 编译EVM的版本。 // 影响到类型检查和代码生成。版本可以是 homestead, // tangerineWhistle, spuriousDragon, byzantium, constantinople, +<<<<<<< HEAD // petersburg, istanbul, berlin, london, paris 或 shanghai(默认)。 "evmVersion": "shanghai", // 可选:改变编译管道以通过Yul的中间表示法。 // 这在默认情况下是假的。 +======= + // petersburg, istanbul, berlin, london, paris, shanghai, cancun (default) or prague (experimental). + "evmVersion": "cancun", + // Optional: Change compilation pipeline to go through the Yul intermediate representation. + // This is false by default. +>>>>>>> english/develop "viaIR": true, // 可选: 调试设置 "debug": { @@ -354,6 +429,7 @@ EVM版本选项 "MyLib": "0x123123..." } }, +<<<<<<< HEAD // 以下可用于根据文件和合约名称选择所需的输出。 // 如果这个字段被省略,那么编译器就会加载并进行类型检查,但除了错误之外不会产生任何输出。 // 第一层键是文件名,第二层键是合约名。 @@ -363,6 +439,21 @@ EVM版本选项 // 要选择编译器可能产生的所有输出, // 使用 "outputSelection"。{ "*": { "*": [ "*" ], "": [ "*" ] } }", // 但要注意,这可能会不必要地减慢编译过程。 +======= + // The following can be used to select desired outputs based + // on file and contract names. + // If this field is omitted, then the compiler loads and does type checking, + // but will not generate any outputs apart from errors. + // The first level key is the file name and the second level key is the contract name. + // An empty contract name is used for outputs that are not tied to a contract + // but to the whole source file like the AST. + // A star as contract name refers to all contracts in the file. + // Similarly, a star as a file name matches all files. + // To select all outputs the compiler can possibly generate, with the exclusion of + // Yul intermediate representation outputs, use + // "outputSelection: { "*": { "*": [ "*" ], "": [ "*" ] } }" + // but note that this might slow down the compilation process needlessly. +>>>>>>> english/develop // // 可用的输出类型如下: // @@ -371,6 +462,7 @@ EVM版本选项 // // 合约级别(需要合约名称或 "*"): // abi - ABI +<<<<<<< HEAD // devdoc - 开发者文档(Natspec格式) // userdoc - 用户文档(Natspec格式) // metadata - 元数据 @@ -389,6 +481,29 @@ EVM版本选项 // evm.deployedBytecode.immutableReferences - 从AST id到引用不可变的字节码范围的映射 // evm.methodIdentifiers - 函数哈希值的列表 // evm.gasEstimates - 函数以太燃料估计 +======= + // devdoc - Developer documentation (natspec) + // 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 in storage. + // transientStorageLayout - Slots, offsets and types of the contract's state variables in transient storage. + // evm.assembly - New assembly format + // evm.legacyAssembly - Old-style assembly format in JSON + // evm.bytecode.functionDebugData - Debugging information at function level + // evm.bytecode.object - Bytecode object + // evm.bytecode.opcodes - Opcodes list + // evm.bytecode.sourceMap - Source mapping (useful for debugging) + // evm.bytecode.linkReferences - Link references (if unlinked object) + // evm.bytecode.generatedSources - Sources generated by the compiler + // evm.deployedBytecode* - Deployed bytecode (has all the options that evm.bytecode has) + // 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 +>>>>>>> english/develop // // 注意,使用 `evm`, `evm.bytecode` 等将选择该输出的每个目标部分。 // 此外, `*` 可以作为通配符来请求所有东西。 @@ -431,18 +546,35 @@ EVM版本选项 "extCalls": "trusted", // 选择哪些类型的不变性应该报告给用户:合约,重入。 "invariants": ["contract", "reentrancy"], +<<<<<<< HEAD // 选择是否输出所有验证过的目标。默认为 `false`。 "showProved": true, // 选择是否输出所有未验证的目标。默认为 `false`。 +======= + // Choose whether to output all proved targets. The default is `false`. + "showProvedSafe": true, + // Choose whether to output all unproved targets. The default is `false`. +>>>>>>> english/develop "showUnproved": true, // 选择是否输出所有不支持的语言功能。默认为 `false`。 "showUnsupported": true, +<<<<<<< HEAD // 如果有的话,选择应该使用哪些求解器。 // 关于求解器的描述,见形式验证部分。 "solvers": ["cvc4", "smtlib2", "z3"], // 选择哪些目标应该被检查:常数条件,下溢,溢出,除以零,余额,断言,弹出空数组,界外。 // 如果没有给出该选项,所有目标都被默认检查,除了 Solidity >=0.8.7 的下溢/溢出。 // 目标描述见形式化验证部分。 +======= + // Choose which solvers should be used, if available. + // See the Formal Verification section for the solvers description. + "solvers": ["cvc5", "smtlib2", "z3"], + // Choose which targets should be checked: constantCondition, + // underflow, overflow, divByZero, balance, assert, popEmptyArray, outOfBounds. + // If the option is not given all targets are checked by default, + // except underflow/overflow for Solidity >=0.8.7. + // See the Formal Verification section for the targets description. +>>>>>>> english/develop "targets": ["underflow", "overflow", "assert"], // 每个SMT查询的超时时间,以毫秒为单位。 // 如果没有给出这个选项,SMTChecker将默认使用确定性的资源限制。 @@ -527,7 +659,13 @@ EVM版本选项 "irOptimizedAst": {/* ... */}, // 请参阅存储布局文档。 "storageLayout": {"storage": [/* ... */], "types": {/* ... */} }, +<<<<<<< HEAD // EVM相关输出 +======= + // See the Storage Layout documentation. + "transientStorageLayout": {"storage": [/* ... */], "types": {/* ... */} }, + // EVM-related outputs +>>>>>>> english/develop "evm": { // 汇编 (string) "assembly": "", diff --git a/docs/yul.rst b/docs/yul.rst index 72504819162b..0e08da44de69 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -662,16 +662,27 @@ EVM语言 下表列出了所有内置函数(取决于EVM版本),并提供了函数/操作码的语义的简短描述。 本文件并不想成为以太坊虚拟机的完整描述。如果您对精确的语义感兴趣,请参考另一份文件。 +<<<<<<< HEAD 标有 ``-`` 的操作码不返回结果,所有其他操作码正好返回一个值。 标有 ``F``, ``H``, ``B``, ``C``, ``I``, ``L``和 ``P`` 的操作码分别 是从Frontier,Homestead,Byzantium,Constantinople,Istanbul,London 或 Paris 版本出现的。 在下文中, ``mem[a...b)`` 表示从位置 ``a`` 开始到不包括位置 ``b`` 的内存字节, ``storage[p]`` 表示插槽 ``p`` 的存储内容。 +======= +Opcodes marked with ``-`` do not return a result and all others return exactly one value. +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``, ``storage[p]`` signifies the storage contents at slot ``p``, and +similarly, ``transientStorage[p]`` signifies the transient storage contents at slot ``p``. +>>>>>>> english/develop 由于Yul管理着局部变量和控制流,所以不能使用干扰这些功能的操作码。 这包括 ``dup`` 和 ``swap`` 指令,以及 ``jump`` 指令,标签和 ``push`` 指令。 +<<<<<<< HEAD +-------------------------+-----+-----+-----------------------------------------------------------------------------+ | 指令 | | | 解释 | +=========================+=====+=====+=============================================================================+ @@ -846,6 +857,192 @@ EVM语言 +-------------------------+-----+-----+-----------------------------------------------------------------------------+ | gaslimit() | | F | 当前区块的区块以太燃料限制 | +-------------------------+-----+-----+-----------------------------------------------------------------------------+ +======= ++-------------------------+-----+---+-----------------------------------------------------------------+ +| Instruction | | | Explanation | ++=========================+=====+===+=================================================================+ +| stop() | `-` | F | stop execution, identical to return(0, 0) | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| add(x, y) | | F | x + y | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| sub(x, y) | | F | x - y | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| mul(x, y) | | F | x * y | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| div(x, y) | | F | x / y or 0 if y == 0 | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| sdiv(x, y) | | F | x / y, for signed numbers in two's complement, 0 if y == 0 | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| mod(x, y) | | F | x % y, 0 if y == 0 | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| smod(x, y) | | F | x % y, for signed numbers in two's complement, 0 if y == 0 | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| exp(x, y) | | F | x to the power of y | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| not(x) | | F | bitwise "not" of x (every bit of x is negated) | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| lt(x, y) | | F | 1 if x < y, 0 otherwise | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| gt(x, y) | | F | 1 if x > y, 0 otherwise | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| slt(x, y) | | F | 1 if x < y, 0 otherwise, for signed numbers in two's complement | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| sgt(x, y) | | F | 1 if x > y, 0 otherwise, for signed numbers in two's complement | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| eq(x, y) | | F | 1 if x == y, 0 otherwise | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| iszero(x) | | F | 1 if x == 0, 0 otherwise | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| and(x, y) | | F | bitwise "and" of x and y | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| or(x, y) | | F | bitwise "or" of x and y | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| xor(x, y) | | F | bitwise "xor" of x and y | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| byte(n, x) | | F | nth byte of x, where the most significant byte is the 0th byte | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| shl(x, y) | | C | logical shift left y by x bits | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| shr(x, y) | | C | logical shift right y by x bits | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| sar(x, y) | | C | signed arithmetic shift right y by x bits | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| addmod(x, y, m) | | F | (x + y) % m with arbitrary precision arithmetic, 0 if m == 0 | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| mulmod(x, y, m) | | F | (x * y) % m with arbitrary precision arithmetic, 0 if m == 0 | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| signextend(i, x) | | F | sign extend from (i*8+7)th bit counting from least significant | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| keccak256(p, n) | | F | keccak(mem[p...(p+n))) | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| pop(x) | `-` | F | discard value x | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| mload(p) | | F | mem[p...(p+32)) | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| mstore(p, v) | `-` | F | mem[p...(p+32)) := v | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| mstore8(p, v) | `-` | F | mem[p] := v & 0xff (only modifies a single byte) | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| sload(p) | | F | storage[p] | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| 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 | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| address() | | F | address of the current contract / execution context | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| balance(a) | | F | wei balance at address a | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| selfbalance() | | I | equivalent to balance(address()), but cheaper | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| caller() | | F | call sender (excluding ``delegatecall``) | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| callvalue() | | F | wei sent together with the current call | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| calldataload(p) | | F | call data starting from position p (32 bytes) | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| calldatasize() | | F | size of call data in bytes | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| calldatacopy(t, f, s) | `-` | F | copy s bytes from calldata at position f to mem at position t | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| codesize() | | F | size of the code of the current contract / execution context | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| codecopy(t, f, s) | `-` | F | copy s bytes from code at position f to mem at position t | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| extcodesize(a) | | F | size of the code at address a | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| extcodecopy(a, t, f, s) | `-` | F | like codecopy(t, f, s) but take code at address a | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| returndatasize() | | B | size of the last returndata | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| 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 | +| | | | and return the new address; returns 0 on error | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| create2(v, p, n, s) | | C | create new contract with code mem[p...(p+n)) at address | +| | | | keccak256(0xff . this . s . keccak256(mem[p...(p+n))) | +| | | | and send v wei and return the new address, where ``0xff`` is a | +| | | | 1 byte value, ``this`` is the current contract's address | +| | | | as a 20 byte value and ``s`` is a big-endian 256-bit value; | +| | | | returns 0 on error | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| call(g, a, v, in, | | F | call contract at address a with input mem[in...(in+insize)) | +| insize, out, outsize) | | | providing g gas and v wei and output area | +| | | | mem[out...(out+outsize)) returning 0 on error (eg. out of gas) | +| | | | and 1 on success | +| | | | :ref:`See more ` | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| callcode(g, a, v, in, | | F | identical to ``call`` but only use the code from a and stay | +| insize, out, outsize) | | | in the context of the current contract otherwise | +| | | | :ref:`See more ` | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| delegatecall(g, a, in, | | H | identical to ``callcode`` but also keep ``caller`` | +| insize, out, outsize) | | | and ``callvalue`` | +| | | | :ref:`See more ` | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| staticcall(g, a, in, | | B | identical to ``call(g, a, 0, in, insize, out, outsize)`` but do | +| insize, out, outsize) | | | not allow state modifications | +| | | | :ref:`See more ` | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| return(p, s) | `-` | F | end execution, return data mem[p...(p+s)) | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| 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 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 data mem[p...(p+s)) with topics t1, t2 | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| 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 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, 0 if blob does not | +| | | | exist | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| 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 (see note below) | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| prevrandao() | | P | randomness provided by the beacon chain (see note below) | ++-------------------------+-----+---+-----------------------------------------------------------------+ +| gaslimit() | | F | block gas limit of the current block | ++-------------------------+-----+---+-----------------------------------------------------------------+ +>>>>>>> english/develop .. _yul-call-return-area: @@ -1133,7 +1330,12 @@ Yul优化器对Yul代码进行操作,并对输入、输出和中间状态使 优化步骤顺序 -------------------------- +<<<<<<< HEAD 有关优化顺序的详细信息以及缩写列表可在 :ref:`优化器文档 ` 中找到。 +======= +Detailed information regarding the optimization sequence as well as a list of abbreviations is +available in the :ref:`optimizer docs `. +>>>>>>> english/develop .. _erc20yul: