diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index d50c44566a..0000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -/docs/style-guide.rst @fulldecent diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 30c09039ef..2d3e38a63a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,46 +1,39 @@ --- -name: Bug Report -about: Problems, deficiencies, inaccuracies or crashes discovered on Solidity. +name: Bug report +about: Use this template for reporting issues title: '' -labels: 'bug :bug:' +labels: bug assignees: '' - --- - +#### πŸ€” Expected Behavior -## Description +Describe what you expected to happen. - +#### 😯 Current Behavior -## Environment +Describe what actually happened. -- Compiler version: -- Target EVM version (as per compiler settings): -- Framework/IDE (e.g. Truffle or Remix): -- EVM execution environment / backend / blockchain client: -- Operating system: +#### πŸ–₯️ Environment -## Steps to Reproduce +Any relevant environment details. - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 69f42abb0f..0000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Initiate a language design or feedback discussion - url: https://forum.soliditylang.org - about: Open a thread on the Solidity forum. diff --git a/.github/ISSUE_TEMPLATE/documentation_issue.md b/.github/ISSUE_TEMPLATE/documentation_issue.md deleted file mode 100644 index 91082a9aaf..0000000000 --- a/.github/ISSUE_TEMPLATE/documentation_issue.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Documentation Issue -about: Corrections, improvements or requests for new content on Solidity's documentation. -title: '' -labels: 'documentation :book:' -assignees: '' - ---- - -## Page - - - -## Abstract - - - -## Pull request - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 7ec729b1c7..d921e066cc 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,43 +1,21 @@ --- -name: Feature Request -about: Ideas, comments or messages asking for a particular functionality to be added - to Solidity. +name: Feature request +about: Use this template for requesting features title: '' -labels: feature +labels: feat assignees: '' - --- - - -## Abstract - - - -## Motivation +### 🌟 Feature Request - +#### πŸ“ Description -## Specification +Provide a clear and concise description of the feature you'd like to see. - +#### πŸ€” Rationale -## Backwards Compatibility +Explain why this feature is important and how it benefits the project. - +Add any other context or information about the feature request here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..54b4193537 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,19 @@ +# What ❔ + + + + + +## Why ❔ + + + + +## Checklist + + + + +- [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). +- [ ] Tests for the changes have been added / updated. +- [ ] Documentation comments have been added / updated. diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml new file mode 100644 index 0000000000..174dae8c41 --- /dev/null +++ b/.github/workflows/benchmarks.yml @@ -0,0 +1,207 @@ +name: Benchmarking + +on: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + benchmarks_candidate: + runs-on: [self-hosted, ci-runner-compiler] + container: + image: matterlabs/llvm_runner:latest + credentials: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + steps: + - uses: AutoModality/action-clean@492b2d2e2e77247bfd0b17eaa89a371b2f3430ee # v1 + - name: Preparing workspace. Setting environment. + run: | + echo "BENCHMARK_MODE=${{ github.event.inputs.compiler_llvm_benchmark_mode || '+M^B3' }}" >> $GITHUB_ENV + echo "BENCHMARK_PATH=${{ github.event.inputs.compiler_llvm_benchmark_path || 'tests/solidity/' }}" >> $GITHUB_ENV + echo "CANDIDATE_BRANCH_NAME=${{ github.event.inputs.compiler_tester_candidate_branch }}" >> $GITHUB_ENV + + - name: Getting the branch name (pull request) + if: github.event_name == 'pull_request' + shell: bash + run: echo "BRANCH_NAME=$(echo ${GITHUB_BASE_REF} | tr / -)" >> $GITHUB_ENV + + - name: Checking out the Solidity repository + uses: actions/checkout@v4 + with: + submodules: recursive + path: solidity + + - name: Checking out the compiler-tester candidate + uses: actions/checkout@v4 + with: + repository: matter-labs/era-compiler-tester + submodules: recursive + path: compiler-tester + + - name: Building the Solidity compiler + working-directory: solidity + run: | + mkdir -p ./build + cd ./build + cmake .. -DCMAKE_BUILD_TYPE='Release' -DSOLC_VERSION_ZKEVM='1.0.0-lts' -DPEDANTIC=OFF -DCMAKE_CXX_FLAGS='-w' -DUSE_Z3=OFF -DUSE_CVC4=OFF + make -j$(nproc) + + - name: Benchmarking the Solidity compiler candidate + id: compiler_tester_run + working-directory: compiler-tester + run: | + mkdir -p './solc-bin/' + cp '../solidity/build/solc/solc' "./solc-bin/solc-${BRANCH_NAME}" + chmod +x "./solc-bin/solc-${BRANCH_NAME}" + + cargo install compiler-llvm-builder + /usr/local/cargo/bin/zkevm-llvm clone && /usr/local/cargo/bin/zkevm-llvm build + + export RUST_BACKTRACE='full' + export LLVM_SYS_150_PREFIX="$(pwd)/target-llvm/target-final/" + cargo build --verbose --release --bin 'compiler-tester' + cargo build --verbose --release --manifest-path /usr/local/cargo/git/checkouts/era-compiler-solidity-*/*/Cargo.toml --target-dir './target-zksolc/' + cargo build --verbose --release --manifest-path /usr/local/cargo/git/checkouts/era-compiler-vyper-*/*/Cargo.toml --target-dir './target-zkvyper/' + + ./target/release/compiler-tester \ + --zksolc './target-zksolc/release/zksolc' \ + --zkvyper './target-zkvyper/release/zkvyper' \ + --path="${{ env.BENCHMARK_PATH || '' }}" \ + --mode="${{ env.BENCHMARK_MODE || '' }}" \ + --benchmark='candidate.json' \ + --solc-bin-config-path="configs/solc-bin-zkevm-candidate-${BRANCH_NAME}.json" + + - uses: actions/upload-artifact@v4 + with: + name: candidate-benchmark + path: compiler-tester/candidate.json + + benchmarks_reference: + runs-on: [self-hosted, ci-runner-compiler] + container: + image: matterlabs/llvm_runner:latest + credentials: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + steps: + - uses: AutoModality/action-clean@492b2d2e2e77247bfd0b17eaa89a371b2f3430ee # v1 + - name: Preparing workspace. Setting environment. + run: | + echo "BENCHMARK_MODE=${{ github.event.inputs.compiler_llvm_benchmark_mode || '+M^B3' }}" >> $GITHUB_ENV + echo "BENCHMARK_PATH=${{ github.event.inputs.compiler_llvm_benchmark_path || 'tests/solidity/' }}" >> $GITHUB_ENV + echo "REFERENCE_BRANCH_NAME=${{ github.event.inputs.compiler_tester_reference_branch }}" >> $GITHUB_ENV + + - name: Getting the branch name (pull request) + if: github.event_name == 'pull_request' + shell: bash + run: echo "BRANCH_NAME=$(echo ${GITHUB_BASE_REF} | tr / -)" >> $GITHUB_ENV + + - name: Checking out the Solidity repository + uses: actions/checkout@v4 + with: + submodules: recursive + path: solidity + + - name: Checking out the compiler-tester reference + uses: actions/checkout@v4 + with: + repository: matter-labs/era-compiler-tester + ref: main + submodules: recursive + path: compiler-tester + + - name: Benchmarking the Solidity compiler reference + working-directory: compiler-tester + id: compiler_tester_run + run: | + cargo install compiler-llvm-builder + /usr/local/cargo/bin/zkevm-llvm clone && /usr/local/cargo/bin/zkevm-llvm build + + export RUST_BACKTRACE='full' + export LLVM_SYS_150_PREFIX="$(pwd)/target-llvm/target-final/" + cargo build --verbose --release --bin 'compiler-tester' + cargo build --verbose --release --manifest-path /usr/local/cargo/git/checkouts/era-compiler-solidity-*/*/Cargo.toml --target-dir './target-zksolc/' + cargo build --verbose --release --manifest-path /usr/local/cargo/git/checkouts/era-compiler-vyper-*/*/Cargo.toml --target-dir './target-zkvyper/' + + ./target/release/compiler-tester \ + --zksolc './target-zksolc/release/zksolc' \ + --zkvyper './target-zkvyper/release/zkvyper' \ + --path="${{ env.BENCHMARK_PATH || '' }}" \ + --mode="${{ env.BENCHMARK_MODE || '' }}" \ + --benchmark='reference.json' \ + --solc-bin-config-path="configs/solc-bin-zkevm-reference-${BRANCH_NAME}.json" + + - uses: actions/upload-artifact@v4 + with: + name: reference-benchmark + path: compiler-tester/reference.json + + benchmarks_analysis: + runs-on: [matterlabs-ci-runner] + needs: [benchmarks_candidate, benchmarks_reference] + container: + image: matterlabs/llvm_runner:latest + credentials: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + steps: + - uses: AutoModality/action-clean@492b2d2e2e77247bfd0b17eaa89a371b2f3430ee # v1 + - name: Getting the branch name (pull request) + if: github.event_name == 'pull_request' + shell: bash + run: echo "BRANCH_NAME=$(echo ${GITHUB_BASE_REF} | tr / -)" >> $GITHUB_ENV + + - name: Checking out the compiler-tester repository + uses: actions/checkout@v4 + with: + repository: matter-labs/era-compiler-tester + submodules: recursive + path: compiler-tester + + - uses: actions/download-artifact@v4 + with: + name: candidate-benchmark + path: compiler-tester + + - uses: actions/download-artifact@v4 + with: + name: reference-benchmark + path: compiler-tester + + - name: Comparing the benchmark results + id: compiler_tester_run + run: | + cd compiler-tester && \ + export RUST_BACKTRACE=full && \ + cargo run --release --bin benchmark-analyzer -- \ + --reference 'reference.json' \ + --candidate 'candidate.json' \ + --output-file 'result.txt' && \ + chown 1000:1000 result.txt + + - name: Posting the benchmark results to the step summary + run: | + printf "Benchmark results:\n" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + cat ./compiler-tester/result.txt >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + cat $GITHUB_STEP_SUMMARY > ./compiler-tester/result.txt + + - name: Posting the benchmark results to a PR comment + if: github.event_name == 'pull_request' + uses: mshick/add-pr-comment@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + message-path: ./compiler-tester/result.txt + + - uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + fields: repo,commit,author,action,eventName,ref,workflow,job,took,pullRequest # selectable (default: repo,message) + env: + SLACK_WEBHOOK_URL: ${{ secrets.COMPILER_CI_MATTERMOST_WEBHOOK }} # required + if: ${{ failure() || success() }} # Skip canceled jobs diff --git a/.github/workflows/build_and_release_binary.yaml b/.github/workflows/build_and_release_binary.yaml new file mode 100644 index 0000000000..7b8cac2cb3 --- /dev/null +++ b/.github/workflows/build_and_release_binary.yaml @@ -0,0 +1,368 @@ +name: Build and release binaries + +on: + workflow_dispatch: + pull_request: + push: + tags: + - "**" +jobs: + setup: + name: Setup + runs-on: [ubuntu-latest] + outputs: + release_version: ${{ steps.set.outputs.release_version }} + git_tag: ${{ steps.set.outputs.git_tag }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3 + + - name: Generate output with git tag + id: set + run: | + if [[ ${{ github.event_name }} != 'pull_request' ]]; then + version=$(cut -d "-" -f1 <<< ${GITHUB_REF#refs/*/}) + echo "release_version=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT + echo "git_tag=${version}" >> $GITHUB_OUTPUT + else + echo "release_version=${{ github.base_ref }}" >> $GITHUB_OUTPUT + echo "git_tag=${{ github.base_ref }}" >> $GITHUB_OUTPUT + fi + + + build_linux_amd64: + runs-on: [matterlabs-ci-runner] + needs: [setup] + container: + image: matterlabs/llvm_runner:latest + credentials: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + steps: + - name: Checkout source + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + submodules: recursive + ref: ${{ steps.set.outputs.release_version }} + + - name: Building the Solidity compiler + run: | + mkdir -p ./build + cd ./build + cmake .. -DCMAKE_BUILD_TYPE="Release" -DSOLC_VERSION_ZKEVM="${{ needs.setup.outputs.release_version }}" -DUSE_Z3=OFF + make -j$(nproc) + pwd + ls -la ./solc/ + ls -la ./solc/solc + + - name: Prepare binary file name + run: | + mkdir -p releases/linux-amd64 + ./build/solc/solc --version + mv ./build/solc/solc releases/linux-amd64/solc-linux-amd64-${{ needs.setup.outputs.release_version }} + + - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3 + with: + name: release_linux_amd64 + path: releases + + build_linux_arm64: + runs-on: [matterlabs-ci-runner-arm] + needs: [setup] + container: + image: matterlabs/llvm_runner:latest + credentials: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + steps: + - name: Checkout source + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + submodules: recursive + ref: ${{ steps.set.outputs.release_version }} + + - name: Building the Solidity compiler + run: | + mkdir -p ./build + cd ./build + cmake .. -DCMAKE_BUILD_TYPE="Release" -DSOLC_VERSION_ZKEVM="${{ needs.setup.outputs.release_version }}" -DUSE_Z3=OFF -DUSE_CVC4=OFF + make -j$(nproc) + pwd + ls -la ./solc/ + ls -la ./solc/solc + + - name: Prepare binary file name + run: | + mkdir -p releases/linux-arm64 + ./build/solc/solc --version + mv ./build/solc/solc releases/linux-arm64/solc-linux-arm64-${{ needs.setup.outputs.release_version }} + + - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3 + with: + name: release_linux_arm64 + path: releases + + build_macos_amd64: + runs-on: macos-12-xl + needs: [setup] + steps: + - name: Checkout source + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + submodules: recursive + ref: ${{ steps.set.outputs.release_version }} + + # It is needed as we use some commands which a deprecated in newer versions of boost + - name: Install BOOST + shell: zsh {0} + run: | + curl -L -o boost_1_71_0.tar.gz https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.gz + tar xzf ./boost_1_71_0.tar.gz + cd ./boost_1_71_0 + ./bootstrap.sh --prefix=/usr/local --with-python-version=2.7 + ./b2 -j$(sysctl -n hw.ncpu) + ./b2 install -j$(sysctl -n hw.ncpu) + + - name: Cmake gen + shell: zsh {0} + env: + CXXFLAGS: "-Wno-narrowing" + run: | + mkdir -p ./build + cd ./build + cmake .. -DCMAKE_BUILD_TYPE="Release" -DSOLC_VERSION_ZKEVM="${{ needs.setup.outputs.release_version }}" -DUSE_Z3=OFF + + - name: Building the Solidity compiler + run: | + cd ./build + make -j12 + ./solc/solc --version + + - name: Prepare binary file name + shell: zsh {0} + run: | + mkdir -p ./releases/macosx-amd64 + ./build/solc/solc --version + mv ./build/solc/solc ./releases/macosx-amd64/solc-macosx-amd64-${{ needs.setup.outputs.release_version }} + + - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3 + with: + name: release_macos_amd64 + path: releases + + build_macos_arm64: + runs-on: [self-hosted, macOS, ARM64] + needs: [setup] + steps: + - name: Clear repository + run: rm -rf ~/.gitconfig; rm -rf {*,.*} || true + + - name: Checkout source + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + submodules: recursive + ref: ${{ steps.set.outputs.release_version }} + + # It is needed as we use some commands which a deprecated in newer versions of boost + - name: Install BOOST + shell: zsh {0} + run: | + curl -L -o boost_1_71_0.tar.gz https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.gz + tar xzf ./boost_1_71_0.tar.gz + cd ./boost_1_71_0 + export BOOST_DIR=$(pwd)/boost + mkdir $BOOST_DIR + ./bootstrap.sh --prefix=$BOOST_DIR + ./b2 -j12 + ./b2 install -j12 + + - name: Cmake gen + shell: zsh {0} + env: + CXXFLAGS: "-Wno-narrowing" + run: | + mkdir -p ./build + cd ./build + cmake .. -DCMAKE_BUILD_TYPE="Release" -DSOLC_VERSION_ZKEVM="${{ needs.setup.outputs.release_version }}" -DUSE_Z3=OFF + + - name: Building the Solidity compiler + shell: zsh {0} + run: | + cd ./build + make -j12 + ./solc/solc --version + + - name: Prepare binary file name + shell: zsh {0} + run: | + mkdir -p ./releases/macosx-arm64 + ./build/solc/solc --version + mv ./build/solc/solc ./releases/macosx-arm64/solc-macosx-arm64-${{ needs.setup.outputs.release_version }} + + - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3 + with: + name: release_macos_arm64 + path: releases + + build_windows_amd64: + runs-on: windows-2019-github-hosted-16core + needs: [setup] + outputs: + version_to_skip: ${{ steps.compare_version.outputs.result }} + steps: + + # Had to install node to determine release version. + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + + - name: Install semver + run: npm install semver + + - name: Check that version is >= 0.6.0 + id: compare_version + uses: actions/github-script@v5 + with: + script: | + const semver = require('semver'); + const currentVersion = '${{ needs.setup.outputs.git_tag }}'; + const result = semver.lt(currentVersion, '0.6.0'); + console.log(`Is the version < 0.6.0? ${result}`); + return result; + result-encoding: string + + - name: Checkout source + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + if: steps.compare_version.outputs.result != 'true' + with: + submodules: recursive + ref: ${{ steps.set.outputs.release_version }} + + - name: Install LLVM and Clang + uses: KyleMayes/install-llvm-action@v1 + if: steps.compare_version.outputs.result != 'true' + with: + version: "15.0.7" + + - name: Prepare environment + if: steps.compare_version.outputs.result != 'true' + run: | + git config --global user.email "runner@github.com" + git fetch --all + # try to apply win patch + git cherry-pick 860226e25dca397b5afd70680530963712aff050 || git cherry-pick --abort + # latest llvm for MSVC + git clone -q --depth=1 --branch=main https://github.com/zufuliu/llvm-utils.git c:\projects\llvm-utils + Invoke-Item "c:\projects\llvm-utils\VS2017\install.bat" + clang --version + + + - name: Install windows Deps + if: steps.compare_version.outputs.result != 'true' + run: | + if ( -not (Test-Path "deps\boost") ) { + New-Item -ItemType Directory -Force -Path "deps" + + Invoke-WebRequest -URI "https://github.com/Kitware/CMake/releases/download/v3.27.1/cmake-3.27.1-windows-x86_64.zip" -OutFile cmake.zip + + tar -xf cmake.zip + mv cmake-3.27.1-windows-x86_64 "deps\cmake" + + # and serving it a page that requires JavaScript. + Invoke-WebRequest -URI "https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/boost_1_77_0.zip" -OutFile boost.zip + + tar -xf boost.zip + cd boost_1_77_0 + .\bootstrap.bat --with-toolset=clang + .\b2 -j4 -d0 toolset=clang cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" link=static runtime-link=static variant=release threading=multi address-model=64 --prefix="..\deps\boost" --with-filesystem --with-system --with-program_options --with-test --with-regex --with-thread install + if ( -not $? ) { throw "Error building boost." } + cd .. + } + + - name: Building the Solidity compiler + if: steps.compare_version.outputs.result != 'true' + run: | + $env:path += ";deps\cmake\bin\" + $env:CXXFLAGS="-Wno-narrowing -Qunused-arguments -Wno-everything -DBOOST_REGEX_NO_LIB -D_REGEX_MAX_STACK_COUNT=200000L -DJSON_USE_INT64_DOUBLE_CONVERSION -std=c++17 -stdlib=libc++" + mkdir build + cd build + $boost_dir=(Resolve-Path ..\deps\boost\lib\cmake\Boost-*) + cmake .. -D SOLC_VERSION_ZKEVM="${{ needs.setup.outputs.release_version }}" -D USE_Z3="OFF" -DBoost_DIR="$boost_dir\" -DBoost_USE_STATIC_RUNTIME=1 -DBoost_USE_STATIC_LIBS=1 -DBoost_COMPILER=clang15 -T LLVM_v142 -DPEDANTIC=OFF -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded + cmake --build . -j 10 --target install --config Release + + - name: Prepare binary file name + if: steps.compare_version.outputs.result != 'true' + run: | + mkdir -p releases\windows-amd64 + ls .\build\solc\Release\ + .\build\solc\Release\solc.exe --version + mv .\build\solc\Release\solc.exe releases\windows-amd64\solc-windows-amd64-${{ needs.setup.outputs.release_version }}.exe + + - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3 + if: steps.compare_version.outputs.result != 'true' + with: + name: release_windows_amd64 + path: releases + + prepare-release: + runs-on: [ matterlabs-default-infra-runners ] + if: startsWith(github.ref, 'refs/tags/') + needs: + - setup + - build_macos_arm64 + - build_macos_amd64 + - build_linux_arm64 + - build_linux_amd64 + - build_windows_amd64 + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ steps.set.outputs.release_version }} + + - name: Download artifact macos_arm64 + uses: actions/download-artifact@v3 + with: + name: release_macos_arm64 + path: releases + + - name: Download artifact macosx_amd64 + uses: actions/download-artifact@v3 + with: + name: release_macos_amd64 + path: releases + + - name: Download artifact linux_amd64 + uses: actions/download-artifact@v3 + with: + name: release_linux_amd64 + path: releases + + - name: Download artifact linux_arm64 + uses: actions/download-artifact@v3 + with: + name: release_linux_arm64 + path: releases + + - name: Download artifact release_windows_amd64 + if: needs.build_windows_amd64.outputs.version_to_skip != 'true' + uses: actions/download-artifact@v3 + with: + name: release_windows_amd64 + path: releases + + - name: Generate changelog + id: changelog + shell: bash + run: | + awk '/###/ {flag=!flag; if (seen++) exit; next} flag' ./Changelog.md > tmp_changelog.txt + + - name: Prepare release + uses: softprops/action-gh-release@v1 + with: + generate_release_notes: false + name: zkVM solc ${{ needs.setup.outputs.release_version }} + body_path: ./tmp_changelog.txt + tag_name: ${{ needs.setup.outputs.release_version }} + files: | + releases/**/** diff --git a/.github/workflows/buildpack-deps.yml b/.github/workflows/buildpack-deps.yml deleted file mode 100644 index 6a261bd2eb..0000000000 --- a/.github/workflows/buildpack-deps.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: buildpack-deps - -on: - pull_request: - branches: [ develop ] - paths: - - 'scripts/docker/buildpack-deps/Dockerfile.emscripten' - - 'scripts/docker/buildpack-deps/Dockerfile.ubuntu.clang.ossfuzz' - - 'scripts/docker/buildpack-deps/Dockerfile.ubuntu2004' - - 'scripts/docker/buildpack-deps/Dockerfile.ubuntu2204.clang' - - 'scripts/docker/buildpack-deps/Dockerfile.ubuntu2204' - -jobs: - buildpack-deps: - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} - DOCKER_REPOSITORY: solbuildpackpusher/solidity-buildpack-deps - IMAGE_NAME: buildpack-deps - - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - image_variant: [emscripten, ubuntu.clang.ossfuzz, ubuntu2004, ubuntu2204.clang, ubuntu2204] - - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Upgrade ${{ env.IMAGE_NAME }}-${{ matrix.image_variant }} - run: | - echo ${DOCKERHUB_TOKEN} | docker login -u solbuildpackpusher --password-stdin - scripts/ci/docker_upgrade.sh ${{ env.IMAGE_NAME }} ${{ matrix.image_variant }} ${{ env.DOCKER_REPOSITORY }} - docker logout - - - name: comment PR - if: "env.DOCKER_IMAGE" - # NOTE: Can't update to v1.3.1 due to an error: `/entrypoint.sh:5:in 'require_relative': cannot load such file -- /lib/github (LoadError)` - uses: unsplash/comment-on-pr@ffe8f97ccc63ce12c3c23c6885b169db67958d3b #v1.3.0 - with: - msg: "`${{ env.DOCKER_IMAGE }} ${{ env.DOCKER_REPO_DIGEST }}`." - check_for_duplicate_msg: false - diff --git a/.github/workflows/secrets_scanner.yaml b/.github/workflows/secrets_scanner.yaml new file mode 100644 index 0000000000..d0fea22668 --- /dev/null +++ b/.github/workflows/secrets_scanner.yaml @@ -0,0 +1,17 @@ +name: Leaked Secrets Scan +on: [pull_request] +jobs: + TruffleHog: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: TruffleHog OSS + uses: trufflesecurity/trufflehog@11394ea318a12a5bf99c1b0cb7ba5e44b3c7a79c # v3.63.2 + with: + path: ./ + base: ${{ github.event.repository.default_branch }} + head: HEAD + extra_args: --debug --only-verified --exclude-paths=.truffleignore diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100644 index d982c43f2b..0000000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Check stale issues and pull requests - -on: - workflow_dispatch: - schedule: - - cron: '0 12 * * *' - -permissions: - issues: write - pull-requests: write - -env: - BEFORE_ISSUE_STALE: 90 - BEFORE_ISSUE_CLOSE: 7 - BEFORE_PR_STALE: 14 - BEFORE_PR_CLOSE: 7 - -jobs: - stale: - runs-on: ubuntu-latest - steps: - - uses: actions/stale@v6 - with: - debug-only: false - days-before-issue-stale: ${{ env.BEFORE_ISSUE_STALE }} - days-before-issue-close: ${{ env.BEFORE_ISSUE_CLOSE }} - stale-issue-message: | - This issue has been marked as stale due to inactivity for the last ${{ env.BEFORE_ISSUE_STALE }} days. - It will be automatically closed in ${{ env.BEFORE_ISSUE_CLOSE }} days. - close-issue-message: | - Hi everyone! This issue has been automatically closed due to inactivity. - If you think this issue is still relevant in the latest Solidity version and you have something to [contribute](https://docs.soliditylang.org/en/latest/contributing.html), feel free to reopen. - However, unless the issue is a concrete proposal that can be implemented, we recommend starting a language discussion on the [forum](https://forum.soliditylang.org) instead. - ascending: true - stale-issue-label: stale - close-issue-label: 'closed due inactivity' - exempt-issue-labels: 'bug :bug:,epic,roadmap,selected for development,must have,must have eventually,smt' - stale-pr-message: | - This pull request is stale because it has been open for ${{ env.BEFORE_PR_STALE }} days with no activity. - It will be closed in ${{ env.BEFORE_PR_CLOSE }} days unless the `stale` label is removed. - close-pr-message: | - This pull request was closed due to a lack of activity for ${{ env.BEFORE_PR_CLOSE }} days after it was stale. - stale-pr-label: stale - close-pr-label: closed-due-inactivity - days-before-pr-stale: ${{ env.BEFORE_PR_STALE }} - days-before-pr-close: ${{ env.BEFORE_PR_CLOSE }} - exempt-pr-labels: 'external contribution :star:,roadmap,epic' - exempt-draft-pr: false - exempt-all-milestones: true - remove-stale-when-updated: true - operations-per-run: 256 diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000000..62bdb48cd9 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,74 @@ +name: Integration testing + +on: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + testing: + runs-on: [self-hosted, ci-runner-compiler] + container: + image: matterlabs/llvm_runner:latest + credentials: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + steps: + - name: Getting the branch name (pull request) + if: github.event_name == 'pull_request' + shell: bash + run: echo "BRANCH_NAME=$(echo ${GITHUB_BASE_REF} | tr / -)" >> $GITHUB_ENV + + - name: Checking out the Solidity repository + uses: actions/checkout@v4 + with: + submodules: recursive + path: solidity + + - name: Checking out the compiler-tester repository + uses: actions/checkout@v4 + with: + repository: matter-labs/era-compiler-tester + path: compiler-tester + submodules: recursive + + - name: Building the Solidity compiler + working-directory: solidity + run: | + mkdir -p ./build + cd ./build + cmake .. -DCMAKE_BUILD_TYPE='Release' -DSOLC_VERSION_ZKEVM='1.0.0-lts' -DPEDANTIC=OFF -DCMAKE_CXX_FLAGS='-w' -DUSE_Z3=OFF -DUSE_CVC4=OFF + make -j$(nproc) + + - name: Building and running the compiler tester + id: compiler_tester_run + working-directory: compiler-tester + run: | + mkdir -p './solc-bin/' + cp '../solidity/build/solc/solc' "./solc-bin/solc-${BRANCH_NAME}" + chmod +x "./solc-bin/solc-${BRANCH_NAME}" + + cargo install compiler-llvm-builder + /usr/local/cargo/bin/zkevm-llvm clone && /usr/local/cargo/bin/zkevm-llvm build + + export RUST_BACKTRACE='full' + export LLVM_SYS_150_PREFIX="$(pwd)/target-llvm/target-final/" + cargo build --verbose --release --bin 'compiler-tester' + cargo build --verbose --release --manifest-path /usr/local/cargo/git/checkouts/era-compiler-solidity-*/*/Cargo.toml --target-dir './target-zksolc/' + cargo build --verbose --release --manifest-path /usr/local/cargo/git/checkouts/era-compiler-vyper-*/*/Cargo.toml --target-dir './target-zkvyper/' + + ./target/release/compiler-tester \ + --zksolc './target-zksolc/release/zksolc' \ + --zkvyper './target-zkvyper/release/zkvyper' \ + --path='tests/solidity/' \ + --solc-bin-config-path="configs/solc-bin-zkevm-candidate-${BRANCH_NAME}.json" + + - uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + fields: repo,commit,author,action,eventName,ref,workflow,job,took,pullRequest # selectable (default: repo,message) + env: + SLACK_WEBHOOK_URL: ${{ secrets.COMPILER_CI_MATTERMOST_WEBHOOK }} # required + if: ${{ failure() || success() }} # Skip canceled jobs diff --git a/.github/workflows/welcome-external-pr.yml b/.github/workflows/welcome-external-pr.yml deleted file mode 100644 index ac8d1362ea..0000000000 --- a/.github/workflows/welcome-external-pr.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: External contributor greeter - -on: - pull_request_target: - types: - - opened - -env: - DRY_RUN: false - -jobs: - comment-external-pr: - runs-on: ubuntu-latest - steps: - # Note: this step requires that the INTERNAL_CONTRIBUTORS environment variable - # is already defined in the repository with the current json list of internal contributors. - - name: Comment on external contribution PR - if: "!contains(fromJSON(vars.INTERNAL_CONTRIBUTORS), github.event.pull_request.user.login)" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR: ${{ github.event.pull_request.html_url }} - run: | - echo "Commenting in a newly submitted or reopened external PR: $PR" - if [[ $DRY_RUN == 'false' ]]; then - gh pr edit "$PR" --add-label "external contribution :star:" - comment_body=( - "Thank you for your contribution to the Solidity compiler! A team member will follow up shortly." - "\n\n" - "If you haven't read our [contributing guidelines](https://docs.soliditylang.org/en/latest/contributing.html) and our " - "[review checklist](https://github.com/ethereum/solidity/blob/develop/ReviewChecklist.md) before, " - "please do it now, this makes the reviewing process and accepting your contribution smoother." - "\n\n" - "If you have any questions or need our help, feel free to post them in the PR or talk to us directly on the " - "[#solidity-dev](https://matrix.to/#/#ethereum_solidity-dev:gitter.im) channel on Matrix." - ) - gh pr comment $PR --body "$(IFS='' ; echo -e "${comment_body[*]}")" - fi diff --git a/.truffleignore b/.truffleignore new file mode 100644 index 0000000000..3b2af7f987 --- /dev/null +++ b/.truffleignore @@ -0,0 +1 @@ +test/benchmarks/chains.sol diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 4c75649ae8..0000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,74 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at solidity@ethereum.org. -To report an issue involving the Solidity team please email JosΓ© Pedro Cabrita at zepedro@ethereum.org. -All complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org diff --git a/CODING_STYLE.md b/CODING_STYLE.md deleted file mode 100644 index 5b9129fbd0..0000000000 --- a/CODING_STYLE.md +++ /dev/null @@ -1,243 +0,0 @@ -## 0. Formatting - -**GOLDEN RULE**: Follow the style of the existing code when you make changes. - -1. Use tabs for leading indentation: - - tab stops are every 4 characters (only relevant for line length). - - one indentation level -> exactly one byte (i.e. a tab character) in the source file. -2. Line widths: - - Lines should be at most 99 characters wide to make diff views readable and reduce merge conflicts. - - Lines of comments should be formatted according to ease of viewing, but simplicity is to be preferred over beauty. -3. Single-statement blocks should not have braces, unless required for clarity. -4. Never place condition bodies on same line as condition. -5. Space between keyword and opening parenthesis, but not following opening parenthesis or before final parenthesis. -6. No spaces for unary operators, `->` or `.`. -7. No space before `:` but one after it, except in the ternary operator: one on both sides. -8. Add spaces around all other operators. -9. Braces, when used, always have their own lines and are at same indentation level as "parent" scope. -10. If lines are broken, a list of elements enclosed with parentheses (of any kind) and separated by a separator (of any kind) are formatted such that there is exactly one element per line, followed by the separator, the opening parenthesis is on the first line, followed by a line break and the closing parenthesis is on a line of its own unindented). See example below. - -Yes: -```cpp -if (a == b[i]) - printf("Hello\n"); // NOTE spaces used instead of tab here for clarity - first byte should be '\t'. -foo->bar( - someLongVariableName, - anotherLongVariableName, - anotherLongVariableName, - anotherLongVariableName, - anotherLongVariableName -); -cout << - "some very long string that contains completely irrelevant " << - "text that talks about this and that and contains the words " << - "\"lorem\" and \"ipsum\"" << - endl; -``` - -No: -```cpp -if( a==b[ i ] ) { printf ("Hello\n"); } -foo->bar(someLongVariableName, - anotherLongVariableName, - anotherLongVariableName, - anotherLongVariableName, - anotherLongVariableName); -cout << "some very long string that contains completely irrelevant text that talks about this and that and contains the words \"lorem\" and \"ipsum\"" << endl; -``` - -To set indentation and tab width settings uniformly, the repository contains an [EditorConfig](https://editorconfig.org/) [`.editorconfig`](https://github.com/ethereum/solidity/blob/develop/.editorconfig) file, which describes some of the styles used and which is recognized by many IDE's and editors. - -## 1. Namespaces - -1. No `using namespace` declarations in header files. -2. `using namespace solidity;` and other project local namespaces is fine in cpp files, and generally encouraged. -3. Avoid `using namespace` at file level for third party libraries, such as boost, ranges, etc. -4. All symbols should be declared in a namespace except for final applications. -5. Use anonymous namespaces for helpers whose scope is a cpp file only. -6. Preprocessor symbols should be prefixed with the namespace in all-caps and an underscore. - -Only in the header: -```cpp -#include -namespace myNamespace -{ -std::tuple meanAndSigma(std::vector const& _v); -} -``` - -## 2. Preprocessor - -1. File comment is always at top, and includes: - - Copyright - - License (e.g. see COPYING) -2. Never use `#ifdef`/`#define`/`#endif` file guards. Prefer `#pragma` once as first line below file comment. -3. Prefer static constexpr variables to value macros. -4. Prefer inline constexpr functions to function macros. -5. Split complex macro on multiple lines with `\`. - -## 3. Capitalization - -**GOLDEN RULE**: Preprocessor: `ALL_CAPS`; C++: `camelCase`. - -1. Use camelCase for splitting words in names, except where obviously extending STL/boost functionality in which case follow those naming conventions. -2. The following entities' first alpha is upper case: - - Type names - - Template parameters - - Enum members - - static const variables that form an external API. -3. All preprocessor symbols (macros, macro arguments) in full uppercase with underscore word separation. - -All other entities' first alpha is lower case. - -## 4. Variable prefixes - -1. Leading underscore "_" to parameter names: - - Exception: "o_parameterName" when it is used exclusively for output. See 6(f). - - Exception: "io_parameterName" when it is used for both input and output. See 6(f). -2. Leading "g_" to global (non-const) variables. -3. Leading "s_" to static (non-const, non-global) variables. - -## 5. Assertions - -Use `solAssert` and `solUnimplementedAssert` generously to check assumptions that span across different parts of the code base, for example before dereferencing a pointer. - -## 6. Declarations - -1. {Typename} + {qualifiers} + {name}. -2. Only one per line. -3. Associate */& with type, not variable (at ends with parser, but more readable, and safe if in conjunction with (b)). -4. Favour declarations close to use; do not habitually declare at top of scope ala C. -5. Pass non-trivial parameters as const reference, unless the data is to be copied into the function, then either pass by const reference or by value and use std::move. -6. If a function returns multiple values, use std::tuple (std::pair acceptable) or better introduce a struct type. Do not use */& arguments. -7. Use parameters of pointer type only if ``nullptr`` is a valid argument, use references otherwise. Often, ``std::optional`` is better suited than a raw pointer. -8. Never use a macro where adequate non-preprocessor C++ can be written. -9. Only use ``auto`` if the type is very long and rather irrelevant. -10. Do not pass bools: prefer enumerations instead. -11. Prefer enum class to straight enum. -12. Always initialize POD variables, even if their value is overwritten later. - -Yes: -```cpp -enum class Accuracy -{ - Approximate, - Exact -}; -struct MeanSigma -{ - float mean = 0.0f; - float standardDeviation = 1.0f; -}; -double const d = 0; -int i = 0; -int j = 0; -char* s = nullptr; -MeanAndSigma ms meanAndSigma(std::vector const& _v, Accuracy _a); -Derived* x = dynamic_cast(base); -for (auto i = x->begin(); i != x->end(); ++i) {} -``` - -No: -```cpp -const double d = 0; -int i, j; -char *s; -float meanAndSigma(std::vector _v, float* _sigma, bool _approximate); -Derived* x(dynamic_cast(base)); -for (map::iterator i = l.begin(); i != l.end(); ++l) {} -``` - -## 7. Structs & classes - -1. Structs to be used when all members public and no virtual functions: - - In this case, members should be named naturally and not prefixed with `m_`. -2. Classes to be used in all other circumstances. - -## 8. Members - -1. One member per line only. -2. Private, non-static, non-const fields prefixed with `m_`. -3. Avoid public fields, except in structs. -4. Use override, final and const as much as possible. -5. No implementations with the class declaration, except: - - template or force-inline method (though prefer implementation at bottom of header file). - - one-line implementation (in which case include it in same line as declaration). -6. For a property `foo` - - Member: `m_foo` - - Getter: `foo()` [ also: for booleans, `isFoo()` ] - - Setter: `setFoo()` - -## 9. Naming - -1. Avoid unpronounceable names. -2. Names should be shortened only if they are extremely common, but shortening should be generally avoided -3. Avoid prefixes of initials (e.g. do not use `IMyInterface`, `CMyImplementation`) -4. Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments: - - A dictionary and thesaurus are your friends; - - Spell correctly; - - Think carefully about the class's purpose; - - Imagine it as an isolated component to try to decontextualise it when considering its name; - - Don't be trapped into naming it (purely) in terms of its implementation. - -## 10. Type definitions - -1. Prefer `using` to `typedef`. e.g. `using ints = std::vector;` rather than typedef `std::vector ints;` -2. Generally avoid shortening a standard form that already includes all important information: - - e.g. stick to `shared_ptr` rather than shortening to `ptr`. -3. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently: - - e.g. `using Guard = std::lock_guard;` ///< Guard is used throughout the codebase since it is clear in meaning and used commonly. -4. In general expressions should be roughly as important/semantically meaningful as the space they occupy. -5. Avoid introducing aliases for types unless they are very complicated. Consider the number of items a brain can keep track of at the same time. - -## 11. Commenting - -1. Comments should be doxygen-compilable, using @notation rather than \notation. -2. Document the interface, not the implementation: - - Documentation should be able to remain completely unchanged, even if the method is reimplemented; - - Comment in terms of the method properties and intended alteration to class state (or what aspects of the state it reports); - - Be careful to scrutinise documentation that extends only to intended purpose and usage; - - Reject documentation that is simply an English transaction of the implementation. -3. Avoid in-code comments. Instead, try to extract blocks of functionality into functions. This often already eliminates the need for an in-code comment. - -## 12. Include Headers - -1. Includes should go in increasing order of generality (`libsolidity` -> `libevmasm` -> `libsolutil` -> `boost` -> `STL`). -2. The corresponding `.h` file should be the first include in the respective `.cpp` file. -3. Insert empty lines between blocks of include files. - -Example: -```cpp -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include - -#include -#include -``` - -See [this issue](https://stackoverflow.com/questions/614302/c-header-order/614333#614333 "C header order") for the reason: this makes it easier to find missing includes in header files. - -## 13. Recommended reading - -- Herb Sutter and Bjarne Stroustrup: - - [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md) - -- Herb Sutter and Andrei Alexandrescu: - - "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices" - -- Scott Meyers: - - "Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition)" - - "More Effective C++: 35 New Ways to Improve Your Programs and Designs" - - "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e071a2290d..152aec38d3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,43 @@ # Contribution Guidelines -Please see our contribution guidelines in [the Solidity documentation](https://docs.soliditylang.org/en/latest/contributing.html). +Hello! Thanks for your interest in joining the mission to accelerate the mass adoption of crypto for personal +sovereignty! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes! -Thank you for your help! +## Ways to contribute + +There are many ways to contribute to the ZK Stack: + +1. Open issues: if you find a bug, have something you believe needs to be fixed, or have an idea for a feature, please + open an issue. +2. Add color to existing issues: provide screenshots, code snippets, and whatever you think would be helpful to resolve + issues. +3. Resolve issues: either by showing an issue isn't a problem and the current state is ok as is or by fixing the problem + and opening a PR. +4. Report security issues, see [our security policy](./github/SECURITY.md). +5. [Join the team!](https://matterlabs.notion.site/Shape-the-future-of-Ethereum-at-Matter-Labs-dfb3b5a037044bb3a8006af2eb0575e0) + +## Fixing issues + +To contribute code fixing issues, please fork the repo, fix an issue, commit, add documentation as per the PR template, +and the repo's maintainers will review the PR. +[here](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) +for guidance how to work with PRs created from a fork. + +## Licenses + +If you contribute to this project, your contributions will be made to the project under both Apache 2.0 and the MIT +license. + +## Resources + +We aim to make it as easy as possible to contribute to the mission. This is still WIP, and we're happy for contributions +and suggestions here too. Some resources to help: + +1. [zkSync Era docs!](https://era.zksync.io/docs/) +2. Company links can be found in the [repo's readme](README.md) + +## Code of Conduct + +Be polite and respectful. + +### Thank you diff --git a/Changelog.md b/Changelog.md index d36470b016..aae49bdbd3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,16 @@ +### solc v0.8.24-legacy for zkVM - revision 1.0.0 - Legacy edition + +This release has changes in the lowering of EVM assembly in order to get the zkSync's translator (targeting LLVM IR) to work correctly. + +Added: +* A new metadata output field called "extraMetadata" in standard-json that stores information of recursive functions + +Changed: +* Internal function pointers are lowered to static jump tables +* Disabled evmasm optimizations to avoid any potential invalidation of the new metadata for recursive functions +* Minor changes in the control-flow when lowering a try-catch block + + ### 0.8.24 (2024-01-25) Language Features: diff --git a/README.md b/README.md index e64f8cbfd3..bfb637ed21 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,32 @@ -# The Solidity Contract-Oriented Programming Language +# zkSync Era: Solidity Compiler -[![Matrix Chat](https://img.shields.io/badge/Matrix%20-chat-brightgreen?style=plastic&logo=matrix)](https://matrix.to/#/#ethereum_solidity:gitter.im) -[![Gitter Chat](https://img.shields.io/badge/Gitter%20-chat-brightgreen?style=plastic&logo=gitter)](https://gitter.im/ethereum/solidity) -[![SolidityΒ Forum](https://img.shields.io/badge/Solidity_Forum%20-discuss-brightgreen?style=plastic&logo=discourse)](https://forum.soliditylang.org/) -[![X Follow](https://img.shields.io/twitter/follow/solidity_lang?style=plastic&logo=x)](https://X.com/solidity_lang) -[![Mastodon Follow](https://img.shields.io/mastodon/follow/000335908?domain=https%3A%2F%2Ffosstodon.org%2F&logo=mastodon&style=plastic)](https://fosstodon.org/@solidity) +[![Logo](eraLogo.svg)](https://zksync.io/) -You can talk to us on Gitter and Matrix, tweet at us on X (previously Twitter) or create a new topic in the Solidity forum. Questions, feedback, and suggestions are welcome! +zkSync Era is a layer 2 rollup that uses zero-knowledge proofs to scale Ethereum without compromising on security +or decentralization. As it's EVM-compatible (with Solidity/Vyper), 99% of Ethereum projects can redeploy without +needing to refactor or re-audit any code. zkSync Era also uses an LLVM-based compiler that will eventually enable +developers to write smart contracts in popular languages such as C++ and Rust. -Solidity is a statically typed, contract-oriented, high-level language for implementing smart contracts on the Ethereum platform. - -For a good overview and starting point, please check out the official [Solidity Language Portal](https://soliditylang.org). - -## Table of Contents - -- [Background](#background) -- [Build and Install](#build-and-install) -- [Example](#example) -- [Documentation](#documentation) -- [Development](#development) -- [Maintainers](#maintainers) -- [License](#license) -- [Security](#security) - -## Background - -Solidity is a statically-typed curly-braces programming language designed for developing smart contracts -that run on the Ethereum Virtual Machine. Smart contracts are programs that are executed inside a peer-to-peer -network where nobody has special authority over the execution, and thus they allow anyone to implement tokens of value, -ownership, voting, and other kinds of logic. - -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). - -## Build and Install - -Instructions about how to build and install the Solidity compiler can be -found in the [Solidity documentation](https://docs.soliditylang.org/en/latest/installing-solidity.html#building-from-source). - - -## Example - -A "Hello World" program in Solidity is of even less use than in other languages, but still: - -```solidity -// SPDX-License-Identifier: MIT -pragma solidity >=0.6.0 <0.9.0; - -contract HelloWorld { - function helloWorld() external pure returns (string memory) { - return "Hello, World!"; - } -} -``` - -To get started with Solidity, you can use [Remix](https://remix.ethereum.org/), which is a -browser-based IDE. Here are some example contracts: - -1. [Voting](https://docs.soliditylang.org/en/latest/solidity-by-example.html#voting) -2. [Blind Auction](https://docs.soliditylang.org/en/latest/solidity-by-example.html#blind-auction) -3. [Safe remote purchase](https://docs.soliditylang.org/en/latest/solidity-by-example.html#safe-remote-purchase) -4. [Micropayment Channel](https://docs.soliditylang.org/en/latest/solidity-by-example.html#micropayment-channel) - -## Documentation - -The Solidity documentation is hosted using [Read the Docs](https://docs.soliditylang.org). - -## Development - -Solidity is still under development. Contributions are always welcome! -Please follow the -[Developers Guide](https://docs.soliditylang.org/en/latest/contributing.html) -if you want to help. - -You can find our current feature and bug priorities for forthcoming -releases in the [projects section](https://github.com/ethereum/solidity/projects). - -## Maintainers -The Solidity programming language and compiler are open-source community projects governed by a core team. -The core team is sponsored by the [Ethereum Foundation](https://ethereum.foundation/). +This repository contains the Solidity compiler and language tuned for EraVM. ## License + Solidity is licensed under [GNU General Public License v3.0](LICENSE.txt). Some third-party code has its [own licensing terms](cmake/templates/license.h.in). -## Security +## Official Links + +- [Website](https://zksync.io/) +- [GitHub](https://github.com/matter-labs) +- [Twitter](https://twitter.com/zksync) +- [Twitter for Devs](https://twitter.com/zkSyncDevs) +- [Discord](https://join.zksync.dev/) + +## Disclaimer -The security policy may be [found here](SECURITY.md). +zkSync Era has been through extensive testing and audits, and although it is live, it is still in alpha state and +will undergo further audits and bug bounty programs. We would love to hear our community's thoughts and suggestions +about it! +It's important to note that forking it now could potentially lead to missing important +security updates, critical features, and performance improvements. diff --git a/ReleaseChecklist.md b/ReleaseChecklist.md deleted file mode 100644 index 167417a95d..0000000000 --- a/ReleaseChecklist.md +++ /dev/null @@ -1,118 +0,0 @@ -## Checklist for making a release: - -### Requirements - - [ ] GitHub account with access to [solidity](https://github.com/ethereum/solidity), [solc-js](https://github.com/ethereum/solc-js), - [solc-bin](https://github.com/ethereum/solc-bin), [solidity-website](https://github.com/ethereum/solidity-website). - - [ ] DockerHub account with push rights to the [``solc`` image](https://hub.docker.com/r/ethereum/solc). - - [ ] Launchpad (Ubuntu One) account with a membership in the ["Ethereum" team](https://launchpad.net/~ethereum) and - a gnupg key for your email in the ``ethereum.org`` domain (has to be version 1, gpg2 won't work). - - [ ] Ubuntu/Debian dependencies of the PPA scripts: ``devscripts``, ``debhelper``, ``dput``, ``git``, ``wget``, ``ca-certificates``. - - [ ] [npm Registry](https://www.npmjs.com) account added as a collaborator for the [``solc`` package](https://www.npmjs.com/package/solc). - - [ ] Access to the [solidity_lang Twitter account](https://twitter.com/solidity_lang). - - [ ] [Reddit](https://www.reddit.com) account that is at least 10 days old with a minimum of 20 comment karma (``/r/ethereum`` requirements). - -### Pre-flight checks -At least a day before the release: - - [ ] Run ``make linkcheck`` from within ``docs/`` and fix any broken links it finds. - Ignore false positives caused by ``href`` anchors and dummy links not meant to work. - - [ ] Double-check that [the most recent docs builds at readthedocs](https://readthedocs.org/projects/solidity/builds/) succeeded. - - [ ] Make sure that all merged PRs that should have changelog entries do have them. - - [ ] Rerun CI on the top commits of main branches in all repositories that do not have daily activity by creating a test branch or PR: - - [ ] ``solc-js`` - - [ ] ``solc-bin`` (make sure the bytecode comparison check did run) - - [ ] (Optional) Create a prerelease in our Ubuntu PPA by following the steps in the PPA section below on ``develop`` rather than on a tag. - This is recommended especially when dealing with PPA for the first time, when we add a new Ubuntu version or when the PPA scripts were modified in this release cycle. - - [ ] Verify that the release tarball of ``solc-js`` works. - Bump version locally, add ``soljson.js`` from CI, build it, compare the file structure with the previous version, install it locally and try to use it. - -### Drafts -At least a day before the release: - - [ ] Create a draft PR to sort the changelog. - - [ ] Create draft PRs to bump version in ``solidity`` and ``solc-js``. - **Note**: The ``solc-js`` PR won't pass CI checks yet because it depends on the soljson binary from ``solc-bin``. - - [ ] Create a draft of the release on github. - - [ ] Create a draft PR to update soliditylang.org. - - [ ] Create drafts of blog posts. - - [ ] Prepare drafts of Twitter, Reddit and Solidity Forum announcements. - -### Blog Post - - [ ] Create a post on [solidity-website](https://github.com/ethereum/solidity-website/tree/main/src/posts) in the ``Releases`` category and explain some of the new features or concepts. - - [ ] Create a post on [solidity-website](https://github.com/ethereum/solidity-website/tree/main/src/posts) in the ``Security Alerts`` category in case of important bug(s). - -### Changelog - - [ ] Sort the changelog entries alphabetically and correct any errors you notice. Commit it. - - [ ] Update the changelog to include a release date. - - [ ] Run ``scripts/update_bugs_by_version.py`` to regenerate ``bugs_by_version.json`` from the changelog and ``bugs.json``. - Make sure that the resulting ``bugs_by_version.json`` has a new, empty entry for the new version. - - [ ] Commit changes, create a pull request and wait for the tests. Then merge it. - - [ ] Copy the changelog into the release blog post. - -### Create the Release - - [ ] Create a [release on GitHub](https://github.com/ethereum/solidity/releases/new). - Set the target to the ``develop`` branch and the tag to the new version, e.g. ``v0.8.5``. - Include the following warning: ``**The release is still in progress and the binaries may not yet be available from all sources.**``. - Do not publish it yet - click the ``Save draft`` button instead. - - [ ] Thank voluntary contributors in the GitHub release notes. - Use ``scripts/list_contributors.sh v`` to get initial list of names. - Remove different variants of the same name manually before using the output. - - [ ] Check that all tests on the latest commit in ``develop`` are green. - - [ ] Click the ``Publish release`` button on the release page, creating the tag. - **Important: Must not be done before all the PRs, including changelog cleanup and date, are merged.** - - [ ] Wait for the CI runs on the tag itself. - -### Upload Release Artifacts and Publish Binaries - - [ ] Switch to the tag that archives have to be created for. - - [ ] Create the ``prerelease.txt`` file: (``echo -n > prerelease.txt``). - - [ ] Run ``scripts/create_source_tarball.sh`` while being on the tag to create the source tarball. This will create the tarball in a directory called ``upload``. - - [ ] Take the tarball from the upload directory (its name should be ``solidity_x.x.x.tar.gz``, otherwise ``prerelease.txt`` was missing in the step before) and upload the source tarball to the release page. - - [ ] Take the ``github-binaries.tar`` tarball from ``c_release_binaries`` run of the tagged commit in circle-ci and add all binaries from it to the release page. - Make sure it contains four binaries: ``solc-windows.exe``, ``solc-macos``, ``solc-static-linux`` and ``soljson.js``. - - [ ] Take the ``solc-bin-binaries.tar`` tarball from ``c_release_binaries`` run of the tagged commit in circle-ci and add all binaries from it to solc-bin. - - [ ] Run ``npm run update -- --reuse-hashes`` in ``solc-bin`` and verify that the script has updated ``list.js``, ``list.txt`` and ``list.json`` files correctly and that symlinks to the new release have been added in ``solc-bin/wasm/`` and ``solc-bin/emscripten-wasm32/``. - - [ ] Create a pull request in solc-bin and merge. - -### Homebrew and MacOS - - [ ] Update the version and the hash (``sha256sum solidity_$VERSION.tar.gz``) in the [``solidity`` formula in Homebrew core repository](https://github.com/Homebrew/homebrew-core/blob/master/Formula/solidity.rb). - -### Docker - - [ ] Run ``./scripts/docker_deploy_manual.sh v$VERSION``. - -### PPA - - [ ] Create ``.release_ppa_auth`` at the root of your local Solidity checkout and set ``LAUNCHPAD_EMAIL`` and ``LAUNCHPAD_KEYID`` to your key's email and key id. - - [ ] Double-check that the ``DISTRIBUTIONS`` list in ``scripts/release_ppa.sh`` and ``scripts/deps-ppa/static_z3.sh`` contains the most recent versions of Ubuntu. - - [ ] Make sure the [``~ethereum/cpp-build-deps`` PPA repository](https://launchpad.net/~ethereum/+archive/ubuntu/cpp-build-deps) contains ``libz3-static-dev builds`` for all current versions of Ubuntu. - Note that it may be included in the ``z3-static`` multipackage (follow the ``View package details`` link to check). - If not present, run ``scripts/deps-ppa/static_z3.sh`` and wait for the builds to succeed before continuing. - - [ ] Run ``scripts/release_ppa.sh v$VERSION`` to create the PPA release. - This will create a single package containing static binary for older Ubuntu versions in the [``~ethereum/ethereum-static`` PPA](https://launchpad.net/~ethereum/+archive/ubuntu/ethereum-static) - and separate packages with dynamically-linked binaries for recent versions (those listed in ``DISTRIBUTIONS``) in the [``~ethereum/ethereum`` PPA](https://launchpad.net/~ethereum/+archive/ubuntu/ethereum). - - [ ] Wait for the build to be finished and published for *all architectures* (currently we only build for ``amd64``, but we may add ``arm`` in the future). - **SERIOUSLY: DO NOT PROCEED EARLIER!!!** - - [ ] *After* the package with the static build is *published*, use it to create packages for older Ubuntu versions. - Copy the static package to the [``~ethereum/ethereum`` PPA](https://launchpad.net/~ethereum/+archive/ubuntu/ethereum) - for the destination series ``Trusty``, ``Xenial`` and ``Bionic`` while selecting ``Copy existing binaries``. - -### Release solc-js - - [ ] Wait until solc-bin was properly deployed. You can test this via remix - a test run through remix is advisable anyway. - - [ ] Increment the version number, create a pull request for that, merge it after tests succeeded. - - [ ] Create a tag using ``git tag --annotate v$VERSION`` and push it with ``git push --tags``. - - [ ] Wait for the CI runs on the tag itself. - - [ ] Take the ``solc-x.y.z.tgz`` artifact from ``build-package`` run on the tagged commit in circle-ci. - Inspect the tarball to ensure that it contains an up-to-date compiler binary (``soljson.js``). - - [ ] Run ``npm publish solc-x.y.z.tgz`` to publish the newly created tarball. - -### Post-release - - [ ] Make sure the documentation for the new release has been published successfully. - Go to the [documentation status page at ReadTheDocs](https://readthedocs.org/projects/solidity/) and verify that the new version is listed, works and is marked as default. - - [ ] Remove "still in progress" warning from the [release notes](https://github.com/ethereum/solidity/releases). - - [ ] Merge the [blog posts](https://github.com/ethereum/solidity-website/pulls) related to the release. - - [ ] Create a commit to increase the version number on ``develop`` in ``CMakeLists.txt`` and add a new skeleton changelog entry. - - [ ] Update the release information section [in the source of soliditylang.org](https://github.com/ethereum/solidity-website/blob/main/src/pages/index.tsx). - - [ ] Announce on [Twitter](https://twitter.com/solidity_lang), including links to the release and the blog post. - - [ ] Announce on [Fosstodon](https://fosstodon.org/@solidity/), including links to the release and the blog post. - - [ ] Share the announcement on Reddit in [``/r/ethdev``](https://reddit.com/r/ethdev/), cross-posted to [``/r/ethereum``](https://reddit.com/r/ethereum/). - - [ ] Share the announcement on the [Solidity forum](https://forum.soliditylang.org) in the ``Announcements`` category. - - [ ] Share the announcement on [Project Updates](https://discord.com/channels/420394352083337236/798974456704925696) - - [ ] Share the announcement on [`#solidity` channel on Matrix](https://matrix.to/#/#ethereum_solidity:gitter.im) - - [ ] Share the announcement on [`#solc-tooling`](https://matrix.to/#/#solc-tooling:matrix.org) - - [ ] Lean back, wait for bug reports and repeat from step 1 :). diff --git a/ReviewChecklist.md b/ReviewChecklist.md deleted file mode 100644 index 3f0af6f981..0000000000 --- a/ReviewChecklist.md +++ /dev/null @@ -1,200 +0,0 @@ -# PR Review Checklist -The Solidity compiler is a critical piece of infrastructure in the Ethereum ecosystem. -For this reason, our review process is quite strict and all PRs have to fulfill certain quality -expectations and guidelines. -The list below is meant to reduce the workload on the core team by helping contributors self-identify -and solve common issues before they are pointed out in the review. -It is also meant to serve as a final checklist for reviewers to go through before approving a PR. - -## Before You Submit a PR -- [ ] **Do you have any other open PRs?** - Work on a PR is not done until it is merged or closed. - Our reviewing capacity is limited, so we require that external contributors work on **no more than one PR at a time**. - - If your PR is not getting reviewed, feel free to bring it to our attention on the [#solidity-dev](https://gitter.im/ethereum/solidity-dev) channel. - - Unless they were requested, we are going to close any excess PRs, leaving only the earliest one open. - You may reopen them, one at a time, when your current PR is done. -- [ ] **Is the issue ready to be worked on?** - - If the issue does not have a desirability label (`nice to have`, `should have`, - `must have eventually`, `must have`, `roadmap`) we have not yet decided whether to implement it. - - If the issue has the `needs design` label, we have not yet decided how it should be implemented. - - `good first issue candidate` means that the issue will potentially be a `good first issue` - eventually but at the moment it is not yet ready to be worked on. -- [ ] **Is this a breaking change?** Breaking changes should be based on the `breaking` branch rather than on the `develop` branch. -- [ ] **Does the PR actually address the issue?** - - [ ] Mention the issue number in the PR description. - If the PR solves it completely, use the `Fixes #` form so that Github will close the issue automatically. - - [ ] Do not include the issue number in the PR title, branch name or commit description. -- [ ] When submitting a PR from a fork **create a branch and give it a descriptive name.** - E.g. `fix-array-abi-encoding-bug`. - Do not submit PRs directly from the `develop` branch of your fork since it makes rebasing and fetching new changes harder. -- [ ] **Does the PR depend on other PRs?** - - [ ] If the PR has dependencies, mention them in bold in the description. - - [ ] Avoid basing PRs from forks on branches other than `develop` or `breaking` because - GitHub closes them when the base branch gets merged. - Do this only for PRs created directly in the main repo. -- [ ] **Does the PR update test expectations to match the modified code?** If not, your PR will not pass some of the `_soltest_`, jobs in CI. - In many cases the expectations can be updated automatically: - - `cmdlineTests.sh --update` for command-line tests. - - `isoltest --enforce-gas-cost --accept-updates` for soltest-based tests. - - If your PR affects gas costs, an extra run of `isoltest --enforce-gas-cost --optimize --accept-updates` is needed to update gas expectations with optimizer enabled. - - Review updated files before committing them. - **Are expectations correct and do updated tests still serve their purpose?** - -## Abandoned PRs -- [ ] **Is the submitter still responsive?** - - If the PR had no activity from the submitter in the last 2 weeks (despite receiving reviews and our prompts) we consider it abandoned. -- [ ] **Is the abandoned PR easy to finish or relevant?** - - Apply the `takeover` label if the PR can be finished without significant effort or is something that actually needs to be done right now. - Otherwise close it. - It can still be taken over later or reopened by the submitter but until then we should not be getting sidetracked by it. - -## Light Review -Before an in-depth review, it is recommended to give new PRs a quick, superficial review, which -is not meant to provide complete and detailed feedback, but instead give the submitter a rough idea -if the PR is even on the right track and let them solve the obvious problems on their own. - -Light review should focus on the following three areas: -- [ ] **Are there any obvious mistakes?** Style issues, bad practices, easy to identify bugs, etc. -- [ ] **Is there anything missing?** Tests (of the right kind), documentation, etc. Does it address the whole issue? -- [ ] **Is it the right solution?** Are there better ways to do this? Is the change even necessary? - -If the answers above are "Yes, Yes, No", thank the contributor for their effort and **close the PR**. - -## Coding Style and Good Practices -- [ ] Does the PR follow our [coding style](CODING_STYLE.md)? - -### Reliability -- [ ] **Use assertions liberally.** If you are certain your assumption will not be broken, prove it with `solAssert()`. -- [ ] **Validate inputs and handle errors**. Note that assertions are **not** validation. - -### Readability -- [ ] **Choose good names.** - - [ ] Is the name straightforward to understand? - Do you feel the need to jump back to the definition and remind yourself what it was whenever you see it? - - [ ] Is the name unambiguous in the context where it is used? - - [ ] Avoid abbreviations. -- [ ] **Source files, classes and public functions should have docstrings.** -- [ ] **Avoid code duplication.** But not fanatically. Minimal amounts of duplication are acceptable if it aids readability. -- [ ] **Do not leave dead or commented-out code behind.** You can still see old code in history. - If you really have a good reason to do it, always leave a comment explaining what it is and why it is there. -- [ ] **Mark hacks as such.** If you have to leave behind a temporary workaround, make - sure to include a comment that explains why and in what circumstances it can be removed. - Preferably link to an issue you reported upstream. -- [ ] **Avoid obvious comments.** -- [ ] **Do include comments when the reader may need extra context to understand the code.** - -### Commits and PRs -- [ ] **Avoid hiding functional changes inside refactors.** - E.g. when fixing a small bug, or changing user-visible behavior, put the change in a separate commit. - Do not mix it with another change that renames things or reformats the code around, making the fix itself hard to identify. -- [ ] **Whenever possible, split off refactors or unrelated changes into separate PRs.** - Smaller PRs are easier and quicker to review. - Splitting off refactors helps focus on the main point of the PR. - -### Common Pitfalls -The following points are all covered by the coding style but come up so often that it is worth singling them out here: -- [ ] **Always initialize value types in the definition,** even if you are sure you will assign them later. -- [ ] **Use "east const" style.** I.e. `T const*`, not `const T *`. -- [ ] **Keep indentation consistent.** See our [`.editorconfig`](.editorconfig). - - [ ] Tabs for C++. But use them for indentation only. Any whitespace later on the line must consist of spaces. - - [ ] 4 spaces for most other file types. -- [ ] **Use `auto` sparingly.** Only use it when the actual type is very long and complicated or when it is - already used elsewhere in the same expression. -- [ ] **Indent braces and parentheses in a way that makes nesting clear.** -- [ ] **Use `using namespace` only in `.cpp` files.** Use it for `std` and our own modules. - Avoid unnecessary `std::` prefix in `.cpp` files (except for `std::move` and `std::forward`). -- [ ] **Use range-based loops and destructuring.** -- [ ] **Include any headers you use directly,** even if they are implicitly included through other headers. - -## Documentation -- [ ] **Does the PR update relevant documentation?** - -### Documentation Style and Good Practices -- [ ] **Use double backticks in RST (``` ``x`` ```). Prefer single backticks in Markdown (`` `x` ``),** - but note that double backticks are valid too and we use them in some cases for legacy reasons. -- [ ] **Always start a new sentence on a new line.** - This way you do not have to rewrap the surrounding text when you rewrite the sentence. - This also makes changes actually easier to spot in the diff. - -## Testing - -### What to Test -- [ ] **Is newly added code adequately covered by tests?** Have you considered all the important corner cases? -- If it is a bugfix: - - [ ] **The PR must include tests that reproduce the bug.** - - [ ] **Are there gaps in test coverage of the buggy feature?** Fill them by adding more tests. - - [ ] **Try to break it.** Can you of any similar features that could also be buggy? - Play with the repro and include prominent variants as separate test cases, even if they don't trigger a bug. -- [ ] **Positive cases (code that compiles) should have a semantic test.** -- [ ] **Negative cases (code with compilation errors) should have a syntax test.** -- [ ] **Avoid mixing positive and negative cases in the same syntax test.** - If the test produces an error, we stop at the analysis stage and we will not detect - problems that only occur in code generation, optimizer or assembler. - - [ ] If you have to do it, at least mark positive cases inside the file with a short comment. - - This way, when the test is updated, it is easier to verify that these cases still do not trigger an error. -- [ ] New syntax: **does it have an [`ASTJSON`](test/libsolidity/ASTJSON/) test?** -- [ ] New CLI or StandardJSON option: - - [ ] **Does it have a [command-line test](test/cmdlineTests/)?** - - [ ] **Is the option listed for every input mode in [`CommandLineParser` tests](test/solc/CommandLineParser.cpp)?** -- [ ] **Did you consider interactions with other language features?** - - [ ] Are all types covered? Structs? Enums? Contracts/libraries/interfaces? User-defined value types? - Value types: integers, fixed bytes, `address`, `address payable`, `bool`? Function pointers? - Static and dynamic arrays? `string` and `bytes`? Mappings? - Values of types that cannot be named: literals, tuples, array slices, storage references? - - [ ] If it accepts a function, does it also accept an event or an error? These have function types but are not functions. - - [ ] If it affects free functions, what about internal library functions? - - [ ] Attached library functions? Functions attached with `using for`? - - [ ] Possible combinations of `storage`, `memory`, `calldata`, `immutable`, `constant`? - Remember that internal functions can take `storage` arguments. - - [ ] Does it work at construction time as well? What if you store it at construction time and read after deployment? - - [ ] What about importing it from a different module or inheriting it? - - [ ] Have you tested it with the ternary operator? - -### Test Style and Good Practices -- [ ] **Make test case file names long and specific enough** so that it is easy to guess what is inside. - When checking if we have the case already covered the name is usually the only clue we see. - - [ ] Place them in the right subdirectory. - - [ ] **Avoid simply appending numbers to the name to distinguish similar cases.** - Coming up with good names is hard but figuring out if any of hundreds of tests with names that - match your search actually fits your case is even harder. -- [ ] **Do not include version pragma and the SPDX comment in semantic and syntax test cases**. - In other test types include them if necessary to suppress warnings. -- [ ] **If you have to use a version pragma, avoid hard-coding version.** Use `pragma solidity *`. -- [ ] **When writing StandardJSON command-line tests, use `urls` instead of `content`** and put - the Solidity or Yul code in a separate file. - -## Compiler-specific -- [ ] **Are error messages sensible and understandable to users?** -- [ ] **Are error codes consistent?** - - [ ] Avoid randomly changing or reassigning error codes. - - [ ] Avoid defining separate codes for trivial variants of the same issue. - Make it easy for tools to consistently refer to the same error with the same code. -- [ ] **Error messages should end with a full stop.** -- [ ] **Prefer Ranges v3 to Boost where possible.** - -## Take a Step Back -- [ ] **Do you fully understand what the PR does and why?** -- [ ] **Are you confident that the code works and does not break unrelated functionality?** -- [ ] **Is this a reasonable way to achieve the goal stated in the issue?** -- [ ] **Is the code simple?** Does the PR achieve its objective at the cost of significant - complexity that may be a source of future bugs? -- [ ] **Is the code efficient?** Does the PR introduce any major performance bottlenecks? -- [ ] **Does the PR introduce any breaking changes beyond what was agreed in the issue?** - -## Final Checks Before Merging -- [ ] **Is the PR rebased on top of the `develop` branch** (or `breaking` if it is a breaking change)? -- [ ] **Did all CI checks pass?** - - Note that we have a few jobs that tend to randomly fail due to outside factors, especially external tests (with `_ext_` in the name). - If these fail, rebase on latest `develop` (or `breaking`) and try rerunning them. - Note also that not all of these checks are required for the PR to be merged. -- [ ] If the change is visible to users, **does the PR have a [changelog](Changelog.md) entry?** - - [ ] Is the changelog entry in the right section? - Make sure to move it up if there was a release recently. -- [ ] **Is commit history simple and understandable?** - - [ ] Each commit should be a self-contained, logical step leading the goal of the PR, without going back and forth. - In particular, review fixups should be squashed into the commits they fix. - - [ ] Do not include any merge commits in your branch. Please use rebase to keep up to date with the base branch. -- [ ] **Is the PR properly labeled?** - - Use `external contribution` label to mark PRs not coming from the core team. - - If the PR depends on other PRs, use `has dependencies` and set the base branch accordingly. - - Labels like `documentation` or `optimizer` are helpful for filtering PRs. diff --git a/SECURITY.md b/SECURITY.md index d319b332f2..2f2871cea1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,52 +1,74 @@ # Security Policy -The Solidity team and community take all security bugs in Solidity seriously. -We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions. - -## Scope - -Bugs in the Solidity repository are in scope. -Bugs in third-party dependencies e.g., jsoncpp, boost etc. are not in scope unless they result in a Solidity specific bug. - -Only bugs that have a demonstrable security impact on smart contracts are in scope. -For example, a Solidity program whose optimization is incorrect (e.g., leads to an incorrect output) qualifies as a security bug. -Please note that the [rules][2] of the [Ethereum bounty program][1] have precedence over this security policy. - -## Supported Versions - -As a general rule, only the latest release gets security updates. -Exceptions may be made when the current breaking release is relatively new, e.g. less than three months old. -If you are reporting a bug, please state clearly the Solidity version(s) it affects. - -Example 1: Assuming the current release is `0.6.3` and a security bug has been found in it that affects both `0.5.x` and `0.6.x` trees, we may not only patch `0.6.3` (the bug-fix release numbered `0.6.4`) but `0.5.x` as well (the bug-fix release numbered `0.5.(x+1)`). - -Example 2: Assuming the current release is `0.6.25` and a security bug has been found in it, we may only patch `0.6.25` (in the bug-fix release numbered `0.6.26`) even if the bug affects a previous tree such as `0.5.x`. - -## Reporting a Vulnerability - -To report a vulnerability, please follow the instructions stated in the [Ethereum bounty program][1]. - -In the bug report, please include all details necessary to reproduce the vulnerability such as: - -- Input program that triggers the bug -- Compiler version affected -- Target EVM version -- Framework/IDE if applicable -- EVM execution environment/client if applicable -- Operating system - -Please include steps to reproduce the bug you have found in as much detail as possible. - -Once we have received your bug report, we will try to reproduce it and provide a more detailed response. -Once the reported bug has been successfully reproduced, the Solidity team will work on a fix. - -The Solidity team maintains the following JSON-formatted lists of patched security vulnerabilities: - -- [Summary of known security vulnerabilities][3] -- [List of security vulnerabilities affecting a specific version of the compiler][4]. - - -[1]: https://bounty.ethereum.org/ -[2]: https://bounty.ethereum.org/#rules -[3]: https://docs.soliditylang.org/en/develop/bugs.html -[4]: https://github.com/ethereum/solidity/blob/develop/docs/bugs_by_version.json +We truly appreciate efforts to discover and disclose security issues responsibly! + +## Vulnerabilities + +If you'd like to report a security issue in the repositories of matter-labs organization, please proceed to our +[Bug Bounty Program on Immunefi](https://era.zksync.io/docs/reference/troubleshooting/audit-bug-bounty.html#bug-bounty-program). + +## Other Security Issues + +We take an impact-first approach instead of a rules-first approach. Therefore, if you believe you found the impactful +issue but can't report it via the Bug Bounty, please email us at +[security@matterlabs.dev](mailto:security@matterlabs.dev). + +### PGP Key + +The following PGP key may be used to communicate sensitive information to developers: + +Fingerprint: `5FED B2D0 EA2C 4906 DD66 71D7 A2C5 0B40 CE3C F297` + +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBGEBmQkBEAD6tlkBEZFMvR8kOgxXX857nC2+oTik6TopJz4uCskuqDaeldMy +l+26BBzLkIeO1loS+bzVgnNFJRrGt9gv98MzNEHJVv6D7GsSLlUX/pz7Lxn0J4ry +o5XIk3MQTCUBdaXGs6GBLl5Xe8o+zNj4MKd4zjgDLinITNlE/YZCDsXyvYS3YFTQ +cwaUTNlawkKgw4BLaEqwB2JuyEhI9wx5X7ibjFL32sWMolYsNAlzFQzM09HCurTn +q0DYau9kPJARcEk9/DK2iq0z3gMCQ8iRTDaOWd8IbSP3HxcEoM5j5ZVAlULmjmUE +StDaMPLj0Kh01Tesh/j+vjchPXHT0n4zqi1+KOesAOk7SIwLadHfQMTpkU7G2fR1 +BrA5MtlzY+4Rm6o7qu3dpZ+Nc4iM3FUnaQRpvn4g5nTh8vjG94OCzX8DXWrCKyxx +amCs9PLDYOpx84fXYv4frkWpKh2digDSUGKhoHaOSnqyyvu3BNWXBCQZJ20rqEIu +sXOQMxWIoWCOOPRRvrHrKDA2hpoKjs3pGsProfpVRzb9702jhWpTfbDp9WjQlFtX +2ZIDxlwAxcugClgrp5JiUxvhg2A9lDNwCF7r1e68uNv5usBZQVKPJmnvS2nWgKy8 +x9oJsnwrEjxwiRHd34UvfMkwY9RENSJ+NoXqBdS7Lwz4m6vgbzq6K56WPQARAQAB +tCRaa1N5bmMgU2VjdXJpdHkgPHNlY3VyaXR5QHprc3luYy5pbz6JAk4EEwEKADgW +IQRf7bLQ6ixJBt1mcdeixQtAzjzylwUCYQGZCQIbAwULCQgHAgYVCgkICwIEFgID +AQIeAQIXgAAKCRCixQtAzjzyl5y8EAC/T3oq88Dak2b+5TlWdU2Gpm6924eAqlMt +y1KksDezzNQUlPiCUVllpin2PIjU/S+yzMWKXJA04LoVkEPfPOWjAaavLOjRumxu +MR6P2dVUg1InqzYVsJuRhKSpeexzNA5qO2BPM7/I2Iea1IoJPjogGbfXCo0r5kne +KU7a5GEa9eDHxpHTsbphQe2vpQ1239mUJrFpzAvILn6jV1tawMn5pNCXbsa8l6l2 +gtlyQPdOQECy77ZJxrgzaUBcs/RPzUGhwA/qNuvpF0whaCvZuUFMVuCTEu5LZka2 +I9Rixy+3jqBeONBgb+Fiz5phbiMX33M9JQwGONFaxdvpFTerLwPK2N1T8zcufa01 +ypzkWGheScFZemBxUwXwK4x579wjsnfrY11w0p1jtDgPTnLlXUA2mom4+7MyXPg0 +F75qh6vU1pdXaCVkruFgPVtIw+ccw2AxD50iZQ943ZERom9k165dR9+QxOVMXQ4P +VUxsFZWvK70/s8TLjsGljvSdSOa85iEUqSqh0AlCwIAxLMiDwh5s/ZgiHoIM6Xih +oCpuZyK9p0dn+DF/XkgAZ/S91PesMye3cGm6M5r0tS26aoc2Pk6X37Hha1pRALwo +MOHyaGjc/jjcXXxv6o55ALrOrzS0LQmLZ+EHuteCT15kmeY3kqYJ3og62KgiDvew +dKHENvg7d7kCDQRhAZleARAA6uD6WfdqGeKV5i170+kLsxR3QGav0qGNAbxpSJyn +iHQ8u7mQk3S+ziwN2AAopfBk1je+vCWtEGC3+DWRRfJSjLbtaBG8e6kLP3/cGA75 +qURz6glTG4nl5fcEAa6B1st0OxjVWiSLX3g/yjz8lznQb9awuRjdeHMnyx5DsJUN +d+Iu5KxGupQvKGOMKivSvC8VWk9taaQRpRF+++6stLCDk3ZtlxiopMs3X2jAp6xG +sOBbix1cv9BTsfaiL7XDL/gviqBPXYY5L42x6+jnPo5lROfnlLYkWrv6KZr7HD4k +tRXeaSwxLD2EkUyb16Jpp0be/ofvBtITGUDDLCGBiaXtx/v8d52MARjsyLJSYloj +1yiW01LfAiWHUC4z5jl2T7E7sicrlLH1M8Z6WbuqjdeaYwtfyPA2YCKr/3fn6pIo +D+pYaBSESmhA92P+XVaf5y2BZ6Qf8LveDpWwsVGdBGh9T0raA1ooe1GESLjmIjUa +z5AeQ/uXL5Md9I6bpMUUJYQiH19RPcFlJriI3phXyyf6Wlkk8oVEeCWyzcmw+x1V +deRTvE2x4WIwKGLXRNjin2j1AP7vU2HaNwlPrLijqdyi68+0irRQONoH7Qonr4ca +xWgL+pAaa3dWxf0xqK7uZFp4aTVWlr2uXtV/eaUtLmGMCU0jnjb109wg5L0F7WRT +PfEAEQEAAYkCNgQYAQoAIBYhBF/tstDqLEkG3WZx16LFC0DOPPKXBQJhAZleAhsM +AAoJEKLFC0DOPPKXAAEP/jK7ch9GkoaYlsuqY/aHtxEwVddUDOxjyn3FMDoln85L +/n8AmLQb2bcpKSqpaJwMbmfEyr5MDm8xnsBTfx3u6kgaLOWfKxjLQ6PM7kgIMdi4 +bfaRRuSEI1/R6c/hNpiGnzAeeexldH1we+eH1IVmh4crdat49S2xh7Qlv9ahvgsP +LfKl3rJ+aaX/Ok0AHzhvSfhFpPr1gAaGeaRt+rhlZsx2QyG4Ez8p2nDAcAzPiB3T +73ENoBIX6mTPfPm1UgrRyFKBqtUzAodz66j3r6ebBlWzIRg8iZenVMAxzjINAsxN +w1Bzfgsi5ZespfsSlmEaa7jJkqqDuEcLa2YuiFAue7Euqwz1aGeq1GfTicQioSCb +Ur/LGyz2Mj3ykbaP8p5mFVcUN51yQy6OcpvR/W1DfRT9SHFT/bCf9ixsjB2HlZGo +uxPJowwqmMgHd755ZzPDUM9YDgLI1yXdcYshObv3Wq537JAxnZJCGRK4Y8SwrMSh +8WRxlaM0AGWXiJFIDD4bQPIdnF3X8w0cGWE5Otkb8mMHOT+rFTVlDODwm1zF6oIG +PTwfVrpiZBwiUtfJol1exr/MzSPyGoJnYs3cRf2E3O+D1LbcR8w0LbjGuUy38Piz +ZO/vCeyJ3JZC5kE8nD+XBA4idwzh0BKEfH9t+WchQ3Up9rxyzLyQamoqt5Xby4pY +=xkM3 +-----END PGP PUBLIC KEY BLOCK----- +``` diff --git a/cmake/EthBuildInfo.cmake b/cmake/EthBuildInfo.cmake index 1316a888cd..96e3e92daf 100644 --- a/cmake/EthBuildInfo.cmake +++ b/cmake/EthBuildInfo.cmake @@ -40,6 +40,7 @@ function(create_build_info NAME) -DPROJECT_VERSION_MAJOR="${PROJECT_VERSION_MAJOR}" -DPROJECT_VERSION_MINOR="${PROJECT_VERSION_MINOR}" -DPROJECT_VERSION_PATCH="${PROJECT_VERSION_PATCH}" + -DSOLC_VERSION_ZKEVM="${SOLC_VERSION_ZKEVM}" -P "${ETH_SCRIPTS_DIR}/buildinfo.cmake" ) include_directories("${PROJECT_BINARY_DIR}/include") diff --git a/cmake/scripts/buildinfo.cmake b/cmake/scripts/buildinfo.cmake index 3fb6beb2b7..ceabaa17ed 100644 --- a/cmake/scripts/buildinfo.cmake +++ b/cmake/scripts/buildinfo.cmake @@ -25,7 +25,6 @@ if (EXISTS ${ETH_SOURCE_DIR}/prerelease.txt) file(READ ${ETH_SOURCE_DIR}/prerelease.txt SOL_VERSION_PRERELEASE) string(STRIP "${SOL_VERSION_PRERELEASE}" SOL_VERSION_PRERELEASE) else() - string(TIMESTAMP SOL_VERSION_PRERELEASE "develop.%Y.%m.%d" UTC) string(REPLACE .0 . SOL_VERSION_PRERELEASE "${SOL_VERSION_PRERELEASE}") endif() @@ -64,6 +63,10 @@ set(SOL_VERSION_COMMIT "commit.${SOL_COMMIT_HASH}") set(SOl_VERSION_PLATFORM ETH_BUILD_PLATFORM) set(SOL_VERSION_BUILDINFO "commit.${SOL_COMMIT_HASH}.${ETH_BUILD_PLATFORM}") +if (NOT SOLC_VERSION_ZKEVM) + set(SOLC_VERSION_ZKEVM "undefined") +endif() + set(TMPFILE "${ETH_DST_DIR}/BuildInfo.h.tmp") set(OUTFILE "${ETH_DST_DIR}/BuildInfo.h") diff --git a/cmake/templates/BuildInfo.h.in b/cmake/templates/BuildInfo.h.in index 9c295a85f0..33e8e9e377 100644 --- a/cmake/templates/BuildInfo.h.in +++ b/cmake/templates/BuildInfo.h.in @@ -13,3 +13,4 @@ #define SOL_VERSION_BUILDINFO "@SOL_VERSION_BUILDINFO@" #define SOL_VERSION_COMMIT "@SOL_VERSION_COMMIT@" #define SOL_VERSION_PLATFORM "@SOL_VERSION_PLATFORM@" +#define SOL_VERSION_ZKEVM "@SOLC_VERSION_ZKEVM@" diff --git a/eraLogo.svg b/eraLogo.svg new file mode 100644 index 0000000000..6ec790c081 --- /dev/null +++ b/eraLogo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index b6e4d0006c..0094613883 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -689,7 +689,7 @@ AssemblyItem Assembly::newImmutableAssignment(std::string const& _identifier) Assembly& Assembly::optimise(OptimiserSettings const& _settings) { - optimiseInternal(_settings, {}); + (void) _settings; return *this; } diff --git a/libevmasm/LinkerObject.cpp b/libevmasm/LinkerObject.cpp index 1b09f4ced0..c1998ef225 100644 --- a/libevmasm/LinkerObject.cpp +++ b/libevmasm/LinkerObject.cpp @@ -48,6 +48,7 @@ void LinkerObject::link(std::map const& _libraryAddresses) std::string LinkerObject::toHex() const { + return "The EVM bytecode is unavailable in the zkEVM edition of solc"; std::string hex = solidity::util::toHex(bytecode); for (auto const& ref: linkReferences) { diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 3db857241f..3a93803ffc 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -82,6 +82,10 @@ set(sources codegen/ContractCompiler.h codegen/ExpressionCompiler.cpp codegen/ExpressionCompiler.h + codegen/ExtraMetadata.cpp + codegen/ExtraMetadata.h + codegen/FuncPtrTracker.cpp + codegen/FuncPtrTracker.h codegen/LValue.cpp codegen/LValue.h codegen/MultiUseYulFunctionCollector.h diff --git a/libsolidity/analysis/FunctionCallGraph.cpp b/libsolidity/analysis/FunctionCallGraph.cpp index 1d01f1a6bc..98b4126a65 100644 --- a/libsolidity/analysis/FunctionCallGraph.cpp +++ b/libsolidity/analysis/FunctionCallGraph.cpp @@ -120,10 +120,21 @@ bool FunctionCallGraphBuilder::visit(FunctionCall const& _functionCall) solAssert(functionType, ""); if (functionType->kind() == FunctionType::Kind::Internal && !_functionCall.expression().annotation().calledDirectly) + { + for (FunctionDefinition const* funcPtrRef: m_contract.annotation().intFuncPtrRefs) + { + FunctionType const* funcPtrRefType = funcPtrRef->functionType(/*_internal=*/true); + solAssert(funcPtrRefType, ""); + if (!funcPtrRefType->hasEqualParameterTypes(*functionType) + || !funcPtrRefType->hasEqualReturnTypes(*functionType) || !funcPtrRef->isImplemented()) + continue; + m_graph.indirectEdges[m_currentNode].insert(funcPtrRef); + } // If it's not a direct call, we don't really know which function will be called (it may even // change at runtime). All we can do is to add an edge to the dispatch which in turn has // edges to all functions could possibly be called. add(m_currentNode, CallGraph::SpecialNode::InternalDispatch); + } else if (functionType->kind() == FunctionType::Kind::Error) m_graph.usedErrors.insert(&dynamic_cast(functionType->declaration())); diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index e68614f464..2ce96e73a7 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -29,6 +29,8 @@ #include +#include + #include #include #include @@ -164,6 +166,8 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocu util::SetOnce> creationCallGraph; /// A graph with edges representing calls between functions that may happen in a deployed contract. util::SetOnce> deployedCallGraph; + /// Set of internal functions referenced as function pointers + std::set> intFuncPtrRefs; /// List of contracts whose bytecode is referenced by this contract, e.g. through "new". /// The Value represents the ast node that referenced the contract. @@ -226,6 +230,8 @@ struct InlineAssemblyAnnotation: StatementAnnotation bool markedMemorySafe = false; /// True, if the assembly block involves any memory opcode or assigns to variables in memory. util::SetOnce hasMemoryEffects; + /// The yul block of the InlineAssembly::operations() after optimizations. + std::shared_ptr optimizedOperations; }; struct BlockAnnotation: StatementAnnotation, ScopableAnnotation diff --git a/libsolidity/ast/CallGraph.cpp b/libsolidity/ast/CallGraph.cpp index 04275c3740..060f0aeebc 100644 --- a/libsolidity/ast/CallGraph.cpp +++ b/libsolidity/ast/CallGraph.cpp @@ -43,3 +43,132 @@ bool CallGraph::CompareByID::operator()(int64_t _lhs, Node const& _rhs) const return _lhs < std::get(_rhs)->id(); } + +/// Populates reachable cycles from m_src into paths; +class CycleFinder +{ + CallGraph const& m_callGraph; + CallableDeclaration const* m_src; + std::set m_processing; + std::set m_processed; + std::vector m_paths; + + /// Populates `m_paths` with cycles reachable from @a _callable + void getCyclesInternal(CallableDeclaration const* _callable, CallGraph::Path& _path) + { + if (m_processed.count(_callable)) + return; + + auto directCallees = m_callGraph.edges.find(_callable); + auto indirectCallees = m_callGraph.indirectEdges.find(_callable); + // Is _callable a leaf node? + if (directCallees == m_callGraph.edges.end() && indirectCallees == m_callGraph.indirectEdges.end()) + { + solAssert(m_processing.count(_callable) == 0, ""); + m_processed.insert(_callable); + return; + } + + m_processing.insert(_callable); + _path.push_back(_callable); + + // Traverse all the direct and indirect callees + std::set callees; + if (directCallees != m_callGraph.edges.end()) + callees.insert(directCallees->second.begin(), directCallees->second.end()); + if (indirectCallees != m_callGraph.indirectEdges.end()) + callees.insert(indirectCallees->second.begin(), indirectCallees->second.end()); + for (auto const& calleeVariant: callees) + { + if (!std::holds_alternative(calleeVariant)) + continue; + auto* callee = std::get(calleeVariant); + + if (m_processing.count(callee)) + { + // Extract the cycle + auto cycleStart = std::find(_path.begin(), _path.end(), callee); + solAssert(cycleStart != _path.end(), ""); + m_paths.emplace_back(cycleStart, _path.end()); + continue; + } + + getCyclesInternal(callee, _path); + } + + m_processing.erase(_callable); + m_processed.insert(_callable); + _path.pop_back(); + } + +public: + CycleFinder(CallGraph const& _callGraph, CallableDeclaration const* _src): m_callGraph(_callGraph), m_src(_src) {} + + std::vector getCycles() + { + CallGraph::Path p; + getCyclesInternal(m_src, p); + return m_paths; + } + + void dump(std::ostream& _out) + { + for (CallGraph::Path const& path: m_paths) + { + for (CallableDeclaration const* func: path) + _out << func->name() << " -> "; + _out << "\n"; + } + } +}; + +void CallGraph::getReachableFuncs(CallableDeclaration const* _src, std::set& _funcs) const +{ + if (_funcs.count(_src)) + return; + _funcs.insert(_src); + + auto directCallees = edges.find(_src); + auto indirectCallees = indirectEdges.find(_src); + // Is _src a leaf node? + if (directCallees == edges.end() && indirectCallees == indirectEdges.end()) + return; + + // Traverse all the direct and indirect callees + std::set callees; + if (directCallees != edges.end()) + callees.insert(directCallees->second.begin(), directCallees->second.end()); + if (indirectCallees != indirectEdges.end()) + callees.insert(indirectCallees->second.begin(), indirectCallees->second.end()); + + for (auto const& calleeVariant: callees) + { + if (!std::holds_alternative(calleeVariant)) + continue; + auto* callee = std::get(calleeVariant); + getReachableFuncs(callee, _funcs); + } +} + +std::set CallGraph::getReachableFuncs(CallableDeclaration const* _src) const +{ + std::set funcs; + getReachableFuncs(_src, funcs); + return funcs; +} + +std::set CallGraph::getReachableCycleFuncs(CallableDeclaration const* _src) const +{ + std::set funcs; + CycleFinder cf{*this, _src}; + std::vector paths = cf.getCycles(); + + for (CallGraph::Path const& path: paths) + { + for (CallableDeclaration const* func: path) + { + funcs.insert(func); + } + } + return funcs; +} diff --git a/libsolidity/ast/CallGraph.h b/libsolidity/ast/CallGraph.h index c4b4e957a7..d71b727170 100644 --- a/libsolidity/ast/CallGraph.h +++ b/libsolidity/ast/CallGraph.h @@ -47,6 +47,7 @@ struct CallGraph }; using Node = std::variant; + using Path = std::vector; struct CompareByID { @@ -61,6 +62,9 @@ struct CallGraph /// any calls. std::map, CompareByID> edges; + /// Graph edges for indirect calls + std::map, CompareByID> indirectEdges; + /// Contracts that need to be compiled before this one can be compiled. /// The value is the ast node that created the dependency. std::map> bytecodeDependency; @@ -70,6 +74,17 @@ struct CallGraph /// Errors that are used by functions present in the graph. std::set usedErrors; + + /// Returns functions reachable from @a _src that belong to a cycle. Note that the cycle can be due to indirect + /// calls. + std::set getReachableCycleFuncs(CallableDeclaration const* _src) const; + + /// Returns functions reachable (including the ones from indirect calls) from @a _src. + std::set getReachableFuncs(CallableDeclaration const* _src) const; + +private: + /// Populates @a _funcs with the functions reachable (including the ones from indirect calls) from @a _src. + void getReachableFuncs(CallableDeclaration const* _src, std::set& _funcs) const; }; } diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index e73ddfbae8..4cc3cf8aa5 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -296,6 +296,17 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons _context << Instruction::POP; } ); + + if (auto* structType = dynamic_cast(_sourceType.baseType())) + { + if (structType->recursive()) + { + std::string name{"$copyArrayToStorage_" + sourceType->identifier() + "_to_" + targetType->identifier()}; + auto tag = m_context.lowLevelFunctionTagIfExists(name); + solAssert(tag != evmasm::AssemblyItem(evmasm::UndefinedItem), ""); + m_context.addRecursiveLowLevelFunc({name, tag.data().convert_to(), /*ins=*/3, /*outs=*/1}); + } + } } void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWordBoundaries) const @@ -598,6 +609,17 @@ void ArrayUtils::clearArray(ArrayType const& _typeIn) const solAssert(_context.stackHeight() == stackHeightStart - 2, ""); } ); + + if (auto* structType = dynamic_cast(_typeIn.baseType())) + { + if (structType->recursive()) + { + std::string name{"$clearArray_" + _typeIn.identifier()}; + auto tag = m_context.lowLevelFunctionTagIfExists(name); + solAssert(tag != evmasm::AssemblyItem(evmasm::UndefinedItem), ""); + m_context.addRecursiveLowLevelFunc({name, tag.data().convert_to(), /*ins=*/2, /*outs=*/0}); + } + } } void ArrayUtils::clearDynamicArray(ArrayType const& _type) const diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index 844de8ba82..ce26e83f6e 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include using namespace solidity; @@ -50,6 +52,9 @@ void Compiler::compileContract( m_context.optimise(m_optimiserSettings); + ExtraMetadataRecorder extraMetadataRecorder{m_context, m_runtimeContext}; + m_extraMetadata = extraMetadataRecorder.run(_contract); + solAssert(m_context.appendYulUtilityFunctionsRan(), "appendYulUtilityFunctions() was not called."); solAssert(m_runtimeContext.appendYulUtilityFunctionsRan(), "appendYulUtilityFunctions() was not called."); } diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index 1267c1a2d9..4ddb037b8c 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -61,8 +61,10 @@ class Compiler std::string generatedYulUtilityCode() const { return m_context.generatedYulUtilityCode(); } std::string runtimeGeneratedYulUtilityCode() const { return m_runtimeContext.generatedYulUtilityCode(); } + Json::Value extraMetadata() const { return m_extraMetadata; } private: + Json::Value m_extraMetadata; OptimiserSettings const m_optimiserSettings; CompilerContext m_runtimeContext; size_t m_runtimeSub = size_t(-1); ///< Identifier of the runtime sub-assembly, if present. diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index d9264c6ac5..7ad6a5e38d 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -169,6 +169,15 @@ evmasm::AssemblyItem CompilerContext::lowLevelFunctionTag( return it->second; } +evmasm::AssemblyItem CompilerContext::lowLevelFunctionTagIfExists(std::string const& _name) +{ + auto it = m_lowLevelFunctions.find(_name); + if (it == m_lowLevelFunctions.end()) + return evmasm::AssemblyItem(evmasm::UndefinedItem); + else + return it->second; +} + void CompilerContext::appendMissingLowLevelFunctions() { while (!m_lowLevelFunctionGenerationQueue.empty()) @@ -517,11 +526,13 @@ void CompilerContext::appendInlineAssembly( reportError("Failed to analyze inline assembly block."); solAssert(errorReporter.errors().empty(), "Failed to analyze inline assembly block."); + std::shared_ptr yulContext; yul::CodeGenerator::assemble( *parserResult, analysisInfo, *m_asm, m_evmVersion, + yulContext, identifierAccess.generateCode, _system, _optimiserSettings.optimizeStackAllocation diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 8eba084eba..853297a812 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -163,6 +164,10 @@ class CompilerContext unsigned _outArgs, std::function const& _generator ); + /// Returns the entry tag of the low-level function with the name @a _name if already generated; Returns + /// evmasm::AssemblyItem(evmasm::UndefinedItem) if the entry tag is not generated. + evmasm::AssemblyItem lowLevelFunctionTagIfExists(std::string const& _name); + /// Generates the code for missing low-level functions, i.e. calls the generators passed above. void appendMissingLowLevelFunctions(); ABIFunctions& abiFunctions() { return m_abiFunctions; } @@ -296,6 +301,40 @@ class CompilerContext /// Should be avoided except when adding sub-assemblies. std::shared_ptr assemblyPtr() const { return m_asm; } + /// Adds the @a _p_asm -> @a _context mapping in the internal inline assembly to context mapping + void addInlineAsmContextMapping(InlineAssembly const* _p_asm, std::shared_ptr _context) + { + m_inlineAsmContextMap[_p_asm] = _context; + } + + /// Returns the context for @a _p_asm; nullptr if not found + yul::CodeTransformContext const* findInlineAsmContextMapping(InlineAssembly const* _p_asm) const + { + auto findIt = m_inlineAsmContextMap.find(_p_asm); + if (findIt == m_inlineAsmContextMap.end()) + return nullptr; + return findIt->second.get(); + } + + struct FunctionInfo + { + std::string const name; + unsigned tag; + unsigned ins; + unsigned outs; + + bool operator<(FunctionInfo const& _other) const + { + return tie(name, tag, ins, outs) < tie(_other.name, _other.tag, _other.ins, _other.outs); + } + }; + + /// Adds @a _func to the set of low level utility functions that are recursive + void addRecursiveLowLevelFunc(FunctionInfo _func) { m_recursiveLowLevelFuncs.insert(_func); } + + /// Returns the set of low level utility functions that are recursive + std::set const& recursiveLowLevelFuncs() const { return m_recursiveLowLevelFuncs; } + /** * Helper class to pop the visited nodes stack when a scope closes */ @@ -310,6 +349,11 @@ class CompilerContext RevertStrings revertStrings() const { return m_revertStrings; } + // HACK! + // We track the success tag here for the `TryStatement` lowering. This is to avoid the redundant status check and + // the conditional jump. Such patterns can confuse the zksolc translator. + evmasm::AssemblyItem currTryCallSuccessTag{evmasm::AssemblyItemType::UndefinedItem}; + private: /// Updates source location set in the assembly. void updateSourceLocation(); @@ -393,6 +437,10 @@ class CompilerContext std::queue>> m_lowLevelFunctionGenerationQueue; /// Flag to check that appendYulUtilityFunctions() was called exactly once bool m_appendYulUtilityFunctionsRan = false; + /// Maps an InlineAssembly AST node to its CodeTransformContext created during its lowering + std::map> m_inlineAsmContextMap; + /// Set of low level utility functions generated in this context that are recursive + std::set m_recursiveLowLevelFuncs; }; } diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index bf4f25bf28..d83075f3ad 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1197,12 +1197,21 @@ void CompilerUtils::convertType( _context << Instruction::POP << Instruction::POP; }; if (typeOnStack.recursive()) + { m_context.callLowLevelFunction( "$convertRecursiveArrayStorageToMemory_" + typeOnStack.identifier() + "_to_" + targetType.identifier(), 1, 1, conversionImpl ); + std::string name{ + "$convertRecursiveArrayStorageToMemory_" + typeOnStack.identifier() + "_to_" + + targetType.identifier()}; + auto tag = m_context.lowLevelFunctionTagIfExists(name); + solAssert(tag != evmasm::AssemblyItem(evmasm::UndefinedItem), ""); + m_context.addRecursiveLowLevelFunc( + {name, tag.data().convert_to(), /*ins=*/1, /*outs=*/1}); + } else conversionImpl(m_context); break; diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 186cebc787..56803c28ab 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -716,6 +717,20 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { solAssert(_context == yul::IdentifierContext::RValue || _context == yul::IdentifierContext::LValue, ""); auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); + if (ref == _inlineAssembly.annotation().externalReferences.end()) + { + // The yul AST might be copied from the original (In case we ran the Disambiguator, for instance). So we'll + // search for the identifier's name instead. + auto& externalReferences = _inlineAssembly.annotation().externalReferences; + for (auto extRef = externalReferences.begin(); extRef != externalReferences.end(); ++extRef) + { + if (extRef->first->name == _identifier.name) + { + ref = extRef; + break; + } + } + } solAssert(ref != _inlineAssembly.annotation().externalReferences.end(), ""); Declaration const* decl = ref->second.declaration; solAssert(!!decl, ""); @@ -946,18 +961,55 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) m_context.optimizeYul(object, *dialect, m_optimiserSettings); code = object.code.get(); + _inlineAssembly.annotation().optimizedOperations = object.code; + analysisInfo = object.analysisInfo.get(); + } + else + { + auto const* dialect = dynamic_cast(&_inlineAssembly.dialect()); + solAssert(dialect, ""); + + // Run the disambiguator. + // We need this so that the yul::CallGraphGenerator runs correctly (which is required for setting the + // "recursiveFunctions" record in the extraMetadata for inline assembly) + std::set reservedIdentifiers = dialect->fixedFunctionNames(); + for (auto extRef: _inlineAssembly.annotation().externalReferences) + { + reservedIdentifiers.insert(extRef.first->name); + } + yul::Disambiguator disambiguator(*dialect, *analysisInfo, reservedIdentifiers); + object.code = std::make_shared(std::get(disambiguator(*code))); + + // Run the AsmAnalyzer on `object.code`. + // Create a resolver that accepts any identifiers. This is OK since the TypeChecker already did the resolution + // and the disambiguator should have left them as it is. + yul::ExternalIdentifierAccess::Resolver resolver + = [](yul::Identifier const& _identifier, yul::IdentifierContext _context, bool) -> bool + { + (void) _identifier; + (void) _context; + return true; + }; + object.analysisInfo = std::make_shared( + yul::AsmAnalyzer::analyzeStrictAssertCorrect(*dialect, object, resolver)); + + code = object.code.get(); + _inlineAssembly.annotation().optimizedOperations = object.code; analysisInfo = object.analysisInfo.get(); } + std::shared_ptr yulContext; yul::CodeGenerator::assemble( *code, *analysisInfo, *m_context.assemblyPtr(), m_context.evmVersion(), + yulContext, identifierAccessCodeGen, false, m_optimiserSettings.optimizeStackAllocation ); + m_context.addInlineAsmContextMapping(&_inlineAssembly, yulContext); m_context.setStackOffset(static_cast(startStackHeight)); return false; } @@ -971,7 +1023,7 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement) int const returnSize = static_cast(_tryStatement.externalCall().annotation().type->sizeOnStack()); // Stack: [ return values] - evmasm::AssemblyItem successTag = m_context.appendConditionalJump(); + m_context << Instruction::POP; // Catch case. m_context.adjustStackOffset(-returnSize); @@ -980,7 +1032,8 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement) evmasm::AssemblyItem endTag = m_context.appendJumpToNew(); - m_context << successTag; + solAssert(m_context.currTryCallSuccessTag.type() == AssemblyItemType::Tag, ""); + m_context << m_context.currTryCallSuccessTag; m_context.adjustStackOffset(returnSize); { // Success case. diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 494d106c83..83e493b0cd 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -618,6 +618,68 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) return false; } +void ExpressionCompiler::generateSelector(FunctionType const& _funcType) +{ + // Are we in the creation context? + if (m_context.runtimeContext()) + { + // Extract only the low 32 bits for matching in the tag selector + m_context << u256(0xffffffff) << Instruction::AND; + } + + struct TagInfo + { + evmasm::AssemblyItem const tag; + FunctionDefinition const* func; + }; + std::vector tagInfos; + + for (auto* intFuncPtrRef: m_context.mostDerivedContract().annotation().intFuncPtrRefs) + { + FunctionType const* intFuncPtrRefType = intFuncPtrRef->functionType(true); + // ContractDefinitionAnnotation::intFuncPtrRefs should only contain refs to internal functions + solAssert(intFuncPtrRefType, ""); + if (!intFuncPtrRefType->hasEqualParameterTypes(_funcType) || !intFuncPtrRefType->hasEqualReturnTypes(_funcType) + || !intFuncPtrRef->isImplemented()) + continue; + + // The loaded function pointer + m_context << Instruction::DUP1; + // We don't need to resolve the function here since FuncPtrTracker already did that. + m_context << m_context.functionEntryLabel(*intFuncPtrRef).pushTag(); + m_context << Instruction::EQ; + + evmasm::AssemblyItem newTag = m_context.newTag(); + m_context.appendConditionalJumpTo(newTag); + tagInfos.push_back({newTag, intFuncPtrRef}); + } + + if (tagInfos.empty()) + { + // Pop the original function pointer + m_context << Instruction::POP; + } + // If we can't match the entry tag of any of the internal function + m_context.appendPanic(PanicCode::InvalidInternalFunction); + + unsigned int stkOffsetAfterJumpI = m_context.stackHeight(); + for (TagInfo& tagInfo: tagInfos) + { + // The PC is set to this tag from the jumpi, so we need to set the stack offset correctly + m_context.setStackOffset((int) stkOffsetAfterJumpI); + + m_context << tagInfo.tag; + + // Pop the original function pointer + m_context << Instruction::POP; + + // We don't need to resolve the function here since FuncPtrTracker already did that. + m_context << m_context.functionEntryLabel(*tagInfo.func).pushTag(); + m_context.appendJump(evmasm::AssemblyItem::JumpType::IntoFunction); + // After the call, the vm's pc should be set to the return label since it is pushed to the stack. + } +} + bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { auto functionCallKind = *_functionCall.annotation().kind; @@ -709,6 +771,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) parameterSize += function.selfType()->sizeOnStack(); } + // There can be cases when ExpressionAnnotation::calledDirectly is false but we can infer that it is a + // direct call if the target PC is a literal tag + bool directCallInferred = false; + auto const& currAsmItems = m_context.assembly().items(); + if (!currAsmItems.empty() && currAsmItems.back().type() == AssemblyItemType::PushTag) + directCallInferred = true; + if (m_context.runtimeContext()) // We have a runtime context, so we need the creation part. utils().rightShiftNumberOnStack(32); @@ -716,7 +785,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // Extract the runtime part. m_context << ((u256(1) << 32) - 1) << Instruction::AND; - m_context.appendJump(evmasm::AssemblyItem::JumpType::IntoFunction); + // Is this a direct call? + if (_functionCall.expression().annotation().calledDirectly || directCallInferred) + m_context.appendJump(evmasm::AssemblyItem::JumpType::IntoFunction); + else + generateSelector(function); + m_context << returnLabel; unsigned returnParametersSize = CompilerUtils::sizeOnStack(function.returnParameterTypes()); @@ -792,7 +866,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // If this is a try call, return "
1" in the success case and // "0" in the error case. AssemblyItem errorCase = m_context.appendConditionalJump(); - m_context << u256(1); + m_context.currTryCallSuccessTag = m_context.appendJumpToNew(); + m_context.adjustStackOffset(1); m_context << errorCase; } else @@ -2917,7 +2992,8 @@ void ExpressionCompiler::appendExternalFunctionCall( if (_tryCall) { // Success branch will reach this, failure branch will directly jump to endTag. - m_context << u256(1); + m_context.currTryCallSuccessTag = m_context.appendJumpToNew(); + m_context.adjustStackOffset(1); m_context << endTag; } } diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index 13e1e3106e..63cf25cf07 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -139,6 +139,9 @@ class ExpressionCompiler: private ASTConstVisitor /// @returns the CompilerUtils object containing the current context. CompilerUtils utils(); + /// Generates the selector for internal function pointer with type @a _funcType. + void generateSelector(FunctionType const& _funcType); + bool m_optimiseOrderLiterals; CompilerContext& m_context; std::unique_ptr m_currentLValue; diff --git a/libsolidity/codegen/ExtraMetadata.cpp b/libsolidity/codegen/ExtraMetadata.cpp new file mode 100644 index 0000000000..ca05d1dca5 --- /dev/null +++ b/libsolidity/codegen/ExtraMetadata.cpp @@ -0,0 +1,182 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +#include +#include + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::frontend; + +class InlineAsmRecursiveFuncRecorder: public ASTConstVisitor +{ +public: + void run() { m_func.accept(*this); } + + InlineAsmRecursiveFuncRecorder( + CallableDeclaration const& _func, + CompilerContext const& _context, + CompilerContext const& _runtimeContext, + Json::Value& _recFuncs) + : m_func(_func), m_context(_context), m_runtimeContext(_runtimeContext), m_recFuncs(_recFuncs) + { + } + +private: + CallableDeclaration const& m_func; + CompilerContext const& m_context; + CompilerContext const& m_runtimeContext; + Json::Value& m_recFuncs; + + // Record recursions in @_asm for the extra metadata + void record(InlineAssembly const& _p_asm, CompilerContext const& _context) + { + auto findRes = _context.findInlineAsmContextMapping(&_p_asm); + if (!findRes) + return; + yul::CodeTransformContext const& yulContext = *findRes; + + set recFuncs; + if (_p_asm.annotation().optimizedOperations) + { + yul::Block const& code = *_p_asm.annotation().optimizedOperations; + recFuncs = yul::CallGraphGenerator::callGraph(code).recursiveFunctions(); + } + else + { + recFuncs = yul::CallGraphGenerator::callGraph(_p_asm.operations()).recursiveFunctions(); + } + for (auto recFunc: recFuncs) + { + auto findIt = yulContext.functionInfoMap.find(recFunc); + if (findIt == yulContext.functionInfoMap.end()) + continue; + for (auto& func: findIt->second) + { + Json::Value record(Json::objectValue); + record["name"] = recFunc.str(); + if (_context.runtimeContext()) + record["creationTag"] = Json::Value(Json::LargestUInt(func.label)); + else + record["runtimeTag"] = Json::Value(Json::LargestUInt(func.label)); + record["totalParamSize"] = Json::Value(Json::LargestUInt(func.ast->parameters.size())); + record["totalRetParamSize"] = Json::Value(Json::LargestUInt(func.ast->returnVariables.size())); + m_recFuncs.append(record); + } + } + } + + void endVisit(InlineAssembly const& _p_asm) + { + record(_p_asm, m_context); + record(_p_asm, m_runtimeContext); + } +}; + +Json::Value ExtraMetadataRecorder::run(ContractDefinition const& _contract) +{ + // Set "recursiveFunctions" + Json::Value recFuncs(Json::arrayValue); + + // Record recursions in low level calls + auto recordRecursiveLowLevelFuncs = [&](CompilerContext const& _context) + { + for (auto fn: _context.recursiveLowLevelFuncs()) + { + Json::Value func(Json::objectValue); + func["name"] = fn.name; + if (_context.runtimeContext()) + func["creationTag"] = fn.tag; + else + func["runtimeTag"] = fn.tag; + func["totalParamSize"] = fn.ins; + func["totalRetParamSize"] = fn.outs; + recFuncs.append(func); + } + }; + recordRecursiveLowLevelFuncs(m_context); + recordRecursiveLowLevelFuncs(m_runtimeContext); + + // Get reachable functions from the call-graphs; And get cycles in the call-graphs + auto& creationCallGraph = _contract.annotation().creationCallGraph; + auto& runtimeCallGraph = _contract.annotation().deployedCallGraph; + + set reachableCycleFuncs, reachableFuncs; + + for (FunctionDefinition const* fn: _contract.definedFunctions()) + { + if (fn->isConstructor() && creationCallGraph.set()) + { + reachableCycleFuncs += (*creationCallGraph)->getReachableCycleFuncs(fn); + reachableFuncs += (*creationCallGraph)->getReachableFuncs(fn); + } + else if (runtimeCallGraph.set()) + { + reachableCycleFuncs += (*runtimeCallGraph)->getReachableCycleFuncs(fn); + reachableFuncs += (*runtimeCallGraph)->getReachableFuncs(fn); + } + } + + // Record recursions in inline assembly + for (auto* fn: reachableFuncs) + { + InlineAsmRecursiveFuncRecorder inAsmRecorder{*fn, m_context, m_runtimeContext, recFuncs}; + inAsmRecorder.run(); + } + + // Record recursions in the solidity source + auto recordRecursiveSolFuncs = [&](CompilerContext const& _context) + { + for (auto* fn: reachableCycleFuncs) + { + evmasm::AssemblyItem const& tag = _context.functionEntryLabelIfExists(*fn); + if (tag == evmasm::AssemblyItem(evmasm::UndefinedItem)) + continue; + + Json::Value func(Json::objectValue); + func["name"] = fn->name(); + + // Assembly::new[Push]Tag() asserts that the tag is 32 bits + auto tagNum = tag.data().convert_to(); + if (_context.runtimeContext()) + func["creationTag"] = tagNum; + else + func["runtimeTag"] = tagNum; + + unsigned totalParamSize = 0, totalRetParamSize = 0; + for (auto& param: fn->parameters()) + totalParamSize += param->type()->sizeOnStack(); + func["totalParamSize"] = totalParamSize; + for (auto& param: fn->returnParameters()) + totalRetParamSize += param->type()->sizeOnStack(); + func["totalRetParamSize"] = totalRetParamSize; + + recFuncs.append(func); + } + }; + recordRecursiveSolFuncs(m_context); + recordRecursiveSolFuncs(m_runtimeContext); + + if (!recFuncs.empty()) + m_metadata["recursiveFunctions"] = recFuncs; + return m_metadata; +} diff --git a/libsolidity/codegen/ExtraMetadata.h b/libsolidity/codegen/ExtraMetadata.h new file mode 100644 index 0000000000..4536c5248e --- /dev/null +++ b/libsolidity/codegen/ExtraMetadata.h @@ -0,0 +1,53 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * The extra metadata recorder + */ + +#include +#include + +#include + +#include + +#pragma once + +namespace solidity::frontend +{ + +class ExtraMetadataRecorder +{ + CompilerContext const& m_context; + CompilerContext const& m_runtimeContext; + /// The root JSON value of the metadata + /// Current mappings: + /// - "recursiveFunctions": array of functions involved in recursion + Json::Value m_metadata; + +public: + ExtraMetadataRecorder(CompilerContext const& _context, CompilerContext const& _runtimeContext) + : m_context(_context), m_runtimeContext(_runtimeContext) + { + } + + /// Stores the extra metadata of @a _contract in `metadata` + Json::Value run(ContractDefinition const& _contract); +}; + +} diff --git a/libsolidity/codegen/FuncPtrTracker.cpp b/libsolidity/codegen/FuncPtrTracker.cpp new file mode 100644 index 0000000000..393abb577d --- /dev/null +++ b/libsolidity/codegen/FuncPtrTracker.cpp @@ -0,0 +1,106 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::frontend; + +void FuncPtrTracker::endVisit(Identifier const& _identifier) +{ + Declaration const* declaration = _identifier.annotation().referencedDeclaration; + FunctionDefinition const* functionDef = dynamic_cast(declaration); + if (!functionDef) + return; + + solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual); + FunctionDefinition const& resolvedFunctionDef = functionDef->resolveVirtual(m_contract); + + solAssert(resolvedFunctionDef.functionType(true)); + solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal); + if (_identifier.annotation().calledDirectly) + return; + m_contract.annotation().intFuncPtrRefs.insert(&resolvedFunctionDef); +} + +void FuncPtrTracker::endVisit(MemberAccess const& _memberAccess) +{ + auto memberFunctionType = dynamic_cast(_memberAccess.annotation().type); + + if (memberFunctionType && memberFunctionType->hasBoundFirstArgument()) + { + solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static); + if (memberFunctionType->kind() == FunctionType::Kind::Internal) + m_contract.annotation().intFuncPtrRefs.insert( + &dynamic_cast(memberFunctionType->declaration())); + } + + Type::Category objectCategory = _memberAccess.expression().annotation().type->category(); + switch (objectCategory) + { + case Type::Category::TypeType: + { + Type const& actualType + = *dynamic_cast(*_memberAccess.expression().annotation().type).actualType(); + + if (actualType.category() == Type::Category::Contract) + { + ContractType const& contractType = dynamic_cast(actualType); + if (contractType.isSuper()) + { + solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved."); + ContractDefinition const* super = contractType.contractDefinition().superContract(m_contract); + solAssert(super, "Super contract not available."); + FunctionDefinition const& resolvedFunctionDef + = dynamic_cast(*_memberAccess.annotation().referencedDeclaration) + .resolveVirtual(m_contract, super); + + solAssert(resolvedFunctionDef.functionType(true)); + solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal); + m_contract.annotation().intFuncPtrRefs.insert(&resolvedFunctionDef); + } + else if (memberFunctionType && memberFunctionType->kind() == FunctionType::Kind::Internal) + { + if (auto const* function + = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + m_contract.annotation().intFuncPtrRefs.insert(function); + } + } + break; + } + case Type::Category::Module: + { + if (auto const* function + = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + { + auto funType = dynamic_cast(_memberAccess.annotation().type); + solAssert(function && function->isFree()); + solAssert(function->functionType(true)); + solAssert(function->functionType(true)->kind() == FunctionType::Kind::Internal); + solAssert(funType->kind() == FunctionType::Kind::Internal); + solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static); + + m_contract.annotation().intFuncPtrRefs.insert(function); + } + break; + } + default: + break; + } +} diff --git a/libsolidity/codegen/FuncPtrTracker.h b/libsolidity/codegen/FuncPtrTracker.h new file mode 100644 index 0000000000..4b5621c877 --- /dev/null +++ b/libsolidity/codegen/FuncPtrTracker.h @@ -0,0 +1,55 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Tracks function pointer references + */ + +#pragma once + +#include +#include + +namespace solidity::frontend +{ + +/** + * This class is used to add all the function pointer references in the contract and its ancestor contracts to the + * ContractDefinitionAnnotation::intFuncPtrRefs. The visitor is copied from the yul codegen pipeline's usage of + * IRGeneratorForStatements::assignInternalFunctionIDIfNotCalledDirectly() + */ +class FuncPtrTracker: private ASTConstVisitor +{ +public: + FuncPtrTracker(ContractDefinition const& _contract): m_contract(_contract) {} + + void run() + { + for (ContractDefinition const* base: m_contract.annotation().linearizedBaseContracts) + { + base->accept(*this); + } + } + +private: + ContractDefinition const& m_contract; + + void endVisit(Identifier const& _identifier); + void endVisit(MemberAccess const& _memberAccess); +}; + +} diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 9b5c87818b..91bd9014cb 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -126,6 +127,21 @@ CompilerStack::~CompilerStack() TypeProvider::reset(); } +void CompilerStack::populateFuncPtrRefs() +{ + for (Source const* source: m_sourceOrder) + { + if (!source->ast) + continue; + + for (ContractDefinition const* contract: ASTNode::filteredNodes(source->ast->nodes())) + { + FuncPtrTracker tracker{*contract}; + tracker.run(); + } + } +} + void CompilerStack::createAndAssignCallGraphs() { for (Source const* source: m_sourceOrder) @@ -583,6 +599,7 @@ bool CompilerStack::analyzeLegacy(bool _noErrorsSoFar) // Create & assign callgraphs and check for contract dependency cycles if (noErrors) { + populateFuncPtrRefs(); createAndAssignCallGraphs(); annotateInternalFunctionIDs(); findAndReportCyclicContractDependencies(); @@ -1158,6 +1175,17 @@ std::string const& CompilerStack::metadata(Contract const& _contract) const return _contract.metadata.init([&]{ return createMetadata(_contract, m_viaIR); }); } +Json::Value const& CompilerStack::extraMetadata(std::string const& _contractName) const +{ + Contract const& contr = contract(_contractName); + if (m_stackState < AnalysisSuccessful) + solThrow(CompilerError, "Analysis was not successful."); + + solAssert(contr.contract, ""); + + return contr.extraMetadata; +} + CharStream const& CompilerStack::charStream(std::string const& _sourceName) const { if (m_stackState < SourcesSet) @@ -1490,6 +1518,7 @@ void CompilerStack::compileContract( solAssert(false, "Optimizer exception during compilation"); } + compiledContract.extraMetadata = compiler->extraMetadata(); _otherCompilers[compiledContract.contract] = compiler; assembleYul(_contract, compiler->assemblyPtr(), compiler->runtimeAssemblyPtr()); diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 57d30e602d..7fdbbd5d23 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -341,6 +341,9 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac /// @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)); } + /// @returns the contract metadata containing miscellaneous information + Json::Value const& extraMetadata(std::string const& _contractName) const; + /// @returns the CBOR-encoded metadata matching the pipeline selected using the viaIR setting. bytes cborMetadata(std::string const& _contractName) const { return cborMetadata(_contractName, m_viaIR); } @@ -392,6 +395,7 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac std::string yulIROptimized; ///< Optimized Yul IR code. Json::Value yulIRAst; ///< JSON AST of Yul IR code. Json::Value yulIROptimizedAst; ///< JSON AST of optimized Yul IR code. + Json::Value extraMetadata; ///< Misc metadata util::LazyInit metadata; ///< The metadata json that will be hashed into the chain. util::LazyInit abi; util::LazyInit storageLayout; @@ -403,6 +407,9 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac mutable std::optional runtimeSourceMapping; }; + /// Populates the function pointer references in the AST annotation of each contract + void populateFuncPtrRefs(); + void createAndAssignCallGraphs(); void findAndReportCyclicContractDependencies(); diff --git a/libsolidity/interface/OptimiserSettings.h b/libsolidity/interface/OptimiserSettings.h index 46683088a0..7667961525 100644 --- a/libsolidity/interface/OptimiserSettings.h +++ b/libsolidity/interface/OptimiserSettings.h @@ -70,7 +70,6 @@ struct OptimiserSettings static OptimiserSettings minimal() { OptimiserSettings s = none(); - s.runJumpdestRemover = true; s.runPeephole = true; s.simpleCounterForLoopUncheckedIncrement = true; return s; @@ -80,10 +79,7 @@ struct OptimiserSettings { OptimiserSettings s; s.runOrderLiterals = true; - s.runInliner = true; - s.runJumpdestRemover = true; s.runPeephole = true; - s.runDeduplicate = true; s.runCSE = true; s.runConstantOptimiser = true; s.simpleCounterForLoopUncheckedIncrement = true; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 85a5a5d232..876c005ced 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -1535,6 +1535,10 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting if (compilationSuccess && isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "evm.gasEstimates", wildcardMatchesExperimental)) evmData["gasEstimates"] = compilerStack.gasEstimates(contractName); + Json::Value extraMetadata = compilerStack.extraMetadata(contractName); + if (compilationSuccess && !extraMetadata.empty()) + evmData["extraMetadata"] = extraMetadata; + if (compilationSuccess && isArtifactRequested( _inputsAndSettings.outputSelection, file, diff --git a/libsolidity/interface/Version.cpp b/libsolidity/interface/Version.cpp index 565ff2a60e..7eb2c84cc7 100644 --- a/libsolidity/interface/Version.cpp +++ b/libsolidity/interface/Version.cpp @@ -26,6 +26,7 @@ #include char const* solidity::frontend::VersionNumber = ETH_PROJECT_VERSION; +char const* solidity::frontend::ZKEVMVersionString = SOL_VERSION_ZKEVM; std::string const solidity::frontend::VersionString = std::string(solidity::frontend::VersionNumber) + diff --git a/libsolidity/interface/Version.h b/libsolidity/interface/Version.h index bc05fb4033..590960dd3a 100644 --- a/libsolidity/interface/Version.h +++ b/libsolidity/interface/Version.h @@ -39,6 +39,7 @@ extern std::string const VersionString; extern std::string const VersionStringStrict; extern bytes const VersionCompactBytes; extern bool const VersionIsRelease; +extern char const* ZKEVMVersionString; } } diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index cc811f75d1..12e715147f 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -98,6 +98,18 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, return analysisInfo; } +AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect( + Dialect const& _dialect, Object const& _object, yul::ExternalIdentifierAccess::Resolver _resolver) +{ + ErrorList errorList; + langutil::ErrorReporter errors(errorList); + AsmAnalysisInfo analysisInfo; + bool success = yul::AsmAnalyzer(analysisInfo, errors, _dialect, _resolver, _object.qualifiedDataNames()) + .analyze(*_object.code); + yulAssert(success && !errors.hasErrors(), "Invalid assembly/yul code."); + return analysisInfo; +} + std::vector AsmAnalyzer::operator()(Literal const& _literal) { expectValidType(_literal.type, nativeLocationOf(_literal)); diff --git a/libyul/AsmAnalysis.h b/libyul/AsmAnalysis.h index c49e685591..48f1f12b02 100644 --- a/libyul/AsmAnalysis.h +++ b/libyul/AsmAnalysis.h @@ -78,6 +78,8 @@ class AsmAnalyzer /// Performs analysis on the outermost code of the given object and returns the analysis info. /// Asserts on failure. static AsmAnalysisInfo analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object); + static AsmAnalysisInfo analyzeStrictAssertCorrect( + Dialect const& _dialect, Object const& _object, yul::ExternalIdentifierAccess::Resolver _resolver); std::vector operator()(Literal const& _literal); std::vector operator()(Identifier const&); diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index 811a6239b7..2dda3fed18 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -64,6 +64,8 @@ add_library(yul backends/evm/StackLayoutGenerator.h backends/evm/VariableReferenceCounter.h backends/evm/VariableReferenceCounter.cpp + backends/evm/ZKEVMIntrinsics.cpp + backends/evm/ZKEVMIntrinsics.h optimiser/ASTCopier.cpp optimiser/ASTCopier.h optimiser/ASTWalker.cpp diff --git a/libyul/backends/evm/AsmCodeGen.cpp b/libyul/backends/evm/AsmCodeGen.cpp index 645d1fd87b..f8df4b355b 100644 --- a/libyul/backends/evm/AsmCodeGen.cpp +++ b/libyul/backends/evm/AsmCodeGen.cpp @@ -38,6 +38,7 @@ void CodeGenerator::assemble( AsmAnalysisInfo& _analysisInfo, evmasm::Assembly& _assembly, langutil::EVMVersion _evmVersion, + std::shared_ptr& _context, // out ExternalIdentifierAccess::CodeGenerator _identifierAccessCodeGen, bool _useNamedLabelsForFunctions, bool _optimizeStackAllocation @@ -58,6 +59,7 @@ void CodeGenerator::assemble( CodeTransform::UseNamedLabels::Never ); transform(_parsedData); + _context = transform.context(); if (!transform.stackErrors().empty()) assertThrow( false, diff --git a/libyul/backends/evm/AsmCodeGen.h b/libyul/backends/evm/AsmCodeGen.h index b793380749..5c87b3cbc3 100644 --- a/libyul/backends/evm/AsmCodeGen.h +++ b/libyul/backends/evm/AsmCodeGen.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include @@ -44,6 +45,7 @@ class CodeGenerator AsmAnalysisInfo& _analysisInfo, evmasm::Assembly& _assembly, langutil::EVMVersion _evmVersion, + std::shared_ptr& _context, // out ExternalIdentifierAccess::CodeGenerator _identifierAccess = {}, bool _useNamedLabelsForFunctions = false, bool _optimizeStackAllocation = false diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 50e48f7681..e7cc751a1e 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -608,6 +608,9 @@ void CodeTransform::createFunctionEntryID(FunctionDefinition const& _function) astID ) : m_assembly.newLabelId(); + + m_context->functionInfoMap[_function.name].emplace( + CodeTransformContext::FunctionInfo{&_function, m_context->functionEntryIDs[&scopeFunction]}); } AbstractAssembly::LabelID CodeTransform::functionEntryID(Scope::Function const& _scopeFunction) const diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h index bad9a357ff..d0248b3c4f 100644 --- a/libyul/backends/evm/EVMCodeTransform.h +++ b/libyul/backends/evm/EVMCodeTransform.h @@ -42,7 +42,18 @@ struct AsmAnalysisInfo; struct CodeTransformContext { + struct FunctionInfo + { + FunctionDefinition const* ast; + AbstractAssembly::LabelID label; + bool operator<(FunctionInfo const& _other) const + { + return std::less{}(ast, _other.ast); + } + }; + std::map functionEntryIDs; + std::map> functionInfoMap; std::map variableStackHeights; std::map variableReferences; @@ -143,6 +154,7 @@ class CodeTransform void operator()(Continue const&); void operator()(Leave const&); void operator()(Block const& _block); + std::shared_ptr context() { return m_context; } private: AbstractAssembly::LabelID labelFromIdentifier(Identifier const& _identifier); diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index f3c529bb1a..2e0a9313ec 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -32,9 +32,11 @@ #include #include #include +#include #include #include +#include #include @@ -171,6 +173,10 @@ std::set createReservedIdentifiers(langutil::EVMVersion _evmVersion) ) reserved.emplace(name); } + for (auto const& intr: solidity::zkevm::intrInfos) + { + reserved.emplace(intr.name); + } reserved += std::vector{ "linkersymbol"_yulstring, "datasize"_yulstring, @@ -182,6 +188,56 @@ std::set createReservedIdentifiers(langutil::EVMVersion _evmVersion) return reserved; } +std::pair createVerbatimWrapper( + const std::string& _name, + size_t _params, + size_t _returns, + bool _sideEffects, + const std::vector>& _literalKinds) +{ + SideEffects sideEffects{}; + if (_sideEffects) + { + sideEffects + = {/*movable=*/false, + /*movableApartFromEffects=*/false, + /*canBeRemoved=*/false, + /*canBeRemovedIfNoMSize=*/false, + /*cannotLoop=*/true, + /*otherState=*/SideEffects::Effect::Write, + /*storage=*/SideEffects::Effect::Write, + /*memory=*/SideEffects::Effect::Write}; + } + + std::function genCode; + if (!_literalKinds.empty()) + { + genCode = [=](FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&) + { + yulAssert(_call.arguments.size() == _literalKinds.size(), ""); + size_t numLits = 0; + for (const auto&& [arg, kind]: ranges::views::zip(_call.arguments, _literalKinds)) + { + if (!kind) + continue; + + yulAssert(std::holds_alternative(arg), "Expected literal"); + yulAssert(std::get(arg).kind == kind, "Unexpected literal kind"); + numLits++; + } + + _assembly.appendVerbatim(asBytes(_name), _params - numLits, _returns); + }; + } + else + { + genCode = [=](FunctionCall const&, AbstractAssembly& _assembly, BuiltinContext&) + { _assembly.appendVerbatim(asBytes(_name), _params, _returns); }; + } + + return createFunction(_name, _params, _returns, sideEffects, _literalKinds, genCode); +} + std::map createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess) { @@ -210,6 +266,11 @@ std::map createBuiltins(langutil::EVMVersion _ builtins.emplace(createEVMFunction(_evmVersion, name, opcode)); } + for (auto const& intr: solidity::zkevm::intrInfos) + { + builtins.emplace(createVerbatimWrapper(intr.name, intr.args, intr.ret, intr.sideEffects, intr.literalKinds)); + } + if (_objectAccess) { builtins.emplace(createFunction("linkersymbol", 1, 1, SideEffects{}, {LiteralKind::String}, []( @@ -532,6 +593,8 @@ EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectA })); m_functions["u256_to_bool"_yulstring].parameters = {"u256"_yulstring}; m_functions["u256_to_bool"_yulstring].returns = {"bool"_yulstring}; + + m_functions["$zk_to_l1"_yulstring].parameters = {boolType, defaultType, defaultType}; } BuiltinFunctionForEVM const* EVMDialectTyped::discardFunction(YulString _type) const diff --git a/libyul/backends/evm/ZKEVMIntrinsics.cpp b/libyul/backends/evm/ZKEVMIntrinsics.cpp new file mode 100644 index 0000000000..fba3237332 --- /dev/null +++ b/libyul/backends/evm/ZKEVMIntrinsics.cpp @@ -0,0 +1,61 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include +#include +using namespace solidity::zkevm; + +// clang-format off +const std::array solidity::zkevm::intrInfos{{ +// Name Args Rets SideEffect Literals + {"$zk_to_l1", 3, 0, true}, + {"$zk_code_source", 0, 1, false}, + {"$zk_precompile", 2, 1, true}, + {"$zk_meta", 0, 1, false}, + {"$zk_mimic_call", 3, 1, true}, + {"$zk_system_mimic_call", 5, 1, true}, + {"$zk_mimic_call_byref", 2, 1, true}, + {"$zk_system_mimic_call_byref", 4, 1, true}, + {"$zk_raw_call", 4, 1, true}, + {"$zk_raw_call_byref", 3, 1, true}, + {"$zk_system_call", 6, 1, true}, + {"$zk_system_call_byref", 5, 1, true}, + {"$zk_static_raw_call", 4, 1, true}, + {"$zk_static_raw_call_byref", 3, 1, true}, + {"$zk_static_system_call", 6, 1, true}, + {"$zk_static_system_call_byref", 5, 1, true}, + {"$zk_delegate_raw_call", 4, 1, true}, + {"$zk_delegate_raw_call_byref", 3, 1, true}, + {"$zk_delegate_system_call", 6, 1, true}, + {"$zk_delegate_system_call_byref", 5, 1, true}, + {"$zk_set_context_u128", 1, 0, true}, + {"$zk_set_pubdata_price", 1, 0, true}, + {"$zk_increment_tx_counter", 0, 0, true}, + {"$zk_event_initialize", 2, 0, true}, + {"$zk_event_write", 2, 0, true}, + {"$zk_load_calldata_into_active_ptr", 0, 0, true}, + {"$zk_load_returndata_into_active_ptr", 0, 0, true}, + {"$zk_ptr_add_into_active", 1, 0, true}, + {"$zk_ptr_shrink_into_active", 1, 0, true}, + {"$zk_ptr_pack_into_active", 1, 0, true}, + {"$zk_multiplication_high", 2, 1, false}, + {"$zk_global_load", 1, 1, false, {yul::LiteralKind::String}}, + {"$zk_global_store", 2, 0, true, {yul::LiteralKind::String, std::nullopt}}, + {"$zk_global_extra_abi_data", 1, 1, false} +}}; +// clang-format on diff --git a/libyul/backends/evm/ZKEVMIntrinsics.h b/libyul/backends/evm/ZKEVMIntrinsics.h new file mode 100644 index 0000000000..9261fc0478 --- /dev/null +++ b/libyul/backends/evm/ZKEVMIntrinsics.h @@ -0,0 +1,37 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include + +namespace solidity::zkevm +{ + +struct IntrInfo +{ + using LiteralKinds = const std::vector>; + const std::string name; + const size_t args; + const size_t ret; + const bool sideEffects; + LiteralKinds literalKinds = {}; +}; + +extern const std::array intrInfos; +} diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 7181bfd4cc..b060cb0a03 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -780,8 +780,9 @@ void CommandLineInterface::processInput() void CommandLineInterface::printVersion() { - sout() << "solc, the solidity compiler commandline interface" << std::endl; + sout() << "solc, the zkEVM Solidity compiler commandline interface" << std::endl; sout() << "Version: " << solidity::frontend::VersionString << std::endl; + sout() << "zkEVM: " << solidity::frontend::ZKEVMVersionString << std::endl; } void CommandLineInterface::printLicense() diff --git a/test/libyul/yulSyntaxTests/zkevm/code_source.yul b/test/libyul/yulSyntaxTests/zkevm/code_source.yul new file mode 100644 index 0000000000..b61f33052b --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/code_source.yul @@ -0,0 +1,6 @@ +{ + let a := $zk_code_source() +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/event.yul b/test/libyul/yulSyntaxTests/zkevm/event.yul new file mode 100644 index 0000000000..4a9ff0c485 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/event.yul @@ -0,0 +1,7 @@ +{ + $zk_event_initialize(0xa, 0xb) + $zk_event_write(0xa, 0xb) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/global.yul b/test/libyul/yulSyntaxTests/zkevm/global.yul new file mode 100644 index 0000000000..0970b9de2d --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/global.yul @@ -0,0 +1,8 @@ +{ + let a := $zk_global_load("memory_pointer") + $zk_global_store("memory_pointer", 0xa) + let b := $zk_global_extra_abi_data(0xb) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/increment_tx_counter.yul b/test/libyul/yulSyntaxTests/zkevm/increment_tx_counter.yul new file mode 100644 index 0000000000..b773fe504c --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/increment_tx_counter.yul @@ -0,0 +1,6 @@ +{ + $zk_increment_tx_counter() +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/code_source.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/code_source.yul new file mode 100644 index 0000000000..df1f062db1 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/code_source.yul @@ -0,0 +1,7 @@ +{ + $zk_code_source() +} +// ==== +// dialect: evm +// ---- +// TypeError 3083: (3-20): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/event.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/event.yul new file mode 100644 index 0000000000..f8261b1d79 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/event.yul @@ -0,0 +1,9 @@ +{ + $zk_event_initialize(0xa) + $zk_event_write(0xa) +} +// ==== +// dialect: evm +// ---- +// TypeError 7000: (3-23): Function "$zk_event_initialize" expects 2 arguments but got 1. +// TypeError 7000: (30-45): Function "$zk_event_write" expects 2 arguments but got 1. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/global.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/global.yul new file mode 100644 index 0000000000..4759716711 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/global.yul @@ -0,0 +1,11 @@ +{ + $zk_global_load("memory_pointer") + $zk_global_store(0xa, 0xa) + $zk_global_extra_abi_data(0xb) +} +// ==== +// dialect: evm +// ---- +// TypeError 3083: (3-36): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 5859: (55-58): Function expects string literal. +// TypeError 3083: (66-96): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/increment_tx_counter.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/increment_tx_counter.yul new file mode 100644 index 0000000000..aee27cf1fe --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/increment_tx_counter.yul @@ -0,0 +1,7 @@ +{ + let a := $zk_increment_tx_counter() +} +// ==== +// dialect: evm +// ---- +// DeclarationError 3812: (3-38): Variable count mismatch for declaration of "a": 1 variables and 0 values. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/load_into_active_ptr.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/load_into_active_ptr.yul new file mode 100644 index 0000000000..d76e8bb038 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/load_into_active_ptr.yul @@ -0,0 +1,9 @@ +{ + let a := $zk_load_calldata_into_active_ptr() + let b := $zk_load_returndata_into_active_ptr() +} +// ==== +// dialect: evm +// ---- +// DeclarationError 3812: (3-47): Variable count mismatch for declaration of "a": 1 variables and 0 values. +// DeclarationError 3812: (49-95): Variable count mismatch for declaration of "b": 1 variables and 0 values. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/meta.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/meta.yul new file mode 100644 index 0000000000..eee810f853 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/meta.yul @@ -0,0 +1,7 @@ +{ + $zk_meta() +} +// ==== +// dialect: evm +// ---- +// TypeError 3083: (3-13): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/mimic_call.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/mimic_call.yul new file mode 100644 index 0000000000..7eb798e201 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/mimic_call.yul @@ -0,0 +1,9 @@ +{ + $zk_mimic_call(0xa, 0xb, 0xc) + $zk_mimic_call_byref(0xa, 0xb) +} +// ==== +// dialect: evm +// ---- +// TypeError 3083: (3-32): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (34-64): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/multiplication_high.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/multiplication_high.yul new file mode 100644 index 0000000000..623ab875c6 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/multiplication_high.yul @@ -0,0 +1,7 @@ +{ + $zk_multiplication_high(0xa, 0xb) +} +// ==== +// dialect: evm +// ---- +// TypeError 3083: (3-36): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/precompile.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/precompile.yul new file mode 100644 index 0000000000..460182adb1 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/precompile.yul @@ -0,0 +1,7 @@ +{ + $zk_precompile(0xa, 0xb) +} +// ==== +// dialect: evm +// ---- +// TypeError 3083: (3-27): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/ptr_into_active_ptr.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/ptr_into_active_ptr.yul new file mode 100644 index 0000000000..e0765fbab2 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/ptr_into_active_ptr.yul @@ -0,0 +1,11 @@ +{ + $zk_ptr_add_into_active() + $zk_ptr_shrink_into_active() + $zk_ptr_pack_into_active() +} +// ==== +// dialect: evm +// ---- +// TypeError 7000: (3-26): Function "$zk_ptr_add_into_active" expects 1 arguments but got 0. +// TypeError 7000: (30-56): Function "$zk_ptr_shrink_into_active" expects 1 arguments but got 0. +// TypeError 7000: (60-84): Function "$zk_ptr_pack_into_active" expects 1 arguments but got 0. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/raw_call.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/raw_call.yul new file mode 100644 index 0000000000..e26c99865f --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/raw_call.yul @@ -0,0 +1,17 @@ +{ + $zk_raw_call(0xa, 0xb, 0xc, 0xd) + $zk_raw_call_byref(0xa, 0xb, 0xc) + $zk_static_raw_call(0xa, 0xb, 0xc, 0xd) + $zk_static_raw_call_byref(0xa, 0xb, 0xc) + $zk_delegate_raw_call(0xa, 0xb, 0xc, 0xd) + $zk_delegate_raw_call_byref(0xa, 0xb, 0xc) +} +// ==== +// dialect: evm +// ---- +// TypeError 3083: (3-35): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (37-70): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (72-111): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (113-153): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (155-196): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (198-240): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/set_context_u128.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/set_context_u128.yul new file mode 100644 index 0000000000..b5f34b113f --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/set_context_u128.yul @@ -0,0 +1,7 @@ +{ + $zk_set_context_u128() +} +// ==== +// dialect: evm +// ---- +// TypeError 7000: (3-23): Function "$zk_set_context_u128" expects 1 arguments but got 0. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/set_pubdata_price.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/set_pubdata_price.yul new file mode 100644 index 0000000000..834104aa07 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/set_pubdata_price.yul @@ -0,0 +1,7 @@ +{ + $zk_set_pubdata_price() +} +// ==== +// dialect: evm +// ---- +// TypeError 7000: (3-24): Function "$zk_set_pubdata_price" expects 1 arguments but got 0. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/system_call.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/system_call.yul new file mode 100644 index 0000000000..ae5c26644e --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/system_call.yul @@ -0,0 +1,17 @@ +{ + $zk_system_call(0xa, 0xb, 0xc, 0xd, 0xe, 0xf) + $zk_system_call_byref(0xa, 0xb, 0xc, 0xd, 0xe) + $zk_static_system_call(0xa, 0xb, 0xc, 0xd, 0xe, 0xf) + $zk_static_system_call_byref(0xa, 0xb, 0xc, 0xd, 0xe) + $zk_delegate_system_call(0xa, 0xb, 0xc, 0xd, 0xe, 0xf) + $zk_delegate_system_call_byref(0xa, 0xb, 0xc, 0xd, 0xe) +} +// ==== +// dialect: evm +// ---- +// TypeError 3083: (3-48): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (50-96): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (98-150): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (152-205): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (207-261): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (263-318): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/system_mimic_call.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/system_mimic_call.yul new file mode 100644 index 0000000000..3894b80bc1 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/system_mimic_call.yul @@ -0,0 +1,9 @@ +{ + $zk_system_mimic_call(0xa, 0xb, 0xc, 0xd, 0xe) + $zk_system_mimic_call_byref(0xa, 0xb, 0xc, 0xd) +} +// ==== +// dialect: evm +// ---- +// TypeError 3083: (3-49): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (51-98): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/to_l1.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/to_l1.yul new file mode 100644 index 0000000000..bfd32bdbfe --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/to_l1.yul @@ -0,0 +1,7 @@ +{ + $zk_to_l1(0xa, 0xb) +} +// ==== +// dialect: evm +// ---- +// TypeError 7000: (3-12): Function "$zk_to_l1" expects 3 arguments but got 2. diff --git a/test/libyul/yulSyntaxTests/zkevm/invalid/to_l1_typed.yul b/test/libyul/yulSyntaxTests/zkevm/invalid/to_l1_typed.yul new file mode 100644 index 0000000000..aa15cd22f7 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/invalid/to_l1_typed.yul @@ -0,0 +1,7 @@ +{ + $zk_to_l1(0xa, 0xa, 0xb) +} +// ==== +// dialect: evmTyped +// ---- +// TypeError 3781: (13-16): Expected a value of type "bool" but got "u256". diff --git a/test/libyul/yulSyntaxTests/zkevm/load_into_active_ptr.yul b/test/libyul/yulSyntaxTests/zkevm/load_into_active_ptr.yul new file mode 100644 index 0000000000..1d467b7344 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/load_into_active_ptr.yul @@ -0,0 +1,7 @@ +{ + $zk_load_calldata_into_active_ptr() + $zk_load_returndata_into_active_ptr() +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/meta.yul b/test/libyul/yulSyntaxTests/zkevm/meta.yul new file mode 100644 index 0000000000..3314db1530 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/meta.yul @@ -0,0 +1,6 @@ +{ + let a := $zk_meta() +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/mimic_call.yul b/test/libyul/yulSyntaxTests/zkevm/mimic_call.yul new file mode 100644 index 0000000000..20a3e15850 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/mimic_call.yul @@ -0,0 +1,7 @@ +{ + let a := $zk_mimic_call(0xa, 0xb, 0xc) + let b := $zk_mimic_call_byref(0xa, 0xb) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/multiplication_high.yul b/test/libyul/yulSyntaxTests/zkevm/multiplication_high.yul new file mode 100644 index 0000000000..0204b49fbc --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/multiplication_high.yul @@ -0,0 +1,6 @@ +{ + let a := $zk_multiplication_high(0xa, 0xb) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/precompile.yul b/test/libyul/yulSyntaxTests/zkevm/precompile.yul new file mode 100644 index 0000000000..88f1561b70 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/precompile.yul @@ -0,0 +1,6 @@ +{ + let a := $zk_precompile(0xa, 0xb) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/ptr_into_active_ptr.yul b/test/libyul/yulSyntaxTests/zkevm/ptr_into_active_ptr.yul new file mode 100644 index 0000000000..1459122782 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/ptr_into_active_ptr.yul @@ -0,0 +1,8 @@ +{ + $zk_ptr_add_into_active(0xa) + $zk_ptr_shrink_into_active(0xa) + $zk_ptr_pack_into_active(0xa) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/raw_call.yul b/test/libyul/yulSyntaxTests/zkevm/raw_call.yul new file mode 100644 index 0000000000..18abff37d5 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/raw_call.yul @@ -0,0 +1,11 @@ +{ + let a := $zk_raw_call(0xa, 0xb, 0xc, 0xd) + let b := $zk_raw_call_byref(0xa, 0xb, 0xc) + let c := $zk_static_raw_call(0xa, 0xb, 0xc, 0xd) + let d := $zk_static_raw_call_byref(0xa, 0xb, 0xc) + let e := $zk_delegate_raw_call(0xa, 0xb, 0xc, 0xd) + let f := $zk_delegate_raw_call_byref(0xa, 0xb, 0xc) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/set_context_u128.yul b/test/libyul/yulSyntaxTests/zkevm/set_context_u128.yul new file mode 100644 index 0000000000..9511745266 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/set_context_u128.yul @@ -0,0 +1,6 @@ +{ + $zk_set_context_u128(0xa) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/set_pubdata_price.yul b/test/libyul/yulSyntaxTests/zkevm/set_pubdata_price.yul new file mode 100644 index 0000000000..4e76f22c07 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/set_pubdata_price.yul @@ -0,0 +1,6 @@ +{ + $zk_set_pubdata_price(0xa) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/system_call.yul b/test/libyul/yulSyntaxTests/zkevm/system_call.yul new file mode 100644 index 0000000000..30ceb553cc --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/system_call.yul @@ -0,0 +1,11 @@ +{ + let a := $zk_system_call(0xa, 0xb, 0xc, 0xd, 0xe, 0xf) + let b := $zk_system_call_byref(0xa, 0xb, 0xc, 0xd, 0xe) + let c := $zk_static_system_call(0xa, 0xb, 0xc, 0xd, 0xe, 0xf) + let d := $zk_static_system_call_byref(0xa, 0xb, 0xc, 0xd, 0xe) + let e := $zk_delegate_system_call(0xa, 0xb, 0xc, 0xd, 0xe, 0xf) + let f := $zk_delegate_system_call_byref(0xa, 0xb, 0xc, 0xd, 0xe) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/system_mimic_call.yul b/test/libyul/yulSyntaxTests/zkevm/system_mimic_call.yul new file mode 100644 index 0000000000..7458ac94a4 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/system_mimic_call.yul @@ -0,0 +1,7 @@ +{ + let a := $zk_system_mimic_call(0xa, 0xb, 0xc, 0xd, 0xe) + let b := $zk_system_mimic_call_byref(0xa, 0xb, 0xc, 0xd) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/to_l1.yul b/test/libyul/yulSyntaxTests/zkevm/to_l1.yul new file mode 100644 index 0000000000..253fefdfb9 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/to_l1.yul @@ -0,0 +1,6 @@ +{ + $zk_to_l1(true, 0xa, 0xb) +} +// ==== +// dialect: evm +// ---- diff --git a/test/libyul/yulSyntaxTests/zkevm/to_l1_typed.yul b/test/libyul/yulSyntaxTests/zkevm/to_l1_typed.yul new file mode 100644 index 0000000000..4886a59180 --- /dev/null +++ b/test/libyul/yulSyntaxTests/zkevm/to_l1_typed.yul @@ -0,0 +1,6 @@ +{ + $zk_to_l1(true, 0xa, 0xb) +} +// ==== +// dialect: evmTyped +// ---- diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index 7a4f625c15..f952e890b7 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -141,7 +141,8 @@ BOOST_AUTO_TEST_CASE(version) OptionsReaderAndMessages result = runCLI({"solc", "--version"}, ""); BOOST_TEST(result.success); - BOOST_TEST(boost::ends_with(result.stdoutContent, "Version: " + solidity::frontend::VersionString + "\n")); + BOOST_TEST(boost::ends_with(result.stdoutContent, "Version: " + solidity::frontend::VersionString + "\n" + + "zkEVM: " + solidity::frontend::ZKEVMVersionString + "\n")); BOOST_TEST(result.stderrContent == ""); BOOST_TEST(result.options.input.mode == InputMode::Version); }