mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
commit
0801c48e11
@ -214,6 +214,16 @@ defaults:
|
||||
command: ./test/lsp.py ./build/solc/solc
|
||||
- gitter_notify_failure_unless_pr
|
||||
|
||||
- steps_build: &steps_build
|
||||
steps:
|
||||
- checkout
|
||||
- run: *run_build
|
||||
- store_artifacts: *artifacts_solc
|
||||
- store_artifacts: *artifact_solidity_upgrade
|
||||
- store_artifacts: *artifact_yul_phaser
|
||||
- persist_to_workspace: *artifacts_executables
|
||||
- gitter_notify_failure_unless_pr
|
||||
|
||||
- steps_soltest_all: &steps_soltest_all
|
||||
steps:
|
||||
- checkout
|
||||
@ -234,6 +244,14 @@ defaults:
|
||||
- store_artifacts: *artifacts_test_results
|
||||
- gitter_notify_failure_unless_pr
|
||||
|
||||
- steps_install_dependencies_osx: &steps_install_dependencies_osx
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- dependencies-osx-{{ arch }}-{{ checksum ".circleci/osx_install_dependencies.sh" }}
|
||||
- attach_workspace:
|
||||
at: .
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Base Image Templates
|
||||
|
||||
@ -565,7 +583,7 @@ defaults:
|
||||
project: uniswap
|
||||
binary_type: native
|
||||
nodejs_version: '16'
|
||||
- job_native_test_prb_math: &job_native_test_prb_math
|
||||
- job_native_test_ext_prb_math: &job_native_test_ext_prb_math
|
||||
<<: *workflow_ubuntu2004_static
|
||||
name: t_native_test_ext_prb_math
|
||||
project: prb-math
|
||||
@ -586,6 +604,15 @@ defaults:
|
||||
nodejs_version: '14'
|
||||
resource_class: medium
|
||||
|
||||
- job_b_ubu_asan_clang: &job_b_ubu_asan_clang
|
||||
<<: *workflow_trigger_on_tags
|
||||
name: b_ubu_asan_clang
|
||||
cmake_options: -DSANITIZE=address
|
||||
- job_b_ubu_ubsan_clang: &job_b_ubu_ubsan_clang
|
||||
<<: *workflow_trigger_on_tags
|
||||
name: b_ubu_ubsan_clang
|
||||
cmake_options: -DSANITIZE=address
|
||||
|
||||
# -----------------------------------------------------------------------------------------------
|
||||
jobs:
|
||||
|
||||
@ -731,14 +758,7 @@ jobs:
|
||||
# this runs 2x faster on xlarge but takes 4x more resources (compared to medium).
|
||||
# Enough other jobs depend on it that it's worth it though.
|
||||
<<: *base_ubuntu2004_xlarge
|
||||
steps:
|
||||
- checkout
|
||||
- run: *run_build
|
||||
- store_artifacts: *artifacts_solc
|
||||
- store_artifacts: *artifact_solidity_upgrade
|
||||
- store_artifacts: *artifact_yul_phaser
|
||||
- persist_to_workspace: *artifacts_executables
|
||||
- gitter_notify_failure_unless_pr
|
||||
<<: *steps_build
|
||||
|
||||
# x64 ASAN build, for testing for memory related bugs
|
||||
b_ubu_asan: &b_ubu_asan
|
||||
@ -748,12 +768,7 @@ jobs:
|
||||
CMAKE_OPTIONS: -DSANITIZE=address
|
||||
MAKEFLAGS: -j 3
|
||||
CMAKE_BUILD_TYPE: Release
|
||||
steps:
|
||||
- checkout
|
||||
- run: *run_build
|
||||
- store_artifacts: *artifacts_solc
|
||||
- persist_to_workspace: *artifacts_executables
|
||||
- gitter_notify_failure_unless_pr
|
||||
<<: *steps_build
|
||||
|
||||
b_ubu_clang: &b_ubu_clang
|
||||
<<: *base_ubuntu2004_clang_large
|
||||
@ -762,42 +777,21 @@ jobs:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
MAKEFLAGS: -j 10
|
||||
steps:
|
||||
- checkout
|
||||
- run: *run_build
|
||||
- store_artifacts: *artifacts_solc
|
||||
- persist_to_workspace: *artifacts_executables
|
||||
- gitter_notify_failure_unless_pr
|
||||
<<: *steps_build
|
||||
|
||||
b_ubu_asan_clang: &b_ubu_asan_clang
|
||||
b_ubu_san_clang:
|
||||
# This runs a bit faster on large and xlarge but on nightly efficiency matters more.
|
||||
parameters:
|
||||
cmake_options:
|
||||
type: string
|
||||
<<: *base_ubuntu2004_clang
|
||||
environment:
|
||||
TERM: xterm
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
CMAKE_OPTIONS: -DSANITIZE=address
|
||||
MAKEFLAGS: -j 3
|
||||
steps:
|
||||
- checkout
|
||||
- run: *run_build
|
||||
- store_artifacts: *artifacts_solc
|
||||
- persist_to_workspace: *artifacts_executables
|
||||
- gitter_notify_failure_unless_pr
|
||||
|
||||
b_ubu_ubsan_clang: &b_ubu_ubsan_clang
|
||||
# This runs a bit faster on large and xlarge but on nightly efficiency matters more.
|
||||
<<: *base_ubuntu2004_clang
|
||||
environment:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
CMAKE_OPTIONS: -DSANITIZE=undefined
|
||||
MAKEFLAGS: -j 3
|
||||
steps:
|
||||
- checkout
|
||||
- run: *run_build
|
||||
- store_artifacts: *artifacts_solc
|
||||
- persist_to_workspace: *artifacts_executables
|
||||
- gitter_notify_failure_unless_pr
|
||||
CMAKE_OPTIONS: << parameters.cmake_options >>
|
||||
<<: *steps_build
|
||||
|
||||
b_ubu_release: &b_ubu_release
|
||||
<<: *b_ubu
|
||||
@ -949,7 +943,7 @@ jobs:
|
||||
- build/test/tools/solfuzzer
|
||||
- gitter_notify_failure_unless_pr
|
||||
|
||||
t_osx_soltest:
|
||||
t_osx_soltest: &t_osx_soltest
|
||||
<<: *base_osx
|
||||
environment:
|
||||
EVM: << pipeline.parameters.evm-version >>
|
||||
@ -957,11 +951,9 @@ jobs:
|
||||
TERM: xterm
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- dependencies-osx-{{ arch }}-{{ checksum ".circleci/osx_install_dependencies.sh" }}
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- when:
|
||||
condition: true
|
||||
<<: *steps_install_dependencies_osx
|
||||
- run: *run_soltest
|
||||
- store_test_results: *store_test_results
|
||||
- store_artifacts: *artifacts_test_results
|
||||
@ -971,11 +963,9 @@ jobs:
|
||||
<<: *base_osx
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- dependencies-osx-{{ arch }}-{{ checksum ".circleci/osx_install_dependencies.sh" }}
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- when:
|
||||
condition: true
|
||||
<<: *steps_install_dependencies_osx
|
||||
- run: *run_cmdline_tests
|
||||
- store_artifacts: *artifacts_test_results
|
||||
- gitter_notify_failure_unless_pr
|
||||
@ -992,10 +982,10 @@ jobs:
|
||||
command: |
|
||||
scripts/ci/build_emscripten.sh
|
||||
- store_artifacts:
|
||||
path: emscripten_build/libsolc/soljson.js
|
||||
path: upload/soljson.js
|
||||
destination: soljson.js
|
||||
- run: mkdir -p workspace
|
||||
- run: cp emscripten_build/libsolc/soljson.js workspace/soljson.js
|
||||
- run: cp upload/soljson.js workspace/soljson.js
|
||||
- run: scripts/get_version.sh > workspace/version.txt
|
||||
- persist_to_workspace:
|
||||
root: workspace
|
||||
@ -1108,6 +1098,7 @@ jobs:
|
||||
parallelism: 20
|
||||
environment:
|
||||
EVM: << pipeline.parameters.evm-version >>
|
||||
SOLTEST_FLAGS: --no-smt
|
||||
<<: *steps_soltest
|
||||
|
||||
t_ubu_ubsan_clang_cli:
|
||||
@ -1215,8 +1206,34 @@ jobs:
|
||||
name: External <<parameters.project>> tests (native)
|
||||
command: |
|
||||
test/externalTests/<<parameters.project>>.sh native /tmp/workspace/solc/solc
|
||||
- store_artifacts:
|
||||
path: reports/externalTests/
|
||||
# persist_to_workspace fails if the directory does not exist and the test script will create
|
||||
# it only if it actually has benchmark results.
|
||||
- run: mkdir -p reports/externalTests/
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- reports/externalTests/
|
||||
- gitter_notify_failure_unless_pr
|
||||
|
||||
c_ext_benchmarks:
|
||||
<<: *base_node_small
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: Combine benchmark reports
|
||||
command: cat reports/externalTests/benchmark-*.json | scripts/externalTests/merge_benchmarks.sh > reports/externalTests/all-benchmarks.json
|
||||
- run:
|
||||
name: Summarize reports
|
||||
command: cat reports/externalTests/all-benchmarks.json | scripts/externalTests/summarize_benchmarks.sh > reports/externalTests/summarized-benchmarks.json
|
||||
- store_artifacts:
|
||||
path: reports/externalTests/all-benchmarks.json
|
||||
- store_artifacts:
|
||||
path: reports/externalTests/summarized-benchmarks.json
|
||||
|
||||
b_win: &b_win
|
||||
<<: *base_win_powershell_large
|
||||
steps:
|
||||
@ -1464,9 +1481,27 @@ workflows:
|
||||
- t_ems_ext: *job_native_test_ext_pool_together
|
||||
- t_ems_ext: *job_native_test_ext_perpetual_pools
|
||||
- t_ems_ext: *job_native_test_ext_uniswap
|
||||
- t_ems_ext: *job_native_test_prb_math
|
||||
- t_ems_ext: *job_native_test_ext_prb_math
|
||||
- t_ems_ext: *job_native_test_ext_elementfi
|
||||
|
||||
- c_ext_benchmarks:
|
||||
<<: *workflow_trigger_on_tags
|
||||
requires:
|
||||
- t_ems_compile_ext_colony
|
||||
- t_native_compile_ext_gnosis
|
||||
- t_native_test_ext_gnosis_v2
|
||||
- t_native_test_ext_zeppelin
|
||||
- t_native_test_ext_ens
|
||||
- t_native_test_ext_trident
|
||||
- t_native_test_ext_euler
|
||||
- t_native_test_ext_yield_liquidator
|
||||
- t_native_test_ext_bleeps
|
||||
- t_native_test_ext_pool_together
|
||||
- t_native_test_ext_perpetual_pools
|
||||
- t_native_test_ext_uniswap
|
||||
- t_native_test_ext_prb_math
|
||||
- t_native_test_ext_elementfi
|
||||
|
||||
# Windows build and tests
|
||||
- b_win: *workflow_trigger_on_tags
|
||||
- b_win_release: *workflow_trigger_on_tags
|
||||
@ -1519,13 +1554,13 @@ workflows:
|
||||
|
||||
# ASan build and tests
|
||||
- b_ubu_asan: *workflow_trigger_on_tags
|
||||
- b_ubu_asan_clang: *workflow_trigger_on_tags
|
||||
- b_ubu_san_clang: *job_b_ubu_asan_clang
|
||||
- t_ubu_asan_soltest: *workflow_ubuntu2004_asan
|
||||
- t_ubu_asan_clang_soltest: *workflow_ubuntu2004_asan_clang
|
||||
- t_ubu_asan_cli: *workflow_ubuntu2004_asan
|
||||
|
||||
# UBSan build and tests
|
||||
- b_ubu_ubsan_clang: *workflow_trigger_on_tags
|
||||
- b_ubu_san_clang: *job_b_ubu_ubsan_clang
|
||||
- t_ubu_ubsan_clang_soltest: *workflow_ubuntu2004_ubsan_clang
|
||||
- t_ubu_ubsan_clang_cli: *workflow_ubuntu2004_ubsan_clang
|
||||
|
||||
|
@ -21,7 +21,7 @@ include(EthPolicy)
|
||||
eth_policy()
|
||||
|
||||
# project name and version should be set after cmake_policy CMP0048
|
||||
set(PROJECT_VERSION "0.8.12")
|
||||
set(PROJECT_VERSION "0.8.13")
|
||||
# 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
Changelog.md
34
Changelog.md
@ -9,30 +9,46 @@ Breaking changes:
|
||||
* Commandline Interface: Assembler mode no longer enables all outputs by default.
|
||||
|
||||
|
||||
### 0.8.12 (unreleased)
|
||||
### 0.8.13 (unreleased)
|
||||
|
||||
Language Features:
|
||||
* General: Support ``ContractName.functionName`` for ``abi.encodeCall``, in addition to external function pointers.
|
||||
* General: Add equality-comparison operators for external function types.
|
||||
|
||||
|
||||
Compiler Features:
|
||||
|
||||
|
||||
Bugfixes:
|
||||
|
||||
|
||||
|
||||
### 0.8.12 (2022-02-16)
|
||||
|
||||
Language Features:
|
||||
* General: Add equality-comparison operators for external function types.
|
||||
* General: Support ``ContractName.functionName`` for ``abi.encodeCall``, in addition to external function pointers.
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* Commandline Interface: Event and error signatures are also returned when using ``--hashes``.
|
||||
* Yul Optimizer: Remove ``mstore`` and ``sstore`` operations if the slot already contains the same value.
|
||||
* Yul: Emit immutable references for pure yul code when requested.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
* Antlr Grammar: Allow builtin names in ``yulPath`` to support ``.address`` in function pointers.
|
||||
* Code Generator: Fix ICE when accessing the members of external functions occupying more than two stack slots.
|
||||
* Code Generator: Fix ICE when doing an explicit conversion from ``string calldata`` to ``bytes``.
|
||||
* Code Generator: Fix internal error when accessing the members of external functions occupying more than two stack slots.
|
||||
* Code Generator: Fix internal error when doing an explicit conversion from ``string calldata`` to ``bytes``.
|
||||
* Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis.
|
||||
* General: ``string.concat`` now properly takes strings as arguments and returns ``string memory``. It was accidentally introduced as a copy of ``bytes.concat`` before.
|
||||
* Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the derived contract contains immutable variables.
|
||||
* Inheritance: Consider functions in all ancestors during override analysis.
|
||||
* IR Generator: Add missing cleanup during the conversion of fixed bytes types to smaller fixed bytes types.
|
||||
* IR Generator: Add missing cleanup for indexed event arguments of value type.
|
||||
* IR Generator: Fix internal error when copying reference types in calldata and storage to struct or array members in memory.
|
||||
* IR Generator: Fix IR syntax error when copying storage arrays of structs containing functions.
|
||||
* Natspec: Fix ICE when overriding a struct getter with a Natspec-documented return value and the name in the struct is different.
|
||||
* TypeChecker: Fix ICE when a constant variable declaration forward references a struct.
|
||||
* Natspec: Fix internal error when overriding a struct getter with a Natspec-documented return value and the name in the struct is different.
|
||||
* Type Checker: Fix internal error when a constant variable declaration forward references a struct.
|
||||
* Yul EVM Code Transform: Improved stack shuffling in corner cases.
|
||||
|
||||
|
||||
Solc-Js:
|
||||
@ -40,6 +56,10 @@ Solc-Js:
|
||||
* The code has been ported to TypeScript.
|
||||
|
||||
|
||||
Build System:
|
||||
* Emscripten builds store the embedded WebAssembly binary in LZ4 compressed format and transparently decompress on loading.
|
||||
|
||||
|
||||
### 0.8.11 (2021-12-20)
|
||||
|
||||
Language Features:
|
||||
|
@ -142,8 +142,6 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s WASM=1")
|
||||
# Set webassembly build to synchronous loading.
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s WASM_ASYNC_COMPILATION=0")
|
||||
# Output a single js file with the wasm binary embedded as base64 string.
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s SINGLE_FILE=1")
|
||||
# Allow new functions to be added to the wasm module via addFunction.
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_TABLE_GROWTH=1")
|
||||
# Disable warnings about not being pure asm.js due to memory growth.
|
||||
@ -153,6 +151,9 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
|
||||
|
||||
# The major alternative compiler to GCC/Clang is Microsoft's Visual C++ compiler, only available on Windows.
|
||||
elseif (DEFINED MSVC)
|
||||
# Remove NDEBUG from RELWITHDEBINFO (to enable asserts)
|
||||
# CMAKE_CXX_FLAGS_RELWITHDEBINFO for GCC/Clang does not include NDEBUG
|
||||
string(REPLACE "/DNDEBUG" " " CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
|
||||
add_compile_options(/MP) # enable parallel compilation
|
||||
add_compile_options(/EHsc) # specify Exception Handling Model in msvc
|
||||
|
@ -137,6 +137,36 @@ evmc:
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
mini-lz4:
|
||||
The file scripts/ci/mini-lz4.js is derived from the emscripten adaptation of
|
||||
node-lz4 and licensed under the following terms:
|
||||
|
||||
Copyright (c) 2012 Pierre Curto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
base64:
|
||||
The file scripts/ci/base64DecToArr.js is derived from a code example
|
||||
in the MDN Web Docs, which permits use under CC0 terms:
|
||||
|
||||
Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
|
||||
All other code is licensed under GPL version 3:
|
||||
|
||||
|
@ -1552,6 +1552,10 @@
|
||||
"bugs": [],
|
||||
"released": "2021-12-20"
|
||||
},
|
||||
"0.8.12": {
|
||||
"bugs": [],
|
||||
"released": "2022-02-16"
|
||||
},
|
||||
"0.8.2": {
|
||||
"bugs": [
|
||||
"SignedImmutables",
|
||||
|
@ -86,6 +86,8 @@ Global Variables
|
||||
to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature)), ...)``
|
||||
- ``bytes.concat(...) returns (bytes memory)``: :ref:`Concatenates variable number of
|
||||
arguments to one byte array<bytes-concat>`
|
||||
- ``string.concat(...) returns (string memory)``: :ref:`Concatenates variable number of
|
||||
arguments to one string array<string-concat>`
|
||||
- ``block.basefee`` (``uint``): current block's base fee (`EIP-3198 <https://eips.ethereum.org/EIPS/eip-3198>`_ and `EIP-1559 <https://eips.ethereum.org/EIPS/eip-1559>`_)
|
||||
- ``block.chainid`` (``uint``): current chain id
|
||||
- ``block.coinbase`` (``address payable``): current block miner's address
|
||||
|
@ -94,6 +94,13 @@ dependencies (`evmone <https://github.com/ethereum/evmone/releases>`_,
|
||||
On macOS some of the testing scripts expect GNU coreutils to be installed.
|
||||
This can be easiest accomplished using Homebrew: ``brew install coreutils``.
|
||||
|
||||
On Windows systems make sure that you have a privilege to create symlinks,
|
||||
otherwise several tests may fail.
|
||||
Administrators should have that privilege, but you may also
|
||||
`grant it to other users <https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links#policy-management>`_
|
||||
or
|
||||
`enable Developer Mode <https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development>`_.
|
||||
|
||||
Running the Tests
|
||||
-----------------
|
||||
|
||||
|
@ -130,9 +130,12 @@ of votes.
|
||||
|
||||
// Since `sender` is a reference, this
|
||||
// modifies `voters[msg.sender].voted`
|
||||
Voter storage delegate_ = voters[to];
|
||||
|
||||
// Voters cannot delegate to wallets that cannot vote.
|
||||
require(delegate_.weight >= 1);
|
||||
sender.voted = true;
|
||||
sender.delegate = to;
|
||||
Voter storage delegate_ = voters[to];
|
||||
if (delegate_.voted) {
|
||||
// If the delegate already voted,
|
||||
// directly add to the number of votes
|
||||
|
@ -24,7 +24,7 @@ actual release. They are not meant for production use.
|
||||
|
||||
When deploying contracts, you should use the latest released version of Solidity. This
|
||||
is because breaking changes, as well as new features and bug fixes are introduced regularly.
|
||||
We currently use a 0.x version number [to indicate this fast pace of change](https://semver.org/#spec-item-4).
|
||||
We currently use a 0.x version number `to indicate this fast pace of change <https://semver.org/#spec-item-4>`_.
|
||||
|
||||
Remix
|
||||
=====
|
||||
|
@ -56,7 +56,8 @@ as individual values.
|
||||
of Solidity due to the fact that storage pointers can be passed to libraries. This means that
|
||||
any change to the rules outlined in this section is considered a breaking change
|
||||
of the language and due to its critical nature should be considered very carefully before
|
||||
being executed.
|
||||
being executed. In the event of such a breaking change, we would want to release a
|
||||
compatibility mode in which the compiler would generate bytecode supporting the old layout.
|
||||
|
||||
|
||||
Mappings and Dynamic Arrays
|
||||
|
@ -222,7 +222,7 @@ than the maximum value of ``uint`` (``2**256 - 1``). This is also true for the s
|
||||
|
||||
:ref:`Errors <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 <revert-statement>`. The revert statement unconditionally
|
||||
:ref:`revert statement <revert-statement>`. The ``revert`` statement unconditionally
|
||||
aborts and reverts all changes similar to the ``require`` function, but it also
|
||||
allows you to provide the name of an error and additional data which will be supplied to the caller
|
||||
(and eventually to the front-end application or block explorer) so that
|
||||
|
@ -27,6 +27,9 @@ it does include the supplied string in the :ref:`bytecode metadata <metadata>`.
|
||||
|
||||
If you do not want to specify a license or if the source code is
|
||||
not open-source, please use the special value ``UNLICENSED``.
|
||||
Note that ``UNLICENSED`` (no usage allowed, not present in SPDX license list)
|
||||
is different from ``UNLICENSE`` (grants all rights to everyone).
|
||||
Solidity follows `the npm recommendation <https://docs.npmjs.com/cli/v7/configuring-npm/package-json#license>`_.
|
||||
|
||||
Supplying this comment of course does not free you from other
|
||||
obligations related to licensing like having to mention
|
||||
|
@ -82,6 +82,9 @@ Editor Integrations
|
||||
* `Visual Studio Code extension <https://juan.blanco.ws/solidity-contracts-in-visual-studio-code/>`_
|
||||
Solidity plugin for Microsoft Visual Studio Code that includes syntax highlighting and the Solidity compiler.
|
||||
|
||||
* `Solidity Visual Auditor extension <https://marketplace.visualstudio.com/items?itemName=tintinweb.solidity-visual-auditor>`_
|
||||
Adds security centric syntax and semantic highlighting to Visual Studio Code.
|
||||
|
||||
Solidity Tools
|
||||
==============
|
||||
|
||||
|
@ -8,7 +8,7 @@ Style Guide
|
||||
Introduction
|
||||
************
|
||||
|
||||
This guide is intended to provide coding conventions for writing solidity code.
|
||||
This guide is intended to provide coding conventions for writing Solidity code.
|
||||
This guide should be thought of as an evolving document that will change over
|
||||
time as useful conventions are found and old conventions are rendered obsolete.
|
||||
|
||||
@ -20,7 +20,7 @@ taken from python's
|
||||
`pep8 style guide <https://www.python.org/dev/peps/pep-0008/>`_.
|
||||
|
||||
The goal of this guide is *not* to be the right way or the best way to write
|
||||
solidity code. The goal of this guide is *consistency*. A quote from python's
|
||||
Solidity code. The goal of this guide is *consistency*. A quote from python's
|
||||
`pep8 <https://www.python.org/dev/peps/pep-0008/#a-foolish-consistency-is-the-hobgoblin-of-little-minds>`_
|
||||
captures this concept well.
|
||||
|
||||
@ -28,7 +28,7 @@ captures this concept well.
|
||||
|
||||
A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is most important.
|
||||
|
||||
But most importantly: **know when to be inconsistent** -- sometimes the style guide just doesn't apply. When in doubt, use your best judgement. Look at other examples and decide what looks best. And don't hesitate to ask!
|
||||
But most importantly: **know when to be inconsistent** -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don't hesitate to ask!
|
||||
|
||||
|
||||
***********
|
||||
@ -51,7 +51,7 @@ Mixing tabs and spaces should be avoided.
|
||||
Blank Lines
|
||||
===========
|
||||
|
||||
Surround top level declarations in solidity source with two blank lines.
|
||||
Surround top level declarations in Solidity source with two blank lines.
|
||||
|
||||
Yes:
|
||||
|
||||
@ -680,7 +680,7 @@ No:
|
||||
}
|
||||
|
||||
For long function declarations, it is recommended to drop each argument onto
|
||||
it's own line at the same indentation level as the function body. The closing
|
||||
its own line at the same indentation level as the function body. The closing
|
||||
parenthesis and opening bracket should be placed on their own line as well at
|
||||
the same indentation level as the function declaration.
|
||||
|
||||
@ -933,7 +933,7 @@ Permissible:
|
||||
function shortFunction() public { doSomething(); }
|
||||
|
||||
These guidelines for function declarations are intended to improve readability.
|
||||
Authors should use their best judgement as this guide does not try to cover all
|
||||
Authors should use their best judgment as this guide does not try to cover all
|
||||
possible permutations for function declarations.
|
||||
|
||||
Mappings
|
||||
@ -1023,7 +1023,7 @@ No:
|
||||
|
||||
* Operators with a higher priority than others can exclude surrounding
|
||||
whitespace in order to denote precedence. This is meant to allow for
|
||||
improved readability for complex statement. You should always use the same
|
||||
improved readability for complex statements. You should always use the same
|
||||
amount of whitespace on either side of an operator:
|
||||
|
||||
Yes:
|
||||
|
@ -150,7 +150,7 @@ length or index access.
|
||||
Solidity does not have string manipulation functions, but there are
|
||||
third-party string libraries. You can also compare two strings by their keccak256-hash using
|
||||
``keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))`` and
|
||||
concatenate two strings using ``bytes.concat(bytes(s1), bytes(s2))``.
|
||||
concatenate two strings using ``string.concat(s1, s2)``.
|
||||
|
||||
You should use ``bytes`` over ``bytes1[]`` because it is cheaper,
|
||||
since using ``bytes1[]`` in ``memory`` adds 31 padding bytes between the elements. Note that in ``storage``, the
|
||||
@ -165,31 +165,40 @@ always use one of the value types ``bytes1`` to ``bytes32`` because they are muc
|
||||
that you are accessing the low-level bytes of the UTF-8 representation,
|
||||
and not the individual characters.
|
||||
|
||||
.. index:: ! bytes-concat
|
||||
.. index:: ! bytes-concat, ! string-concat
|
||||
|
||||
.. _bytes-concat:
|
||||
.. _string-concat:
|
||||
|
||||
``bytes.concat`` function
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The functions ``bytes.concat`` and ``string.concat``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can concatenate a variable number of ``bytes`` or ``bytes1 ... bytes32`` using ``bytes.concat``.
|
||||
You can concatenate an arbitrary number of ``string`` values using ``string.concat``.
|
||||
The function returns a single ``string memory`` array that contains the contents of the arguments without padding.
|
||||
If you want to use parameters of other types that are not implicitly convertible to ``string``, you need to convert them to ``string`` first.
|
||||
|
||||
Analogously, the ``bytes.concat`` function can concatenate an arbitrary number of ``bytes`` or ``bytes1 ... bytes32`` values.
|
||||
The function returns a single ``bytes memory`` array that contains the contents of the arguments without padding.
|
||||
If you want to use string parameters or other types, you need to convert them to ``bytes`` or ``bytes1``/.../``bytes32`` first.
|
||||
If you want to use string parameters or other types that are not implicitly convertible to ``bytes``, you need to convert them to ``bytes`` or ``bytes1``/.../``bytes32`` first.
|
||||
|
||||
|
||||
.. code-block:: solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.4;
|
||||
pragma solidity ^0.8.12;
|
||||
|
||||
contract C {
|
||||
bytes s = "Storage";
|
||||
function f(bytes calldata c, string memory m, bytes16 b) public view {
|
||||
bytes memory a = bytes.concat(s, c, c[:2], "Literal", bytes(m), b);
|
||||
assert((s.length + c.length + 2 + 7 + bytes(m).length + 16) == a.length);
|
||||
string s = "Storage";
|
||||
function f(bytes calldata bc, string memory sm, bytes16 b) public view {
|
||||
string memory concat_string = string.concat(s, string(bc), "Literal", sm);
|
||||
assert((bytes(s).length + bc.length + 7 + bytes(sm).length) == bytes(concat_string).length);
|
||||
|
||||
bytes memory concat_bytes = bytes.concat(bytes(s), bc, bc[:2], "Literal", bytes(sm), b);
|
||||
assert((bytes(s).length + bc.length + 2 + 7 + bytes(sm).length + b.length) == concat_bytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
If you call ``bytes.concat`` without arguments it will return an empty ``bytes`` array.
|
||||
If you call ``string.concat`` or ``bytes.concat`` without arguments they return an empty array.
|
||||
|
||||
.. index:: ! array;allocating, new
|
||||
|
||||
|
@ -154,6 +154,14 @@ Members of bytes
|
||||
|
||||
- ``bytes.concat(...) returns (bytes memory)``: :ref:`Concatenates variable number of bytes and bytes1, ..., bytes32 arguments to one byte array<bytes-concat>`
|
||||
|
||||
.. index:: string members
|
||||
|
||||
Members of string
|
||||
-----------------
|
||||
|
||||
- ``string.concat(...) returns (string memory)``: :ref:`Concatenates variable number of string arguments to one string array<string-concat>`
|
||||
|
||||
|
||||
.. index:: assert, revert, require
|
||||
|
||||
Error Handling
|
||||
|
@ -897,10 +897,11 @@ OverrideChecker::OverrideProxyBySignatureMultiSet const& OverrideChecker::inheri
|
||||
if (var->isPublic())
|
||||
functionsInBase.emplace(OverrideProxy{var});
|
||||
|
||||
for (OverrideProxy const& func: inheritedFunctions(*base))
|
||||
functionsInBase.insert(func);
|
||||
|
||||
result += functionsInBase;
|
||||
|
||||
for (OverrideProxy const& func: inheritedFunctions(*base))
|
||||
if (!functionsInBase.count(func))
|
||||
result.insert(func);
|
||||
}
|
||||
|
||||
m_inheritedFunctions[&_contract] = result;
|
||||
|
@ -2207,14 +2207,42 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TypeChecker::typeCheckStringConcatFunction(
|
||||
FunctionCall const& _functionCall,
|
||||
FunctionType const* _functionType
|
||||
)
|
||||
{
|
||||
solAssert(_functionType);
|
||||
solAssert(_functionType->kind() == FunctionType::Kind::StringConcat);
|
||||
solAssert(_functionCall.names().empty());
|
||||
|
||||
typeCheckFunctionGeneralChecks(_functionCall, _functionType);
|
||||
|
||||
for (shared_ptr<Expression const> const& argument: _functionCall.arguments())
|
||||
{
|
||||
Type const* argumentType = type(*argument);
|
||||
bool notConvertibleToString = !argumentType->isImplicitlyConvertibleTo(*TypeProvider::stringMemory());
|
||||
|
||||
if (notConvertibleToString)
|
||||
m_errorReporter.typeError(
|
||||
9977_error,
|
||||
argument->location(),
|
||||
"Invalid type for argument in the string.concat function call. "
|
||||
"string type is required, but " +
|
||||
argumentType->identifier() + " provided."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeChecker::typeCheckBytesConcatFunction(
|
||||
FunctionCall const& _functionCall,
|
||||
FunctionType const* _functionType
|
||||
)
|
||||
{
|
||||
solAssert(_functionType, "");
|
||||
solAssert(_functionType->kind() == FunctionType::Kind::BytesConcat, "");
|
||||
solAssert(_functionCall.names().empty(), "");
|
||||
solAssert(_functionType);
|
||||
solAssert(_functionType->kind() == FunctionType::Kind::BytesConcat);
|
||||
solAssert(_functionCall.names().empty());
|
||||
|
||||
typeCheckFunctionGeneralChecks(_functionCall, _functionType);
|
||||
|
||||
@ -2651,6 +2679,12 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
returnTypes = functionType->returnParameterTypes();
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::StringConcat:
|
||||
{
|
||||
typeCheckStringConcatFunction(_functionCall, functionType);
|
||||
returnTypes = functionType->returnParameterTypes();
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::Wrap:
|
||||
case FunctionType::Kind::Unwrap:
|
||||
{
|
||||
|
@ -113,6 +113,12 @@ private:
|
||||
/// Performs checks specific to the ABI encode functions of type ABIEncodeCall
|
||||
void typeCheckABIEncodeCallFunction(FunctionCall const& _functionCall);
|
||||
|
||||
/// Performs general checks and checks specific to string concat function call
|
||||
void typeCheckStringConcatFunction(
|
||||
FunctionCall const& _functionCall,
|
||||
FunctionType const* _functionType
|
||||
);
|
||||
|
||||
/// Performs general checks and checks specific to bytes concat function call
|
||||
void typeCheckBytesConcatFunction(
|
||||
FunctionCall const& _functionCall,
|
||||
|
@ -192,7 +192,7 @@ FunctionDefinition const* ContractDefinition::receiveFunction() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() const
|
||||
vector<EventDefinition const*> const& ContractDefinition::definedInterfaceEvents() const
|
||||
{
|
||||
return m_interfaceEvents.init([&]{
|
||||
set<string> eventsSeen;
|
||||
@ -213,11 +213,20 @@ vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() cons
|
||||
interfaceEvents.push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
return interfaceEvents;
|
||||
});
|
||||
}
|
||||
|
||||
vector<EventDefinition const*> const ContractDefinition::usedInterfaceEvents() const
|
||||
{
|
||||
solAssert(annotation().creationCallGraph.set(), "");
|
||||
|
||||
return convertContainer<std::vector<EventDefinition const*>>(
|
||||
(*annotation().creationCallGraph)->emittedEvents +
|
||||
(*annotation().deployedCallGraph)->emittedEvents
|
||||
);
|
||||
}
|
||||
|
||||
vector<ErrorDefinition const*> ContractDefinition::interfaceErrors(bool _requireCallGraph) const
|
||||
{
|
||||
set<ErrorDefinition const*, CompareByID> result;
|
||||
@ -227,10 +236,9 @@ vector<ErrorDefinition const*> ContractDefinition::interfaceErrors(bool _require
|
||||
if (_requireCallGraph)
|
||||
solAssert(annotation().creationCallGraph.set(), "");
|
||||
if (annotation().creationCallGraph.set())
|
||||
{
|
||||
result += (*annotation().creationCallGraph)->usedErrors;
|
||||
result += (*annotation().deployedCallGraph)->usedErrors;
|
||||
}
|
||||
result +=
|
||||
(*annotation().creationCallGraph)->usedErrors +
|
||||
(*annotation().deployedCallGraph)->usedErrors;
|
||||
return convertContainer<vector<ErrorDefinition const*>>(move(result));
|
||||
}
|
||||
|
||||
|
@ -519,7 +519,8 @@ public:
|
||||
return ranges::subrange<decltype(b)>(b, e) | ranges::views::values;
|
||||
}
|
||||
std::vector<EventDefinition const*> events() const { return filteredNodes<EventDefinition>(m_subNodes); }
|
||||
std::vector<EventDefinition const*> const& interfaceEvents() const;
|
||||
std::vector<EventDefinition const*> const& definedInterfaceEvents() const;
|
||||
std::vector<EventDefinition const*> const usedInterfaceEvents() const;
|
||||
/// @returns all errors defined in this contract or any base contract
|
||||
/// and all errors referenced during execution.
|
||||
/// @param _requireCallGraph if false, do not fail if the call graph has not been computed yet.
|
||||
|
@ -2932,6 +2932,7 @@ string FunctionType::richIdentifier() const
|
||||
case Kind::ArrayPush: id += "arraypush"; break;
|
||||
case Kind::ArrayPop: id += "arraypop"; break;
|
||||
case Kind::BytesConcat: id += "bytesconcat"; break;
|
||||
case Kind::StringConcat: id += "stringconcat"; break;
|
||||
case Kind::ObjectCreation: id += "objectcreation"; break;
|
||||
case Kind::Assert: id += "assert"; break;
|
||||
case Kind::Require: id += "require"; break;
|
||||
@ -3821,15 +3822,14 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
|
||||
)
|
||||
members.emplace_back("concat", TypeProvider::function(
|
||||
TypePointers{},
|
||||
TypePointers{TypeProvider::bytesMemory()},
|
||||
TypePointers{arrayType->isString() ? TypeProvider::stringMemory() : TypeProvider::bytesMemory()},
|
||||
strings{},
|
||||
strings{string()},
|
||||
FunctionType::Kind::BytesConcat,
|
||||
strings{string{}},
|
||||
arrayType->isString() ? FunctionType::Kind::StringConcat : FunctionType::Kind::BytesConcat,
|
||||
StateMutability::Pure,
|
||||
nullptr,
|
||||
FunctionType::Options::withArbitraryParameters()
|
||||
));
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
|
@ -1228,6 +1228,7 @@ public:
|
||||
ArrayPush, ///< .push() to a dynamically sized array in storage
|
||||
ArrayPop, ///< .pop() from a dynamically sized array in storage
|
||||
BytesConcat, ///< .concat() on bytes (type type)
|
||||
StringConcat, ///< .concat() on string (type type)
|
||||
ObjectCreation, ///< array creation using new
|
||||
Assert, ///< assert()
|
||||
Require, ///< require()
|
||||
|
@ -1101,6 +1101,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
ArrayUtils(m_context).popStorageArrayElement(*arrayType);
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::StringConcat:
|
||||
case FunctionType::Kind::BytesConcat:
|
||||
{
|
||||
_functionCall.expression().accept(*this);
|
||||
@ -1121,10 +1122,18 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
else
|
||||
{
|
||||
solAssert(!dynamic_cast<RationalNumberType const*>(argument->annotation().type), "");
|
||||
if (function.kind() == FunctionType::Kind::StringConcat)
|
||||
{
|
||||
solAssert(argument->annotation().type->isImplicitlyConvertibleTo(*TypeProvider::stringMemory()), "");
|
||||
targetTypes.emplace_back(TypeProvider::stringMemory());
|
||||
}
|
||||
else if (function.kind() == FunctionType::Kind::BytesConcat)
|
||||
{
|
||||
solAssert(argument->annotation().type->isImplicitlyConvertibleTo(*TypeProvider::bytesMemory()), "");
|
||||
targetTypes.emplace_back(TypeProvider::bytesMemory());
|
||||
}
|
||||
}
|
||||
}
|
||||
utils().fetchFreeMemoryPointer();
|
||||
// stack: <arg1> <arg2> ... <argn> <free mem>
|
||||
m_context << u256(32) << Instruction::ADD;
|
||||
|
@ -2475,18 +2475,26 @@ string YulUtilFunctions::copyArrayFromStorageToMemoryFunction(ArrayType const& _
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::bytesConcatFunction(vector<Type const*> const& _argumentTypes)
|
||||
string YulUtilFunctions::bytesOrStringConcatFunction(
|
||||
vector<Type const*> const& _argumentTypes,
|
||||
FunctionType::Kind _functionTypeKind
|
||||
)
|
||||
{
|
||||
string functionName = "bytes_concat";
|
||||
solAssert(_functionTypeKind == FunctionType::Kind::BytesConcat || _functionTypeKind == FunctionType::Kind::StringConcat);
|
||||
std::string functionName = (_functionTypeKind == FunctionType::Kind::StringConcat) ? "string_concat" : "bytes_concat";
|
||||
size_t totalParams = 0;
|
||||
vector<Type const*> targetTypes;
|
||||
|
||||
for (Type const* argumentType: _argumentTypes)
|
||||
{
|
||||
if (_functionTypeKind == FunctionType::Kind::StringConcat)
|
||||
solAssert(argumentType->isImplicitlyConvertibleTo(*TypeProvider::stringMemory()));
|
||||
else if (_functionTypeKind == FunctionType::Kind::BytesConcat)
|
||||
solAssert(
|
||||
argumentType->isImplicitlyConvertibleTo(*TypeProvider::bytesMemory()) ||
|
||||
argumentType->isImplicitlyConvertibleTo(*TypeProvider::fixedBytes(32)),
|
||||
""
|
||||
argumentType->isImplicitlyConvertibleTo(*TypeProvider::fixedBytes(32))
|
||||
);
|
||||
|
||||
if (argumentType->category() == Type::Category::FixedBytes)
|
||||
targetTypes.emplace_back(argumentType);
|
||||
else if (
|
||||
@ -2496,15 +2504,16 @@ string YulUtilFunctions::bytesConcatFunction(vector<Type const*> const& _argumen
|
||||
targetTypes.emplace_back(TypeProvider::fixedBytes(static_cast<unsigned>(literalType->value().size())));
|
||||
else
|
||||
{
|
||||
solAssert(!dynamic_cast<RationalNumberType const*>(argumentType), "");
|
||||
solAssert(argumentType->isImplicitlyConvertibleTo(*TypeProvider::bytesMemory()), "");
|
||||
targetTypes.emplace_back(TypeProvider::bytesMemory());
|
||||
solAssert(!dynamic_cast<RationalNumberType const*>(argumentType));
|
||||
targetTypes.emplace_back(
|
||||
_functionTypeKind == FunctionType::Kind::StringConcat ?
|
||||
TypeProvider::stringMemory() :
|
||||
TypeProvider::bytesMemory()
|
||||
);
|
||||
}
|
||||
|
||||
totalParams += argumentType->sizeOnStack();
|
||||
functionName += "_" + argumentType->identifier();
|
||||
}
|
||||
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>(<parameters>) -> outPtr {
|
||||
|
@ -312,9 +312,13 @@ public:
|
||||
/// of the storage array into it.
|
||||
std::string copyArrayFromStorageToMemoryFunction(ArrayType const& _from, ArrayType const& _to);
|
||||
|
||||
/// @returns the name of a function that does concatenation of variadic number of bytes
|
||||
/// or fixed bytes
|
||||
std::string bytesConcatFunction(std::vector<Type const*> const& _argumentTypes);
|
||||
/// @returns the name of a function that does concatenation of variadic number of
|
||||
/// bytes if @a functionTypeKind is FunctionType::Kind::BytesConcat,
|
||||
/// or of strings, if @a functionTypeKind is FunctionType::Kind::StringConcat.
|
||||
std::string bytesOrStringConcatFunction(
|
||||
std::vector<Type const*> const& _argumentTypes,
|
||||
FunctionType::Kind _functionTypeKind
|
||||
);
|
||||
|
||||
/// @returns the name of a function that performs index access for mappings.
|
||||
/// @param _mappingType the type of the mapping
|
||||
|
@ -1389,6 +1389,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::StringConcat:
|
||||
case FunctionType::Kind::BytesConcat:
|
||||
{
|
||||
TypePointers argumentTypes;
|
||||
@ -1399,11 +1400,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
argumentVars += IRVariable(*argument).stackSlots();
|
||||
}
|
||||
define(IRVariable(_functionCall)) <<
|
||||
m_utils.bytesConcatFunction(argumentTypes) <<
|
||||
m_utils.bytesOrStringConcatFunction(argumentTypes, functionType->kind()) <<
|
||||
"(" <<
|
||||
joinHumanReadable(argumentVars) <<
|
||||
")\n";
|
||||
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::MetaType:
|
||||
|
@ -101,7 +101,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef)
|
||||
method["stateMutability"] = stateMutabilityToString(externalFunctionType->stateMutability());
|
||||
abi.emplace(std::move(method));
|
||||
}
|
||||
for (auto const& it: _contractDef.interfaceEvents())
|
||||
for (auto const& it: _contractDef.definedInterfaceEvents())
|
||||
{
|
||||
Json::Value event{Json::objectValue};
|
||||
event["type"] = "event";
|
||||
|
@ -75,11 +75,14 @@
|
||||
#include <libsolutil/IpfsHash.h>
|
||||
#include <libsolutil/JSON.h>
|
||||
#include <libsolutil/Algorithms.h>
|
||||
#include <libsolutil/FunctionSelector.h>
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
#include <range/v3/view/concat.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <map>
|
||||
#include <limits>
|
||||
@ -1013,15 +1016,34 @@ Json::Value const& CompilerStack::natspecDev(Contract const& _contract) const
|
||||
return _contract.devDocumentation.init([&]{ return Natspec::devDocumentation(*_contract.contract); });
|
||||
}
|
||||
|
||||
Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const
|
||||
Json::Value CompilerStack::interfaceSymbols(string const& _contractName) const
|
||||
{
|
||||
if (m_stackState < AnalysisPerformed)
|
||||
solThrow(CompilerError, "Analysis was not successful.");
|
||||
|
||||
Json::Value methodIdentifiers(Json::objectValue);
|
||||
Json::Value interfaceSymbols(Json::objectValue);
|
||||
// Always have a methods object
|
||||
interfaceSymbols["methods"] = Json::objectValue;
|
||||
|
||||
for (auto const& it: contractDefinition(_contractName).interfaceFunctions())
|
||||
methodIdentifiers[it.second->externalSignature()] = it.first.hex();
|
||||
return methodIdentifiers;
|
||||
interfaceSymbols["methods"][it.second->externalSignature()] = it.first.hex();
|
||||
for (ErrorDefinition const* error: contractDefinition(_contractName).interfaceErrors())
|
||||
{
|
||||
string signature = error->functionType(true)->externalSignature();
|
||||
interfaceSymbols["errors"][signature] = toHex(toCompactBigEndian(selectorFromSignature32(signature), 4));
|
||||
}
|
||||
|
||||
for (EventDefinition const* event: ranges::concat_view(
|
||||
contractDefinition(_contractName).definedInterfaceEvents(),
|
||||
contractDefinition(_contractName).usedInterfaceEvents()
|
||||
))
|
||||
if (!event->isAnonymous())
|
||||
{
|
||||
string signature = event->functionType(true)->externalSignature();
|
||||
interfaceSymbols["events"][signature] = toHex(u256(h256::Arith(keccak256(signature))));
|
||||
}
|
||||
|
||||
return interfaceSymbols;
|
||||
}
|
||||
|
||||
bytes CompilerStack::cborMetadata(string const& _contractName, bool _forIR) const
|
||||
|
@ -327,8 +327,8 @@ public:
|
||||
/// Prerequisite: Successful call to parse or compile.
|
||||
Json::Value const& natspecDev(std::string const& _contractName) const;
|
||||
|
||||
/// @returns a JSON representing a map of method identifiers (hashes) to function names.
|
||||
Json::Value methodIdentifiers(std::string const& _contractName) const;
|
||||
/// @returns a JSON object with the three members ``methods``, ``events``, ``errors``. Each is a map, mapping identifiers (hashes) to function names.
|
||||
Json::Value interfaceSymbols(std::string const& _contractName) const;
|
||||
|
||||
/// @returns the Contract Metadata matching the pipeline selected using the viaIR setting.
|
||||
std::string const& metadata(std::string const& _contractName) const { return metadata(contract(_contractName)); }
|
||||
|
@ -116,7 +116,6 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so
|
||||
for (auto const& prefix: prefixes)
|
||||
{
|
||||
boost::filesystem::path canonicalPath = normalizeCLIPathForVFS(prefix / strippedSourceUnitName, SymlinkResolution::Enabled);
|
||||
|
||||
if (boost::filesystem::exists(canonicalPath))
|
||||
candidates.push_back(std::move(canonicalPath));
|
||||
}
|
||||
@ -124,7 +123,12 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so
|
||||
auto pathToQuotedString = [](boost::filesystem::path const& _path){ return "\"" + _path.string() + "\""; };
|
||||
|
||||
if (candidates.empty())
|
||||
return ReadCallback::Result{false, "File not found."};
|
||||
return ReadCallback::Result{
|
||||
false,
|
||||
"File not found. Searched the following locations: " +
|
||||
joinHumanReadable(prefixes | ranges::views::transform(pathToQuotedString), ", ") +
|
||||
"."
|
||||
};
|
||||
|
||||
if (candidates.size() >= 2)
|
||||
return ReadCallback::Result{
|
||||
@ -135,11 +139,13 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so
|
||||
"."
|
||||
};
|
||||
|
||||
FileSystemPathSet extraAllowedPaths = {m_basePath.empty() ? "." : m_basePath};
|
||||
extraAllowedPaths += m_includePaths;
|
||||
FileSystemPathSet allowedPaths =
|
||||
m_allowedDirectories +
|
||||
decltype(allowedPaths){m_basePath.empty() ? "." : m_basePath} +
|
||||
m_includePaths;
|
||||
|
||||
bool isAllowed = false;
|
||||
for (boost::filesystem::path const& allowedDir: m_allowedDirectories + extraAllowedPaths)
|
||||
for (boost::filesystem::path const& allowedDir: allowedPaths)
|
||||
if (isPathPrefix(normalizeCLIPathForVFS(allowedDir, SymlinkResolution::Enabled), candidates[0]))
|
||||
{
|
||||
isAllowed = true;
|
||||
@ -147,7 +153,12 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so
|
||||
}
|
||||
|
||||
if (!isAllowed)
|
||||
return ReadCallback::Result{false, "File outside of allowed directories."};
|
||||
return ReadCallback::Result{
|
||||
false,
|
||||
"File outside of allowed directories. The following are allowed: " +
|
||||
joinHumanReadable(allowedPaths | ranges::views::transform(pathToQuotedString), ", ") +
|
||||
"."
|
||||
};
|
||||
|
||||
if (!boost::filesystem::is_regular_file(candidates[0]))
|
||||
return ReadCallback::Result{false, "Not a valid file."};
|
||||
@ -269,7 +280,8 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(
|
||||
if (!isUNCPath(normalizedPath))
|
||||
{
|
||||
boost::filesystem::path workingDirRootPath = canonicalWorkDir.root_path();
|
||||
if (normalizedRootPath == workingDirRootPath)
|
||||
// Ignore drive letter case on Windows (C:\ <=> c:\).
|
||||
if (boost::filesystem::equivalent(normalizedRootPath, workingDirRootPath))
|
||||
normalizedRootPath = "/";
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
||||
doc["methods"][it.second->externalSignature()]["notice"] = value;
|
||||
}
|
||||
|
||||
for (auto const& event: _contractDef.interfaceEvents())
|
||||
for (auto const& event: _contractDef.definedInterfaceEvents())
|
||||
{
|
||||
string value = extractDoc(event->annotation().docTags, "notice");
|
||||
if (!value.empty())
|
||||
|
@ -1298,7 +1298,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.legacyAssembly", wildcardMatchesExperimental))
|
||||
evmData["legacyAssembly"] = compilerStack.assemblyJSON(contractName);
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.methodIdentifiers", wildcardMatchesExperimental))
|
||||
evmData["methodIdentifiers"] = compilerStack.methodIdentifiers(contractName);
|
||||
evmData["methodIdentifiers"] = compilerStack.interfaceSymbols(contractName)["methods"];
|
||||
if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.gasEstimates", wildcardMatchesExperimental))
|
||||
evmData["gasEstimates"] = compilerStack.gasEstimates(contractName);
|
||||
|
||||
|
@ -262,6 +262,11 @@ private:
|
||||
if (ops.sourceMultiplicity(ops.sourceSize() - 1 - swapDepth) < 0)
|
||||
{
|
||||
ops.swap(swapDepth);
|
||||
if (ops.targetIsArbitrary(sourceTop))
|
||||
// Usually we keep a slot that is to-be-removed, if the current top is arbitrary.
|
||||
// However, since we are in a stack-too-deep situation, pop it immediately
|
||||
// to compress the stack (we can always push back junk in the end).
|
||||
ops.pop();
|
||||
return true;
|
||||
}
|
||||
// Otherwise we rely on stack compression or stack-to-memory.
|
||||
@ -321,14 +326,44 @@ private:
|
||||
yulAssert(ops.sourceMultiplicity(i) == 0 && (ops.targetIsArbitrary(i) || ops.targetMultiplicity(i) == 0), "");
|
||||
yulAssert(ops.isCompatible(sourceTop, sourceTop), "");
|
||||
|
||||
auto swappableOffsets = ranges::views::iota(size > 17 ? size - 17 : 0u, size);
|
||||
|
||||
// If we find a lower slot that is out of position, but also compatible with the top, swap that up.
|
||||
for (size_t offset: swappableOffsets)
|
||||
if (!ops.isCompatible(offset, offset) && ops.isCompatible(sourceTop, offset))
|
||||
{
|
||||
ops.swap(size - offset - 1);
|
||||
return true;
|
||||
}
|
||||
// Swap up any reachable slot that is still out of position.
|
||||
for (size_t offset: swappableOffsets)
|
||||
if (!ops.isCompatible(offset, offset) && !ops.sourceIsSame(offset, sourceTop))
|
||||
{
|
||||
ops.swap(size - offset - 1);
|
||||
return true;
|
||||
}
|
||||
// We are in a stack-too-deep situation and try to reduce the stack size.
|
||||
// If the current top is merely kept since the target slot is arbitrary, pop it.
|
||||
if (ops.targetIsArbitrary(sourceTop) && ops.sourceMultiplicity(sourceTop) <= 0)
|
||||
{
|
||||
ops.pop();
|
||||
return true;
|
||||
}
|
||||
// If any reachable slot is merely kept, since the target slot is arbitrary, swap it up and pop it.
|
||||
for (size_t offset: swappableOffsets)
|
||||
if (ops.targetIsArbitrary(offset) && ops.sourceMultiplicity(offset) <= 0)
|
||||
{
|
||||
ops.swap(size - offset - 1);
|
||||
ops.pop();
|
||||
return true;
|
||||
}
|
||||
// We cannot avoid a stack-too-deep error. Repeat the above without restricting to reachable slots.
|
||||
for (size_t offset: ranges::views::iota(0u, size))
|
||||
if (!ops.isCompatible(offset, offset) && ops.isCompatible(sourceTop, offset))
|
||||
{
|
||||
ops.swap(size - offset - 1);
|
||||
return true;
|
||||
}
|
||||
// Swap up any slot that is still out of position.
|
||||
for (size_t offset: ranges::views::iota(0u, size))
|
||||
if (!ops.isCompatible(offset, offset) && !ops.sourceIsSame(offset, sourceTop))
|
||||
{
|
||||
|
46
scripts/ci/base64DecToArr.js
Normal file
46
scripts/ci/base64DecToArr.js
Normal file
@ -0,0 +1,46 @@
|
||||
function base64DecToArr (sBase64) {
|
||||
/*\
|
||||
|*|
|
||||
|*| Base64 / binary data / UTF-8 strings utilities
|
||||
|*|
|
||||
|*| https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
|
||||
|*|
|
||||
\*/
|
||||
|
||||
/* Array of bytes to Base64 string decoding */
|
||||
|
||||
function b64ToUint6 (nChr) {
|
||||
|
||||
return nChr > 64 && nChr < 91 ?
|
||||
nChr - 65
|
||||
: nChr > 96 && nChr < 123 ?
|
||||
nChr - 71
|
||||
: nChr > 47 && nChr < 58 ?
|
||||
nChr + 4
|
||||
: nChr === 43 ?
|
||||
62
|
||||
: nChr === 47 ?
|
||||
63
|
||||
:
|
||||
0;
|
||||
|
||||
}
|
||||
|
||||
var
|
||||
nInLen = sBase64.length,
|
||||
nOutLen = nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen);
|
||||
|
||||
for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
|
||||
nMod4 = nInIdx & 3;
|
||||
nUint24 |= b64ToUint6(sBase64.charCodeAt(nInIdx)) << 6 * (3 - nMod4);
|
||||
if (nMod4 === 3 || nInLen - nInIdx === 1) {
|
||||
for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
|
||||
taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
|
||||
}
|
||||
nUint24 = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return taBytes;
|
||||
}
|
@ -40,6 +40,8 @@ else
|
||||
BUILD_DIR="$1"
|
||||
fi
|
||||
|
||||
apt-get update && apt-get install lz4
|
||||
|
||||
WORKSPACE=/root/project
|
||||
|
||||
cd $WORKSPACE
|
||||
@ -71,8 +73,8 @@ make soljson
|
||||
|
||||
cd ..
|
||||
mkdir -p upload
|
||||
cp "$BUILD_DIR/libsolc/soljson.js" upload/
|
||||
cp "$BUILD_DIR/libsolc/soljson.js" ./
|
||||
scripts/ci/pack_soljson.sh "$BUILD_DIR/libsolc/soljson.js" "$BUILD_DIR/libsolc/soljson.wasm" upload/soljson.js
|
||||
cp upload/soljson.js ./
|
||||
|
||||
OUTPUT_SIZE=$(ls -la soljson.js)
|
||||
|
||||
|
116
scripts/ci/mini-lz4.js
Normal file
116
scripts/ci/mini-lz4.js
Normal file
@ -0,0 +1,116 @@
|
||||
function uncompress(source, uncompressedSize) {
|
||||
/*
|
||||
based off https://github.com/emscripten-core/emscripten/blob/main/third_party/mini-lz4.js
|
||||
The license only applies to the body of this function (``uncompress``).
|
||||
====
|
||||
MiniLZ4: Minimal LZ4 block decoding and encoding.
|
||||
|
||||
based off of node-lz4, https://github.com/pierrec/node-lz4
|
||||
|
||||
====
|
||||
Copyright (c) 2012 Pierre Curto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
====
|
||||
|
||||
changes have the same license
|
||||
*/
|
||||
/**
|
||||
* Decode a block. Assumptions: input contains all sequences of a
|
||||
* chunk, output is large enough to receive the decoded data.
|
||||
* If the output buffer is too small, an error will be thrown.
|
||||
* If the returned value is negative, an error occurred at the returned offset.
|
||||
*
|
||||
* @param {ArrayBufferView} input input data
|
||||
* @param {ArrayBufferView} output output data
|
||||
* @param {number=} sIdx
|
||||
* @param {number=} eIdx
|
||||
* @return {number} number of decoded bytes
|
||||
* @private
|
||||
*/
|
||||
function uncompressBlock (input, output, sIdx, eIdx) {
|
||||
sIdx = sIdx || 0
|
||||
eIdx = eIdx || (input.length - sIdx)
|
||||
// Process each sequence in the incoming data
|
||||
for (var i = sIdx, n = eIdx, j = 0; i < n;) {
|
||||
var token = input[i++]
|
||||
|
||||
// Literals
|
||||
var literals_length = (token >> 4)
|
||||
if (literals_length > 0) {
|
||||
// length of literals
|
||||
var l = literals_length + 240
|
||||
while (l === 255) {
|
||||
l = input[i++]
|
||||
literals_length += l
|
||||
}
|
||||
|
||||
// Copy the literals
|
||||
var end = i + literals_length
|
||||
while (i < end) output[j++] = input[i++]
|
||||
|
||||
// End of buffer?
|
||||
if (i === n) return j
|
||||
}
|
||||
|
||||
// Match copy
|
||||
// 2 bytes offset (little endian)
|
||||
var offset = input[i++] | (input[i++] << 8)
|
||||
|
||||
// XXX 0 is an invalid offset value
|
||||
if (offset === 0) return j
|
||||
if (offset > j) return -(i-2)
|
||||
|
||||
// length of match copy
|
||||
var match_length = (token & 0xf)
|
||||
var l = match_length + 240
|
||||
while (l === 255) {
|
||||
l = input[i++]
|
||||
match_length += l
|
||||
}
|
||||
// Copy the match
|
||||
var pos = j - offset // position of the match copy in the current output
|
||||
var end = j + match_length + 4 // minmatch = 4
|
||||
while (j < end) output[j++] = output[pos++]
|
||||
}
|
||||
|
||||
return j
|
||||
}
|
||||
var result = new ArrayBuffer(uncompressedSize);
|
||||
var sourceIndex = 0;
|
||||
var destIndex = 0;
|
||||
var blockSize;
|
||||
while((blockSize = (source[sourceIndex] | (source[sourceIndex + 1] << 8) | (source[sourceIndex + 2] << 16) | (source[sourceIndex + 3] << 24))) > 0)
|
||||
{
|
||||
sourceIndex += 4;
|
||||
if (blockSize & 0x80000000)
|
||||
{
|
||||
blockSize &= 0x7FFFFFFFF;
|
||||
for (var i = 0; i < blockSize; i++) {
|
||||
result[destIndex++] = source[sourceIndex++];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
destIndex += uncompressBlock(source, new Uint8Array(result, destIndex, uncompressedSize - destIndex), sourceIndex, sourceIndex + blockSize);
|
||||
sourceIndex += blockSize;
|
||||
}
|
||||
}
|
||||
return new Uint8Array(result, 0, uncompressedSize);
|
||||
}
|
37
scripts/ci/pack_soljson.sh
Executable file
37
scripts/ci/pack_soljson.sh
Executable file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
script_dir="$(realpath "$(dirname "$0")")"
|
||||
soljson_js="$1"
|
||||
soljson_wasm="$2"
|
||||
soljson_wasm_size=$(wc -c "${soljson_wasm}" | cut -d ' ' -f 1)
|
||||
output="$3"
|
||||
|
||||
(( $# == 3 )) || { >&2 echo "Usage: $0 soljson.js soljson.wasm packed_soljson.js"; exit 1; }
|
||||
|
||||
# If this changes in an emscripten update, it's probably nothing to worry about,
|
||||
# but we should double-check when it happens and adjust the tail command below.
|
||||
[[ $(head -c 5 "${soljson_js}") == "null;" ]] || { >&2 echo 'Expected soljson.js to start with "null;"'; exit 1; }
|
||||
|
||||
echo "Packing $soljson_js and $soljson_wasm to $output."
|
||||
(
|
||||
echo -n 'var Module = Module || {}; Module["wasmBinary"] = '
|
||||
echo -n '(function(source, uncompressedSize) {'
|
||||
# Note that base64DecToArr assumes no trailing equals signs.
|
||||
cpp "${script_dir}/base64DecToArr.js" | grep -v "^#.*"
|
||||
# Note that mini-lz4.js assumes no file header and no frame crc checksums.
|
||||
cpp "${script_dir}/mini-lz4.js" | grep -v "^#.*"
|
||||
echo 'return uncompress(base64DecToArr(source), uncompressedSize);})('
|
||||
echo -n '"'
|
||||
# We fix lz4 format settings, remove the 8 bytes file header and remove the trailing equals signs of the base64 encoding.
|
||||
lz4c --no-frame-crc --best --favor-decSpeed "${soljson_wasm}" - | tail -c +8 | base64 -w 0 | sed 's/[^A-Za-z0-9\+\/]//g'
|
||||
echo '",'
|
||||
echo -n "${soljson_wasm_size});"
|
||||
# Remove "null;" from the js wrapper.
|
||||
tail -c +6 "${soljson_js}"
|
||||
) > "$output"
|
||||
|
||||
echo "Testing $output."
|
||||
echo "process.stdout.write(require('$(realpath "${output}")').wasmBinary)" | node | cmp "${soljson_wasm}" && echo "Binaries match."
|
||||
# Allow the wasm binary to be garbage collected after compilation.
|
||||
echo 'Module["wasmBinary"] = undefined;' >> "${output}"
|
60
scripts/externalTests/merge_benchmarks.sh
Executable file
60
scripts/externalTests/merge_benchmarks.sh
Executable file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Reads multiple individual benchmark reports produced by scripts from
|
||||
# test/externalTests/ from standard input and creates a combined report.
|
||||
#
|
||||
# Usage:
|
||||
# <script name>.sh < <CONCATENATED_REPORTS>
|
||||
#
|
||||
# CONCATENATED_REPORTS: JSON report files concatenated into a single stream (e.g. using cat).
|
||||
#
|
||||
# Example:
|
||||
# cat reports/externalTests/benchmark-*.json | <script name>.sh
|
||||
# ------------------------------------------------------------------------------
|
||||
# This file is part of solidity.
|
||||
#
|
||||
# solidity is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# solidity is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with solidity. If not, see <http://www.gnu.org/licenses/>
|
||||
#
|
||||
# (c) 2021 solidity contributors.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# We expect a series of dicts of the form {"<project>": {"<preset>": {...}}}.
|
||||
# Unfortunately jq's built-in `add` filter can't handle nested dicts and
|
||||
# would just overwrite values sharing a project name instead of merging them.
|
||||
|
||||
# This is done by first grouping the dicts into an array of the form
|
||||
# [
|
||||
# [{"key": "<project1>", "value": {"<preset1>": {...}}}, {"key": "<project1>", "value": {"<preset2>": {...}}, ...],
|
||||
# [{"key": "<project2>", "value": {"<preset1>": {...}}}, {"key": "<project2>", "value": {"<preset2>": {...}}, ...],
|
||||
# ...
|
||||
# ]
|
||||
# and then using reduce() on each group sharing the same project name to convert it into a
|
||||
# dict having preset names as keys.
|
||||
jq --slurp --indent 4 --sort-keys '
|
||||
map(to_entries[]) |
|
||||
group_by(.key) |
|
||||
map({
|
||||
(.[0].key): (
|
||||
reduce (.[].value | to_entries[]) as {$key, $value} (
|
||||
{}; . + {
|
||||
($key): $value
|
||||
}
|
||||
)
|
||||
)
|
||||
}) |
|
||||
add
|
||||
'
|
269
scripts/externalTests/parse_eth_gas_report.py
Executable file
269
scripts/externalTests/parse_eth_gas_report.py
Executable file
@ -0,0 +1,269 @@
|
||||
#!/usr/bin/env python3
|
||||
# coding=utf-8
|
||||
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from typing import Dict, Optional, Tuple
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
REPORT_HEADER_REGEX = re.compile(r'''
|
||||
^[|\s]+ Solc[ ]version:\s*(?P<solc_version>[\w\d.]+)
|
||||
[|\s]+ Optimizer[ ]enabled:\s*(?P<optimize>[\w]+)
|
||||
[|\s]+ Runs:\s*(?P<runs>[\d]+)
|
||||
[|\s]+ Block[ ]limit:\s*(?P<block_limit>[\d]+)\s*gas
|
||||
[|\s]+$
|
||||
''', re.VERBOSE)
|
||||
METHOD_HEADER_REGEX = re.compile(r'^[|\s]+Methods[|\s]+$')
|
||||
METHOD_COLUMN_HEADERS_REGEX = re.compile(r'''
|
||||
^[|\s]+ Contract
|
||||
[|\s]+ Method
|
||||
[|\s]+ Min
|
||||
[|\s]+ Max
|
||||
[|\s]+ Avg
|
||||
[|\s]+ \#[ ]calls
|
||||
[|\s]+ \w+[ ]\(avg\)
|
||||
[|\s]+$
|
||||
''', re.VERBOSE)
|
||||
METHOD_ROW_REGEX = re.compile(r'''
|
||||
^[|\s]+ (?P<contract>[^|]+)
|
||||
[|\s]+ (?P<method>[^|]+)
|
||||
[|\s]+ (?P<min>[^|]+)
|
||||
[|\s]+ (?P<max>[^|]+)
|
||||
[|\s]+ (?P<avg>[^|]+)
|
||||
[|\s]+ (?P<call_count>[^|]+)
|
||||
[|\s]+ (?P<eur_avg>[^|]+)
|
||||
[|\s]+$
|
||||
''', re.VERBOSE)
|
||||
FRAME_REGEX = re.compile(r'^[-|\s]+$')
|
||||
DEPLOYMENT_HEADER_REGEX = re.compile(r'^[|\s]+Deployments[|\s]+% of limit[|\s]+$')
|
||||
DEPLOYMENT_ROW_REGEX = re.compile(r'''
|
||||
^[|\s]+ (?P<contract>[^|]+)
|
||||
[|\s]+ (?P<min>[^|]+)
|
||||
[|\s]+ (?P<max>[^|]+)
|
||||
[|\s]+ (?P<avg>[^|]+)
|
||||
[|\s]+ (?P<percent_of_limit>[^|]+)\s*%
|
||||
[|\s]+ (?P<eur_avg>[^|]+)
|
||||
[|\s]+$
|
||||
''', re.VERBOSE)
|
||||
|
||||
|
||||
class ReportError(Exception):
|
||||
pass
|
||||
|
||||
class ReportValidationError(ReportError):
|
||||
pass
|
||||
|
||||
class ReportParsingError(Exception):
|
||||
def __init__(self, message: str, line: str, line_number: int):
|
||||
# pylint: disable=useless-super-delegation # It's not useless, it adds type annotations.
|
||||
super().__init__(message, line, line_number)
|
||||
|
||||
def __str__(self):
|
||||
return f"Parsing error on line {self.args[2] + 1}: {self.args[0]}\n{self.args[1]}"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MethodGasReport:
|
||||
min_gas: int
|
||||
max_gas: int
|
||||
avg_gas: int
|
||||
call_count: int
|
||||
total_gas: int = field(init=False)
|
||||
|
||||
def __post_init__(self):
|
||||
object.__setattr__(self, 'total_gas', self.avg_gas * self.call_count)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ContractGasReport:
|
||||
min_deployment_gas: Optional[int]
|
||||
max_deployment_gas: Optional[int]
|
||||
avg_deployment_gas: Optional[int]
|
||||
methods: Optional[Dict[str, MethodGasReport]]
|
||||
total_method_gas: int = field(init=False, default=0)
|
||||
|
||||
def __post_init__(self):
|
||||
if self.methods is not None:
|
||||
object.__setattr__(self, 'total_method_gas', sum(method.total_gas for method in self.methods.values()))
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class GasReport:
|
||||
solc_version: str
|
||||
optimize: bool
|
||||
runs: int
|
||||
block_limit: int
|
||||
contracts: Dict[str, ContractGasReport]
|
||||
total_method_gas: int = field(init=False)
|
||||
total_deployment_gas: int = field(init=False)
|
||||
|
||||
def __post_init__(self):
|
||||
object.__setattr__(self, 'total_method_gas', sum(
|
||||
total_method_gas
|
||||
for total_method_gas in (contract.total_method_gas for contract in self.contracts.values())
|
||||
if total_method_gas is not None
|
||||
))
|
||||
object.__setattr__(self, 'total_deployment_gas', sum(
|
||||
contract.avg_deployment_gas
|
||||
for contract in self.contracts.values()
|
||||
if contract.avg_deployment_gas is not None
|
||||
))
|
||||
|
||||
def to_json(self):
|
||||
return json.dumps(asdict(self), indent=4, sort_keys=True)
|
||||
|
||||
|
||||
def parse_bool(input_string: str) -> bool:
|
||||
if input_string == 'true':
|
||||
return True
|
||||
elif input_string == 'false':
|
||||
return True
|
||||
else:
|
||||
raise ValueError(f"Invalid boolean value: '{input_string}'")
|
||||
|
||||
|
||||
def parse_optional_int(input_string: str, default: Optional[int] = None) -> Optional[int]:
|
||||
if input_string.strip() == '-':
|
||||
return default
|
||||
|
||||
return int(input_string)
|
||||
|
||||
|
||||
def parse_report_header(line: str) -> Optional[dict]:
|
||||
match = REPORT_HEADER_REGEX.match(line)
|
||||
if match is None:
|
||||
return None
|
||||
|
||||
return {
|
||||
'solc_version': match.group('solc_version'),
|
||||
'optimize': parse_bool(match.group('optimize')),
|
||||
'runs': int(match.group('runs')),
|
||||
'block_limit': int(match.group('block_limit')),
|
||||
}
|
||||
|
||||
|
||||
def parse_method_row(line: str, line_number: int) -> Optional[Tuple[str, str, MethodGasReport]]:
|
||||
match = METHOD_ROW_REGEX.match(line)
|
||||
if match is None:
|
||||
raise ReportParsingError("Expected a table row with method details.", line, line_number)
|
||||
|
||||
avg_gas = parse_optional_int(match['avg'])
|
||||
call_count = int(match['call_count'])
|
||||
|
||||
if avg_gas is None and call_count == 0:
|
||||
# No calls, no gas values. Uninteresting. Skip the row.
|
||||
return None
|
||||
|
||||
return (
|
||||
match['contract'].strip(),
|
||||
match['method'].strip(),
|
||||
MethodGasReport(
|
||||
min_gas=parse_optional_int(match['min'], avg_gas),
|
||||
max_gas=parse_optional_int(match['max'], avg_gas),
|
||||
avg_gas=avg_gas,
|
||||
call_count=call_count,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def parse_deployment_row(line: str, line_number: int) -> Tuple[str, int, int, int]:
|
||||
match = DEPLOYMENT_ROW_REGEX.match(line)
|
||||
if match is None:
|
||||
raise ReportParsingError("Expected a table row with deployment details.", line, line_number)
|
||||
|
||||
return (
|
||||
match['contract'].strip(),
|
||||
parse_optional_int(match['min'].strip()),
|
||||
parse_optional_int(match['max'].strip()),
|
||||
int(match['avg'].strip()),
|
||||
)
|
||||
|
||||
|
||||
def preprocess_unicode_frames(input_string: str) -> str:
|
||||
# The report has a mix of normal pipe chars and its unicode variant.
|
||||
# Let's just replace all frame chars with normal pipes for easier parsing.
|
||||
return input_string.replace('\u2502', '|').replace('·', '|')
|
||||
|
||||
|
||||
def parse_report(rst_report: str) -> GasReport:
|
||||
report_params = None
|
||||
methods_by_contract = {}
|
||||
deployment_costs = {}
|
||||
expected_row_type = None
|
||||
|
||||
for line_number, line in enumerate(preprocess_unicode_frames(rst_report).splitlines()):
|
||||
try:
|
||||
if (
|
||||
line.strip() == "" or
|
||||
FRAME_REGEX.match(line) is not None or
|
||||
METHOD_COLUMN_HEADERS_REGEX.match(line) is not None
|
||||
):
|
||||
continue
|
||||
if METHOD_HEADER_REGEX.match(line) is not None:
|
||||
expected_row_type = 'method'
|
||||
continue
|
||||
if DEPLOYMENT_HEADER_REGEX.match(line) is not None:
|
||||
expected_row_type = 'deployment'
|
||||
continue
|
||||
|
||||
new_report_params = parse_report_header(line)
|
||||
if new_report_params is not None:
|
||||
if report_params is not None:
|
||||
raise ReportParsingError("Duplicate report header.", line, line_number)
|
||||
|
||||
report_params = new_report_params
|
||||
continue
|
||||
|
||||
if expected_row_type == 'method':
|
||||
parsed_row = parse_method_row(line, line_number)
|
||||
if parsed_row is None:
|
||||
continue
|
||||
|
||||
(contract, method, method_report) = parsed_row
|
||||
|
||||
if contract not in methods_by_contract:
|
||||
methods_by_contract[contract] = {}
|
||||
|
||||
if method in methods_by_contract[contract]:
|
||||
# Report must be generated with full signatures for method names to be unambiguous.
|
||||
raise ReportParsingError(f"Duplicate method row for '{contract}.{method}'.", line, line_number)
|
||||
|
||||
methods_by_contract[contract][method] = method_report
|
||||
elif expected_row_type == 'deployment':
|
||||
(contract, min_gas, max_gas, avg_gas) = parse_deployment_row(line, line_number)
|
||||
|
||||
if contract in deployment_costs:
|
||||
raise ReportParsingError(f"Duplicate contract deployment row for '{contract}'.", line, line_number)
|
||||
|
||||
deployment_costs[contract] = (min_gas, max_gas, avg_gas)
|
||||
else:
|
||||
assert expected_row_type is None
|
||||
raise ReportParsingError("Found data row without a section header.", line, line_number)
|
||||
|
||||
except ValueError as error:
|
||||
raise ReportParsingError(error.args[0], line, line_number) from error
|
||||
|
||||
if report_params is None:
|
||||
raise ReportValidationError("Report header not found.")
|
||||
|
||||
report_params['contracts'] = {
|
||||
contract: ContractGasReport(
|
||||
min_deployment_gas=deployment_costs.get(contract, (None, None, None))[0],
|
||||
max_deployment_gas=deployment_costs.get(contract, (None, None, None))[1],
|
||||
avg_deployment_gas=deployment_costs.get(contract, (None, None, None))[2],
|
||||
methods=methods_by_contract.get(contract),
|
||||
)
|
||||
for contract in methods_by_contract.keys() | deployment_costs.keys()
|
||||
}
|
||||
|
||||
return GasReport(**report_params)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
report = parse_report(sys.stdin.read())
|
||||
print(report.to_json())
|
||||
except ReportError as exception:
|
||||
print(f"{exception}", file=sys.stderr)
|
||||
sys.exit(1)
|
53
scripts/externalTests/summarize_benchmarks.sh
Executable file
53
scripts/externalTests/summarize_benchmarks.sh
Executable file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Reads a combined benchmark report from standard input and outputs an abbreviated
|
||||
# report containing only totals. Can handle individual reports coming directly
|
||||
# from scripts in test/externalTests/ as well as combined report from merge_benchmarks.sh.
|
||||
#
|
||||
# Usage:
|
||||
# <script name>.sh < <CONCATENATED_REPORTS>
|
||||
#
|
||||
# CONCATENATED_REPORTS: JSON report files concatenated into a single stream (e.g. using cat).
|
||||
#
|
||||
# Example:
|
||||
# cat reports/externalTests/benchmark-*.json | <script name>.sh
|
||||
# ------------------------------------------------------------------------------
|
||||
# This file is part of solidity.
|
||||
#
|
||||
# solidity is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# solidity is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with solidity. If not, see <http://www.gnu.org/licenses/>
|
||||
#
|
||||
# (c) 2021 solidity contributors.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
# Iterates over presets in a dict of the form {"<project>": {"<preset>": {...}}} and for each
|
||||
# one preserves only the few keys with totals that we want to see in the summary.
|
||||
exec "${REPO_ROOT}/scripts/externalTests/merge_benchmarks.sh" | jq --indent 4 --sort-keys '
|
||||
with_entries({
|
||||
key: .key,
|
||||
value: .value | with_entries({
|
||||
key: .key,
|
||||
value: {
|
||||
bytecode_size: .value.total_bytecode_size,
|
||||
method_gas: .value.gas.total_method_gas,
|
||||
deployment_gas: .value.gas.total_deployment_gas,
|
||||
version: .value.project.version
|
||||
}
|
||||
})
|
||||
})
|
||||
'
|
@ -270,15 +270,29 @@ void CommandLineInterface::handleSignatureHashes(string const& _contract)
|
||||
if (!m_options.compiler.outputs.signatureHashes)
|
||||
return;
|
||||
|
||||
Json::Value methodIdentifiers = m_compiler->methodIdentifiers(_contract);
|
||||
string out;
|
||||
for (auto const& name: methodIdentifiers.getMemberNames())
|
||||
out += methodIdentifiers[name].asString() + ": " + name + "\n";
|
||||
Json::Value interfaceSymbols = m_compiler->interfaceSymbols(_contract);
|
||||
string out = "Function signatures:\n";
|
||||
for (auto const& name: interfaceSymbols["methods"].getMemberNames())
|
||||
out += interfaceSymbols["methods"][name].asString() + ": " + name + "\n";
|
||||
|
||||
if (interfaceSymbols.isMember("errors"))
|
||||
{
|
||||
out += "\nError signatures:\n";
|
||||
for (auto const& name: interfaceSymbols["errors"].getMemberNames())
|
||||
out += interfaceSymbols["errors"][name].asString() + ": " + name + "\n";
|
||||
}
|
||||
|
||||
if (interfaceSymbols.isMember("events"))
|
||||
{
|
||||
out += "\nEvent signatures:\n";
|
||||
for (auto const& name: interfaceSymbols["events"].getMemberNames())
|
||||
out += interfaceSymbols["events"][name].asString() + ": " + name + "\n";
|
||||
}
|
||||
|
||||
if (!m_options.output.dir.empty())
|
||||
createFile(m_compiler->filesystemFriendlyName(_contract) + ".signatures", out);
|
||||
else
|
||||
sout() << "Function signatures:" << endl << out;
|
||||
sout() << out;
|
||||
}
|
||||
|
||||
void CommandLineInterface::handleMetadata(string const& _contract)
|
||||
@ -822,7 +836,7 @@ void CommandLineInterface::handleCombinedJSON()
|
||||
m_compiler->runtimeObject(contractName).functionDebugData
|
||||
);
|
||||
if (m_options.compiler.combinedJsonRequests->signatureHashes)
|
||||
contractData[g_strSignatureHashes] = m_compiler->methodIdentifiers(contractName);
|
||||
contractData[g_strSignatureHashes] = m_compiler->interfaceSymbols(contractName)["methods"];
|
||||
if (m_options.compiler.combinedJsonRequests->natspecDev)
|
||||
contractData[g_strNatspecDev] = m_compiler->natspecDev(contractName);
|
||||
if (m_options.compiler.combinedJsonRequests->natspecUser)
|
||||
|
@ -147,6 +147,7 @@ set(libyul_sources
|
||||
libyul/Parser.cpp
|
||||
libyul/StackLayoutGeneratorTest.cpp
|
||||
libyul/StackLayoutGeneratorTest.h
|
||||
libyul/StackShufflingTest.cpp
|
||||
libyul/SyntaxTest.h
|
||||
libyul/SyntaxTest.cpp
|
||||
libyul/YulInterpreterTest.cpp
|
||||
|
@ -81,5 +81,6 @@ bool solidity::test::createSymlinkIfSupportedByFilesystem(
|
||||
BOOST_THROW_EXCEPTION(runtime_error(
|
||||
"Failed to create a symbolic link: \"" + _linkName.string() + "\""
|
||||
" -> " + _targetPath.string() + "\"."
|
||||
" " + symlinkCreationError.message() + "."
|
||||
));
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ void removeTestSuite(std::string const& _name)
|
||||
{
|
||||
master_test_suite_t& master = framework::master_test_suite();
|
||||
auto id = master.get(_name);
|
||||
assert(id != INV_TEST_UNIT_ID);
|
||||
soltestAssert(id != INV_TEST_UNIT_ID, "Removing non-existent test suite!");
|
||||
master.remove(id);
|
||||
}
|
||||
|
||||
@ -279,7 +279,6 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
|
||||
"ABIDecoderTest",
|
||||
"ABIEncoderTest",
|
||||
"SolidityAuctionRegistrar",
|
||||
"SolidityFixedFeeRegistrar",
|
||||
"SolidityWallet",
|
||||
"GasMeterTests",
|
||||
"GasCostTests",
|
||||
|
1
test/cmdlineTests/hashes/args
Normal file
1
test/cmdlineTests/hashes/args
Normal file
@ -0,0 +1 @@
|
||||
--hashes
|
28
test/cmdlineTests/hashes/input.sol
Normal file
28
test/cmdlineTests/hashes/input.sol
Normal file
@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
error fileLevelError(uint z);
|
||||
|
||||
library L {
|
||||
event libraryEvent(uint r);
|
||||
error libraryError(uint r);
|
||||
error libraryErrorUnused(uint u);
|
||||
event libraryEventUnused(uint u);
|
||||
}
|
||||
|
||||
contract C {
|
||||
struct S { uint x; }
|
||||
|
||||
event ev(uint y);
|
||||
event anon_ev(uint y) anonymous;
|
||||
|
||||
error err(uint z, uint w);
|
||||
|
||||
function f(S memory s) public {
|
||||
emit L.libraryEvent(3);
|
||||
if (s.x > 1)
|
||||
revert fileLevelError(3);
|
||||
else
|
||||
revert L.libraryError(4);
|
||||
}
|
||||
}
|
24
test/cmdlineTests/hashes/output
Normal file
24
test/cmdlineTests/hashes/output
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
======= hashes/input.sol:C =======
|
||||
Function signatures:
|
||||
3fc03eeb: f((uint256))
|
||||
|
||||
Error signatures:
|
||||
619a0bb7: err(uint256,uint256)
|
||||
82b5f64f: fileLevelError(uint256)
|
||||
8c41f45c: libraryError(uint256)
|
||||
|
||||
Event signatures:
|
||||
2d4dd5fe18ada5a020a9f5591539a8dc3010a5c074ba6a70e1c956659f02786a: ev(uint256)
|
||||
81f3fb02f88d32d3bb08c80c9a622ca3b3223292f131c6ad049811f9a8a606dc: libraryEvent(uint256)
|
||||
|
||||
======= hashes/input.sol:L =======
|
||||
Function signatures:
|
||||
|
||||
Error signatures:
|
||||
8c41f45c: libraryError(uint256)
|
||||
c61c03f5: libraryErrorUnused(uint256)
|
||||
|
||||
Event signatures:
|
||||
81f3fb02f88d32d3bb08c80c9a622ca3b3223292f131c6ad049811f9a8a606dc: libraryEvent(uint256)
|
||||
0a994ad3600197f16ffe1ea1101caea3174efe5ebd9ba9a75d6d5524c5de28cd: libraryEventUnused(uint256)
|
@ -0,0 +1,17 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { }"
|
||||
}
|
||||
},
|
||||
"settings":
|
||||
{
|
||||
"outputSelection":
|
||||
{
|
||||
"*": { "*": ["evm.methodIdentifiers"] }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"contracts":{"A":{"C":{"evm":{"methodIdentifiers":{}}}}},"sources":{"A":{"id":0}}}
|
@ -3,8 +3,8 @@
|
||||
[
|
||||
{
|
||||
"component": "general",
|
||||
"formattedMessage": "Cannot import url (\"in.yul\"): File not found.",
|
||||
"message": "Cannot import url (\"in.yul\"): File not found.",
|
||||
"formattedMessage": "Cannot import url (\"in.yul\"): File not found. Searched the following locations: \"\".",
|
||||
"message": "Cannot import url (\"in.yul\"): File not found. Searched the following locations: \"\".",
|
||||
"severity": "error",
|
||||
"type": "IOError"
|
||||
},
|
||||
|
@ -28,26 +28,26 @@
|
||||
|
||||
set -e
|
||||
|
||||
REPO_ROOT="$(dirname "$0")"
|
||||
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/..")
|
||||
|
||||
verify_input "$@"
|
||||
|
||||
printTask "Running external tests..."
|
||||
|
||||
"$REPO_ROOT/externalTests/zeppelin.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/gnosis.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/gnosis-v2.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/colony.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/ens.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/trident.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/euler.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/yield-liquidator.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/bleeps.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/pool-together.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/perpetual-pools.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/uniswap.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/prb-math.sh" "$@"
|
||||
"$REPO_ROOT/externalTests/elementfi.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/zeppelin.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/gnosis.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/gnosis-v2.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/colony.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/ens.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/trident.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/euler.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/yield-liquidator.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/bleeps.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/pool-together.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/perpetual-pools.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/uniswap.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/prb-math.sh" "$@"
|
||||
"{$REPO_ROOT}/test/externalTests/elementfi.sh" "$@"
|
||||
|
@ -24,13 +24,16 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
SELECTED_PRESETS="$3"
|
||||
|
||||
function compile_fn { npm run compile; }
|
||||
function test_fn { npm run test; }
|
||||
# NOTE: `npm run test` runs `mocha` which seems to disable the gas reporter.
|
||||
function test_fn { HARDHAT_DEPLOY_FIXTURE=true npx --no hardhat --no-compile test; }
|
||||
|
||||
function bleeps_test
|
||||
{
|
||||
@ -87,6 +90,7 @@ function bleeps_test
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var"
|
||||
store_benchmark_report hardhat bleeps "$repo" "$preset"
|
||||
done
|
||||
|
||||
popd
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -73,6 +75,7 @@ function colony_test
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
|
||||
store_benchmark_report truffle colony "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#------------------------------------------------------------------------------
|
||||
set -e
|
||||
|
||||
# Requires "${REPO_ROOT}/scripts/common.sh" to be included before.
|
||||
# Requires $REPO_ROOT to be defined and "${REPO_ROOT}/scripts/common.sh" to be included before.
|
||||
|
||||
CURRENT_EVM_VERSION=london
|
||||
|
||||
@ -71,15 +71,23 @@ function setup_solc
|
||||
local binary_path="$3"
|
||||
local solcjs_branch="${4:-master}"
|
||||
local install_dir="${5:-solc/}"
|
||||
local solcjs_dir="$6"
|
||||
|
||||
[[ $binary_type == native || $binary_type == solcjs ]] || assertFail
|
||||
[[ $binary_type == solcjs || $solcjs_dir == "" ]] || assertFail
|
||||
|
||||
cd "$test_dir"
|
||||
|
||||
if [[ $binary_type == solcjs ]]
|
||||
then
|
||||
printLog "Setting up solc-js..."
|
||||
if [[ $solcjs_dir == "" ]]; then
|
||||
printLog "Cloning branch ${solcjs_branch}..."
|
||||
git clone --depth 1 -b "$solcjs_branch" https://github.com/ethereum/solc-js.git "$install_dir"
|
||||
else
|
||||
printLog "Using local solc-js from ${solcjs_dir}..."
|
||||
cp -ra "$solcjs_dir" solc
|
||||
fi
|
||||
|
||||
pushd "$install_dir"
|
||||
npm install
|
||||
@ -207,9 +215,19 @@ function force_truffle_compiler_settings
|
||||
echo "Compiler version (full): ${SOLCVERSION}"
|
||||
echo "-------------------------------------"
|
||||
|
||||
# Forcing the settings should always work by just overwriting the solc object. Forcing them by using a
|
||||
# dedicated settings objects should only be the fallback.
|
||||
echo "module.exports['compilers'] = $(truffle_compiler_settings "$solc_path" "$preset" "$evm_version");" >> "$config_file"
|
||||
local compiler_settings gas_reporter_settings
|
||||
compiler_settings=$(truffle_compiler_settings "$solc_path" "$preset" "$evm_version")
|
||||
gas_reporter_settings=$(eth_gas_reporter_settings "$preset")
|
||||
|
||||
{
|
||||
echo "require('eth-gas-reporter');"
|
||||
echo "module.exports['mocha'] = {"
|
||||
echo " reporter: 'eth-gas-reporter',"
|
||||
echo " reporterOptions: ${gas_reporter_settings}"
|
||||
echo "};"
|
||||
|
||||
echo "module.exports['compilers'] = ${compiler_settings};"
|
||||
} >> "$config_file"
|
||||
}
|
||||
|
||||
function name_hardhat_default_export
|
||||
@ -278,16 +296,21 @@ function force_hardhat_compiler_settings
|
||||
echo "Compiler version (full): ${SOLCVERSION}"
|
||||
echo "-------------------------------------"
|
||||
|
||||
local settings
|
||||
settings=$(hardhat_compiler_settings "$SOLCVERSION_SHORT" "$preset" "$evm_version")
|
||||
local compiler_settings gas_reporter_settings
|
||||
compiler_settings=$(hardhat_compiler_settings "$SOLCVERSION_SHORT" "$preset" "$evm_version")
|
||||
gas_reporter_settings=$(eth_gas_reporter_settings "$preset")
|
||||
if [[ $config_file == *\.js ]]; then
|
||||
[[ $config_var_name == "" ]] || assertFail
|
||||
echo "module.exports['solidity'] = ${settings}" >> "$config_file"
|
||||
echo "require('hardhat-gas-reporter');"
|
||||
echo "module.exports.gasReporter = ${gas_reporter_settings};"
|
||||
echo "module.exports.solidity = ${compiler_settings};"
|
||||
else
|
||||
[[ $config_file == *\.ts ]] || assertFail
|
||||
[[ $config_var_name != "" ]] || assertFail
|
||||
echo "${config_var_name}.solidity = {compilers: [${settings}]}" >> "$config_file"
|
||||
fi
|
||||
echo 'import "hardhat-gas-reporter";'
|
||||
echo "${config_var_name}.gasReporter = ${gas_reporter_settings};"
|
||||
echo "${config_var_name}.solidity = {compilers: [${compiler_settings}]};"
|
||||
fi >> "$config_file"
|
||||
}
|
||||
|
||||
function truffle_verify_compiler_version
|
||||
@ -320,21 +343,7 @@ function truffle_clean
|
||||
|
||||
function hardhat_clean
|
||||
{
|
||||
rm -rf artifacts/ cache/
|
||||
}
|
||||
|
||||
function run_test
|
||||
{
|
||||
local compile_fn="$1"
|
||||
local test_fn="$2"
|
||||
|
||||
replace_version_pragmas
|
||||
|
||||
printLog "Running compile function..."
|
||||
time $compile_fn
|
||||
|
||||
printLog "Running test function..."
|
||||
$test_fn
|
||||
rm -rf build/ artifacts/ cache/
|
||||
}
|
||||
|
||||
function settings_from_preset
|
||||
@ -368,6 +377,21 @@ function replace_global_solc
|
||||
export PATH="$PWD:$PATH"
|
||||
}
|
||||
|
||||
function eth_gas_reporter_settings
|
||||
{
|
||||
local preset="$1"
|
||||
|
||||
echo "{"
|
||||
echo " enabled: true,"
|
||||
echo " gasPrice: 1," # Gas price does not matter to us at all. Set to whatever to avoid API call.
|
||||
echo " noColors: true,"
|
||||
echo " showTimeSpent: false," # We're not interested in test timing
|
||||
echo " onlyCalledMethods: true," # Exclude entries with no gas for shorter report
|
||||
echo " showMethodSig: true," # Should make diffs more stable if there are overloaded functions
|
||||
echo " outputFile: \"$(gas_report_path "$preset")\""
|
||||
echo "}"
|
||||
}
|
||||
|
||||
function truffle_compiler_settings
|
||||
{
|
||||
local solc_path="$1"
|
||||
@ -495,3 +519,121 @@ function external_test
|
||||
rm -rf "$DIR"
|
||||
echo "Done."
|
||||
}
|
||||
|
||||
function gas_report_path
|
||||
{
|
||||
local preset="$1"
|
||||
|
||||
echo "${DIR}/gas-report-${preset}.rst"
|
||||
}
|
||||
|
||||
function gas_report_to_json
|
||||
{
|
||||
cat - | "${REPO_ROOT}/scripts/externalTests/parse_eth_gas_report.py" | jq '{gas: .}'
|
||||
}
|
||||
|
||||
function detect_hardhat_artifact_dir
|
||||
{
|
||||
if [[ -e build/ && -e artifacts/ ]]; then
|
||||
fail "Cannot determine Hardhat artifact location. Both build/ and artifacts/ exist"
|
||||
elif [[ -e build/ ]]; then
|
||||
echo -n build/artifacts
|
||||
elif [[ -e artifacts/ ]]; then
|
||||
echo -n artifacts
|
||||
else
|
||||
fail "Hardhat build artifacts not found."
|
||||
fi
|
||||
}
|
||||
|
||||
function bytecode_size_json_from_truffle_artifacts
|
||||
{
|
||||
# NOTE: The output of this function is a series of concatenated JSON dicts rather than a list.
|
||||
|
||||
for artifact in build/contracts/*.json; do
|
||||
if [[ $(jq '. | has("unlinked_binary")' "$artifact") == false ]]; then
|
||||
# Each artifact represents compilation output for a single contract. Some top-level keys contain
|
||||
# bits of Standard JSON output while others are generated by Truffle. Process it into a dict
|
||||
# of the form `{"<file>": {"<contract>": <size>}}`.
|
||||
# NOTE: The `bytecode` field starts with 0x, which is why we subtract 1 from size.
|
||||
jq '{
|
||||
(.ast.absolutePath): {
|
||||
(.contractName): (.bytecode | length / 2 - 1)
|
||||
}
|
||||
}' "$artifact"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function bytecode_size_json_from_hardhat_artifacts
|
||||
{
|
||||
# NOTE: The output of this function is a series of concatenated JSON dicts rather than a list.
|
||||
|
||||
for artifact in "$(detect_hardhat_artifact_dir)"/build-info/*.json; do
|
||||
# Each artifact contains Standard JSON output under the `output` key.
|
||||
# Process it into a dict of the form `{"<file>": {"<contract>": <size>}}`,
|
||||
# Note that one Hardhat artifact often represents multiple input files.
|
||||
jq '.output.contracts | to_entries[] | {
|
||||
"\(.key)": .value | to_entries[] | {
|
||||
"\(.key)": (.value.evm.bytecode.object | length / 2)
|
||||
}
|
||||
}' "$artifact"
|
||||
done
|
||||
}
|
||||
|
||||
function combine_artifact_json
|
||||
{
|
||||
# Combine all dicts into a list with `jq --slurp` and then use `reduce` to merge them into one
|
||||
# big dict with keys of the form `"<file>:<contract>"`. Then run jq again to filter out items
|
||||
# with zero size and put the rest under under a top-level `bytecode_size` key. Also add another
|
||||
# key with total bytecode size.
|
||||
# NOTE: The extra inner `bytecode_size` key is there only to make diffs more readable.
|
||||
cat - |
|
||||
jq --slurp 'reduce (.[] | to_entries[]) as {$key, $value} ({}; . + {
|
||||
($key + ":" + ($value | to_entries[].key)): {
|
||||
bytecode_size: $value | to_entries[].value
|
||||
}
|
||||
})' |
|
||||
jq --indent 4 --sort-keys '{
|
||||
bytecode_size: [. | to_entries[] | select(.value.bytecode_size > 0)] | from_entries,
|
||||
total_bytecode_size: (reduce (. | to_entries[]) as {$key, $value} (0; . + $value.bytecode_size))
|
||||
}'
|
||||
}
|
||||
|
||||
function project_info_json
|
||||
{
|
||||
local project_url="$1"
|
||||
|
||||
echo "{"
|
||||
echo " \"project\": {"
|
||||
# NOTE: Given that we clone with `--depth 1`, we'll only get useful output out of `git describe`
|
||||
# if we directly check out a tag. Still better than nothing.
|
||||
echo " \"version\": \"$(git describe --always)\","
|
||||
echo " \"commit\": \"$(git rev-parse HEAD)\","
|
||||
echo " \"url\": \"${project_url}\""
|
||||
echo " }"
|
||||
echo "}"
|
||||
}
|
||||
|
||||
function store_benchmark_report
|
||||
{
|
||||
local framework="$1"
|
||||
local project_name="$2"
|
||||
local project_url="$3"
|
||||
local preset="$4"
|
||||
|
||||
[[ $framework == truffle || $framework == hardhat ]] || assertFail
|
||||
[[ " ${AVAILABLE_PRESETS[*]} " == *" $preset "* ]] || assertFail
|
||||
|
||||
local report_dir="${REPO_ROOT}/reports/externalTests"
|
||||
local output_file="${report_dir}/benchmark-${project_name}-${preset}.json"
|
||||
mkdir -p "$report_dir"
|
||||
|
||||
{
|
||||
if [[ -e $(gas_report_path "$preset") ]]; then
|
||||
gas_report_to_json < "$(gas_report_path "$preset")"
|
||||
fi
|
||||
|
||||
"bytecode_size_json_from_${framework}_artifacts" | combine_artifact_json
|
||||
project_info_json "$project_url"
|
||||
} | jq --slurp "{\"${project_name}\": {\"${preset}\": add}}" --indent 4 --sort-keys > "$output_file"
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -84,6 +86,10 @@ function elementfi_test
|
||||
sed -i 's|delete _twoTokenPoolTokens\[poolId\];|delete _twoTokenPoolTokens[poolId].tokenA;delete _twoTokenPoolTokens[poolId].tokenB;|g' vault/balances/TwoTokenPoolsBalance.sol
|
||||
popd
|
||||
|
||||
# The test suite uses forked mainnet and an expiration period that's too short.
|
||||
# TODO: Remove when https://github.com/element-fi/elf-contracts/issues/243 is fixed.
|
||||
sed -i 's|^\s*require(_expiration - block\.timestamp < _unitSeconds);\s*$||g' contracts/ConvergentCurvePool.sol
|
||||
|
||||
# Several tests fail unless we use the exact versions hard-coded in package-lock.json
|
||||
#neutralize_package_lock
|
||||
|
||||
@ -97,6 +103,7 @@ function elementfi_test
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var"
|
||||
store_benchmark_report hardhat elementfi "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -68,6 +70,7 @@ function ens_test
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
|
||||
store_benchmark_report hardhat ens "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -68,6 +70,7 @@ function euler_test
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
|
||||
store_benchmark_report hardhat euler "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -40,12 +42,12 @@ function gnosis_safe_test
|
||||
local config_file="truffle-config.js"
|
||||
|
||||
local compile_only_presets=(
|
||||
legacy-no-optimize # "Error: while migrating GnosisSafe: Returned error: base fee exceeds gas limit"
|
||||
legacy-no-optimize # Compiles but migrations run out of gas: "Error: while migrating GnosisSafe: Returned error: base fee exceeds gas limit"
|
||||
)
|
||||
local settings_presets=(
|
||||
"${compile_only_presets[@]}"
|
||||
#ir-no-optimize # "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack."
|
||||
#ir-optimize-evm-only # "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack."
|
||||
#ir-no-optimize # Compilation fails with "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack."
|
||||
#ir-optimize-evm-only # Compilation fails with "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack."
|
||||
ir-optimize-evm+yul
|
||||
legacy-optimize-evm-only
|
||||
legacy-optimize-evm+yul
|
||||
@ -65,12 +67,14 @@ function gnosis_safe_test
|
||||
neutralize_package_json_hooks
|
||||
force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$(first_word "$SELECTED_PRESETS")"
|
||||
npm install --package-lock
|
||||
npm install eth-gas-reporter
|
||||
|
||||
replace_version_pragmas
|
||||
[[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc/dist"
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
|
||||
store_benchmark_report truffle gnosis2 "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -42,11 +44,11 @@ function gnosis_safe_test
|
||||
local compile_only_presets=()
|
||||
local settings_presets=(
|
||||
"${compile_only_presets[@]}"
|
||||
#ir-no-optimize # "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack."
|
||||
#ir-optimize-evm-only # "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack."
|
||||
#ir-no-optimize # Compilation fails with "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack."
|
||||
#ir-optimize-evm-only # Compilation fails with "YulException: Variable var_call_430_mpos is 1 slot(s) too deep inside the stack."
|
||||
ir-optimize-evm+yul
|
||||
#legacy-no-optimize # "Stack too deep" error
|
||||
#legacy-optimize-evm-only # "Stack too deep" error
|
||||
#legacy-no-optimize # Compilation fails with "Stack too deep" error
|
||||
#legacy-optimize-evm-only # Compilation fails with "Stack too deep" error
|
||||
legacy-optimize-evm+yul
|
||||
)
|
||||
|
||||
@ -63,12 +65,14 @@ function gnosis_safe_test
|
||||
neutralize_package_json_hooks
|
||||
force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$(first_word "$SELECTED_PRESETS")"
|
||||
npm install --package-lock
|
||||
npm install eth-gas-reporter
|
||||
|
||||
replace_version_pragmas
|
||||
[[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc/dist"
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
|
||||
store_benchmark_report truffle gnosis "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -68,6 +70,7 @@ function perpetual_pools_test
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var"
|
||||
store_benchmark_report hardhat perpetual-pools "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -72,6 +74,7 @@ function pool_together_test
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var"
|
||||
store_benchmark_report hardhat pool-together "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -24,13 +24,16 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
SELECTED_PRESETS="$3"
|
||||
|
||||
function compile_fn { yarn compile; }
|
||||
function test_fn { yarn test; }
|
||||
# NOTE: `yarn test` runs `mocha` which seems to disable the gas reporter.
|
||||
function test_fn { npx --no hardhat --no-compile test; }
|
||||
|
||||
function prb_math_test
|
||||
{
|
||||
@ -70,11 +73,13 @@ function prb_math_test
|
||||
force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH"
|
||||
force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" "$config_var"
|
||||
yarn install --no-lock-file
|
||||
yarn add hardhat-gas-reporter
|
||||
|
||||
replace_version_pragmas
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var"
|
||||
store_benchmark_report hardhat prb-math "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -26,11 +26,9 @@ source test/externalTests/common.sh
|
||||
|
||||
SOLJSON="$1"
|
||||
VERSION="$2"
|
||||
SOLCJS_CHECKOUT="$3" # optional
|
||||
|
||||
[[ $SOLJSON != "" && -f "$SOLJSON" && $VERSION != "" ]] || fail "Usage: $0 <path to soljson.js> <version>"
|
||||
|
||||
function compile_fn { echo "Nothing to compile."; }
|
||||
function test_fn { npm test; }
|
||||
[[ $SOLJSON != "" && -f "$SOLJSON" && $VERSION != "" ]] || fail "Usage: $0 <path to soljson.js> <version> [<path to solc-js>]"
|
||||
|
||||
function solcjs_test
|
||||
{
|
||||
@ -38,7 +36,7 @@ function solcjs_test
|
||||
SOLCJS_INPUT_DIR="$TEST_DIR"/test/externalTests/solc-js
|
||||
|
||||
# set up solc-js on the branch specified
|
||||
setup_solc "$DIR" solcjs "$SOLJSON" master solc/
|
||||
setup_solc "$DIR" solcjs "$SOLJSON" master solc/ "$SOLCJS_CHECKOUT"
|
||||
cd solc/
|
||||
|
||||
printLog "Updating index.js file..."
|
||||
@ -60,7 +58,10 @@ function solcjs_test
|
||||
echo "Updating package.json to version $VERSION"
|
||||
npm version --allow-same-version --no-git-tag-version "$VERSION"
|
||||
|
||||
run_test compile_fn test_fn
|
||||
replace_version_pragmas
|
||||
|
||||
printLog "Running test function..."
|
||||
npm test
|
||||
}
|
||||
|
||||
external_test solc-js solcjs_test
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -92,6 +94,7 @@ function trident_test
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var"
|
||||
store_benchmark_report hardhat trident "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -73,11 +75,13 @@ function uniswap_test
|
||||
yarn add @ethereumjs/tx@3.1.3
|
||||
|
||||
yarn install
|
||||
yarn add hardhat-gas-reporter
|
||||
|
||||
replace_version_pragmas
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var"
|
||||
store_benchmark_report hardhat uniswap "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -65,9 +67,11 @@ function yield_liquidator_test
|
||||
npm install
|
||||
|
||||
replace_version_pragmas
|
||||
neutralize_packaged_contracts
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var"
|
||||
store_benchmark_report hardhat yield_liquidator "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ set -e
|
||||
source scripts/common.sh
|
||||
source test/externalTests/common.sh
|
||||
|
||||
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
|
||||
|
||||
verify_input "$@"
|
||||
BINARY_TYPE="$1"
|
||||
BINARY_PATH="$2"
|
||||
@ -44,8 +46,8 @@ function zeppelin_test
|
||||
)
|
||||
local settings_presets=(
|
||||
"${compile_only_presets[@]}"
|
||||
#ir-no-optimize # "YulException: Variable var_account_852 is 4 slot(s) too deep inside the stack."
|
||||
#ir-optimize-evm-only # "YulException: Variable var_account_852 is 4 slot(s) too deep inside the stack."
|
||||
#ir-no-optimize # Compilation fails with "YulException: Variable var_account_852 is 4 slot(s) too deep inside the stack."
|
||||
#ir-optimize-evm-only # Compilation fails with "YulException: Variable var_account_852 is 4 slot(s) too deep inside the stack."
|
||||
legacy-no-optimize
|
||||
legacy-optimize-evm-only
|
||||
legacy-optimize-evm+yul
|
||||
@ -66,6 +68,7 @@ function zeppelin_test
|
||||
|
||||
for preset in $SELECTED_PRESETS; do
|
||||
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
|
||||
store_benchmark_report hardhat zeppelin "$repo" "$preset"
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -435,7 +435,7 @@ TestCase::TestResult SemanticTest::runTest(
|
||||
{
|
||||
soltestAssert(
|
||||
m_allowNonExistingFunctions ||
|
||||
m_compiler.methodIdentifiers(m_compiler.lastContractName(m_sources.mainSourceFile)).isMember(test.call().signature),
|
||||
m_compiler.interfaceSymbols(m_compiler.lastContractName(m_sources.mainSourceFile))["methods"].isMember(test.call().signature),
|
||||
"The function " + test.call().signature + " is not known to the compiler"
|
||||
);
|
||||
|
||||
|
@ -2582,6 +2582,55 @@ BOOST_AUTO_TEST_CASE(dev_struct_getter_override)
|
||||
checkNatspec(sourceCode, "Thing", natspec2, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_struct_getter_override_no_return_name)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
interface IThing {
|
||||
///@return
|
||||
function value(uint) external returns (uint128,uint128);
|
||||
}
|
||||
|
||||
contract Thing is IThing {
|
||||
struct Value {
|
||||
uint128 x;
|
||||
uint128 A;
|
||||
}
|
||||
mapping(uint=>Value) public override value;
|
||||
}
|
||||
)";
|
||||
|
||||
char const *natspec = R"ABCDEF({
|
||||
"methods":
|
||||
{
|
||||
"value(uint256)":
|
||||
{
|
||||
"returns":
|
||||
{
|
||||
"_0": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
char const *natspec2 = R"ABCDEF({
|
||||
"methods": {},
|
||||
"stateVariables":
|
||||
{
|
||||
"value":
|
||||
{
|
||||
"return": "x ",
|
||||
"returns":
|
||||
{
|
||||
"x": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
})ABCDEF";
|
||||
|
||||
checkNatspec(sourceCode, "IThing", natspec, false);
|
||||
checkNatspec(sourceCode, "Thing", natspec2, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dev_struct_getter_override_different_return_parameter_names)
|
||||
{
|
||||
char const *sourceCode = R"(
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <test/TemporaryDirectory.h>
|
||||
#include <test/libsolidity/util/SoltestErrors.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
@ -192,8 +193,8 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only)
|
||||
|
||||
#if defined(_WIN32)
|
||||
boost::filesystem::path driveLetter = boost::filesystem::current_path().root_name();
|
||||
solAssert(!driveLetter.empty(), "");
|
||||
solAssert(driveLetter.is_relative(), "");
|
||||
soltestAssert(!driveLetter.empty(), "");
|
||||
soltestAssert(driveLetter.is_relative(), "");
|
||||
|
||||
BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(driveLetter, resolveSymlinks), expectedWorkDir);
|
||||
#endif
|
||||
@ -212,13 +213,32 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name)
|
||||
|
||||
for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled})
|
||||
{
|
||||
boost::filesystem::path workDir = boost::filesystem::current_path();
|
||||
|
||||
boost::filesystem::path normalizedPath = FileReader::normalizeCLIPathForVFS(
|
||||
boost::filesystem::current_path(),
|
||||
workDir,
|
||||
resolveSymlinks
|
||||
);
|
||||
BOOST_CHECK_EQUAL(normalizedPath, "/" / boost::filesystem::current_path().relative_path());
|
||||
BOOST_CHECK_EQUAL(normalizedPath, "/" / workDir.relative_path());
|
||||
BOOST_TEST(normalizedPath.root_name().empty());
|
||||
BOOST_CHECK_EQUAL(normalizedPath.root_directory(), "/");
|
||||
|
||||
#if defined(_WIN32)
|
||||
string root = workDir.root_path().string();
|
||||
soltestAssert(root.length() == 3 && root[1] == ':' && root[2] == '\\', "");
|
||||
|
||||
for (auto convert: {boost::to_lower_copy<string>, boost::to_upper_copy<string>})
|
||||
{
|
||||
boost::filesystem::path workDirWin = convert(root, locale()) / workDir.relative_path();
|
||||
normalizedPath = FileReader::normalizeCLIPathForVFS(
|
||||
workDirWin,
|
||||
resolveSymlinks
|
||||
);
|
||||
BOOST_CHECK_EQUAL(normalizedPath, "/" / workDir.relative_path());
|
||||
BOOST_TEST(normalizedPath.root_name().empty());
|
||||
BOOST_CHECK_EQUAL(normalizedPath.root_directory(), "/");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
contract A {
|
||||
uint public x;
|
||||
uint public x = 2;
|
||||
constructor(uint) {}
|
||||
function f() public { x = 4; }
|
||||
function f() public returns(uint) { x = 4; }
|
||||
}
|
||||
contract B is A {
|
||||
constructor() A(f()) {}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// compileViaYul: false
|
||||
// ----
|
||||
// x() -> 4
|
@ -0,0 +1,12 @@
|
||||
contract A {
|
||||
uint public x = 2;
|
||||
constructor(uint) {}
|
||||
function f() public returns(uint) { x = 4; }
|
||||
}
|
||||
contract B is A {
|
||||
constructor() A(f()) {}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// x() -> 2
|
@ -0,0 +1,14 @@
|
||||
contract C {
|
||||
function f(string memory a, string memory b) public returns (string memory) {
|
||||
return string.concat(a, b);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(string,string): 0x40, 0x80, 32, "abcdabcdabcdabcdabcdabcdabcdabcd", 5, "bcdef" -> 0x20, 0x25, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
||||
// f(string,string): 0x40, 0xa0, 64, "abcdabcdabcdabcdabcdabcdabcdabcd", "abcdabcdabcdabcdabcdabcdabcdabcd", 5, "bcdef" -> 0x20, 0x45, 0x6162636461626364616263646162636461626364616263646162636461626364, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
||||
// f(string,string): 0x40, 0x80, 3, "abc", 3, "def" -> 0x20, 6, "abcdef"
|
||||
// f(string,string): 0x40, 0xa0, 34, "abcdabcdabcdabcdabcdabcdabcdabcd", "ab", 30, "cdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x40, 0x6162636461626364616263646162636461626364616263646162636461626364, 0x6162636461626364616263646162636461626364616263646162636461626364
|
||||
// f(string,string): 0x40, 0xa0, 34, "abcdabcdabcdabcdabcdabcdabcdabcd", "ab", 34, "cdabcdabcdabcdabcdabcdabcdabcdab", "cd" -> 0x20, 0x44, 0x6162636461626364616263646162636461626364616263646162636461626364, 0x6162636461626364616263646162636461626364616263646162636461626364, 44048183293808120317390542201052832727062033572611867748297851798484192067584
|
||||
// f(string,string): 0x40, 0x80, 3, "abc", 30, "dabcdabcdabcdabcdabcdabcdabcda" -> 0x20, 0x21, 0x6162636461626364616263646162636461626364616263646162636461626364, 43874346312576839672212443538448152585028080127215369968075725190498334277632
|
@ -0,0 +1,37 @@
|
||||
contract C{
|
||||
string s = "bcdef";
|
||||
|
||||
function f(string memory a) public returns (string memory) {
|
||||
return string.concat(a, "bcdef");
|
||||
}
|
||||
function g(string calldata a) public returns (string memory) {
|
||||
return string.concat(a, "abcdefghabcdefghabcdefghabcdefghab");
|
||||
}
|
||||
function h(string calldata a) public returns (string memory) {
|
||||
return string.concat(a, s);
|
||||
}
|
||||
function j(string calldata a) public returns (string memory) {
|
||||
string storage ref = s;
|
||||
return string.concat(a, ref, s);
|
||||
}
|
||||
function k(string calldata a, bytes memory b) public returns (string memory) {
|
||||
return string.concat(a, string(b));
|
||||
}
|
||||
function slice(string calldata a) public returns (string memory) {
|
||||
require(bytes(a).length > 2, "");
|
||||
return string.concat(a[:2], a[2:]);
|
||||
}
|
||||
function strParam(bytes calldata a) public returns (string memory) {
|
||||
return string.concat(string(a), "bcdef");
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(string): 0x20, 32, "abcdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x25, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
||||
// g(string): 0x20, 32, "abcdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x42, 0x6162636461626364616263646162636461626364616263646162636461626364, 0x6162636465666768616263646566676861626364656667686162636465666768, 44047497324925121336511606693520958599579173549109180625971642598225011015680
|
||||
// h(string): 0x20, 32, "abcdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x25, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
||||
// j(string): 0x20, 32, "abcdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x2a, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928944786876717917111204727192787026596791669343131645116682757734400
|
||||
// k(string,bytes): 0x40, 0x80, 32, "abcdabcdabcdabcdabcdabcdabcdabcd", 5, "bcdef" -> 0x20, 0x25, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
||||
// slice(string): 0x20, 4, "abcd" -> 0x20, 4, "abcd"
|
||||
// strParam(bytes): 0x20, 32, "abcdabcdabcdabcdabcdabcdabcdabcd" -> 0x20, 0x25, 0x6162636461626364616263646162636461626364616263646162636461626364, 44502269928904312298000709931354278973409164155382318144318241583783949107200
|
@ -0,0 +1,10 @@
|
||||
contract C {
|
||||
function f() public returns (string memory) {
|
||||
return string.concat();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileToEwasm: also
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0x20, 0
|
@ -0,0 +1,27 @@
|
||||
contract C {
|
||||
function f() public returns (string memory) {
|
||||
string memory b = "";
|
||||
return string.concat(
|
||||
string.concat(b),
|
||||
string.concat(b, b),
|
||||
string.concat("", b),
|
||||
string.concat(b, "")
|
||||
);
|
||||
}
|
||||
|
||||
function g() public returns (string memory) {
|
||||
return string.concat("", "abc", hex"", "abc", unicode"");
|
||||
}
|
||||
|
||||
function h() public returns (string memory) {
|
||||
string memory b = "";
|
||||
return string.concat(b, "abc", b, "abc", b);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileToEwasm: also
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0x20, 0
|
||||
// g() -> 0x20, 6, "abcabc"
|
||||
// h() -> 0x20, 6, "abcabc"
|
@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
function f(string memory a, string memory b, string memory c) public returns (string memory) {
|
||||
return string.concat(string.concat(a, b), c);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(string,string,string): 0x60, 0x60, 0x60, 2, "ab" -> 0x20, 6, "ababab"
|
@ -0,0 +1,17 @@
|
||||
interface IBase {
|
||||
function foo() external view;
|
||||
}
|
||||
|
||||
contract Base is IBase {
|
||||
function foo() public virtual view {}
|
||||
}
|
||||
|
||||
interface IExt is IBase {}
|
||||
|
||||
contract Ext is IExt, Base {}
|
||||
|
||||
contract T { function foo() public virtual view {} }
|
||||
|
||||
contract Impl is Ext, T {
|
||||
function foo() public view override(IBase, Base, T) {}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
abstract contract IBase {
|
||||
function foo() external view virtual;
|
||||
}
|
||||
|
||||
contract Base is IBase {
|
||||
function foo() public virtual override view {}
|
||||
}
|
||||
|
||||
abstract contract IExt is IBase {}
|
||||
|
||||
contract Ext is IExt, Base {}
|
||||
|
||||
contract T { function foo() public virtual view {} }
|
||||
|
||||
contract Impl is Ext, T {
|
||||
function foo() public view override(IBase, Base, T) {}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
interface IBase {
|
||||
function foo() external view;
|
||||
}
|
||||
|
||||
contract Base is IBase {
|
||||
function foo() public virtual view {}
|
||||
}
|
||||
|
||||
interface IExt is IBase {}
|
||||
|
||||
contract Ext is IExt, Base {}
|
||||
|
||||
contract Impl is Ext {
|
||||
function foo() public view {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9456: (211-240): Overriding function is missing "override" specifier.
|
||||
// TypeError 4327: (211-240): Function needs to specify overridden contracts "Base" and "IBase".
|
@ -0,0 +1,16 @@
|
||||
interface IBase {
|
||||
function foo() external view;
|
||||
}
|
||||
|
||||
contract Base is IBase {
|
||||
function foo() public virtual view {}
|
||||
}
|
||||
|
||||
interface IExt is IBase {}
|
||||
|
||||
contract Ext is IExt, Base {}
|
||||
|
||||
contract Impl is Ext {
|
||||
function foo() public view override (IBase, Base) {}
|
||||
}
|
||||
// ----
|
@ -0,0 +1,22 @@
|
||||
interface IBase {
|
||||
function foo() external view;
|
||||
}
|
||||
|
||||
contract Base1 is IBase { function foo() public virtual view {} }
|
||||
contract Base2 is IBase { function foo() public virtual view {} }
|
||||
|
||||
interface IExt1a is IBase {}
|
||||
interface IExt1b is IBase {}
|
||||
interface IExt2a is IBase {}
|
||||
interface IExt2b is IBase {}
|
||||
|
||||
contract Ext1 is IExt1a, IExt1b, Base1 {}
|
||||
contract Ext2 is IExt2a, IExt2b, Base2 {}
|
||||
|
||||
contract Impl is Ext1, Ext2 {
|
||||
function foo() public view {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9456: (424-453): Overriding function is missing "override" specifier.
|
||||
// TypeError 9456: (424-453): Overriding function is missing "override" specifier.
|
||||
// TypeError 4327: (424-453): Function needs to specify overridden contracts "Base1", "Base2" and "IBase".
|
@ -0,0 +1,18 @@
|
||||
interface IBase {
|
||||
function foo() external view;
|
||||
}
|
||||
|
||||
contract Base1 is IBase { function foo() public virtual view {} }
|
||||
contract Base2 is IBase { function foo() public virtual view {} }
|
||||
|
||||
interface IExt1a is IBase {}
|
||||
interface IExt1b is IBase {}
|
||||
interface IExt2a is IBase {}
|
||||
interface IExt2b is IBase {}
|
||||
|
||||
contract Ext1 is IExt1a, IExt1b, Base1 {}
|
||||
contract Ext2 is IExt2a, IExt2b, Base2 {}
|
||||
|
||||
contract Impl is Ext1, Ext2 {
|
||||
function foo() public view override (IBase, Base1, Base2) {}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
interface IBase {
|
||||
function foo() external view;
|
||||
}
|
||||
|
||||
contract Base1 is IBase { function foo() public virtual view {} }
|
||||
contract Base2 is IBase { function foo() public virtual view {} }
|
||||
|
||||
interface IExt1a is IBase {}
|
||||
abstract contract IExt1b is IBase {}
|
||||
abstract contract IExt2a is IBase {}
|
||||
interface IExt2b is IBase {}
|
||||
|
||||
contract Ext1 is IExt1a, IExt1b, Base1 {}
|
||||
contract Ext2 is IExt2a, IExt2b, Base2 {}
|
||||
|
||||
contract Impl is Ext1, Ext2 {
|
||||
function foo() public view override (IBase, Base1, Base2) {}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
function g() public pure returns (string memory) {
|
||||
return string.concat;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 6359: (83-96): Return argument type function () pure returns (string memory) is not implicitly convertible to expected type (type of first return variable) string memory.
|
@ -0,0 +1,13 @@
|
||||
contract C {
|
||||
function j() external {
|
||||
string memory a = "hello";
|
||||
string memory b = " world";
|
||||
|
||||
string memory d = string.concat(bytes(a), bytes(b));
|
||||
string memory e = string.concat(a, 0);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9977: (153-161): Invalid type for argument in the string.concat function call. string type is required, but t_bytes_memory_ptr provided.
|
||||
// TypeError 9977: (163-171): Invalid type for argument in the string.concat function call. string type is required, but t_bytes_memory_ptr provided.
|
||||
// TypeError 9977: (217-218): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
@ -0,0 +1,15 @@
|
||||
contract C {
|
||||
string s;
|
||||
function f(string calldata c, string calldata c1) public {
|
||||
string memory a;
|
||||
bytes16 b;
|
||||
uint8[] memory num;
|
||||
bytes1[] memory m;
|
||||
string memory d = string.concat(a, b, c, num, s, "abc", m, c1, bytes(c1));
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9977: (232-233): Invalid type for argument in the string.concat function call. string type is required, but t_bytes16 provided.
|
||||
// TypeError 9977: (238-241): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_uint8_$dyn_memory_ptr provided.
|
||||
// TypeError 9977: (253-254): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_bytes1_$dyn_memory_ptr provided.
|
||||
// TypeError 9977: (260-269): Invalid type for argument in the string.concat function call. string type is required, but t_bytes_calldata_ptr provided.
|
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
function f() public {
|
||||
string.concat([], [], []);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 6378: (61-63): Unable to deduce common type for array elements.
|
@ -0,0 +1,40 @@
|
||||
contract C {
|
||||
struct S {
|
||||
uint x;
|
||||
}
|
||||
|
||||
enum E {A, B, C}
|
||||
|
||||
mapping(uint => E) m;
|
||||
|
||||
function f() public {
|
||||
bool b;
|
||||
uint u;
|
||||
uint8 u8;
|
||||
address a;
|
||||
address payable ap;
|
||||
function () external fext;
|
||||
function () internal fint;
|
||||
uint[] memory uDynamic;
|
||||
uint[2] memory uStatic;
|
||||
C c;
|
||||
S memory s;
|
||||
E e;
|
||||
|
||||
string.concat(b, u, u8, a, ap, fext, fint, uDynamic, uStatic, c, s, e, m);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9977: (426-427): Invalid type for argument in the string.concat function call. string type is required, but t_bool provided.
|
||||
// TypeError 9977: (429-430): Invalid type for argument in the string.concat function call. string type is required, but t_uint256 provided.
|
||||
// TypeError 9977: (432-434): Invalid type for argument in the string.concat function call. string type is required, but t_uint8 provided.
|
||||
// TypeError 9977: (436-437): Invalid type for argument in the string.concat function call. string type is required, but t_address provided.
|
||||
// TypeError 9977: (439-441): Invalid type for argument in the string.concat function call. string type is required, but t_address_payable provided.
|
||||
// TypeError 9977: (443-447): Invalid type for argument in the string.concat function call. string type is required, but t_function_external_nonpayable$__$returns$__$ provided.
|
||||
// TypeError 9977: (449-453): Invalid type for argument in the string.concat function call. string type is required, but t_function_internal_nonpayable$__$returns$__$ provided.
|
||||
// TypeError 9977: (455-463): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_uint256_$dyn_memory_ptr provided.
|
||||
// TypeError 9977: (465-472): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_uint256_$2_memory_ptr provided.
|
||||
// TypeError 9977: (474-475): Invalid type for argument in the string.concat function call. string type is required, but t_contract$_C_$86 provided.
|
||||
// TypeError 9977: (477-478): Invalid type for argument in the string.concat function call. string type is required, but t_struct$_S_$4_memory_ptr provided.
|
||||
// TypeError 9977: (480-481): Invalid type for argument in the string.concat function call. string type is required, but t_enum$_E_$8 provided.
|
||||
// TypeError 9977: (483-484): Invalid type for argument in the string.concat function call. string type is required, but t_mapping$_t_uint256_$_t_enum$_E_$8_$ provided.
|
@ -0,0 +1,58 @@
|
||||
contract C {
|
||||
struct S {
|
||||
uint x;
|
||||
}
|
||||
|
||||
enum E {A, B, C}
|
||||
|
||||
function f() public {
|
||||
string.concat(
|
||||
false,
|
||||
1,
|
||||
1e10,
|
||||
1e-10,
|
||||
0.1,
|
||||
0x1234567,
|
||||
0x11112222333344445555666677778888999900, // One byte less than an address
|
||||
0x1111222233334444555566667777888899990000, // Address
|
||||
0x111122223333444455556666777788889999000011, // One byte more than an address
|
||||
0x00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff, // exactly 32 bytes
|
||||
-0x0000000000000000000000000000000000000000000000000000000000000001, // exactly 32 bytes
|
||||
bytes(bytes32(0x00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff))[:],
|
||||
f,
|
||||
(),
|
||||
(0, 0),
|
||||
[0],
|
||||
[0][:],
|
||||
[0][0],
|
||||
new C(),
|
||||
S(0),
|
||||
E.A
|
||||
);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9640: (698-780): Explicit type conversion not allowed from "bytes32" to "bytes memory".
|
||||
// TypeError 1227: (698-783): Index range access is only supported for dynamic calldata arrays.
|
||||
// TypeError 1227: (865-871): Index range access is only supported for dynamic calldata arrays.
|
||||
// TypeError 9977: (134-139): Invalid type for argument in the string.concat function call. string type is required, but t_bool provided.
|
||||
// TypeError 9977: (153-154): Invalid type for argument in the string.concat function call. string type is required, but t_rational_1_by_1 provided.
|
||||
// TypeError 9977: (168-172): Invalid type for argument in the string.concat function call. string type is required, but t_rational_10000000000_by_1 provided.
|
||||
// TypeError 9977: (186-191): Invalid type for argument in the string.concat function call. string type is required, but t_rational_1_by_10000000000 provided.
|
||||
// TypeError 9977: (205-208): Invalid type for argument in the string.concat function call. string type is required, but t_rational_1_by_10 provided.
|
||||
// TypeError 9977: (222-231): Invalid type for argument in the string.concat function call. string type is required, but t_rational_19088743_by_1 provided.
|
||||
// TypeError 9977: (245-285): Invalid type for argument in the string.concat function call. string type is required, but t_rational_380605192295934637532253317235440047844071680_by_1 provided.
|
||||
// TypeError 9977: (336-378): Invalid type for argument in the string.concat function call. string type is required, but t_address provided.
|
||||
// TypeError 9977: (405-449): Invalid type for argument in the string.concat function call. string type is required, but t_rational_24943341882306372405313753398341798975509081620497_by_1 provided.
|
||||
// TypeError 9977: (496-562): Invalid type for argument in the string.concat function call. string type is required, but t_rational_30272441630670900764332283662402067049651745785153368133042924362431065855_by_1 provided.
|
||||
// TypeError 9977: (597-664): Invalid type for argument in the string.concat function call. string type is required, but t_rational_minus_1_by_1 provided.
|
||||
// TypeError 9977: (698-783): Invalid type for argument in the string.concat function call. string type is required, but t_bytes_memory_ptr_slice provided.
|
||||
// TypeError 9977: (797-798): Invalid type for argument in the string.concat function call. string type is required, but t_function_internal_nonpayable$__$returns$__$ provided.
|
||||
// TypeError 9977: (812-814): Invalid type for argument in the string.concat function call. string type is required, but t_tuple$__$ provided.
|
||||
// TypeError 9977: (828-834): Invalid type for argument in the string.concat function call. string type is required, but t_tuple$_t_rational_0_by_1_$_t_rational_0_by_1_$ provided.
|
||||
// TypeError 9977: (848-851): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_uint8_$1_memory_ptr provided.
|
||||
// TypeError 9977: (865-871): Invalid type for argument in the string.concat function call. string type is required, but t_array$_t_uint8_$1_memory_ptr_slice provided.
|
||||
// TypeError 9977: (885-891): Invalid type for argument in the string.concat function call. string type is required, but t_uint8 provided.
|
||||
// TypeError 9977: (905-912): Invalid type for argument in the string.concat function call. string type is required, but t_contract$_C_$61 provided.
|
||||
// TypeError 9977: (926-930): Invalid type for argument in the string.concat function call. string type is required, but t_struct$_S_$4_memory_ptr provided.
|
||||
// TypeError 9977: (944-947): Invalid type for argument in the string.concat function call. string type is required, but t_enum$_E_$8 provided.
|
@ -0,0 +1,33 @@
|
||||
contract C {
|
||||
function f() public pure {
|
||||
string.concat(
|
||||
0,
|
||||
-0,
|
||||
0.0,
|
||||
-0.0,
|
||||
0e10,
|
||||
-0e10,
|
||||
0e-10,
|
||||
-0e-10,
|
||||
(0),
|
||||
0x00,
|
||||
-0x00,
|
||||
0x0000000000000000000000000000000000000000000000000000000000000000, // exactly 32 bytes
|
||||
-0x0000000000000000000000000000000000000000000000000000000000000000 // exactly 32 bytes
|
||||
);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 9977: (79-80): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (94-96): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (110-113): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (127-131): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (145-149): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (163-168): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (182-187): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (201-207): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (221-224): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (238-242): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (256-261): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (275-341): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
||||
// TypeError 9977: (375-442): Invalid type for argument in the string.concat function call. string type is required, but t_rational_0_by_1 provided.
|
54
test/libyul/StackShufflingTest.cpp
Normal file
54
test/libyul/StackShufflingTest.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* Unit tests for stack shuffling.
|
||||
*/
|
||||
#include <libyul/backends/evm/StackHelpers.h>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::langutil;
|
||||
|
||||
namespace solidity::yul::test
|
||||
{
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(YulStackShuffling)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(swap_cycle)
|
||||
{
|
||||
std::vector<Scope::Variable> scopeVariables;
|
||||
Scope::Function function;
|
||||
std::vector<VariableSlot> v;
|
||||
for (size_t i = 0; i < 17; ++i)
|
||||
scopeVariables.emplace_back(Scope::Variable{""_yulstring, YulString{"v" + to_string(i)}});
|
||||
for (size_t i = 0; i < 17; ++i)
|
||||
v.emplace_back(VariableSlot{scopeVariables[i]});
|
||||
|
||||
Stack sourceStack{
|
||||
v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16],
|
||||
FunctionReturnLabelSlot{function}, FunctionReturnLabelSlot{function}, v[5]};
|
||||
Stack targetStack{
|
||||
v[1], v[0], v[2], v[3], v[4], v[5], v[6], v[7], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16],
|
||||
FunctionReturnLabelSlot{function}, JunkSlot{}, JunkSlot{}
|
||||
};
|
||||
// Used to hit a swapping cycle.
|
||||
createStackLayout(sourceStack, targetStack, [](auto){}, [](auto){}, [](){});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
381
test/scripts/fixtures/eth_gas_report_gnosis.rst
Normal file
381
test/scripts/fixtures/eth_gas_report_gnosis.rst
Normal file
@ -0,0 +1,381 @@
|
||||
·----------------------------------------------------------------------------------------------------------------------------------------|---------------------------|-------------|------------------------------·
|
||||
| Solc version: 0.8.10 · Optimizer enabled: true · Runs: 200 · Block limit: 100000000 gas │
|
||||
·········································································································································|···························|·············|·······························
|
||||
| Methods │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| Contract · Method · Min · Max · Avg · # calls · eur (avg) │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · getMessageHash(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · getMessageHashForSafe(address,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · getModules() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · isValidSignature(bytes,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · isValidSignature(bytes32,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · NAME() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · onERC1155BatchReceived(address,address,uint256[],uint256[],bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · onERC1155Received(address,address,uint256,uint256,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · onERC721Received(address,address,uint256,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · simulate(address,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · supportsInterface(bytes4) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · tokensReceived(address,address,address,uint256,bytes,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CompatibilityFallbackHandler · VERSION() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CreateCall · performCreate(uint256,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| CreateCall · performCreate2(uint256,bytes,bytes32) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DebugTransactionGuard · checkAfterExecution(bytes32,bool) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DebugTransactionGuard · checkTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DebugTransactionGuard · supportsInterface(bytes4) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DebugTransactionGuard · txNonces(bytes32) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DefaultCallbackHandler · NAME() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DefaultCallbackHandler · onERC1155BatchReceived(address,address,uint256[],uint256[],bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DefaultCallbackHandler · onERC1155Received(address,address,uint256,uint256,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DefaultCallbackHandler · onERC721Received(address,address,uint256,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DefaultCallbackHandler · supportsInterface(bytes4) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DefaultCallbackHandler · tokensReceived(address,address,address,uint256,bytes,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DefaultCallbackHandler · VERSION() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DelegateCallTransactionGuard · allowedTarget() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DelegateCallTransactionGuard · checkAfterExecution(bytes32,bool) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DelegateCallTransactionGuard · checkTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| DelegateCallTransactionGuard · supportsInterface(bytes4) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC1155Token · balanceOf(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC1155Token · mint(address,uint256,uint256,bytes) · 47934 · 59804 · 57826 · 6 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC1155Token · safeTransferFrom(address,address,uint256,uint256,bytes) · - · - · 53900 · 2 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20 · allowance(address,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20 · approve(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20 · balanceOf(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20 · decimals() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20 · decreaseAllowance(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20 · increaseAllowance(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20 · name() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20 · symbol() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20 · totalSupply() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20 · transfer(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20 · transferFrom(address,address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · allowance(address,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · approve(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · balanceOf(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · decimals() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · decreaseAllowance(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · increaseAllowance(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · name() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · symbol() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · totalSupply() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · transfer(address,uint256) · - · - · 51567 · 8 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · transferFrom(address,address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| FallbackManager · setFallbackHandler(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · addOwnerWithThreshold(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · approvedHashes(address,bytes32) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · approveHash(bytes32) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · changeThreshold(uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · checkNSignatures(bytes32,bytes,bytes,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · checkSignatures(bytes32,bytes,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · disableModule(address,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · domainSeparator() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · enableModule(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · encodeTransactionData(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes) · 59563 · 151736 · 94816 · 85 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · execTransactionFromModule(address,uint256,bytes,uint8) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · execTransactionFromModuleReturnData(address,uint256,bytes,uint8) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · getChainId() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · getModulesPaginated(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · getOwners() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · getStorageAt(uint256,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · getThreshold() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · getTransactionHash(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · isModuleEnabled(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · isOwner(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · nonce() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · removeOwner(address,address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · requiredTxGas(address,uint256,bytes,uint8) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · setFallbackHandler(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · setGuard(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · setup(address[],uint256,address,bytes,address,address,uint256,address) · 167642 · 263690 · 201944 · 49 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · signedMessages(bytes32) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · simulateAndRevert(address,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · swapOwner(address,address,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafe · VERSION() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · addOwnerWithThreshold(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · approvedHashes(address,bytes32) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · approveHash(bytes32) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · changeThreshold(uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · checkNSignatures(bytes32,bytes,bytes,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · checkSignatures(bytes32,bytes,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · disableModule(address,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · domainSeparator() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · enableModule(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · encodeTransactionData(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · execTransactionFromModule(address,uint256,bytes,uint8) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · execTransactionFromModuleReturnData(address,uint256,bytes,uint8) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · getChainId() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · getModulesPaginated(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · getOwners() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · getStorageAt(uint256,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · getThreshold() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · getTransactionHash(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · isModuleEnabled(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · isOwner(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · nonce() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · removeOwner(address,address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · requiredTxGas(address,uint256,bytes,uint8) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · setFallbackHandler(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · setGuard(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · setup(address[],uint256,address,bytes,address,address,uint256,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · signedMessages(bytes32) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · simulateAndRevert(address,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · swapOwner(address,address,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeL2 · VERSION() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeProxyFactory · calculateCreateProxyWithNonceAddress(address,bytes,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeProxyFactory · createProxy(address,bytes) · 105568 · 105580 · 105568 · 52 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeProxyFactory · createProxyWithCallback(address,bytes,uint256,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeProxyFactory · createProxyWithNonce(address,bytes,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeProxyFactory · proxyCreationCode() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GnosisSafeProxyFactory · proxyRuntimeCode() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| GuardManager · setGuard(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| Migration · migrate() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| Migration · migrationSingleton() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| Migration · safe120Singleton() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · DEFAULT_FALLBACK_VALUE() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenAnyReturn(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenAnyReturnAddress(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenAnyReturnBool(bool) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenAnyReturnUint(uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenAnyRevert() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenAnyRevertWithMessage(string) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenAnyRunOutOfGas() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenCalldataReturn(bytes,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenCalldataReturnAddress(bytes,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenCalldataReturnBool(bytes,bool) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenCalldataReturnUint(bytes,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenCalldataRevert(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenCalldataRevertWithMessage(bytes,string) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenCalldataRunOutOfGas(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenMethodReturn(bytes,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenMethodReturnAddress(bytes,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenMethodReturnBool(bytes,bool) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenMethodReturnUint(bytes,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenMethodRevert(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenMethodRevertWithMessage(bytes,string) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · givenMethodRunOutOfGas(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · invocationCount() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · invocationCountForCalldata(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · invocationCountForMethod(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · MOCKS_LIST_END_HASH() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · MOCKS_LIST_END() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · MOCKS_LIST_START() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · reset() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · SENTINEL_ANY_MOCKS() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MockContract · updateInvocationCount(bytes4,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ModuleManager · disableModule(address,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ModuleManager · enableModule(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ModuleManager · execTransactionFromModule(address,uint256,bytes,uint8) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ModuleManager · execTransactionFromModuleReturnData(address,uint256,bytes,uint8) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ModuleManager · getModulesPaginated(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ModuleManager · isModuleEnabled(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MultiSend · multiSend(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| MultiSendCallOnly · multiSend(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| OwnerManager · addOwnerWithThreshold(address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| OwnerManager · changeThreshold(uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| OwnerManager · getOwners() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| OwnerManager · getThreshold() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| OwnerManager · isOwner(address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| OwnerManager · removeOwner(address,address,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| OwnerManager · swapOwner(address,address,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ReentrancyTransactionGuard · checkAfterExecution(bytes32,bool) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ReentrancyTransactionGuard · checkTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes,address) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| ReentrancyTransactionGuard · supportsInterface(bytes4) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| SignMessageLib · getMessageHash(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| SignMessageLib · signMessage(bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| SimulateTxAccessor · simulate(address,uint256,bytes,uint8) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| StorageAccessible · getStorageAt(uint256,uint256) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| StorageAccessible · simulateAndRevert(address,bytes) · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| TestHandler · dudududu() · - · - · - · 0 · - │
|
||||
·································|·······································································································|·············|·············|·············|···············|···············
|
||||
| Deployments · · % of limit · │
|
||||
·········································································································································|·············|·············|·············|···············|···············
|
||||
| DelegateCallTransactionGuard · 283510 · 283522 · 283516 · 0.3 % · - │
|
||||
·········································································································································|·············|·············|·············|···············|···············
|
||||
| ERC1155Token · - · - · 525869 · 0.5 % · - │
|
||||
·········································································································································|·············|·············|·············|···············|···············
|
||||
| ERC20Token · - · - · 733462 · 0.7 % · - │
|
||||
·----------------------------------------------------------------------------------------------------------------------------------------|-------------|-------------|-------------|---------------|--------------·
|
219
test/scripts/test_externalTests_parse_eth_gas_report.py
Normal file
219
test/scripts/test_externalTests_parse_eth_gas_report.py
Normal file
@ -0,0 +1,219 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from dataclasses import asdict
|
||||
import unittest
|
||||
|
||||
from textwrap import dedent
|
||||
|
||||
from unittest_helpers import FIXTURE_DIR, load_fixture
|
||||
|
||||
# NOTE: This test file file only works with scripts/ added to PYTHONPATH so pylint can't find the imports
|
||||
# pragma pylint: disable=import-error
|
||||
from externalTests.parse_eth_gas_report import parse_report, ReportParsingError, ReportValidationError
|
||||
# pragma pylint: enable=import-error
|
||||
|
||||
ETH_GAS_REPORT_GNOSIS_RST_PATH = FIXTURE_DIR / 'eth_gas_report_gnosis.rst'
|
||||
ETH_GAS_REPORT_GNOSIS_RST_CONTENT = load_fixture(ETH_GAS_REPORT_GNOSIS_RST_PATH)
|
||||
|
||||
|
||||
class TestEthGasReport(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.maxDiff = 10000
|
||||
|
||||
def test_parse_report(self):
|
||||
parsed_report = parse_report(ETH_GAS_REPORT_GNOSIS_RST_CONTENT)
|
||||
|
||||
expected_report = {
|
||||
'solc_version': '0.8.10',
|
||||
'optimize': True,
|
||||
'runs': 200,
|
||||
'block_limit': 100000000,
|
||||
'total_method_gas': 57826 * 6 + 53900 * 2 + 51567 * 8 + 94816 * 85 + 201944 * 49 + 105568 * 52,
|
||||
'total_deployment_gas': 283516 + 525869 + 733462,
|
||||
'contracts': {
|
||||
'DelegateCallTransactionGuard': {
|
||||
'total_method_gas': 0,
|
||||
'min_deployment_gas': 283510,
|
||||
'max_deployment_gas': 283522,
|
||||
'avg_deployment_gas': 283516,
|
||||
'methods': None,
|
||||
},
|
||||
'ERC1155Token': {
|
||||
'total_method_gas': 57826 * 6 + 53900 * 2,
|
||||
'min_deployment_gas': None,
|
||||
'max_deployment_gas': None,
|
||||
'avg_deployment_gas': 525869,
|
||||
'methods': {
|
||||
'mint(address,uint256,uint256,bytes)': {
|
||||
'total_gas': 57826 * 6,
|
||||
'min_gas': 47934,
|
||||
'max_gas': 59804,
|
||||
'avg_gas': 57826,
|
||||
'call_count': 6
|
||||
},
|
||||
'safeTransferFrom(address,address,uint256,uint256,bytes)': {
|
||||
'total_gas': 53900 * 2,
|
||||
'min_gas': 53900,
|
||||
'max_gas': 53900,
|
||||
'avg_gas': 53900,
|
||||
'call_count': 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
'ERC20Token': {
|
||||
'total_method_gas': 51567 * 8,
|
||||
'min_deployment_gas': None,
|
||||
'max_deployment_gas': None,
|
||||
'avg_deployment_gas': 733462,
|
||||
'methods': {
|
||||
'transfer(address,uint256)': {
|
||||
'total_gas': 51567 * 8,
|
||||
'min_gas': 51567,
|
||||
'max_gas': 51567,
|
||||
'avg_gas': 51567,
|
||||
'call_count': 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
'GnosisSafe': {
|
||||
'total_method_gas': 94816 * 85 + 201944 * 49,
|
||||
'min_deployment_gas': None,
|
||||
'max_deployment_gas': None,
|
||||
'avg_deployment_gas': None,
|
||||
'methods': {
|
||||
'execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)': {
|
||||
'total_gas': 94816 * 85,
|
||||
'min_gas': 59563,
|
||||
'max_gas': 151736,
|
||||
'avg_gas': 94816,
|
||||
'call_count': 85,
|
||||
},
|
||||
'setup(address[],uint256,address,bytes,address,address,uint256,address)': {
|
||||
'total_gas': 201944 * 49,
|
||||
'min_gas': 167642,
|
||||
'max_gas': 263690,
|
||||
'avg_gas': 201944,
|
||||
'call_count': 49,
|
||||
},
|
||||
},
|
||||
},
|
||||
'GnosisSafeProxyFactory': {
|
||||
'total_method_gas': 105568 * 52,
|
||||
'min_deployment_gas': None,
|
||||
'max_deployment_gas': None,
|
||||
'avg_deployment_gas': None,
|
||||
'methods': {
|
||||
'createProxy(address,bytes)': {
|
||||
'total_gas': 105568 * 52,
|
||||
'min_gas': 105568,
|
||||
'max_gas': 105580,
|
||||
'avg_gas': 105568,
|
||||
'call_count': 52,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
self.assertEqual(asdict(parsed_report), expected_report)
|
||||
|
||||
def test_parse_report_should_fail_if_report_is_empty(self):
|
||||
text_report = ""
|
||||
with self.assertRaises(ReportValidationError) as manager:
|
||||
parse_report(text_report)
|
||||
self.assertEqual(str(manager.exception), "Report header not found.")
|
||||
|
||||
def test_parse_report_should_fail_if_report_has_no_header(self):
|
||||
text_report = dedent("""
|
||||
| Methods |
|
||||
| ERC1155Token · mint() · 1 · 3 · 2 · 6 · - |
|
||||
| Deployments · · % of limit · │
|
||||
| ERC1155Token · - · - · 5 · 1 % · - |
|
||||
""").strip('\n')
|
||||
with self.assertRaises(ReportValidationError) as manager:
|
||||
parse_report(text_report)
|
||||
self.assertEqual(str(manager.exception), "Report header not found.")
|
||||
|
||||
def test_parse_report_should_fail_if_data_rows_have_no_headers(self):
|
||||
text_report = dedent("""
|
||||
| ERC1155Token · mint() · 1 · 3 · 2 · 6 · - |
|
||||
""").strip('\n')
|
||||
expected_message = dedent("""
|
||||
Parsing error on line 1: Found data row without a section header.
|
||||
| ERC1155Token | mint() | 1 | 3 | 2 | 6 | - |
|
||||
""").strip('\n')
|
||||
|
||||
with self.assertRaises(ReportParsingError) as manager:
|
||||
parse_report(text_report)
|
||||
self.assertEqual(str(manager.exception), expected_message)
|
||||
|
||||
def test_parse_report_should_fail_if_report_has_more_than_one_header(self):
|
||||
text_report = dedent("""
|
||||
| Solc version: 0.8.10 · Optimizer enabled: true · Runs: 200 · Block limit: 100000000 gas |
|
||||
| Solc version: 0.8.9 · Optimizer enabled: false · Runs: 111 · Block limit: 999999999 gas |
|
||||
""").strip('\n')
|
||||
expected_message = dedent("""
|
||||
Parsing error on line 2: Duplicate report header.
|
||||
| Solc version: 0.8.9 | Optimizer enabled: false | Runs: 111 | Block limit: 999999999 gas |
|
||||
""").strip('\n')
|
||||
|
||||
with self.assertRaises(ReportParsingError) as manager:
|
||||
parse_report(text_report)
|
||||
self.assertEqual(str(manager.exception), expected_message)
|
||||
|
||||
def test_parse_report_should_fail_if_row_matching_same_method_call_appears_twice(self):
|
||||
text_report = dedent("""
|
||||
| Methods |
|
||||
| ERC1155Token · mint() · 47934 · 59804 · 57826 · 6 · - |
|
||||
| ERC1155Token · mint() · 11111 · 22222 · 33333 · 4 · - |
|
||||
""").strip('\n')
|
||||
expected_message = dedent("""
|
||||
Parsing error on line 3: Duplicate method row for 'ERC1155Token.mint()'.
|
||||
| ERC1155Token | mint() | 11111 | 22222 | 33333 | 4 | - |
|
||||
""").strip('\n')
|
||||
|
||||
with self.assertRaises(ReportParsingError) as manager:
|
||||
parse_report(text_report)
|
||||
self.assertEqual(str(manager.exception), expected_message)
|
||||
|
||||
def test_parse_report_should_fail_if_row_matching_same_contract_deployment_appears_twice(self):
|
||||
text_report = dedent("""
|
||||
| Deployments · · % of limit · │
|
||||
| ERC1155Token · - · - · 525869 · 0.5 % · - |
|
||||
| ERC1155Token · - · - · 111111 · 0.6 % · - |
|
||||
""").strip('\n')
|
||||
expected_message = dedent("""
|
||||
Parsing error on line 3: Duplicate contract deployment row for 'ERC1155Token'.
|
||||
| ERC1155Token | - | - | 111111 | 0.6 % | - |
|
||||
""").strip('\n')
|
||||
|
||||
with self.assertRaises(ReportParsingError) as manager:
|
||||
parse_report(text_report)
|
||||
self.assertEqual(str(manager.exception), expected_message)
|
||||
|
||||
def test_parse_report_should_fail_if_method_row_appears_under_deployments_header(self):
|
||||
text_report = dedent("""
|
||||
| Deployments · · % of limit · │
|
||||
| ERC1155Token · mint() · 47934 · 59804 · 57826 · 6 · - |
|
||||
""").strip('\n')
|
||||
expected_message = dedent("""
|
||||
Parsing error on line 2: Expected a table row with deployment details.
|
||||
| ERC1155Token | mint() | 47934 | 59804 | 57826 | 6 | - |
|
||||
""").strip('\n')
|
||||
|
||||
with self.assertRaises(ReportParsingError) as manager:
|
||||
parse_report(text_report)
|
||||
self.assertEqual(str(manager.exception), expected_message)
|
||||
|
||||
def test_parse_report_should_fail_if_deployment_row_appears_under_methods_header(self):
|
||||
text_report = dedent("""
|
||||
| Methods |
|
||||
| ERC1155Token · - · - · 525869 · 5 · - |
|
||||
""").strip('\n')
|
||||
expected_message = dedent("""
|
||||
Parsing error on line 2: Expected a table row with method details.
|
||||
| ERC1155Token | - | - | 525869 | 5 | - |
|
||||
""").strip('\n')
|
||||
|
||||
with self.assertRaises(ReportParsingError) as manager:
|
||||
parse_report(text_report)
|
||||
self.assertEqual(str(manager.exception), expected_message)
|
@ -100,7 +100,7 @@ ImportCheck checkImport(
|
||||
return ImportCheck::OK();
|
||||
|
||||
static regex const sourceNotFoundErrorRegex{
|
||||
R"(^Error \(6275\): Source ".+" not found: (.*)\.\n)"
|
||||
R"(^Error \(6275\): Source "[^"]+" not found: (.*)\.\n)"
|
||||
R"(\s*--> .*<stdin>:\d+:\d+:\n)"
|
||||
R"(\s*\|\n)"
|
||||
R"(\d+\s*\| import '.+';\n)"
|
||||
@ -110,12 +110,12 @@ ImportCheck checkImport(
|
||||
smatch submatches;
|
||||
if (!regex_match(cliResult.stderrContent, submatches, sourceNotFoundErrorRegex))
|
||||
return ImportCheck::Unknown("Unexpected stderr content: '" + cliResult.stderrContent + "'");
|
||||
if (submatches[1] != "File not found" && submatches[1] != "File outside of allowed directories")
|
||||
if (submatches[1] != "File not found" && !boost::starts_with(string(submatches[1]), "File outside of allowed directories"))
|
||||
return ImportCheck::Unknown("Unexpected error message: '" + cliResult.stderrContent + "'");
|
||||
|
||||
if (submatches[1] == "File not found")
|
||||
return ImportCheck::FileNotFound();
|
||||
else if (submatches[1] == "File outside of allowed directories")
|
||||
else if (boost::starts_with(string(submatches[1]), "File outside of allowed directories"))
|
||||
return ImportCheck::PathDisallowed();
|
||||
else
|
||||
return ImportCheck::Unknown("Unexpected error message '" + submatches[1].str() + "'");
|
||||
|
@ -58,7 +58,7 @@ optional<CompilerOutput> SolidityCompilationFramework::compileContract()
|
||||
else
|
||||
contractName = m_compilerInput.contractName;
|
||||
evmasm::LinkerObject obj = m_compiler.object(contractName);
|
||||
Json::Value methodIdentifiers = m_compiler.methodIdentifiers(contractName);
|
||||
Json::Value methodIdentifiers = m_compiler.interfaceSymbols(contractName)["methods"];
|
||||
return CompilerOutput{obj.bytecode, methodIdentifiers};
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ public:
|
||||
/// @returns method identifiers in contract called @param _contractName.
|
||||
Json::Value methodIdentifiers(std::string const& _contractName)
|
||||
{
|
||||
return m_compiler.methodIdentifiers(_contractName);
|
||||
return m_compiler.interfaceSymbols(_contractName)["methods"];
|
||||
}
|
||||
/// @returns Compilation output comprising EVM bytecode and list of
|
||||
/// method identifiers in contract if compilation is successful,
|
||||
|
Loading…
Reference in New Issue
Block a user