diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..932c526 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,49 @@ +ARG VARIANT="16" +FROM mcr.microsoft.com/devcontainers/javascript-node:1-${VARIANT} + +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends build-essential ca-certificates clang-format-15 clang-tidy-15 cmake curl git libzstd-dev ninja-build python3 python3-pip ssh sudo wabt wget zlib1g-dev wget git-lfs zlib1g-dev wget libffi-dev libncurses5-dev libncursesw5-dev libxml2-dev binaryen unzip + +# RUN pip3 install cmake-format lit --no-cache-dir +# RUN cd /usr/bin/ && ln -s python3 python && ln -s clang-format-15 clang-format && ln -s clang-tidy-15 clang-tidy && ln -s run-clang-tidy-15 run-clang-tidy + +RUN mkdir -p /opt +WORKDIR /opt + +COPY install_llvm16.sh /opt/install_llvm16.sh +RUN chmod +x /opt/install_llvm16.sh + +RUN wget https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.4/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz && /opt/install_llvm16.sh + +RUN git clone https://github.com/emscripten-core/emsdk.git +WORKDIR /opt/emsdk +RUN ./emsdk install 3.1.69 +RUN ./emsdk activate 3.1.69 + +RUN curl -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh -s -- -y +RUN bash -c ". /root/.cargo/env" +RUN bash -c ". ~/.cargo/env && rustup install 1.84.0 && rustup default 1.84.0" +WORKDIR /home/admin + +WORKDIR /opt + +RUN echo "export PATH=/opt/llvm16/bin:/opt:\$PATH" >> $HOME/.profile +RUN echo "export LLVM_SYS_160_PREFIX=/opt/llvm16" >> $HOME/.profile +ENV PATH=/opt/llvm16/bin:/opt:$PATH +ENV LLVM_SYS_160_PREFIX=/opt/llvm16 + +ENV RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static +ENV RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup +COPY install_rust.sh /opt/install_rust.sh +RUN chmod +x /opt/install_rust.sh +RUN /opt/install_rust.sh + +RUN mkdir -p /root/.cargo && touch /root/.cargo/env +RUN echo "source \"$HOME/.cargo/env\"" >> $HOME/.profile + +# install foundry +RUN curl -L https://foundry.paradigm.xyz | bash +ENV PATH=~/.foundry/bin:$PATH +RUN bash -c "source ~/.bashrc && foundryup" + +WORKDIR /opt diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..810d6b2 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,7 @@ +{ + // ... + // "build": { "dockerfile": "Dockerfile" }, + "image": "dtvmdev1/dtvm-sol-dev-x64:main" + // ... + } + \ No newline at end of file diff --git a/.devcontainer/install_llvm16.sh b/.devcontainer/install_llvm16.sh new file mode 100644 index 0000000..06e4f5b --- /dev/null +++ b/.devcontainer/install_llvm16.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -e +cd /opt +ls +tar -xvf clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz +rm -rf clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz +mv clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04 llvm16 diff --git a/.devcontainer/install_rust.sh b/.devcontainer/install_rust.sh new file mode 100644 index 0000000..4233f17 --- /dev/null +++ b/.devcontainer/install_rust.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e +curl -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh -s -- -y +. "$HOME/.cargo/env" +rustup install 1.84.0 +rustup default 1.84.0 diff --git a/.github/workflows/dtvm_sol_dev_docker_release.yml b/.github/workflows/dtvm_sol_dev_docker_release.yml index d9252bf..1f43c1d 100644 --- a/.github/workflows/dtvm_sol_dev_docker_release.yml +++ b/.github/workflows/dtvm_sol_dev_docker_release.yml @@ -31,6 +31,7 @@ jobs: uses: docker/metadata-action@v4 with: images: dtvmdev1/dtvm-sol-dev-x64 + tags: 1.84.0 - name: Build and push Docker image uses: docker/build-push-action@v3 with: diff --git a/.github/workflows/dtvm_sol_test.yml b/.github/workflows/dtvm_sol_test.yml index 38a180c..585f763 100644 --- a/.github/workflows/dtvm_sol_test.yml +++ b/.github/workflows/dtvm_sol_test.yml @@ -2,15 +2,15 @@ name: DTVM_SolSDK test CI on: push: - paths: - - 'examples/**' - - 'stdlib/**' - - 'src/**' - - 'Cargo.toml' - - '.gitmodules' - - '.gitattributes' - - '.ci/**' - - '.github/workflow/dtvm_sol_test.yml' + paths-ignore: + - 'docs/**' + - "*.md" + - ".gitignore" + pull_request: + paths-ignore: + - 'docs/**' + - "*.md" + - ".gitignore" permissions: contents: read @@ -19,7 +19,7 @@ jobs: name: Build and test DTVM_SolSDK on x86 runs-on: ubuntu-latest container: - image: dtvmdev1/dtvm-sol-dev-x64:main + image: dtvmdev1/dtvm-sol-dev-x64:1.84.0 steps: - name: Check out code uses: actions/checkout@v3 @@ -44,12 +44,12 @@ jobs: . "$HOME/.cargo/env" export PATH=$HOME/.cargo/bin:$PATH - + cd $CUR_PATH export LLVM_SYS_160_PREFIX=/opt/llvm16 export LLVM_DIR=$LLVM_SYS_160_PREFIX/lib/cmake/llvm export PATH=$LLVM_SYS_160_PREFIX/bin:$PATH - + ./download_deps.sh make -f dev.makefile debug cd examples/scripts @@ -80,6 +80,8 @@ jobs: ./build.sh debug ./test_my_token.sh ./test_token_factory.sh + ./build_forge_test.sh debug + ./test_forge_test.sh echo "testing examples/perf_example" cd $CUR_PATH/examples/perf_example diff --git a/.github/workflows/nightly_release.yml b/.github/workflows/nightly_release.yml index e834423..4ca98c8 100644 --- a/.github/workflows/nightly_release.yml +++ b/.github/workflows/nightly_release.yml @@ -1,23 +1,26 @@ -name: nightly-release +name: DTVM_SolSDK Nightly Release + on: workflow_dispatch: paths: - '**' permissions: contents: write + jobs: - Artifact: # Pack and publish to Github Artifact + build_and_package: # Renamed job for clarity + name: Build and Package DTVM_SolSDK Nightly # Updated name runs-on: ubuntu-latest container: - image: dtvmdev1/dtvm-sol-dev-x64:main + image: dtvmdev1/dtvm-sol-dev-x64:1.84.0 steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Use v4 with: lfs: true submodules: "true" - name: Build the Release - working-directory: . + working-directory: . run: | export CUR_PATH=$(pwd) # install rust @@ -32,10 +35,10 @@ jobs: ./download_deps.sh .ci/package.sh - # there should be a DTVM_SolSDK-*.tar.gz file under the target/release directory + # Assuming package.sh creates DTVM_SolSDK-*-nightly.tar.gz in target/release ls target/release - - name: Upload Artifact to Github Releases + - name: Upload Nightly Artifact # Renamed step uses: actions/upload-artifact@v4 with: - name: DTVM_SolSDK-Linux-nightly.tar.gz.zip - path: target/release/DTVM_SolSDK-*.tar.gz + name: DTVM_SolSDK-nightly-latest # Updated artifact name + path: target/release/DTVM_SolSDK-*-nightly.tar.gz # Updated path assuming this name diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 264fd26..79e918c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,18 +1,22 @@ -name: Release +name: DTVM_SolSDK Release + on: push: tags: - - "v*" + - 'v*.*.*' + permissions: contents: write + jobs: - Artifact: # Pack and publish to Github Artifact + build_release_and_upload: + name: Build, Create Release, and Upload Artifact runs-on: ubuntu-latest container: - image: dtvmdev1/dtvm-sol-dev-x64:main + image: dtvmdev1/dtvm-sol-dev-x64:1.84.0 steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: lfs: true submodules: "true" @@ -32,10 +36,27 @@ jobs: ./download_deps.sh .ci/package.sh - # there should be a DTVM_SolSDK-*.tar.gz file under the target/release directory + # Assuming package.sh creates DTVM_SolSDK-*-nightly.tar.gz in target/release ls target/release - - name: Upload Artifact to Github Releases - uses: actions/upload-artifact@v4 + - name: Prepare Release Artifact + id: prepare_artifact + working-directory: target/release + run: | + RELEASE_VERSION=${{ github.ref_name }} + ARTIFACT_NAME="DTVM_SolSDK-${RELEASE_VERSION}-ubuntu22.04.tar.gz" + # Assuming the script generates a file like DTVM_SolSDK.nightly.latest.tar.gz or similar + # If the script generates a versioned file directly, adjust this mv command + GENERATED_ARTIFACT=$(ls DTVM_SolSDK-*-nightly.tar.gz | head -n 1) + echo "Found artifact: $GENERATED_ARTIFACT" + mv "${GENERATED_ARTIFACT}" "${ARTIFACT_NAME}" + echo "artifact_path=$(pwd)/${ARTIFACT_NAME}" >> $GITHUB_OUTPUT + echo "artifact_name=${ARTIFACT_NAME}" >> $GITHUB_OUTPUT + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 with: - name: DTVM_SolSDK-linux-amd64.tar.gz.zip - path: target/release/DTVM_SolSDK-*.tar.gz + files: ${{ steps.prepare_artifact.outputs.artifact_path }} + tag_name: ${{ github.ref_name }} + name: Release ${{ github.ref_name }} + body: "Release for DTVM_SolSDK version ${{ github.ref_name }}" + prerelease: true diff --git a/.gitignore b/.gitignore index 15cb1e1..4c95e87 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ /lib /venv /node_modules + +# coverage +*.profraw diff --git a/Cargo.lock b/Cargo.lock index f8af840..db38b8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -17,18 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy 0.7.35", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -111,9 +99,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arbitrary" @@ -176,15 +164,15 @@ dependencies = [ [[package]] name = "base64" -version = "0.13.1" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bit-set" @@ -203,9 +191,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bitvec" @@ -248,9 +236,9 @@ dependencies = [ [[package]] name = "byte-slice-cast" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "byteorder" @@ -260,15 +248,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cap-fs-ext" -version = "3.4.2" +version = "3.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f78efdd7378980d79c0f36b519e51191742d2c9f91ffa5e228fba9f3806d2e1" +checksum = "e41cc18551193fe8fa6f15c1e3c799bc5ec9e2cfbfaa8ed46f37013e3e6c173c" dependencies = [ "cap-primitives", "cap-std", @@ -278,21 +266,21 @@ dependencies = [ [[package]] name = "cap-net-ext" -version = "3.4.2" +version = "3.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac68674a6042af2bcee1adad9f6abd432642cf03444ce3a5b36c3f39f23baf8" +checksum = "9f83833816c66c986e913b22ac887cec216ea09301802054316fc5301809702c" dependencies = [ "cap-primitives", "cap-std", - "rustix 0.38.44", + "rustix 1.0.5", "smallvec", ] [[package]] name = "cap-primitives" -version = "3.4.2" +version = "3.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc15faeed2223d8b8e8cc1857f5861935a06d06713c4ac106b722ae9ce3c369" +checksum = "0a1e394ed14f39f8bc26f59d4c0c010dbe7f0a1b9bafff451b1f98b67c8af62a" dependencies = [ "ambient-authority", "fs-set-times", @@ -300,16 +288,17 @@ dependencies = [ "io-lifetimes", "ipnet", "maybe-owned", - "rustix 0.38.44", + "rustix 1.0.5", + "rustix-linux-procfs", "windows-sys 0.59.0", "winx", ] [[package]] name = "cap-rand" -version = "3.4.2" +version = "3.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea13372b49df066d1ae654e5c6e41799c1efd9f6b36794b921e877ea4037977" +checksum = "0acb89ccf798a28683f00089d0630dfaceec087234eae0d308c05ddeaa941b40" dependencies = [ "ambient-authority", "rand 0.8.5", @@ -317,35 +306,35 @@ dependencies = [ [[package]] name = "cap-std" -version = "3.4.2" +version = "3.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3dbd3e8e8d093d6ccb4b512264869e1281cdb032f7940bd50b2894f96f25609" +checksum = "07c0355ca583dd58f176c3c12489d684163861ede3c9efa6fd8bba314c984189" dependencies = [ "cap-primitives", "io-extras", "io-lifetimes", - "rustix 0.38.44", + "rustix 1.0.5", ] [[package]] name = "cap-time-ext" -version = "3.4.2" +version = "3.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd736b20fc033f564a1995fb82fc349146de43aabba19c7368b4cb17d8f9ea53" +checksum = "491af520b8770085daa0466978c75db90368c71896523f2464214e38359b1a5b" dependencies = [ "ambient-authority", "cap-primitives", "iana-time-zone", "once_cell", - "rustix 0.38.44", + "rustix 1.0.5", "winx", ] [[package]] name = "cc" -version = "1.2.12" +version = "1.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755717a7de9ec452bf7f3f1a3099085deabd7f2962b861dae91ecd7a365903d2" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" dependencies = [ "jobserver", "libc", @@ -360,9 +349,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.27" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" +checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" dependencies = [ "clap_builder", "clap_derive", @@ -370,9 +359,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.27" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" +checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" dependencies = [ "anstream", "anstyle", @@ -382,9 +371,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.24" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ "heck", "proc-macro2", @@ -447,27 +436,79 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] +[[package]] +name = "cranelift-assembler-x64" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4b56ebe316895d3fa37775d0a87b0c889cc933f5c8b253dbcc7c7bcb7fe7e4" +dependencies = [ + "cranelift-assembler-x64-meta 0.118.0", +] + +[[package]] +name = "cranelift-assembler-x64" +version = "0.120.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5023e06632d8f351c2891793ccccfe4aef957954904392434038745fb6f1f68" +dependencies = [ + "cranelift-assembler-x64-meta 0.120.2", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95cabbc01dfbd7dcd6c329ca44f0212910309c221797ac736a67a5bc8857fe1b" + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.120.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c4012b4c8c1f6eb05c0a0a540e3e1ee992631af51aa2bbb3e712903ce4fd65" +dependencies = [ + "cranelift-srcgen", +] + +[[package]] +name = "cranelift-bforest" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ffe46df300a45f1dc6f609dc808ce963f0e3a2e971682c479a2d13e3b9b8ef" +dependencies = [ + "cranelift-entity 0.118.0", +] + [[package]] name = "cranelift-bforest" -version = "0.116.1" +version = "0.120.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4" +checksum = "4d6d883b4942ef3a7104096b8bc6f2d1a41393f159ac8de12aed27b25d67f895" dependencies = [ - "cranelift-entity", + "cranelift-entity 0.120.2", ] [[package]] name = "cranelift-bitset" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" +checksum = "b265bed7c51e1921fdae6419791d31af77d33662ee56d7b0fa0704dc8d231cab" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-bitset" +version = "0.120.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7b2ee9eec6ca8a716d900d5264d678fb2c290c58c46c8da7f94ee268175d17" dependencies = [ "serde", "serde_derive", @@ -475,70 +516,150 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c22032c4cb42558371cf516bb47f26cdad1819d3475c133e93c49f50ebf304e" +checksum = "e606230a7e3a6897d603761baee0d19f88d077f17b996bb5089488a29ae96e41" dependencies = [ "bumpalo", - "cranelift-bforest", - "cranelift-bitset", - "cranelift-codegen-meta", - "cranelift-codegen-shared", - "cranelift-control", - "cranelift-entity", - "cranelift-isle", + "cranelift-assembler-x64 0.118.0", + "cranelift-bforest 0.118.0", + "cranelift-bitset 0.118.0", + "cranelift-codegen-meta 0.118.0", + "cranelift-codegen-shared 0.118.0", + "cranelift-control 0.118.0", + "cranelift-entity 0.118.0", + "cranelift-isle 0.118.0", "gimli", - "hashbrown 0.14.5", + "hashbrown", "log", - "regalloc2", + "pulley-interpreter 31.0.0", + "regalloc2 0.11.2", "rustc-hash", "serde", "smallvec", "target-lexicon", ] +[[package]] +name = "cranelift-codegen" +version = "0.120.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeda0892577afdce1ac2e9a983a55f8c5b87a59334e1f79d8f735a2d7ba4f4b4" +dependencies = [ + "bumpalo", + "cranelift-assembler-x64 0.120.2", + "cranelift-bforest 0.120.2", + "cranelift-bitset 0.120.2", + "cranelift-codegen-meta 0.120.2", + "cranelift-codegen-shared 0.120.2", + "cranelift-control 0.120.2", + "cranelift-entity 0.120.2", + "cranelift-isle 0.120.2", + "gimli", + "hashbrown", + "log", + "pulley-interpreter 33.0.2", + "regalloc2 0.12.2", + "rustc-hash", + "serde", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a63bffafc23bc60969ad528e138788495999d935f0adcfd6543cb151ca8637d" +dependencies = [ + "cranelift-assembler-x64 0.118.0", + "cranelift-codegen-shared 0.118.0", + "pulley-interpreter 31.0.0", +] + [[package]] name = "cranelift-codegen-meta" -version = "0.116.1" +version = "0.120.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8" +checksum = "e461480d87f920c2787422463313326f67664e68108c14788ba1676f5edfcd15" dependencies = [ - "cranelift-codegen-shared", + "cranelift-assembler-x64-meta 0.120.2", + "cranelift-codegen-shared 0.120.2", + "cranelift-srcgen", + "pulley-interpreter 33.0.2", ] [[package]] name = "cranelift-codegen-shared" -version = "0.116.1" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af50281b67324b58e843170a6a5943cf6d387c06f7eeacc9f5696e4ab7ae7d7e" + +[[package]] +name = "cranelift-codegen-shared" +version = "0.120.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb" +checksum = "976584d09f200c6c84c4b9ff7af64fc9ad0cb64dffa5780991edd3fe143a30a1" [[package]] name = "cranelift-control" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef" +checksum = "8c20c1b38d1abfbcebb0032e497e71156c0e3b8dcb3f0a92b9863b7bcaec290c" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-control" +version = "0.120.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46d43d70f4e17c545aa88dbf4c84d4200755d27c6e3272ebe4de65802fa6a955" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323" +checksum = "0c2c67d95507c51b4a1ff3f3555fe4bfec36b9e13c1b684ccc602736f5d5f4a2" dependencies = [ - "cranelift-bitset", + "cranelift-bitset 0.118.0", "serde", "serde_derive", ] +[[package]] +name = "cranelift-entity" +version = "0.120.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75418674520cb400c8772bfd6e11a62736c78fc1b6e418195696841d1bf91f1" +dependencies = [ + "cranelift-bitset 0.120.2", + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-frontend" +version = "0.118.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e002691cc69c38b54fc7ec93e5be5b744f627d027031d991cc845d1d512d0ce" +dependencies = [ + "cranelift-codegen 0.118.0", + "log", + "smallvec", + "target-lexicon", +] + [[package]] name = "cranelift-frontend" -version = "0.116.1" +version = "0.120.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fac41e16729107393174b0c9e3730fb072866100e1e64e80a1a963b2e484d57" +checksum = "3c8b1a91c86687a344f3c52dd6dfb6e50db0dfa7f2e9c7711b060b3623e1fdeb" dependencies = [ - "cranelift-codegen", + "cranelift-codegen 0.120.2", "log", "smallvec", "target-lexicon", @@ -546,21 +667,44 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d" +checksum = "e93588ed1796cbcb0e2ad160403509e2c5d330d80dd6e0014ac6774c7ebac496" + +[[package]] +name = "cranelift-isle" +version = "0.120.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711baa4e3432d4129295b39ec2b4040cc1b558874ba0a37d08e832e857db7285" [[package]] name = "cranelift-native" -version = "0.116.1" +version = "0.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dee82f3f1f2c4cba9177f1cc5e350fe98764379bcd29340caa7b01f85076c7" +checksum = "e5b09bdd6407bf5d89661b80cf926ce731c9e8cc184bf49102267a2369a8358e" dependencies = [ - "cranelift-codegen", + "cranelift-codegen 0.118.0", "libc", "target-lexicon", ] +[[package]] +name = "cranelift-native" +version = "0.120.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41c83e8666e3bcc5ffeaf6f01f356f0e1f9dcd69ce5511a1efd7ca5722001a3f" +dependencies = [ + "cranelift-codegen 0.120.2", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-srcgen" +version = "0.120.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e3f4d783a55c64266d17dc67d2708852235732a100fc40dd9f1051adc64d7b" + [[package]] name = "crc32fast" version = "1.4.2" @@ -597,9 +741,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-common" @@ -703,9 +847,9 @@ dependencies = [ [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "embedded-io" @@ -739,15 +883,15 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", @@ -766,7 +910,7 @@ dependencies = [ "serde", "serde_json", "sha3", - "thiserror", + "thiserror 1.0.69", "uint 0.9.5", ] @@ -834,9 +978,9 @@ dependencies = [ [[package]] name = "fixedbitset" -version = "0.4.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "foldhash" @@ -965,9 +1109,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -976,14 +1120,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -997,15 +1141,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", -] - [[package]] name = "hashbrown" version = "0.15.2" @@ -1267,12 +1402,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown", "serde", ] @@ -1286,7 +1421,7 @@ dependencies = [ "libc", "llvm-sys", "once_cell", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1338,18 +1473,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "ittapi" @@ -1373,10 +1508,11 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.2", "libc", ] @@ -1411,14 +1547,14 @@ dependencies = [ [[package]] name = "lalrpop" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06093b57658c723a21da679530e061a8c25340fa5a6f98e313b542268c7e2a1f" +checksum = "7047a26de42016abf8f181b46b398aef0b77ad46711df41847f6ed869a2a1d5b" dependencies = [ "ascii-canvas", "bit-set", "ena", - "itertools 0.13.0", + "itertools 0.14.0", "lalrpop-util", "petgraph", "pico-args", @@ -1433,9 +1569,9 @@ dependencies = [ [[package]] name = "lalrpop-util" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feee752d43abd0f4807a921958ab4131f692a44d4d599733d4419c5d586176ce" +checksum = "e8d05b3fe34b8bd562c338db725dfa9beb9451a48f65f129ccb9538b48d2c93b" dependencies = [ "regex-automata", "rustversion", @@ -1461,15 +1597,15 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libm" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" [[package]] name = "libredox" @@ -1483,12 +1619,12 @@ dependencies = [ [[package]] name = "libsecp256k1" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" dependencies = [ "arrayref", - "base64 0.13.1", + "base64 0.22.1", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -1537,9 +1673,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" @@ -1572,9 +1708,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.25" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "mach2" @@ -1608,9 +1744,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -1678,16 +1814,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", - "hashbrown 0.15.2", + "hashbrown", "indexmap", "memchr", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "opaque-debug" @@ -1766,9 +1902,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" -version = "0.6.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset", "indexmap", @@ -1776,9 +1912,9 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] @@ -1821,11 +1957,11 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -1859,52 +1995,68 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88" +checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" dependencies = [ "cc", ] [[package]] name = "pulley-interpreter" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62d95f8575df49a2708398182f49a888cf9dc30210fb1fd2df87c889edcee75d" +checksum = "0c3325791708ad50580aeacfcce06cb5e462c9ba7a2368e109cb2012b944b70e" dependencies = [ - "cranelift-bitset", + "cranelift-bitset 0.118.0", "log", - "sptr", - "wasmtime-math", + "wasmtime-math 31.0.0", +] + +[[package]] +name = "pulley-interpreter" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986beaef947a51d17b42b0ea18ceaa88450d35b6994737065ed505c39172db71" +dependencies = [ + "cranelift-bitset 0.120.2", + "log", + "wasmtime-math 33.0.2", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "radium" version = "0.7.0" @@ -1924,13 +2076,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.0", - "zerocopy 0.8.17", + "rand_core 0.9.3", ] [[package]] @@ -1950,7 +2101,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -1959,17 +2110,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] name = "rand_core" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", - "zerocopy 0.8.17", + "getrandom 0.3.2", ] [[package]] @@ -1994,9 +2144,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" dependencies = [ "bitflags", ] @@ -2007,9 +2157,9 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2020,7 +2170,21 @@ checksum = "dc06e6b318142614e4a48bc725abbf08ff166694835c43c9dae5a9009704639a" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown 0.15.2", + "hashbrown", + "log", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "regalloc2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown", "log", "rustc-hash", "smallvec", @@ -2091,10 +2255,8 @@ checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ "bitflags", "errno", - "itoa", "libc", "linux-raw-sys 0.4.15", - "once_cell", "windows-sys 0.59.0", ] @@ -2107,21 +2269,31 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.9.3", + "linux-raw-sys 0.9.4", "windows-sys 0.59.0", ] +[[package]] +name = "rustix-linux-procfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" +dependencies = [ + "once_cell", + "rustix 1.0.5", +] + [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "ryu" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -2140,27 +2312,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -2169,9 +2341,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.139" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -2239,24 +2411,24 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "siphasher" -version = "0.3.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" dependencies = [ "serde", ] [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2282,12 +2454,11 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "string_cache" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" dependencies = [ "new_debug_unreachable", - "once_cell", "parking_lot", "phf_shared", "precomputed-hash", @@ -2307,9 +2478,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.96" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -2357,26 +2528,25 @@ checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "tempfile" -version = "3.16.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", - "getrandom 0.3.1", + "getrandom 0.3.2", "once_cell", - "rustix 0.38.44", + "rustix 1.0.5", "windows-sys 0.59.0", ] [[package]] name = "term" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3bb6001afcea98122260987f8b7b5da969ecad46dbf0b5453702f776b491a41" +checksum = "8a984c8d058c627faaf5e8e2ed493fa3c51771889196de1016cf9c1c6e90d750" dependencies = [ "home", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2394,7 +2564,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -2408,6 +2587,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -2429,9 +2619,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.1" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ "backtrace", "bytes", @@ -2444,9 +2634,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -2456,26 +2646,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "tracing" version = "0.1.41" @@ -2520,9 +2717,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "uint" @@ -2550,9 +2747,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-width" @@ -2625,9 +2822,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -2692,52 +2889,55 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.202.0" +version = "0.226.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd106365a7f5f7aa3c1916a98cbb3ad477f5ff96ddb130285a91c6e7429e67a" +checksum = "f7d81b727619aec227dce83e7f7420d4e56c79acd044642a356ea045b98d4e13" dependencies = [ - "leb128", + "leb128fmt", + "wasmparser 0.226.0", ] [[package]] name = "wasm-encoder" -version = "0.221.3" +version = "0.228.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc8444fe4920de80a4fe5ab564fff2ae58b6b73166b89751f8c6c93509da32e5" +checksum = "05d30290541f2d4242a162bbda76b8f2d8b1ac59eab3568ed6f2327d52c9b2c4" dependencies = [ - "leb128", - "wasmparser 0.221.3", + "leb128fmt", + "wasmparser 0.228.0", ] [[package]] name = "wasm-encoder" -version = "0.228.0" +version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d30290541f2d4242a162bbda76b8f2d8b1ac59eab3568ed6f2327d52c9b2c4" +checksum = "38ba1d491ecacb085a2552025c10a675a6fddcbd03b1fc9b36c536010ce265d2" dependencies = [ "leb128fmt", - "wasmparser 0.228.0", + "wasmparser 0.229.0", ] [[package]] name = "wasmparser" -version = "0.202.0" +version = "0.226.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6998515d3cf3f8b980ef7c11b29a9b1017d4cf86b99ae93b546992df9931413" +checksum = "bc28600dcb2ba68d7e5f1c3ba4195c2bddc918c0243fd702d0b6dbd05689b681" dependencies = [ "bitflags", + "hashbrown", "indexmap", "semver", + "serde", ] [[package]] name = "wasmparser" -version = "0.221.3" +version = "0.228.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185" +checksum = "4abf1132c1fdf747d56bbc1bb52152400c70f336870f968b85e89ea422198ae3" dependencies = [ "bitflags", - "hashbrown 0.15.2", + "hashbrown", "indexmap", "semver", "serde", @@ -2745,31 +2945,44 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.228.0" +version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4abf1132c1fdf747d56bbc1bb52152400c70f336870f968b85e89ea422198ae3" +checksum = "0cc3b1f053f5d41aa55640a1fa9b6d1b8a9e4418d118ce308d20e24ff3575a8c" dependencies = [ "bitflags", + "hashbrown", "indexmap", "semver", + "serde", +] + +[[package]] +name = "wasmprinter" +version = "0.226.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "753a0516fa6c01756ee861f36878dfd9875f273aea9409d9ea390a333c5bcdc2" +dependencies = [ + "anyhow", + "termcolor", + "wasmparser 0.226.0", ] [[package]] name = "wasmprinter" -version = "0.221.3" +version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7343c42a97f2926c7819ff81b64012092ae954c5d83ddd30c9fcdefd97d0b283" +checksum = "d25dac01892684a99b8fbfaf670eb6b56edea8a096438c75392daeb83156ae2e" dependencies = [ "anyhow", "termcolor", - "wasmparser 0.221.3", + "wasmparser 0.229.0", ] [[package]] name = "wasmtime" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11976a250672556d1c4c04c6d5d7656ac9192ac9edc42a4587d6c21460010e69" +checksum = "b9fe78033c72da8741e724d763daf1375c93a38bfcea99c873ee4415f6098c3f" dependencies = [ "addr2line", "anyhow", @@ -2781,7 +2994,7 @@ dependencies = [ "encoding_rs", "fxprof-processed-profile", "gimli", - "hashbrown 0.14.5", + "hashbrown", "indexmap", "ittapi", "libc", @@ -2793,7 +3006,7 @@ dependencies = [ "paste", "postcard", "psm", - "pulley-interpreter", + "pulley-interpreter 31.0.0", "rayon", "rustix 0.38.44", "semver", @@ -2804,39 +3017,96 @@ dependencies = [ "sptr", "target-lexicon", "trait-variant", - "wasm-encoder 0.221.3", - "wasmparser 0.221.3", - "wasmtime-asm-macros", + "wasm-encoder 0.226.0", + "wasmparser 0.226.0", + "wasmtime-asm-macros 31.0.0", "wasmtime-cache", - "wasmtime-component-macro", - "wasmtime-component-util", - "wasmtime-cranelift", - "wasmtime-environ", - "wasmtime-fiber", + "wasmtime-component-macro 31.0.0", + "wasmtime-component-util 31.0.0", + "wasmtime-cranelift 31.0.0", + "wasmtime-environ 31.0.0", + "wasmtime-fiber 31.0.0", "wasmtime-jit-debug", - "wasmtime-jit-icache-coherence", - "wasmtime-math", - "wasmtime-slab", - "wasmtime-versioned-export-macros", - "wasmtime-winch", + "wasmtime-jit-icache-coherence 31.0.0", + "wasmtime-math 31.0.0", + "wasmtime-slab 31.0.0", + "wasmtime-versioned-export-macros 31.0.0", + "wasmtime-winch 31.0.0", "wat", "windows-sys 0.59.0", ] +[[package]] +name = "wasmtime" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57373e1d8699662fb791270ac5dfac9da5c14f618ecf940cdb29dc3ad9472a3c" +dependencies = [ + "addr2line", + "anyhow", + "async-trait", + "bitflags", + "bumpalo", + "cc", + "cfg-if", + "encoding_rs", + "hashbrown", + "indexmap", + "libc", + "log", + "mach2", + "memfd", + "object", + "once_cell", + "postcard", + "psm", + "pulley-interpreter 33.0.2", + "rustix 1.0.5", + "semver", + "serde", + "serde_derive", + "smallvec", + "sptr", + "target-lexicon", + "trait-variant", + "wasmparser 0.229.0", + "wasmtime-asm-macros 33.0.2", + "wasmtime-component-macro 33.0.2", + "wasmtime-component-util 33.0.2", + "wasmtime-cranelift 33.0.2", + "wasmtime-environ 33.0.2", + "wasmtime-fiber 33.0.2", + "wasmtime-jit-icache-coherence 33.0.2", + "wasmtime-math 33.0.2", + "wasmtime-slab 33.0.2", + "wasmtime-versioned-export-macros 33.0.2", + "wasmtime-winch 33.0.2", + "windows-sys 0.59.0", +] + [[package]] name = "wasmtime-asm-macros" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f178b0d125201fbe9f75beaf849bd3e511891f9e45ba216a5b620802ccf64f2" +checksum = "47f3d44ae977d70ccf80938b371d5ec60b6adedf60800b9e8dd1223bb69f4cbc" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0fc91372865167a695dc98d0d6771799a388a7541d3f34e939d0539d6583de" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1161c8f62880deea07358bc40cceddc019f1c81d46007bc390710b2fe24ffc" +checksum = "e209505770c7f38725513dba37246265fa6f724c30969de1e9d2a9e6c8f55099" dependencies = [ "anyhow", "base64 0.21.7", @@ -2854,60 +3124,108 @@ dependencies = [ [[package]] name = "wasmtime-component-macro" -version = "29.0.1" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397e68ee29eb072d8d8741c9d2c971a284cd1bc960ebf2c1f6a33ea6ba16d6e1" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn", + "wasmtime-component-util 31.0.0", + "wasmtime-wit-bindgen 31.0.0", + "wit-parser 0.226.0", +] + +[[package]] +name = "wasmtime-component-macro" +version = "33.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d74de6592ed945d0a602f71243982a304d5d02f1e501b638addf57f42d57dfaf" +checksum = "25c9c7526675ff9a9794b115023c4af5128e3eb21389bfc3dc1fd344d549258f" dependencies = [ "anyhow", "proc-macro2", "quote", "syn", - "wasmtime-component-util", - "wasmtime-wit-bindgen", - "wit-parser", + "wasmtime-component-util 33.0.2", + "wasmtime-wit-bindgen 33.0.2", + "wit-parser 0.229.0", ] [[package]] name = "wasmtime-component-util" -version = "29.0.1" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f292ef5eb2cf3d414c2bde59c7fa0feeba799c8db9a8c5a656ad1d1a1d05e10b" + +[[package]] +name = "wasmtime-component-util" +version = "33.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707dc7b3c112ab5a366b30cfe2fb5b2f8e6a0f682f16df96a5ec582bfe6f056e" +checksum = "cc42ec8b078875804908d797cb4950fec781d9add9684c9026487fd8eb3f6291" [[package]] name = "wasmtime-cranelift" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "366be722674d4bf153290fbcbc4d7d16895cc82fb3e869f8d550ff768f9e9e87" +checksum = "52fc12eb8ea695a30007a4849a5fd56209dd86a15579e92e0c27c27122818505" dependencies = [ "anyhow", "cfg-if", - "cranelift-codegen", - "cranelift-control", - "cranelift-entity", - "cranelift-frontend", - "cranelift-native", + "cranelift-codegen 0.118.0", + "cranelift-control 0.118.0", + "cranelift-entity 0.118.0", + "cranelift-frontend 0.118.0", + "cranelift-native 0.118.0", "gimli", "itertools 0.12.1", "log", "object", + "pulley-interpreter 31.0.0", "smallvec", "target-lexicon", - "thiserror", - "wasmparser 0.221.3", - "wasmtime-environ", - "wasmtime-versioned-export-macros", + "thiserror 1.0.69", + "wasmparser 0.226.0", + "wasmtime-environ 31.0.0", + "wasmtime-versioned-export-macros 31.0.0", +] + +[[package]] +name = "wasmtime-cranelift" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bd72f0a6a0ffcc6a184ec86ac35c174e48ea0e97bbae277c8f15f8bf77a566" +dependencies = [ + "anyhow", + "cfg-if", + "cranelift-codegen 0.120.2", + "cranelift-control 0.120.2", + "cranelift-entity 0.120.2", + "cranelift-frontend 0.120.2", + "cranelift-native 0.120.2", + "gimli", + "itertools 0.14.0", + "log", + "object", + "pulley-interpreter 33.0.2", + "smallvec", + "target-lexicon", + "thiserror 2.0.12", + "wasmparser 0.229.0", + "wasmtime-environ 33.0.2", + "wasmtime-versioned-export-macros 33.0.2", ] [[package]] name = "wasmtime-environ" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdadc1af7097347aa276a4f008929810f726b5b46946971c660b6d421e9994ad" +checksum = "5b6b4bf08e371edf262cccb62de10e214bd4aaafaa069f1cd49c9c1c3a5ae8e4" dependencies = [ "anyhow", "cpp_demangle", - "cranelift-bitset", - "cranelift-entity", + "cranelift-bitset 0.118.0", + "cranelift-entity 0.118.0", "gimli", "indexmap", "log", @@ -2919,43 +3237,84 @@ dependencies = [ "serde_derive", "smallvec", "target-lexicon", - "wasm-encoder 0.221.3", - "wasmparser 0.221.3", - "wasmprinter", - "wasmtime-component-util", + "wasm-encoder 0.226.0", + "wasmparser 0.226.0", + "wasmprinter 0.226.0", + "wasmtime-component-util 31.0.0", +] + +[[package]] +name = "wasmtime-environ" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6187bb108a23eb25d2a92aa65d6c89fb5ed53433a319038a2558567f3011ff2" +dependencies = [ + "anyhow", + "cranelift-bitset 0.120.2", + "cranelift-entity 0.120.2", + "gimli", + "indexmap", + "log", + "object", + "postcard", + "semver", + "serde", + "serde_derive", + "smallvec", + "target-lexicon", + "wasm-encoder 0.229.0", + "wasmparser 0.229.0", + "wasmprinter 0.229.0", + "wasmtime-component-util 33.0.2", ] [[package]] name = "wasmtime-fiber" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccba90d4119f081bca91190485650730a617be1fff5228f8c4757ce133d21117" +checksum = "f4c8828d7d8fbe90d087a9edea9223315caf7eb434848896667e5d27889f1173" dependencies = [ "anyhow", "cc", "cfg-if", "rustix 0.38.44", - "wasmtime-asm-macros", - "wasmtime-versioned-export-macros", + "wasmtime-asm-macros 31.0.0", + "wasmtime-versioned-export-macros 31.0.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "wasmtime-fiber" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc8965d2128c012329f390e24b8b2758dd93d01bf67e1a1a0dd3d8fd72f56873" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "rustix 1.0.5", + "wasmtime-asm-macros 33.0.2", + "wasmtime-versioned-export-macros 33.0.2", "windows-sys 0.59.0", ] [[package]] name = "wasmtime-jit-debug" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7b61488a5ee00c35c8c22de707c36c0aecacf419a3be803a6a2ba5e860f56a" +checksum = "ab9eff86dedd48b023199de2d266f5d3e37bc7c5bafdc1e3e3057214649ecf5a" dependencies = [ + "cc", "object", "rustix 0.38.44", - "wasmtime-versioned-export-macros", + "wasmtime-versioned-export-macros 31.0.0", ] [[package]] name = "wasmtime-jit-icache-coherence" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec5e8552e01692e6c2e5293171704fed8abdec79d1a6995a0870ab190e5747d1" +checksum = "a54f6c6c7e9d7eeee32dfcc10db7f29d505ee7dd28d00593ea241d5f70698e64" dependencies = [ "anyhow", "cfg-if", @@ -2963,26 +3322,64 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7af0e940cb062a45c0b3f01a926f77da5947149e99beb4e3dd9846d5b8f11619" +dependencies = [ + "anyhow", + "cfg-if", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "wasmtime-math" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1108aad2e6965698f9207ea79b80eda2b3dcc57dcb69f4258296d4664ae32cd" +dependencies = [ + "libm", +] + [[package]] name = "wasmtime-math" -version = "29.0.1" +version = "33.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29210ec2aa25e00f4d54605cedaf080f39ec01a872c5bd520ad04c67af1dde17" +checksum = "acfca360e719dda9a27e26944f2754ff2fd5bad88e21919c42c5a5f38ddd93cb" dependencies = [ "libm", ] [[package]] name = "wasmtime-slab" -version = "29.0.1" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d6a321317281b721c5530ef733e8596ecc6065035f286ccd155b3fa8e0ab2f" + +[[package]] +name = "wasmtime-slab" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e240559cada55c4b24af979d5f6c95e0029f5772f32027ec3c62b258aaff65" + +[[package]] +name = "wasmtime-versioned-export-macros" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb5821a96fa04ac14bc7b158bb3d5cd7729a053db5a74dad396cd513a5e5ccf" +checksum = "5732a5c86efce7bca121a61d8c07875f6b85c1607aa86753b40f7f8bd9d3a780" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "wasmtime-versioned-export-macros" -version = "29.0.1" +version = "33.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ff86db216dc0240462de40c8290887a613dddf9685508eb39479037ba97b5b" +checksum = "d0963c1438357a3d8c0efe152b4ef5259846c1cf8b864340270744fe5b3bae5e" dependencies = [ "proc-macro2", "quote", @@ -2991,9 +3388,9 @@ dependencies = [ [[package]] name = "wasmtime-wasi" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d1be69bfcab1bdac74daa7a1f9695ab992b9c8e21b9b061e7d66434097e0ca4" +checksum = "9b425ede2633fade96bd624b6f35cea5f8be1995d149530882dbc35efbf1e31f" dependencies = [ "anyhow", "async-trait", @@ -3010,43 +3407,129 @@ dependencies = [ "io-lifetimes", "rustix 0.38.44", "system-interface", - "thiserror", + "thiserror 1.0.69", + "tokio", + "tracing", + "url", + "wasmtime 31.0.0", + "wasmtime-wasi-io 31.0.0", + "wiggle 31.0.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "wasmtime-wasi" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae951b72c7c6749a1c15dcdfb6d940a2614c932b4a54f474636e78e2c744b4c" +dependencies = [ + "anyhow", + "async-trait", + "bitflags", + "bytes", + "cap-fs-ext", + "cap-net-ext", + "cap-rand", + "cap-std", + "cap-time-ext", + "fs-set-times", + "futures", + "io-extras", + "io-lifetimes", + "rustix 1.0.5", + "system-interface", + "thiserror 2.0.12", "tokio", "tracing", - "trait-variant", "url", - "wasmtime", - "wiggle", + "wasmtime 33.0.2", + "wasmtime-wasi-io 33.0.2", + "wiggle 33.0.2", "windows-sys 0.59.0", ] +[[package]] +name = "wasmtime-wasi-io" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ec650d8891ec5ff823bdcefe3b370278becd1f33125bcfdcf628943dcde676" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "futures", + "wasmtime 31.0.0", +] + +[[package]] +name = "wasmtime-wasi-io" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a835790dcecc3d7051ec67da52ba9e04af25e1bc204275b9391e3f0042b10797" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "futures", + "wasmtime 33.0.2", +] + +[[package]] +name = "wasmtime-winch" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aa4741ee66a52e2f0ec5f79040017123ba47d2dff9d994b35879cc2b7f468d4" +dependencies = [ + "anyhow", + "cranelift-codegen 0.118.0", + "gimli", + "object", + "target-lexicon", + "wasmparser 0.226.0", + "wasmtime-cranelift 31.0.0", + "wasmtime-environ 31.0.0", + "winch-codegen 31.0.0", +] + [[package]] name = "wasmtime-winch" -version = "29.0.1" +version = "33.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbabfb8f20502d5e1d81092b9ead3682ae59988487aafcd7567387b7a43cf8f" +checksum = "cbc3b117d03d6eeabfa005a880c5c22c06503bb8820f3aa2e30f0e8d87b6752f" dependencies = [ "anyhow", - "cranelift-codegen", + "cranelift-codegen 0.120.2", "gimli", "object", "target-lexicon", - "wasmparser 0.221.3", - "wasmtime-cranelift", - "wasmtime-environ", - "winch-codegen", + "wasmparser 0.229.0", + "wasmtime-cranelift 33.0.2", + "wasmtime-environ 33.0.2", + "winch-codegen 33.0.2", ] [[package]] name = "wasmtime-wit-bindgen" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8358319c2dd1e4db79e3c1c5d3a5af84956615343f9f89f4e4996a36816e06e6" +checksum = "505c13fa0cac6c43e805347acf1e916c8de54e3790f2c22873c5692964b09b62" dependencies = [ "anyhow", "heck", "indexmap", - "wit-parser", + "wit-parser 0.226.0", +] + +[[package]] +name = "wasmtime-wit-bindgen" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1382f4f09390eab0d75d4994d0c3b0f6279f86a571807ec67a8253c87cf6a145" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "wit-parser 0.229.0", ] [[package]] @@ -3060,46 +3543,61 @@ dependencies = [ [[package]] name = "wast" -version = "228.0.0" +version = "229.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5aae124478cb51439f6587f074a3a5e835afd22751c59a87b2e2a882727c97" +checksum = "63fcaff613c12225696bb163f79ca38ffb40e9300eff0ff4b8aa8b2f7eadf0d9" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width", - "wasm-encoder 0.228.0", + "wasm-encoder 0.229.0", ] [[package]] name = "wat" -version = "1.228.0" +version = "1.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec29c89a8d055df988de7236483bf569988ac3d6905899f6af5ef920f9385ad" +checksum = "4189bad08b70455a9e9e67dc126d2dcf91fac143a80f1046747a5dde6d4c33e0" dependencies = [ - "wast 228.0.0", + "wast 229.0.0", ] [[package]] name = "wiggle" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9af35bc9629c52c261465320a9a07959164928b4241980ba1cf923b9e6751d" +checksum = "1dc9a83fe01faa51423fc84941cdbe0ec33ba1e9a75524a560a27a4ad1ff2c3b" dependencies = [ "anyhow", "async-trait", "bitflags", - "thiserror", + "thiserror 1.0.69", "tracing", - "wasmtime", - "wiggle-macro", + "wasmtime 31.0.0", + "wiggle-macro 31.0.0", +] + +[[package]] +name = "wiggle" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649c1aca13ef9e9dccf2d5efbbebf12025bc5521c3fb7754355ef60f5eb810be" +dependencies = [ + "anyhow", + "async-trait", + "bitflags", + "thiserror 2.0.12", + "tracing", + "wasmtime 33.0.2", + "wiggle-macro 33.0.2", ] [[package]] name = "wiggle-generate" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cf267dd05673912c8138f4b54acabe6bd53407d9d1536f0fadb6520dd16e101" +checksum = "d250c01cd52cfdb40aad167fad579af55acbeccb85a54827099d31dc1b90cbd7" dependencies = [ "anyhow", "heck", @@ -3110,16 +3608,42 @@ dependencies = [ "witx", ] +[[package]] +name = "wiggle-generate" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "164870fc34214ee42bd81b8ce9e7c179800fa1a7d4046d17a84e7f7bf422c8ad" +dependencies = [ + "anyhow", + "heck", + "proc-macro2", + "quote", + "syn", + "witx", +] + [[package]] name = "wiggle-macro" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c5c473d4198e6c2d377f3809f713ff0c110cab88a0805ae099a82119ee250c" +checksum = "35be0aee84be808a5e17f6b732e110eb75703d9d6e66e22c7464d841aa2600c5" dependencies = [ "proc-macro2", "quote", "syn", - "wiggle-generate", + "wiggle-generate 31.0.0", +] + +[[package]] +name = "wiggle-macro" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d873bb5b59ca703b5e41562e96a4796d1af61bf4cf80bf8a7abda755a380ec1c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wiggle-generate 33.0.2", ] [[package]] @@ -3155,20 +3679,39 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winch-codegen" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f849ef2c5f46cb0a20af4b4487aaa239846e52e2c03f13fa3c784684552859c" +checksum = "e02f05457f74ec3c94d5c5caac06b84fd8d9d4d7fa21419189845ed245a53477" dependencies = [ "anyhow", - "cranelift-codegen", + "cranelift-codegen 0.118.0", "gimli", - "regalloc2", + "regalloc2 0.11.2", "smallvec", "target-lexicon", - "thiserror", - "wasmparser 0.221.3", - "wasmtime-cranelift", - "wasmtime-environ", + "thiserror 1.0.69", + "wasmparser 0.226.0", + "wasmtime-cranelift 31.0.0", + "wasmtime-environ 31.0.0", +] + +[[package]] +name = "winch-codegen" +version = "33.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7914c296fbcef59d1b89a15e82384d34dc9669bc09763f2ef068a28dd3a64ebf" +dependencies = [ + "anyhow", + "cranelift-assembler-x64 0.120.2", + "cranelift-codegen 0.120.2", + "gimli", + "regalloc2 0.12.2", + "smallvec", + "target-lexicon", + "thiserror 2.0.12", + "wasmparser 0.229.0", + "wasmtime-cranelift 33.0.2", + "wasmtime-environ 33.0.2", ] [[package]] @@ -3314,9 +3857,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.3" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" dependencies = [ "memchr", ] @@ -3333,18 +3876,36 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags", ] [[package]] name = "wit-parser" -version = "0.221.3" +version = "0.226.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f007722bfd43a2978c5b8b90f02c927dddf0f11c5f5b50929816b3358718cd" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.226.0", +] + +[[package]] +name = "wit-parser" +version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896112579ed56b4a538b07a3d16e562d101ff6265c46b515ce0c701eef16b2ac" +checksum = "459c6ba62bf511d6b5f2a845a2a736822e38059c1cfa0b644b467bbbfae4efa6" dependencies = [ "anyhow", "id-arena", @@ -3355,7 +3916,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.221.3", + "wasmparser 0.229.0", ] [[package]] @@ -3366,24 +3927,24 @@ checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" dependencies = [ "anyhow", "log", - "thiserror", + "thiserror 1.0.69", "wast 35.0.2", ] [[package]] name = "wizer" -version = "8.0.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaecdae7465159e72b0cf6de6686fd0737f01e715f49a0adcbd89451ff8cb56a" +checksum = "1aee5402e9c06fb330c2edd1d7ae4bbdc9214b2cd19774199c9f6ec313d0237a" dependencies = [ "anyhow", "cap-std", "log", "rayon", - "wasm-encoder 0.202.0", - "wasmparser 0.202.0", - "wasmtime", - "wasmtime-wasi", + "wasm-encoder 0.228.0", + "wasmparser 0.228.0", + "wasmtime 31.0.0", + "wasmtime-wasi 31.0.0", ] [[package]] @@ -3455,47 +4016,28 @@ dependencies = [ "num-traits", "once_cell", "parity-wasm", - "rand 0.9.0", + "rand 0.9.1", "regex", "tempfile", + "tokio", + "wasmtime-wasi 33.0.2", "wizer", ] [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "byteorder", - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" -dependencies = [ - "zerocopy-derive 0.8.17", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.17" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 28f01f1..f0f8231 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,9 @@ rand = "0.9.0" home = "0.5.11" ethabi = "18.0.0" ethereum-types = "0.14.1" -wizer = "8.0.0" +tokio = "1.44.2" +wasmtime-wasi = "33.0.2" +wizer = "9.0.0" [features] default = ["inkwell/llvm16-0-force-static"] diff --git a/README.md b/README.md index 2a67418..1ff137c 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ DTVM_SolSDK works by accepting Solidity's Yul intermediate representation (IR) a * Solidity Compiler 0.8.29/(0.8.25+) * LLVM 16 -* Rust 1.81 or later +* Rust 1.83 or later * Binaryen (`brew install binaryen` on macOS, `apt install -y binaryen` on Ubuntu) ### Building the Project diff --git a/coverage.sh b/coverage.sh new file mode 100755 index 0000000..0594d7a --- /dev/null +++ b/coverage.sh @@ -0,0 +1,56 @@ +#!/bin/bash +set -e + +# Prerequisites: +# rustup component add llvm-tools-preview +# cargo install rustfilt +# cargo install grcov@0.5.1 +# or download grcov from https://github.com/mozilla/grcov/releases + +export RUSTC_BOOTSTRAP=1 + +# Create the directory for coverage reports +mkdir -p target/coverage + +# Clean any previous coverage data +rm -rf target/coverage/* + +# Clean previous build artifacts to ensure coverage instrumentation is applied +cargo clean +rm -f *.profraw + +export RUSTFLAGS="-Cinstrument-coverage" + +# Build the project with coverage instrumentation + +cargo build --verbose + +# Set environment variables for coverage +export CARGO_INCREMENTAL=0 +export RUSTFLAGS="-C instrument-coverage -Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" +export RUSTDOCFLAGS="-Cpanic=abort" +export LLVM_PROFILE_FILE="target/coverage/coverage-%p-%m.profraw" + +# Run tests with coverage instrumentation +cargo test --no-fail-fast --verbose + +# List all the profraw files to verify they were created +echo "Generated profraw files:" +# ls -la target/coverage/ + +# Generate coverage report +# target/coverage +grcov . --binary-path ./target/debug -s . -t html --branch --ignore-not-existing --ignore "/*" --ignore "target/*" --ignore "tests/*" --ignore "examples/*" -o target/coverage/html + +# Generate a summary report +grcov . --binary-path ./target/debug -s . -t lcov --branch --ignore-not-existing --ignore "/*" --ignore "target/*" --ignore "tests/*" --ignore "examples/*" -o target/coverage/lcov.info + +# Print a message with the location of the coverage report +echo "Coverage report generated at target/coverage/html/index.html" + +ls -la *.profraw +rm -rf *.profraw + +# Start a local web server to view the coverage report +cd target/coverage/html && python3 -m http.server 8080 +# open http://localhost:8080/src/yul2ir/index.html diff --git a/docker/Dockerfile b/docker/Dockerfile index 2846c36..570274f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -23,13 +23,13 @@ RUN ./emsdk activate 3.1.69 USER root RUN curl -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh -s -- -y RUN bash -c ". /root/.cargo/env" -COPY cargo_config /root/.cargo/config -RUN bash -c ". ~/.cargo/env && rustup install 1.81.0 && rustup default 1.81.0" +COPY cargo_config /root/.cargo/config.toml +RUN bash -c ". ~/.cargo/env && rustup install 1.84.0 && rustup default 1.84.0" WORKDIR /home/admin USER root WORKDIR /opt -RUN echo "export PATH=/opt/llvm15/bin:/opt:\$PATH" >> ~/.bash_profile +RUN echo "export PATH=/opt/llvm16/bin:/opt:\$PATH" >> ~/.bash_profile RUN echo "export LLVM_SYS_160_PREFIX=/opt/llvm16" >> ~/.bash_profile ENV PATH=/opt/llvm16/bin:/opt:$PATH ENV LLVM_SYS_160_PREFIX=/opt/llvm16 diff --git a/docker/docker_build.sh b/docker/docker_build.sh index f3a8b2a..bfd0d13 100755 --- a/docker/docker_build.sh +++ b/docker/docker_build.sh @@ -6,6 +6,6 @@ if [ "$1" = "prepare" ]; then ls else cd docker - docker build . --platform linux/x86_64 -f Dockerfile -t dtvmdev1/dtvm-sol-dev-x64:latest + docker build . --platform linux/x86_64 -f Dockerfile -t dtvmdev1/dtvm-sol-dev-x64:1.84.0 cd .. fi diff --git a/docker/install_rust.sh b/docker/install_rust.sh index cd56cf3..4233f17 100644 --- a/docker/install_rust.sh +++ b/docker/install_rust.sh @@ -2,5 +2,5 @@ set -e curl -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh -s -- -y . "$HOME/.cargo/env" -rustup install 1.81.0 -rustup default 1.81.0 +rustup install 1.84.0 +rustup default 1.84.0 diff --git a/docs/compilation-guide.md b/docs/compilation-guide.md index 1d5ff3e..eefec98 100644 --- a/docs/compilation-guide.md +++ b/docs/compilation-guide.md @@ -15,7 +15,7 @@ Before compiling DTVM_SolSDK, you need to install the following dependencies: ### Required Dependencies -1. **Rust 1.81+** +1. **Rust 1.83+** - Rust language and its package manager Cargo 2. **LLVM 16** diff --git a/docs/developer-guide.md b/docs/developer-guide.md index 4b23c46..bd36f27 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -6,7 +6,7 @@ DTVM_SolSDK is a compiler that translates Solidity's Yul intermediate representa ## Development Environment Setup ### Prerequisites -- Rust 1.81 or newer +- Rust 1.83 or newer - LLVM 16 - Solidity Compiler 0.8.25 - Binaryen (for wasm tools like wasm2wat) diff --git a/docs/release_docs/quick-start.md b/docs/release_docs/quick-start.md index c422f1e..190948d 100644 --- a/docs/release_docs/quick-start.md +++ b/docs/release_docs/quick-start.md @@ -10,27 +10,19 @@ docker pull dtvmdev1/dtvm-sol-dev-x64:main Before using DTVM_SolSDK, ensure the following dependencies are installed on your system: -- **LLVM 16** or **lld-16** - **solc** (Solidity compiler) or **Foundry** - **Binaryen** (Optional) - -### Installing LLVM 16 or lld-16 - -```bash -cd /opt -wget https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.4/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz -tar -xvf clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz -rm -rf clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz -mv clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04 llvm16 -export LLVM_SYS_160_PREFIX=/opt/llvm16 -export PATH=$LLVM_SYS_160_PREFIX/bin:/opt:$PATH -``` +- **zstd** (on Mac) ### Installing Solidity Compiler (solc) Download the Solidity compiler from: [https://github.com/ethereum/solidity/releases](https://github.com/ethereum/solidity/releases) +### Installing zstd (on Mac) + +If you are using this tool on Mac, you need to install the **zstd** library. The simplest installation method is to first install `homebrew`, then run `brew install zstd` + ### Installing Foundry Install Foundry from: @@ -55,6 +47,18 @@ solc --ir --optimize-yul -o output_directory --overwrite your_contract.sol yul2wasm --input output_directory/ContractName.yul --output your_contract.wasm ``` +If you're using Foundry for your project, here's how to compile your Solidity contract to WebAssembly: + +```bash +# Step1: Compile foundry project to Yul IR +forge build --extra-output-files ir-optimized + +# If your solidity filename and contract name is ExampleContract + +# Step2: Compile Yul IR to WebAssembly +yul2wasm --input out/ExampleContract.sol/ExampleContract.iropt --output out/ExampleContract.wasm +``` + ### Command Line Options yul2wasm provides several command-line options: diff --git a/docs/user-guide.md b/docs/user-guide.md index 0247d68..64df033 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -12,7 +12,7 @@ Before using DTVM_SolSDK, ensure you have the following prerequisites installed: - Solidity Compiler 0.8.29(0.8.25+) - LLVM 16 -- Rust 1.81 or later +- Rust 1.83 or later - Binaryen (for wasm tools) For detailed installation instructions, refer to the [Developer Guide](developer-guide.md). diff --git a/examples/foundry_erc20/build.sh b/examples/foundry_erc20/build.sh index 7bc7920..088529b 100755 --- a/examples/foundry_erc20/build.sh +++ b/examples/foundry_erc20/build.sh @@ -1,45 +1,26 @@ #!/bin/bash set -e +source ../../tools/build_utils.sh + # install solidity # https://docs.soliditylang.org/en/latest/installing-solidity.html # install foundry # curl -L https://foundry.paradigm.xyz | bash -# Determine the build mode -BUILD_MODE=${1:-release} - -echo "Building in $BUILD_MODE mode" - -# --enable-little-endian-storage-load-store -YUL2WASM_EXTRA_ARGS="--verbose" - -# if env ENABLE_LITTLE_ENDIAN_STORAGE == "ON", then add --enable-little-endian-storage-load-store -if [ "$ENABLE_LITTLE_ENDIAN_STORAGE" == "ON" ]; then - YUL2WASM_EXTRA_ARGS="$YUL2WASM_EXTRA_ARGS --enable-little-endian-storage-load-store" -fi - -# Set the yul2wasm path based on the build mode -if [ "$BUILD_MODE" == "release" ]; then - YUL2WASM_PATH="../../target/release/yul2wasm" -else - YUL2WASM_PATH="../../target/debug/yul2wasm" - YUL2WASM_EXTRA_ARGS="$YUL2WASM_EXTRA_ARGS --debug" -fi - -# npm install @openzeppelin/contracts -# solc --ir --optimize-yul -o . --overwrite TokenFactory.sol MyToken.sol +setup_build_mode ${1:-release} +forge clean forge build --extra-output-files ir-optimized # for debug: forge build --extra-output-files ir # ir generated in out/TokenFactory.sol/TokenFactory.ir -$YUL2WASM_PATH --input out/MyToken.sol/MyToken.iropt --output out/MyToken.wasm $YUL2WASM_EXTRA_ARGS -wasm2wat -o out/MyToken.wat out/MyToken.wasm -echo 'MyToken compiled to wasm in out/MyToken.wasm' +YUL_IR_PATH="out" +# contracts to compile +CONTRACTS=( + "MyToken" + "TokenFactory" +) -# Compile TokenFactory, which will be used to deploy MyToken -$YUL2WASM_PATH --input out/TokenFactory.sol/TokenFactory.iropt --output out/TokenFactory.wasm $YUL2WASM_EXTRA_ARGS -wasm2wat -o out/TokenFactory.wat out/TokenFactory.wasm -echo 'TokenFactory compiled to wasm in out/TokenFactory.wasm' +compile_all_contracts CONTRACTS[@] "$YUL_IR_PATH" diff --git a/examples/foundry_erc20/build_forge_test.sh b/examples/foundry_erc20/build_forge_test.sh new file mode 100755 index 0000000..490cedc --- /dev/null +++ b/examples/foundry_erc20/build_forge_test.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -e + +source ../../tools/build_utils.sh + +# install solidity +# https://docs.soliditylang.org/en/latest/installing-solidity.html + +# install foundry +# curl -L https://foundry.paradigm.xyz | bash + +setup_build_mode ${1:-release} + +forge clean +cp ../scripts/WasmTestVM.sol src/WasmTestVM.sol +forge test --extra-output-files ir-optimized +rm src/WasmTestVM.sol + +YUL_IR_PATH="out" + +# contracts to compile +CONTRACTS=( + "WasmTestVM" + "TestContract" +) + +compile_all_contracts CONTRACTS[@] "$YUL_IR_PATH" diff --git a/examples/foundry_erc20/test/Contract.t.sol b/examples/foundry_erc20/test/Contract.t.sol deleted file mode 100644 index 2852dcd..0000000 --- a/examples/foundry_erc20/test/Contract.t.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.13; - -import "forge-std/Test.sol"; - -import "src/MyToken.sol"; - -contract TestContract is Test { - MyToken c; - - function setUp() public { - c = new MyToken(100000); - } - - function testBar() public { - assertEq(uint256(1), uint256(1), "ok"); - } - - function testFoo(uint256 x) public { - vm.assume(x < type(uint128).max); - assertEq(x + x, x * 2); - } -} diff --git a/examples/foundry_erc20/test/TestContract.sol b/examples/foundry_erc20/test/TestContract.sol new file mode 100644 index 0000000..d78be82 --- /dev/null +++ b/examples/foundry_erc20/test/TestContract.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; + +import "src/MyToken.sol"; + +contract TestContract is Test { + MyToken c; + + address owner = address(this); + address user2 = address(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4); + address user3 = address(0x5B38Da6a701C568545DcFCb03fcb875F56BEDDc5); + + uint256 constant INITIAL_SUPPLY = 1000; + uint256 constant MINT_AMOUNT = 7; + uint256 constant TRANSFER_AMOUNT = 5; + uint256 constant APPROVE_AMOUNT = 10; + + function setUp() public { + c = new MyToken(INITIAL_SUPPLY); + } + + function testDeployAndTotalSupply() public { + assertEq(c.totalSupply(), INITIAL_SUPPLY, "Initial total supply should match"); + } + + function testMint() public { + uint256 user2_balance = c.balanceOf(user2); + c.mint(user2, MINT_AMOUNT); + assertEq(c.balanceOf(user2), user2_balance + MINT_AMOUNT, "User2 balance should be correct after mint"); + } + + function testApproveAndAllowance() public { + uint256 user2_allowance = c.allowance(owner, user2); + c.approve(user2, APPROVE_AMOUNT); + assertEq(c.allowance(owner, user2), user2_allowance + APPROVE_AMOUNT, "Allowance should be set correctly"); + } + + function testTransfer() public { + assertEq(c.balanceOf(address(this)), INITIAL_SUPPLY, "Owner balance should be 0 before testTransfer"); + c.mint(address(this), MINT_AMOUNT); + assertEq(c.balanceOf(address(this)), INITIAL_SUPPLY + MINT_AMOUNT, "Owner balance should be 5 before transfer"); + + uint256 user2_balance = c.balanceOf(user2); + c.transfer(user2, TRANSFER_AMOUNT); + + assertEq(c.balanceOf(user2), user2_balance + TRANSFER_AMOUNT, "User2 should receive correct amount"); + assertEq(c.balanceOf(address(this)), INITIAL_SUPPLY + MINT_AMOUNT - TRANSFER_AMOUNT, "Owner balance should be decreased"); + } + + event ValueLogged(uint256 value); + + event AddressLogged(address value); + + function testTransferFrom() public { + emit AddressLogged(address(this)); + uint256 user2_allowance = c.allowance(address(this), user2); + vm.startPrank(owner); + uint256 this_balance = c.balanceOf(address(this)); + emit ValueLogged(this_balance); + c.mint(address(this), MINT_AMOUNT); + emit ValueLogged(c.balanceOf(address(this))); + c.approve(user2, APPROVE_AMOUNT); + vm.stopPrank(); + + vm.startPrank(user2); + uint256 user3_balance = c.balanceOf(user3); + emit ValueLogged(user3_balance); + c.transferFrom(address(this), user3, APPROVE_AMOUNT); + vm.stopPrank(); + emit ValueLogged(c.balanceOf(address(this))); + + assertEq(c.balanceOf(user3), user3_balance + APPROVE_AMOUNT, "User3 should receive correct amount"); + assertEq(c.balanceOf(address(this)), this_balance + MINT_AMOUNT - APPROVE_AMOUNT, "Owner balance should be decreased"); + assertEq(c.allowance(address(this), user2), user2_allowance + APPROVE_AMOUNT - APPROVE_AMOUNT, "Allowance should be decreased"); + } + + // CompleteFlow: deploy -> mint -> transfer -> approve -> transferFrom + function testCompleteFlow() public { + uint256 owner_balance = c.balanceOf(owner); + uint256 user2_balance = c.balanceOf(user2); + uint256 user2_allowance_before_approve = c.allowance(owner, user2); + uint256 user3_balance = c.balanceOf(user3); + + vm.startPrank(owner); + + assertEq(c.totalSupply(), INITIAL_SUPPLY, "Initial total supply should match"); + + c.mint(owner, MINT_AMOUNT); + assertEq(c.balanceOf(owner), owner_balance + MINT_AMOUNT, "Owner should receive minted tokens"); + + c.transfer(user2, TRANSFER_AMOUNT); + assertEq(c.balanceOf(user2), user2_balance + TRANSFER_AMOUNT, "User2 should receive transferred tokens"); + + c.approve(user2, APPROVE_AMOUNT); + uint256 user2_allowance_after_approve = c.allowance(owner, user2); + assertEq(c.allowance(owner, user2), user2_allowance_before_approve + APPROVE_AMOUNT, "Allowance should be set correctly"); + + vm.stopPrank(); + + vm.startPrank(user2); + c.transferFrom(owner, user3, APPROVE_AMOUNT); + vm.stopPrank(); + + assertEq(c.balanceOf(user3), user3_balance + APPROVE_AMOUNT, "User3 should receive correct amount"); + assertEq(c.allowance(owner, user2), user2_allowance_after_approve - APPROVE_AMOUNT, "Allowance should be decreased"); + } +} diff --git a/examples/foundry_erc20/test_forge_test.sh b/examples/foundry_erc20/test_forge_test.sh new file mode 100755 index 0000000..6b7423e --- /dev/null +++ b/examples/foundry_erc20/test_forge_test.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -e + +cd .. +source ../tools/forge_test_utils.sh +cd foundry_erc20 + +YUL_IR_PATH="out" +wasm_vm_file="$YUL_IR_PATH/WasmTestVM.wasm" +contract_file="$YUL_IR_PATH/TestContract.wasm" +# deploy WasmTestVM, Cheat code address from: abstract contract CommonBase, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D +WASM_TEST_VM_DEPLOY_ADDR=0x7109709ecfa91a80626ff3989d68f67f5b1dd12d +DEPLOYER_INITIALIZER_ADDR=0x11bbccddeeffaabbccddeeffaabbccddeeffaa11 + +run_single_test() { + init_test "$wasm_vm_file" "$WASM_TEST_VM_DEPLOY_ADDR" "$contract_file" "$DEPLOYER_INITIALIZER_ADDR" + + local wasm_file=$1 + local function_name=$2 + local expected_result=$3 + call_contract_function "$wasm_file" "$DEPLOYER_INITIALIZER_ADDR" "$function_name" "$expected_output" + echo "Test success: $function_name" +} + +# testDeployAndTotalSupply() - 0x39eb0c5c +run_single_test $contract_file "testDeployAndTotalSupply()" 'evm finish with result hex: 00000000000000000000000000000000000000000000000000000000000003e8' +# testMint() - 0x9642ddaf +run_single_test $contract_file "testMint()" 'evm finish with result hex: 0000000000000000000000000000000000000000000000000000000000000007' +# testApproveAndAllowance() - 0xba5af22d +run_single_test $contract_file "testApproveAndAllowance()" 'evm finish with result hex: 0000000000000000000000000000000000000000000000000000000000000001' +# testTransfer() - 0xd591221f +run_single_test $contract_file "testTransfer()" 'evm finish with result hex: 00000000000000000000000000000000000000000000000000000000000003ea' +# testTransferFrom() - 0x70557298 +run_single_test $contract_file "testTransferFrom()" 'evm finish with result hex:' +# testCompleteFlow() - 0xe44962e7 +run_single_test $contract_file "testCompleteFlow()" 'evm finish with result hex:' + +echo "All tests success!" diff --git a/examples/scripts/WasmTestVM.sol b/examples/scripts/WasmTestVM.sol new file mode 100644 index 0000000..28cc5db --- /dev/null +++ b/examples/scripts/WasmTestVM.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + +contract WasmTestVM { + /// Asserts that two `int256` values are equal and includes error message into revert string on failure. + function assertEq(uint256 left, uint256 right, string memory err) public pure { + require(left == right, err); + } +} diff --git a/src/tests/chain_context_tests.rs b/src/tests/chain_context_tests.rs new file mode 100644 index 0000000..b9a5d10 --- /dev/null +++ b/src/tests/chain_context_tests.rs @@ -0,0 +1,512 @@ +// Copyright (C) 2024-2025 the DTVM authors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused)] +use super::test_helper::solidity_selector; +#[allow(unused)] +use super::test_helper::TestRuntime; +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_yul_gaslimit() { + let mut runtime = TestRuntime::new("GaslimitTest", "target/test_yul_gaslimit"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "GaslimitTest" { + code { + } + object "GaslimitTest_deployed" { + code { + function test_gaslimit() -> r { + r := gaslimit() + } + + let r := test_gaslimit() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_gaslimit()"), &[]) + .unwrap(); + // DEFAULT_GAS_LIMIT: 10000000 + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000989680"); + } + + #[test] + fn test_yul_gas() { + let mut runtime = TestRuntime::new("GasTest", "target/test_yul_gas"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "GasTest" { + code { + } + object "GasTest_deployed" { + code { + function test_gas() -> r { + r := gas() + } + + let r := test_gas() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime.call(&solidity_selector("test_gas()"), &[]).unwrap(); + // DEFAULT_GAS_LIMIT: 10000000; DELTA_GAS: 100; + runtime.assert_result("000000000000000000000000000000000000000000000000000000000098961c"); + // 9999900 + } + + #[test] + fn test_yul_chainid() { + let mut runtime = TestRuntime::new("ChainidTest", "target/test_yul_chainid"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "ChainidTest" { + code { + } + object "ChainidTest_deployed" { + code { + function test_chainid() -> r { + r := chainid() + } + + let r := test_chainid() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_chainid()"), &[]) + .unwrap(); + // DEFAULT_CHAIN_ID: 1234 + runtime.assert_result("00000000000000000000000000000000000000000000000000000000000004d2"); + } + + #[test] + fn test_yul_gasprice() { + let mut runtime = TestRuntime::new("GaspriceTest", "target/test_yul_gasprice"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "GaspriceTest" { + code { + } + object "GaspriceTest_deployed" { + code { + function test_gasprice() -> r { + r := gasprice() + } + + let r := test_gasprice() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_gasprice()"), &[]) + .unwrap(); + // DEFAULT_GAS_PRICE: 1 + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000001"); + } + + #[test] + fn test_yul_basefee() { + let mut runtime = TestRuntime::new("BasefeeTest", "target/test_yul_basefee"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "BasefeeTest" { + code { + } + object "BasefeeTest_deployed" { + code { + function test_basefee() -> r { + r := basefee() + } + + let r := test_basefee() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_basefee()"), &[]) + .unwrap(); + // DEFAULT_BASE_FEE: 0 + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000000"); + } + + #[test] + fn test_yul_blobbasefee() { + let mut runtime = TestRuntime::new("BolbbasefeeTest", "target/test_yul_blobbasefee"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "BolbbasefeeTest" { + code { + } + object "BolbbasefeeTest_deployed" { + code { + function test_blobbasefee() ->r { + r := blobbasefee() + } + + let r := test_blobbasefee() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_blobbasefee()"), &[]) + .unwrap(); + // DEFAULT_BLOB_BASE_FEE: 0 + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000000"); + } + + #[test] + fn test_yul_coinbase() { + let mut runtime = TestRuntime::new("CoinbaseTest", "target/test_yul_coinbase"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "CoinbaseTest" { + code { + } + object "CoinbaseTest_deployed" { + code { + function test_coinbase() ->r { + r := coinbase() + } + + let r := test_coinbase() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_coinbase()"), &[]) + .unwrap(); + // DEFAULT_COINBASE: 0000000000000000000000000303030303030303030303030303030303030303 + runtime.assert_result("0000000000000000000000000303030303030303030303030303030303030303"); + } + + #[test] + fn test_yul_prevrandao() { + let mut runtime = TestRuntime::new("PrevrandaoTest", "target/test_yul_prevrandao"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "PrevrandaoTest" { + code { + } + object "PrevrandaoTest_deployed" { + code { + function test_prevrandao() ->r { + r := prevrandao() + } + + let r := test_prevrandao() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_prevrandao()"), &[]) + .unwrap(); + // DEFAULT_PREVRANDAO: 0505050505050505050505050505050505050505050505050505050505050505 + runtime.assert_result("0505050505050505050505050505050505050505050505050505050505050505"); + } + + #[test] + fn test_yul_difficulty() { + let mut runtime = TestRuntime::new("DifficultyTest", "target/test_yul_difficulty"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "DifficultyTest" { + code { + } + object "DifficultyTest_deployed" { + code { + function test_difficulty() ->r { + r := difficulty() // same method as prevrandao + } + + let r := test_difficulty() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_difficulty()"), &[]) + .unwrap(); + // DEFAULT_PREVRANDAO: 0505050505050505050505050505050505050505050505050505050505050505 + runtime.assert_result("0505050505050505050505050505050505050505050505050505050505050505"); + } + + #[test] + fn test_yul_timestamp() { + let mut runtime = TestRuntime::new("TimestampTest", "target/test_yul_timestamp"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "TimestampTest" { + code { + } + object "TimestampTest_deployed" { + code { + function test_timestamp() ->r { + r := timestamp() + } + + let r := test_timestamp() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_timestamp()"), &[]) + .unwrap(); + // DEFAULT_TIMESTAMP: 1234567890 + runtime.assert_result("00000000000000000000000000000000000000000000000000000000499602d2"); + } + + #[test] + fn test_yul_number() { + let mut runtime = TestRuntime::new("NumberTest", "target/test_yul_number"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "NumberTest" { + code { + } + object "NumberTest_deployed" { + code { + function test_number() ->r { + r := number() + } + + let r := test_number() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_number()"), &[]) + .unwrap(); + // DEFAULT_NUMBER: 12345 + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000003039"); + } + + #[test] + fn test_yul_caller0() { + let mut runtime = TestRuntime::new("Caller0Test", "target/test_yul_caller0"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "Caller0Test" { + code { + } + object "Caller0Test_deployed" { + code { + function test_caller() -> r { + r := caller() + } + + let r := test_caller() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_caller()"), &[]) + .unwrap(); + // DEFAULT_SENDER_ADDRESS_HEX: 0x0011223344556677889900112233445566778899 + runtime.assert_result("0000000000000000000000000011223344556677889900112233445566778899"); + } + + #[test] + fn test_yul_caller1() { + let mut runtime = TestRuntime::new("Caller1Test", "target/test_yul_caller1"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "Caller1Test" { + code { + } + object "Caller1Test_deployed" { + code { + function test_caller() -> r { + r := caller() + } + + let r := test_caller() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.set_sender(Some( + "0x1234567890123456789012345678901234567890".to_string(), + )); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_caller()"), &[]) + .unwrap(); + runtime.assert_result("0000000000000000000000001234567890123456789012345678901234567890"); + } + + #[test] + fn test_yul_caller2() { + let mut runtime = TestRuntime::new("Caller2Test", "target/test_yul_caller2"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "Caller2Test" { + code { + let _datasize := datasize("Caller2Test_deployed") + datacopy(0x00, dataoffset("Caller2Test_deployed"), _datasize) + return(0x00, _datasize) + } + + object "Caller2Test_deployed" { + code { + // Deploy "ContractA" and test if `caller` opcode is correctly resolved in nested calls. + datacopy(0x00, dataoffset("ContractA"), datasize("ContractA")) + let addrContractA := create(0, 0x00, datasize("ContractA")) + mstore(0x00, 0x4d49c1ea) // selector for "test_caller()" + let success := call(gas(), addrContractA, 0, 0x00, 0x04, 0x00, 0x20) + if iszero(success) { revert(0x00, 0x00) } // Revert if failed + + return(0x00, 0x20) + } + + object "ContractA" { + code { + let _aDatasize := datasize("ContractA_deployed") + datacopy(0x00, dataoffset("ContractA_deployed"), _aDatasize) + return(0x00, _aDatasize) + } + + object "ContractA_deployed" { + code { + // Deploy "ContractB", call `test_caller()`, and verify returned `caller` address. + let _bDatasize := datasize("ContractB") + datacopy(0x00, dataoffset("ContractB"), _bDatasize) + let addrContractB := create(0, 0x00, _bDatasize) + mstore(0x00, 0x4d49c1ea) // selector for "test_caller()" + // Call "test_caller" in ContractB + let success := call(gas(), addrContractB, 0, 0x00, 0x04, 0x00, 0x20) + if iszero(success) { revert(0x00, 0x00) } + + let callerFromB := mload(0x00) + mstore(0x00, 0) // Default output + // Check if caller value is the deployment address + if eq(callerFromB, address()) { + mstore(0x00, 1) // Set output to 1 if match + } + + return(0x00, 0x20) + } + + object "ContractB" { + code { + } + + object "ContractB_deployed" { + code { + function test_caller() -> result { + result := caller() + } + mstore(0x00, test_caller()) + return(0x00, 0x20) + } + } + } + } + } + } + } + "#, + ) + .unwrap(); + runtime.set_sender(Some( + "0x1234567890123456789012345678901234567890".to_string(), + )); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_caller()"), &[]) + .unwrap(); + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000001"); + } +} diff --git a/src/tests/function_optimize_tests.rs b/src/tests/function_optimize_tests.rs new file mode 100644 index 0000000..1f1a9cd --- /dev/null +++ b/src/tests/function_optimize_tests.rs @@ -0,0 +1,215 @@ +// Copyright (C) 2024-2025 the DTVM authors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused)] +use super::test_helper::solidity_selector; +#[allow(unused)] +use super::test_helper::TestRuntime; + +#[cfg(test)] +mod tests { + use super::*; + use crate::yul2ir::transform::UNIFIED_REVERT_ERROR_ZERO; + use std::io::{BufRead, BufReader}; + + fn contains_string(file_path: &str, target: &str) -> std::io::Result { + let file = std::fs::File::open(file_path)?; + let reader = BufReader::new(file); + + for line in reader.lines() { + if line?.contains(target) { + return Ok(true); + } + } + Ok(false) + } + + #[test] + fn test_yul_opt_revert_zero1() { + let mut runtime = TestRuntime::new("RevertZeroTest1", "target/test_revert_zero1"); + let emited_bc = runtime + .compile_test_yul( + r#" + object "RevertZeroTest1" { + code { + } + object "RevertZeroTest1_deployed" { + code { + function test_revert_error_1() { + revert(0, 0) + } + function test_revert_error_2() { + revert(0, 0) + } + function test_func() -> r { + r := 0 + if callvalue() { + test_revert_error_1() + } + if iszero(lt(calldatasize(), 4)) { + r := 1 + } + test_revert_error_2() + } + + let r := test_func() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + std::fs::write("target/test_revert_zero1/test_revert_zero1.wasm", emited_bc).unwrap(); + runtime.wasm2wat( + "target/test_revert_zero1/test_revert_zero1.wasm", + "target/test_revert_zero1/test_revert_zero1.wat", + ); + assert!(contains_string( + "target/test_revert_zero1/test_revert_zero1.wat", + UNIFIED_REVERT_ERROR_ZERO + ) + .unwrap()); + assert!(!contains_string( + "target/test_revert_zero1/test_revert_zero1.wat", + "test_revert_error_1" + ) + .unwrap()); + assert!(!contains_string( + "target/test_revert_zero1/test_revert_zero1.wat", + "test_revert_error_2" + ) + .unwrap()); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_func()"), &[]) + .unwrap(); + } + + #[test] + fn test_yul_opt_revert_zero2() { + let mut runtime = TestRuntime::new("RevertZeroTest2", "target/test_revert_zero2"); + let emited_bc = runtime + .compile_test_yul( + r#" + object "RevertZeroTest2" { + code { + } + object "RevertZeroTest2_deployed" { + code { + let r := test_func() + mstore(0x00, r) + return(0x00, 0x20) + + function test_revert_error_1() { + revert(0, 0) + } + function test_revert_error_2() { + revert(0, 0) + } + function test_func() -> r { + r := 0 + if callvalue() { + test_revert_error_1() + } + if iszero(lt(calldatasize(), 4)) { + r := 1 + } + test_revert_error_2() + } + } + } + } + "#, + ) + .unwrap(); + std::fs::write("target/test_revert_zero2/test_revert_zero2.wasm", emited_bc).unwrap(); + runtime.wasm2wat( + "target/test_revert_zero2/test_revert_zero2.wasm", + "target/test_revert_zero2/test_revert_zero2.wat", + ); + assert!(contains_string( + "target/test_revert_zero2/test_revert_zero2.wat", + UNIFIED_REVERT_ERROR_ZERO + ) + .unwrap()); + assert!(!contains_string( + "target/test_revert_zero2/test_revert_zero2.wat", + "test_revert_error_1" + ) + .unwrap()); + assert!(!contains_string( + "target/test_revert_zero2/test_revert_zero2.wat", + "test_revert_error_2" + ) + .unwrap()); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_func()"), &[]) + .unwrap(); + } + + #[test] + fn test_yul_opt_revert_zero3() { + let mut runtime = TestRuntime::new("RevertZeroTest3", "target/test_revert_zero3"); + let emited_bc = runtime + .compile_test_yul( + r#" + object "RevertZeroTest3" { + code { + } + object "RevertZeroTest3_deployed" { + code { + let r := test_func() + mstore(0x00, r) + return(0x00, 0x20) + + function test_func() -> r { + r := 0 + if callvalue() { + test_revert_error_1() + } + if iszero(lt(calldatasize(), 4)) { + r := 1 + } + test_revert_error_2() + } + function test_revert_error_1() { + revert(0, 0) + } + function test_revert_error_2() { + revert(0, 0) + } + } + } + } + "#, + ) + .unwrap(); + std::fs::write("target/test_revert_zero3/test_revert_zero3.wasm", emited_bc).unwrap(); + runtime.wasm2wat( + "target/test_revert_zero3/test_revert_zero3.wasm", + "target/test_revert_zero3/test_revert_zero3.wat", + ); + assert!(contains_string( + "target/test_revert_zero3/test_revert_zero3.wat", + UNIFIED_REVERT_ERROR_ZERO + ) + .unwrap()); + assert!(!contains_string( + "target/test_revert_zero3/test_revert_zero3.wat", + "test_revert_error_1" + ) + .unwrap()); + assert!(!contains_string( + "target/test_revert_zero3/test_revert_zero3.wat", + "test_revert_error_2" + ) + .unwrap()); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_func()"), &[]) + .unwrap(); + } +} diff --git a/src/tests/hostapi_tests.rs b/src/tests/hostapi_tests.rs index ec17943..09536a8 100644 --- a/src/tests/hostapi_tests.rs +++ b/src/tests/hostapi_tests.rs @@ -212,38 +212,6 @@ mod tests { runtime.assert_result("000000000000000000000000aabbccddeeffaabbccddeeffaabbccddeeffaabb"); } - #[test] - fn test_yul_gaslimit() { - let mut runtime = TestRuntime::new("GaslimitTest", "target/test_yul_gaslimit"); - let _emited_bc = runtime - .compile_test_yul( - r#" - object "GaslimitTest" { - code { - } - object "GaslimitTest_deployed" { - code { - function test_gaslimit() -> r { - r := gaslimit() - } - - let r := test_gaslimit() - mstore(0x00, r) - return(0x00, 0x20) - } - } - } - "#, - ) - .unwrap(); - runtime.deploy(&[]).unwrap(); - runtime - .call(&solidity_selector("test_gaslimit()"), &[]) - .unwrap(); - // DEFAULT_GAS_LIMIT: 10000000 - runtime.assert_result("0000000000000000000000000000000000000000000000000000000000989680"); - } - #[test] fn test_callvalue_not_zero() { let mut runtime = @@ -360,4 +328,68 @@ mod tests { .unwrap(); runtime.assert_result("f248a1c000000000000000000000000000000000000000000000000000000000"); } + + #[test] + fn test_solidity_revert_short_string() { + let mut runtime = TestRuntime::new( + "test_solidity_revert_short_string", + "target/test_solidity_revert_short_string", + ); + runtime.clear_testdata(); + let yul_code = runtime.compile_solidity_to_yul( + r#" + pragma solidity ^0.8.0; + + contract TestContract { + function test() public { + revert("helloworld"); + } + } + + "#, + "TestContract", + ); + if let Err(err) = &yul_code { + eprintln!("compile to yul error: {err}"); + } + assert!(yul_code.is_ok()); + let yul_code = yul_code.unwrap(); + let _emited_bc = runtime.compile_test_yul(&yul_code).unwrap(); + runtime.set_enable_gas_meter(false); + runtime.deploy(&[]).unwrap(); + runtime.call(&solidity_selector("test()"), &[]).unwrap(); + runtime.assert_revert("08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a68656c6c6f776f726c6400000000000000000000000000000000000000000000"); + } + + #[test] + fn test_solidity_revert_long_string() { + let mut runtime = TestRuntime::new( + "test_solidity_revert_long_string", + "target/test_solidity_revert_long_string", + ); + runtime.clear_testdata(); + let yul_code = runtime.compile_solidity_to_yul( + r#" + pragma solidity ^0.8.0; + + contract TestContract { + function test() public { + revert("helloworld. This is a long revert string longer than 32bytes"); + } + } + + "#, + "TestContract", + ); + if let Err(err) = &yul_code { + eprintln!("compile to yul error: {err}"); + } + assert!(yul_code.is_ok()); + let yul_code = yul_code.unwrap(); + let _emited_bc = runtime.compile_test_yul(&yul_code).unwrap(); + runtime.set_enable_gas_meter(false); + runtime.deploy(&[]).unwrap(); + runtime.call(&solidity_selector("test()"), &[]).unwrap(); + runtime.assert_revert("08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003c68656c6c6f776f726c642e20546869732069732061206c6f6e672072657665727420737472696e67206c6f6e676572207468616e203332627974657300000000"); + } } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 9899a91..733b329 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -4,7 +4,9 @@ mod arithmetic_tests; mod bool_tests; mod byte_tests; +mod chain_context_tests; mod create_tests; +mod function_optimize_tests; mod hostapi_tests; mod int_cast_tests; mod int_constant_tests; @@ -13,6 +15,7 @@ mod mod_arithmetic_tests; mod mstore_tests; mod shift_tests; mod signed_arithmetic_tests; +mod solidity_strings; mod string_tests; mod syntax_tests; mod test; @@ -20,3 +23,4 @@ mod test_helper; mod transfer_tests; mod tstore_tload_tests; mod tuple_tests; +mod var_redefine_tests; diff --git a/src/tests/openzepplin_strings_full.sol b/src/tests/openzepplin_strings_full.sol new file mode 100644 index 0000000..4b18555 --- /dev/null +++ b/src/tests/openzepplin_strings_full.sol @@ -0,0 +1,2189 @@ +// from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol +// this file is used in solidity_strings.rs to test + +// node_modules/@openzeppelin/contracts/utils/Panic.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol) + +/** + * @dev Helper library for emitting standardized panic codes. + * + * ```solidity + * contract Example { + * using Panic for uint256; + * + * // Use any of the declared internal constants + * function foo() { Panic.GENERIC.panic(); } + * + * // Alternatively + * function foo() { Panic.panic(Panic.GENERIC); } + * } + * ``` + * + * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. + * + * _Available since v5.1._ + */ +// slither-disable-next-line unused-state +library Panic { + /// @dev generic / unspecified error + uint256 internal constant GENERIC = 0x00; + /// @dev used by the assert() builtin + uint256 internal constant ASSERT = 0x01; + /// @dev arithmetic underflow or overflow + uint256 internal constant UNDER_OVERFLOW = 0x11; + /// @dev division or modulo by zero + uint256 internal constant DIVISION_BY_ZERO = 0x12; + /// @dev enum conversion error + uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; + /// @dev invalid encoding in storage + uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; + /// @dev empty array pop + uint256 internal constant EMPTY_ARRAY_POP = 0x31; + /// @dev array out of bounds access + uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; + /// @dev resource error (too large allocation or too large array) + uint256 internal constant RESOURCE_ERROR = 0x41; + /// @dev calling invalid internal function + uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; + + /// @dev Reverts with a panic code. Recommended to use with + /// the internal constants with predefined codes. + function panic(uint256 code) internal pure { + assembly ("memory-safe") { + mstore(0x00, 0x4e487b71) + mstore(0x20, code) + revert(0x1c, 0x24) + } + } +} + +// node_modules/@openzeppelin/contracts/utils/math/SafeCast.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol) +// This file was procedurally generated from scripts/generate/templates/SafeCast.js. + +/** + * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. `SafeCast` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeCast { + /** + * @dev Value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); + + /** + * @dev An int value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedIntToUint(int256 value); + + /** + * @dev Value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); + + /** + * @dev An uint value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedUintToInt(uint256 value); + + /** + * @dev Returns the downcasted uint248 from uint256, reverting on + * overflow (when the input is greater than largest uint248). + * + * Counterpart to Solidity's `uint248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toUint248(uint256 value) internal pure returns (uint248) { + if (value > type(uint248).max) { + revert SafeCastOverflowedUintDowncast(248, value); + } + return uint248(value); + } + + /** + * @dev Returns the downcasted uint240 from uint256, reverting on + * overflow (when the input is greater than largest uint240). + * + * Counterpart to Solidity's `uint240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toUint240(uint256 value) internal pure returns (uint240) { + if (value > type(uint240).max) { + revert SafeCastOverflowedUintDowncast(240, value); + } + return uint240(value); + } + + /** + * @dev Returns the downcasted uint232 from uint256, reverting on + * overflow (when the input is greater than largest uint232). + * + * Counterpart to Solidity's `uint232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toUint232(uint256 value) internal pure returns (uint232) { + if (value > type(uint232).max) { + revert SafeCastOverflowedUintDowncast(232, value); + } + return uint232(value); + } + + /** + * @dev Returns the downcasted uint224 from uint256, reverting on + * overflow (when the input is greater than largest uint224). + * + * Counterpart to Solidity's `uint224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toUint224(uint256 value) internal pure returns (uint224) { + if (value > type(uint224).max) { + revert SafeCastOverflowedUintDowncast(224, value); + } + return uint224(value); + } + + /** + * @dev Returns the downcasted uint216 from uint256, reverting on + * overflow (when the input is greater than largest uint216). + * + * Counterpart to Solidity's `uint216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toUint216(uint256 value) internal pure returns (uint216) { + if (value > type(uint216).max) { + revert SafeCastOverflowedUintDowncast(216, value); + } + return uint216(value); + } + + /** + * @dev Returns the downcasted uint208 from uint256, reverting on + * overflow (when the input is greater than largest uint208). + * + * Counterpart to Solidity's `uint208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toUint208(uint256 value) internal pure returns (uint208) { + if (value > type(uint208).max) { + revert SafeCastOverflowedUintDowncast(208, value); + } + return uint208(value); + } + + /** + * @dev Returns the downcasted uint200 from uint256, reverting on + * overflow (when the input is greater than largest uint200). + * + * Counterpart to Solidity's `uint200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toUint200(uint256 value) internal pure returns (uint200) { + if (value > type(uint200).max) { + revert SafeCastOverflowedUintDowncast(200, value); + } + return uint200(value); + } + + /** + * @dev Returns the downcasted uint192 from uint256, reverting on + * overflow (when the input is greater than largest uint192). + * + * Counterpart to Solidity's `uint192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toUint192(uint256 value) internal pure returns (uint192) { + if (value > type(uint192).max) { + revert SafeCastOverflowedUintDowncast(192, value); + } + return uint192(value); + } + + /** + * @dev Returns the downcasted uint184 from uint256, reverting on + * overflow (when the input is greater than largest uint184). + * + * Counterpart to Solidity's `uint184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toUint184(uint256 value) internal pure returns (uint184) { + if (value > type(uint184).max) { + revert SafeCastOverflowedUintDowncast(184, value); + } + return uint184(value); + } + + /** + * @dev Returns the downcasted uint176 from uint256, reverting on + * overflow (when the input is greater than largest uint176). + * + * Counterpart to Solidity's `uint176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toUint176(uint256 value) internal pure returns (uint176) { + if (value > type(uint176).max) { + revert SafeCastOverflowedUintDowncast(176, value); + } + return uint176(value); + } + + /** + * @dev Returns the downcasted uint168 from uint256, reverting on + * overflow (when the input is greater than largest uint168). + * + * Counterpart to Solidity's `uint168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toUint168(uint256 value) internal pure returns (uint168) { + if (value > type(uint168).max) { + revert SafeCastOverflowedUintDowncast(168, value); + } + return uint168(value); + } + + /** + * @dev Returns the downcasted uint160 from uint256, reverting on + * overflow (when the input is greater than largest uint160). + * + * Counterpart to Solidity's `uint160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toUint160(uint256 value) internal pure returns (uint160) { + if (value > type(uint160).max) { + revert SafeCastOverflowedUintDowncast(160, value); + } + return uint160(value); + } + + /** + * @dev Returns the downcasted uint152 from uint256, reverting on + * overflow (when the input is greater than largest uint152). + * + * Counterpart to Solidity's `uint152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toUint152(uint256 value) internal pure returns (uint152) { + if (value > type(uint152).max) { + revert SafeCastOverflowedUintDowncast(152, value); + } + return uint152(value); + } + + /** + * @dev Returns the downcasted uint144 from uint256, reverting on + * overflow (when the input is greater than largest uint144). + * + * Counterpart to Solidity's `uint144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toUint144(uint256 value) internal pure returns (uint144) { + if (value > type(uint144).max) { + revert SafeCastOverflowedUintDowncast(144, value); + } + return uint144(value); + } + + /** + * @dev Returns the downcasted uint136 from uint256, reverting on + * overflow (when the input is greater than largest uint136). + * + * Counterpart to Solidity's `uint136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toUint136(uint256 value) internal pure returns (uint136) { + if (value > type(uint136).max) { + revert SafeCastOverflowedUintDowncast(136, value); + } + return uint136(value); + } + + /** + * @dev Returns the downcasted uint128 from uint256, reverting on + * overflow (when the input is greater than largest uint128). + * + * Counterpart to Solidity's `uint128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toUint128(uint256 value) internal pure returns (uint128) { + if (value > type(uint128).max) { + revert SafeCastOverflowedUintDowncast(128, value); + } + return uint128(value); + } + + /** + * @dev Returns the downcasted uint120 from uint256, reverting on + * overflow (when the input is greater than largest uint120). + * + * Counterpart to Solidity's `uint120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toUint120(uint256 value) internal pure returns (uint120) { + if (value > type(uint120).max) { + revert SafeCastOverflowedUintDowncast(120, value); + } + return uint120(value); + } + + /** + * @dev Returns the downcasted uint112 from uint256, reverting on + * overflow (when the input is greater than largest uint112). + * + * Counterpart to Solidity's `uint112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toUint112(uint256 value) internal pure returns (uint112) { + if (value > type(uint112).max) { + revert SafeCastOverflowedUintDowncast(112, value); + } + return uint112(value); + } + + /** + * @dev Returns the downcasted uint104 from uint256, reverting on + * overflow (when the input is greater than largest uint104). + * + * Counterpart to Solidity's `uint104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toUint104(uint256 value) internal pure returns (uint104) { + if (value > type(uint104).max) { + revert SafeCastOverflowedUintDowncast(104, value); + } + return uint104(value); + } + + /** + * @dev Returns the downcasted uint96 from uint256, reverting on + * overflow (when the input is greater than largest uint96). + * + * Counterpart to Solidity's `uint96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toUint96(uint256 value) internal pure returns (uint96) { + if (value > type(uint96).max) { + revert SafeCastOverflowedUintDowncast(96, value); + } + return uint96(value); + } + + /** + * @dev Returns the downcasted uint88 from uint256, reverting on + * overflow (when the input is greater than largest uint88). + * + * Counterpart to Solidity's `uint88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toUint88(uint256 value) internal pure returns (uint88) { + if (value > type(uint88).max) { + revert SafeCastOverflowedUintDowncast(88, value); + } + return uint88(value); + } + + /** + * @dev Returns the downcasted uint80 from uint256, reverting on + * overflow (when the input is greater than largest uint80). + * + * Counterpart to Solidity's `uint80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toUint80(uint256 value) internal pure returns (uint80) { + if (value > type(uint80).max) { + revert SafeCastOverflowedUintDowncast(80, value); + } + return uint80(value); + } + + /** + * @dev Returns the downcasted uint72 from uint256, reverting on + * overflow (when the input is greater than largest uint72). + * + * Counterpart to Solidity's `uint72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toUint72(uint256 value) internal pure returns (uint72) { + if (value > type(uint72).max) { + revert SafeCastOverflowedUintDowncast(72, value); + } + return uint72(value); + } + + /** + * @dev Returns the downcasted uint64 from uint256, reverting on + * overflow (when the input is greater than largest uint64). + * + * Counterpart to Solidity's `uint64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toUint64(uint256 value) internal pure returns (uint64) { + if (value > type(uint64).max) { + revert SafeCastOverflowedUintDowncast(64, value); + } + return uint64(value); + } + + /** + * @dev Returns the downcasted uint56 from uint256, reverting on + * overflow (when the input is greater than largest uint56). + * + * Counterpart to Solidity's `uint56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toUint56(uint256 value) internal pure returns (uint56) { + if (value > type(uint56).max) { + revert SafeCastOverflowedUintDowncast(56, value); + } + return uint56(value); + } + + /** + * @dev Returns the downcasted uint48 from uint256, reverting on + * overflow (when the input is greater than largest uint48). + * + * Counterpart to Solidity's `uint48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toUint48(uint256 value) internal pure returns (uint48) { + if (value > type(uint48).max) { + revert SafeCastOverflowedUintDowncast(48, value); + } + return uint48(value); + } + + /** + * @dev Returns the downcasted uint40 from uint256, reverting on + * overflow (when the input is greater than largest uint40). + * + * Counterpart to Solidity's `uint40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toUint40(uint256 value) internal pure returns (uint40) { + if (value > type(uint40).max) { + revert SafeCastOverflowedUintDowncast(40, value); + } + return uint40(value); + } + + /** + * @dev Returns the downcasted uint32 from uint256, reverting on + * overflow (when the input is greater than largest uint32). + * + * Counterpart to Solidity's `uint32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toUint32(uint256 value) internal pure returns (uint32) { + if (value > type(uint32).max) { + revert SafeCastOverflowedUintDowncast(32, value); + } + return uint32(value); + } + + /** + * @dev Returns the downcasted uint24 from uint256, reverting on + * overflow (when the input is greater than largest uint24). + * + * Counterpart to Solidity's `uint24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toUint24(uint256 value) internal pure returns (uint24) { + if (value > type(uint24).max) { + revert SafeCastOverflowedUintDowncast(24, value); + } + return uint24(value); + } + + /** + * @dev Returns the downcasted uint16 from uint256, reverting on + * overflow (when the input is greater than largest uint16). + * + * Counterpart to Solidity's `uint16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toUint16(uint256 value) internal pure returns (uint16) { + if (value > type(uint16).max) { + revert SafeCastOverflowedUintDowncast(16, value); + } + return uint16(value); + } + + /** + * @dev Returns the downcasted uint8 from uint256, reverting on + * overflow (when the input is greater than largest uint8). + * + * Counterpart to Solidity's `uint8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toUint8(uint256 value) internal pure returns (uint8) { + if (value > type(uint8).max) { + revert SafeCastOverflowedUintDowncast(8, value); + } + return uint8(value); + } + + /** + * @dev Converts a signed int256 into an unsigned uint256. + * + * Requirements: + * + * - input must be greater than or equal to 0. + */ + function toUint256(int256 value) internal pure returns (uint256) { + if (value < 0) { + revert SafeCastOverflowedIntToUint(value); + } + return uint256(value); + } + + /** + * @dev Returns the downcasted int248 from int256, reverting on + * overflow (when the input is less than smallest int248 or + * greater than largest int248). + * + * Counterpart to Solidity's `int248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toInt248(int256 value) internal pure returns (int248 downcasted) { + downcasted = int248(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(248, value); + } + } + + /** + * @dev Returns the downcasted int240 from int256, reverting on + * overflow (when the input is less than smallest int240 or + * greater than largest int240). + * + * Counterpart to Solidity's `int240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toInt240(int256 value) internal pure returns (int240 downcasted) { + downcasted = int240(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(240, value); + } + } + + /** + * @dev Returns the downcasted int232 from int256, reverting on + * overflow (when the input is less than smallest int232 or + * greater than largest int232). + * + * Counterpart to Solidity's `int232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toInt232(int256 value) internal pure returns (int232 downcasted) { + downcasted = int232(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(232, value); + } + } + + /** + * @dev Returns the downcasted int224 from int256, reverting on + * overflow (when the input is less than smallest int224 or + * greater than largest int224). + * + * Counterpart to Solidity's `int224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toInt224(int256 value) internal pure returns (int224 downcasted) { + downcasted = int224(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(224, value); + } + } + + /** + * @dev Returns the downcasted int216 from int256, reverting on + * overflow (when the input is less than smallest int216 or + * greater than largest int216). + * + * Counterpart to Solidity's `int216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toInt216(int256 value) internal pure returns (int216 downcasted) { + downcasted = int216(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(216, value); + } + } + + /** + * @dev Returns the downcasted int208 from int256, reverting on + * overflow (when the input is less than smallest int208 or + * greater than largest int208). + * + * Counterpart to Solidity's `int208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toInt208(int256 value) internal pure returns (int208 downcasted) { + downcasted = int208(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(208, value); + } + } + + /** + * @dev Returns the downcasted int200 from int256, reverting on + * overflow (when the input is less than smallest int200 or + * greater than largest int200). + * + * Counterpart to Solidity's `int200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toInt200(int256 value) internal pure returns (int200 downcasted) { + downcasted = int200(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(200, value); + } + } + + /** + * @dev Returns the downcasted int192 from int256, reverting on + * overflow (when the input is less than smallest int192 or + * greater than largest int192). + * + * Counterpart to Solidity's `int192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toInt192(int256 value) internal pure returns (int192 downcasted) { + downcasted = int192(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(192, value); + } + } + + /** + * @dev Returns the downcasted int184 from int256, reverting on + * overflow (when the input is less than smallest int184 or + * greater than largest int184). + * + * Counterpart to Solidity's `int184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toInt184(int256 value) internal pure returns (int184 downcasted) { + downcasted = int184(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(184, value); + } + } + + /** + * @dev Returns the downcasted int176 from int256, reverting on + * overflow (when the input is less than smallest int176 or + * greater than largest int176). + * + * Counterpart to Solidity's `int176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toInt176(int256 value) internal pure returns (int176 downcasted) { + downcasted = int176(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(176, value); + } + } + + /** + * @dev Returns the downcasted int168 from int256, reverting on + * overflow (when the input is less than smallest int168 or + * greater than largest int168). + * + * Counterpart to Solidity's `int168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toInt168(int256 value) internal pure returns (int168 downcasted) { + downcasted = int168(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(168, value); + } + } + + /** + * @dev Returns the downcasted int160 from int256, reverting on + * overflow (when the input is less than smallest int160 or + * greater than largest int160). + * + * Counterpart to Solidity's `int160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toInt160(int256 value) internal pure returns (int160 downcasted) { + downcasted = int160(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(160, value); + } + } + + /** + * @dev Returns the downcasted int152 from int256, reverting on + * overflow (when the input is less than smallest int152 or + * greater than largest int152). + * + * Counterpart to Solidity's `int152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toInt152(int256 value) internal pure returns (int152 downcasted) { + downcasted = int152(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(152, value); + } + } + + /** + * @dev Returns the downcasted int144 from int256, reverting on + * overflow (when the input is less than smallest int144 or + * greater than largest int144). + * + * Counterpart to Solidity's `int144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toInt144(int256 value) internal pure returns (int144 downcasted) { + downcasted = int144(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(144, value); + } + } + + /** + * @dev Returns the downcasted int136 from int256, reverting on + * overflow (when the input is less than smallest int136 or + * greater than largest int136). + * + * Counterpart to Solidity's `int136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toInt136(int256 value) internal pure returns (int136 downcasted) { + downcasted = int136(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(136, value); + } + } + + /** + * @dev Returns the downcasted int128 from int256, reverting on + * overflow (when the input is less than smallest int128 or + * greater than largest int128). + * + * Counterpart to Solidity's `int128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toInt128(int256 value) internal pure returns (int128 downcasted) { + downcasted = int128(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(128, value); + } + } + + /** + * @dev Returns the downcasted int120 from int256, reverting on + * overflow (when the input is less than smallest int120 or + * greater than largest int120). + * + * Counterpart to Solidity's `int120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toInt120(int256 value) internal pure returns (int120 downcasted) { + downcasted = int120(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(120, value); + } + } + + /** + * @dev Returns the downcasted int112 from int256, reverting on + * overflow (when the input is less than smallest int112 or + * greater than largest int112). + * + * Counterpart to Solidity's `int112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toInt112(int256 value) internal pure returns (int112 downcasted) { + downcasted = int112(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(112, value); + } + } + + /** + * @dev Returns the downcasted int104 from int256, reverting on + * overflow (when the input is less than smallest int104 or + * greater than largest int104). + * + * Counterpart to Solidity's `int104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toInt104(int256 value) internal pure returns (int104 downcasted) { + downcasted = int104(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(104, value); + } + } + + /** + * @dev Returns the downcasted int96 from int256, reverting on + * overflow (when the input is less than smallest int96 or + * greater than largest int96). + * + * Counterpart to Solidity's `int96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toInt96(int256 value) internal pure returns (int96 downcasted) { + downcasted = int96(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(96, value); + } + } + + /** + * @dev Returns the downcasted int88 from int256, reverting on + * overflow (when the input is less than smallest int88 or + * greater than largest int88). + * + * Counterpart to Solidity's `int88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toInt88(int256 value) internal pure returns (int88 downcasted) { + downcasted = int88(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(88, value); + } + } + + /** + * @dev Returns the downcasted int80 from int256, reverting on + * overflow (when the input is less than smallest int80 or + * greater than largest int80). + * + * Counterpart to Solidity's `int80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toInt80(int256 value) internal pure returns (int80 downcasted) { + downcasted = int80(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(80, value); + } + } + + /** + * @dev Returns the downcasted int72 from int256, reverting on + * overflow (when the input is less than smallest int72 or + * greater than largest int72). + * + * Counterpart to Solidity's `int72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toInt72(int256 value) internal pure returns (int72 downcasted) { + downcasted = int72(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(72, value); + } + } + + /** + * @dev Returns the downcasted int64 from int256, reverting on + * overflow (when the input is less than smallest int64 or + * greater than largest int64). + * + * Counterpart to Solidity's `int64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toInt64(int256 value) internal pure returns (int64 downcasted) { + downcasted = int64(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(64, value); + } + } + + /** + * @dev Returns the downcasted int56 from int256, reverting on + * overflow (when the input is less than smallest int56 or + * greater than largest int56). + * + * Counterpart to Solidity's `int56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toInt56(int256 value) internal pure returns (int56 downcasted) { + downcasted = int56(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(56, value); + } + } + + /** + * @dev Returns the downcasted int48 from int256, reverting on + * overflow (when the input is less than smallest int48 or + * greater than largest int48). + * + * Counterpart to Solidity's `int48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toInt48(int256 value) internal pure returns (int48 downcasted) { + downcasted = int48(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(48, value); + } + } + + /** + * @dev Returns the downcasted int40 from int256, reverting on + * overflow (when the input is less than smallest int40 or + * greater than largest int40). + * + * Counterpart to Solidity's `int40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toInt40(int256 value) internal pure returns (int40 downcasted) { + downcasted = int40(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(40, value); + } + } + + /** + * @dev Returns the downcasted int32 from int256, reverting on + * overflow (when the input is less than smallest int32 or + * greater than largest int32). + * + * Counterpart to Solidity's `int32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toInt32(int256 value) internal pure returns (int32 downcasted) { + downcasted = int32(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(32, value); + } + } + + /** + * @dev Returns the downcasted int24 from int256, reverting on + * overflow (when the input is less than smallest int24 or + * greater than largest int24). + * + * Counterpart to Solidity's `int24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toInt24(int256 value) internal pure returns (int24 downcasted) { + downcasted = int24(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(24, value); + } + } + + /** + * @dev Returns the downcasted int16 from int256, reverting on + * overflow (when the input is less than smallest int16 or + * greater than largest int16). + * + * Counterpart to Solidity's `int16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toInt16(int256 value) internal pure returns (int16 downcasted) { + downcasted = int16(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(16, value); + } + } + + /** + * @dev Returns the downcasted int8 from int256, reverting on + * overflow (when the input is less than smallest int8 or + * greater than largest int8). + * + * Counterpart to Solidity's `int8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toInt8(int256 value) internal pure returns (int8 downcasted) { + downcasted = int8(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(8, value); + } + } + + /** + * @dev Converts an unsigned uint256 into a signed int256. + * + * Requirements: + * + * - input must be less than or equal to maxInt256. + */ + function toInt256(uint256 value) internal pure returns (int256) { + // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive + if (value > uint256(type(int256).max)) { + revert SafeCastOverflowedUintToInt(value); + } + return int256(value); + } + + /** + * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. + */ + function toUint(bool b) internal pure returns (uint256 u) { + assembly ("memory-safe") { + u := iszero(iszero(b)) + } + } +} + +// node_modules/@openzeppelin/contracts/utils/math/SignedMath.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol) + +/** + * @dev Standard signed math utilities missing in the Solidity language. + */ +library SignedMath { + /** + * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. + * + * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. + * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute + * one branch when needed, making this function more expensive. + */ + function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) { + unchecked { + // branchless ternary works because: + // b ^ (a ^ b) == a + // b ^ 0 == b + return b ^ ((a ^ b) * int256(SafeCast.toUint(condition))); + } + } + + /** + * @dev Returns the largest of two signed numbers. + */ + function max(int256 a, int256 b) internal pure returns (int256) { + return ternary(a > b, a, b); + } + + /** + * @dev Returns the smallest of two signed numbers. + */ + function min(int256 a, int256 b) internal pure returns (int256) { + return ternary(a < b, a, b); + } + + /** + * @dev Returns the average of two signed numbers without overflow. + * The result is rounded towards zero. + */ + function average(int256 a, int256 b) internal pure returns (int256) { + // Formula from the book "Hacker's Delight" + int256 x = (a & b) + ((a ^ b) >> 1); + return x + (int256(uint256(x) >> 255) & (a ^ b)); + } + + /** + * @dev Returns the absolute unsigned value of a signed value. + */ + function abs(int256 n) internal pure returns (uint256) { + unchecked { + // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson. + // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift, + // taking advantage of the most significant (or "sign" bit) in two's complement representation. + // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result, + // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative). + int256 mask = n >> 255; + + // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it. + return uint256((n + mask) ^ mask); + } + } +} + +// node_modules/@openzeppelin/contracts/utils/math/Math.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol) + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + enum Rounding { + Floor, // Toward negative infinity + Ceil, // Toward positive infinity + Trunc, // Toward zero + Expand // Away from zero + } + + /** + * @dev Returns the addition of two unsigned integers, with an success flag (no overflow). + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow). + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + if (b > a) return (false, 0); + return (true, a - b); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow). + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + if (b == 0) return (false, 0); + return (true, a / b); + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + if (b == 0) return (false, 0); + return (true, a % b); + } + } + + /** + * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. + * + * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. + * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute + * one branch when needed, making this function more expensive. + */ + function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) { + unchecked { + // branchless ternary works because: + // b ^ (a ^ b) == a + // b ^ 0 == b + return b ^ ((a ^ b) * SafeCast.toUint(condition)); + } + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return ternary(a > b, a, b); + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return ternary(a < b, a, b); + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds towards infinity instead + * of rounding towards zero. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + if (b == 0) { + // Guarantee the same behavior as in a regular Solidity division. + Panic.panic(Panic.DIVISION_BY_ZERO); + } + + // The following calculation ensures accurate ceiling division without overflow. + // Since a is non-zero, (a - 1) / b will not overflow. + // The largest possible result occurs when (a - 1) / b is type(uint256).max, + // but the largest value we can obtain is type(uint256).max - 1, which happens + // when a = type(uint256).max and b = 1. + unchecked { + return SafeCast.toUint(a > 0) * ((a - 1) / b + 1); + } + } + + /** + * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or + * denominator == 0. + * + * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by + * Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use + // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2²⁵⁶ + prod0. + uint256 prod0 = x * y; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division. + if (prod1 == 0) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return prod0 / denominator; + } + + // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0. + if (denominator <= prod1) { + Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW)); + } + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. + // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. + + uint256 twos = denominator & (0 - denominator); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such + // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv ≡ 1 mod 2⁴. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also + // works in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2⁸ + inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶ + inverse *= 2 - denominator * inverse; // inverse mod 2³² + inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴ + inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸ + inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶ + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is + // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @dev Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0); + } + + /** + * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. + * + * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0. + * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. + * + * If the input value is not inversible, 0 is returned. + * + * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the + * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}. + */ + function invMod(uint256 a, uint256 n) internal pure returns (uint256) { + unchecked { + if (n == 0) return 0; + + // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) + // Used to compute integers x and y such that: ax + ny = gcd(a, n). + // When the gcd is 1, then the inverse of a modulo n exists and it's x. + // ax + ny = 1 + // ax = 1 + (-y)n + // ax ≡ 1 (mod n) # x is the inverse of a modulo n + + // If the remainder is 0 the gcd is n right away. + uint256 remainder = a % n; + uint256 gcd = n; + + // Therefore the initial coefficients are: + // ax + ny = gcd(a, n) = n + // 0a + 1n = n + int256 x = 0; + int256 y = 1; + + while (remainder != 0) { + uint256 quotient = gcd / remainder; + + (gcd, remainder) = ( + // The old remainder is the next gcd to try. + remainder, + // Compute the next remainder. + // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd + // where gcd is at most n (capped to type(uint256).max) + gcd - remainder * quotient + ); + + (x, y) = ( + // Increment the coefficient of a. + y, + // Decrement the coefficient of n. + // Can overflow, but the result is casted to uint256 so that the + // next value of y is "wrapped around" to a value between 0 and n - 1. + x - y * int256(quotient) + ); + } + + if (gcd != 1) return 0; // No inverse exists. + return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative. + } + } + + /** + * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`. + * + * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is + * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that + * `a**(p-2)` is the modular multiplicative inverse of a in Fp. + * + * NOTE: this function does NOT check that `p` is a prime greater than `2`. + */ + function invModPrime(uint256 a, uint256 p) internal view returns (uint256) { + unchecked { + return Math.modExp(a, p - 2, p); + } + } + + /** + * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) + * + * Requirements: + * - modulus can't be zero + * - underlying staticcall to precompile must succeed + * + * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make + * sure the chain you're using it on supports the precompiled contract for modular exponentiation + * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, + * the underlying function will succeed given the lack of a revert, but the result may be incorrectly + * interpreted as 0. + */ + function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) { + (bool success, uint256 result) = tryModExp(b, e, m); + if (!success) { + Panic.panic(Panic.DIVISION_BY_ZERO); + } + return result; + } + + /** + * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). + * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying + * to operate modulo 0 or if the underlying precompile reverted. + * + * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain + * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in + * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack + * of a revert, but the result may be incorrectly interpreted as 0. + */ + function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) { + if (m == 0) return (false, 0); + assembly ("memory-safe") { + let ptr := mload(0x40) + // | Offset | Content | Content (Hex) | + // |-----------|------------|--------------------------------------------------------------------| + // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | + // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | + // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | + // | 0x60:0x7f | value of b | 0x<.............................................................b> | + // | 0x80:0x9f | value of e | 0x<.............................................................e> | + // | 0xa0:0xbf | value of m | 0x<.............................................................m> | + mstore(ptr, 0x20) + mstore(add(ptr, 0x20), 0x20) + mstore(add(ptr, 0x40), 0x20) + mstore(add(ptr, 0x60), b) + mstore(add(ptr, 0x80), e) + mstore(add(ptr, 0xa0), m) + + // Given the result < m, it's guaranteed to fit in 32 bytes, + // so we can use the memory scratch space located at offset 0. + success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) + result := mload(0x00) + } + } + + /** + * @dev Variant of {modExp} that supports inputs of arbitrary length. + */ + function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) { + (bool success, bytes memory result) = tryModExp(b, e, m); + if (!success) { + Panic.panic(Panic.DIVISION_BY_ZERO); + } + return result; + } + + /** + * @dev Variant of {tryModExp} that supports inputs of arbitrary length. + */ + function tryModExp( + bytes memory b, + bytes memory e, + bytes memory m + ) internal view returns (bool success, bytes memory result) { + if (_zeroBytes(m)) return (false, new bytes(0)); + + uint256 mLen = m.length; + + // Encode call args in result and move the free memory pointer + result = abi.encodePacked(b.length, e.length, mLen, b, e, m); + + assembly ("memory-safe") { + let dataPtr := add(result, 0x20) + // Write result on top of args to avoid allocating extra memory. + success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen) + // Overwrite the length. + // result.length > returndatasize() is guaranteed because returndatasize() == m.length + mstore(result, mLen) + // Set the memory pointer after the returned data. + mstore(0x40, add(dataPtr, mLen)) + } + } + + /** + * @dev Returns whether the provided byte array is zero. + */ + function _zeroBytes(bytes memory byteArray) private pure returns (bool) { + for (uint256 i = 0; i < byteArray.length; ++i) { + if (byteArray[i] != 0) { + return false; + } + } + return true; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded + * towards zero. + * + * This method is based on Newton's method for computing square roots; the algorithm is restricted to only + * using integer operations. + */ + function sqrt(uint256 a) internal pure returns (uint256) { + unchecked { + // Take care of easy edge cases when a == 0 or a == 1 + if (a <= 1) { + return a; + } + + // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a + // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between + // the current value as `ε_n = | x_n - sqrt(a) |`. + // + // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root + // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is + // bigger than any uint256. + // + // By noticing that + // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)` + // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar + // to the msb function. + uint256 aa = a; + uint256 xn = 1; + + if (aa >= (1 << 128)) { + aa >>= 128; + xn <<= 64; + } + if (aa >= (1 << 64)) { + aa >>= 64; + xn <<= 32; + } + if (aa >= (1 << 32)) { + aa >>= 32; + xn <<= 16; + } + if (aa >= (1 << 16)) { + aa >>= 16; + xn <<= 8; + } + if (aa >= (1 << 8)) { + aa >>= 8; + xn <<= 4; + } + if (aa >= (1 << 4)) { + aa >>= 4; + xn <<= 2; + } + if (aa >= (1 << 2)) { + xn <<= 1; + } + + // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1). + // + // We can refine our estimation by noticing that the middle of that interval minimizes the error. + // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2). + // This is going to be our x_0 (and ε_0) + xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2) + + // From here, Newton's method give us: + // x_{n+1} = (x_n + a / x_n) / 2 + // + // One should note that: + // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a + // = ((x_n² + a) / (2 * x_n))² - a + // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a + // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) + // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²) + // = (x_n² - a)² / (2 * x_n)² + // = ((x_n² - a) / (2 * x_n))² + // ≥ 0 + // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n + // + // This gives us the proof of quadratic convergence of the sequence: + // ε_{n+1} = | x_{n+1} - sqrt(a) | + // = | (x_n + a / x_n) / 2 - sqrt(a) | + // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | + // = | (x_n - sqrt(a))² / (2 * x_n) | + // = | ε_n² / (2 * x_n) | + // = ε_n² / | (2 * x_n) | + // + // For the first iteration, we have a special case where x_0 is known: + // ε_1 = ε_0² / | (2 * x_0) | + // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) + // ≤ 2**(2*e-4) / (3 * 2**(e-1)) + // ≤ 2**(e-3) / 3 + // ≤ 2**(e-3-log2(3)) + // ≤ 2**(e-4.5) + // + // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n: + // ε_{n+1} = ε_n² / | (2 * x_n) | + // ≤ (2**(e-k))² / (2 * 2**(e-1)) + // ≤ 2**(2*e-2*k) / 2**e + // ≤ 2**(e-2*k) + xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above + xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5 + xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9 + xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18 + xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36 + xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72 + + // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision + // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either + // sqrt(a) or sqrt(a) + 1. + return xn - SafeCast.toUint(xn > a / xn); + } + } + + /** + * @dev Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a); + } + } + + /** + * @dev Return the log in base 2 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + uint256 exp; + unchecked { + exp = 128 * SafeCast.toUint(value > (1 << 128) - 1); + value >>= exp; + result += exp; + + exp = 64 * SafeCast.toUint(value > (1 << 64) - 1); + value >>= exp; + result += exp; + + exp = 32 * SafeCast.toUint(value > (1 << 32) - 1); + value >>= exp; + result += exp; + + exp = 16 * SafeCast.toUint(value > (1 << 16) - 1); + value >>= exp; + result += exp; + + exp = 8 * SafeCast.toUint(value > (1 << 8) - 1); + value >>= exp; + result += exp; + + exp = 4 * SafeCast.toUint(value > (1 << 4) - 1); + value >>= exp; + result += exp; + + exp = 2 * SafeCast.toUint(value > (1 << 2) - 1); + value >>= exp; + result += exp; + + result += SafeCast.toUint(value > 1); + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value); + } + } + + /** + * @dev Return the log in base 10 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value); + } + } + + /** + * @dev Return the log in base 256 of a positive value rounded towards zero. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + uint256 isGt; + unchecked { + isGt = SafeCast.toUint(value > (1 << 128) - 1); + value >>= isGt * 128; + result += isGt * 16; + + isGt = SafeCast.toUint(value > (1 << 64) - 1); + value >>= isGt * 64; + result += isGt * 8; + + isGt = SafeCast.toUint(value > (1 << 32) - 1); + value >>= isGt * 32; + result += isGt * 4; + + isGt = SafeCast.toUint(value > (1 << 16) - 1); + value >>= isGt * 16; + result += isGt * 2; + + result += SafeCast.toUint(value > (1 << 8) - 1); + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value); + } + } + + /** + * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. + */ + function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { + return uint8(rounding) % 2 == 1; + } +} + +// node_modules/@openzeppelin/contracts/utils/Strings.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (utils/Strings.sol) + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant HEX_DIGITS = "0123456789abcdef"; + uint8 private constant ADDRESS_LENGTH = 20; + + /** + * @dev The `value` string doesn't fit in the specified `length`. + */ + error StringsInsufficientHexLength(uint256 value, uint256 length); + + /** + * @dev The string being parsed contains characters that are not in scope of the given base. + */ + error StringsInvalidChar(); + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + assembly ("memory-safe") { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + assembly ("memory-safe") { + mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toStringSigned(int256 value) internal pure returns (string memory) { + return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + uint256 localValue = value; + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = HEX_DIGITS[localValue & 0xf]; + localValue >>= 4; + } + if (localValue != 0) { + revert StringsInsufficientHexLength(value, length); + } + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal + * representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal + * representation, according to EIP-55. + */ + function toChecksumHexString(address addr) internal pure returns (string memory) { + bytes memory buffer = bytes(toHexString(addr)); + + // hash the hex part of buffer (skip length + 2 bytes, length 40) + uint256 hashValue; + assembly ("memory-safe") { + hashValue := shr(96, keccak256(add(buffer, 0x22), 40)) + } + + for (uint256 i = 41; i > 1; --i) { + // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f) + if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) { + // case shift by xoring with 0x20 + buffer[i] ^= 0x20; + } + hashValue >>= 4; + } + return string(buffer); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); + } + + /** + * @dev Parse a decimal string and returns the value as a `uint256`. + * + * Requirements: + * - The string must be formatted as `[0-9]*` + * - The result must fit into an `uint256` type + */ + function parseUint(string memory input) internal pure returns (uint256) { + return parseUint(input, 0, bytes(input).length); + } + + /** + * @dev Variant of {parseUint} that parses a substring of `input` located between position `begin` (included) and + * `end` (excluded). + * + * Requirements: + * - The substring must be formatted as `[0-9]*` + * - The result must fit into an `uint256` type + */ + function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) { + (bool success, uint256 value) = tryParseUint(input, begin, end); + if (!success) revert StringsInvalidChar(); + return value; + } + + /** + * @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character. + * + * NOTE: This function will revert if the result does not fit in a `uint256`. + */ + function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) { + return _tryParseUintUncheckedBounds(input, 0, bytes(input).length); + } + + /** + * @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid + * character. + * + * NOTE: This function will revert if the result does not fit in a `uint256`. + */ + function tryParseUint( + string memory input, + uint256 begin, + uint256 end + ) internal pure returns (bool success, uint256 value) { + if (end > bytes(input).length || begin > end) return (false, 0); + return _tryParseUintUncheckedBounds(input, begin, end); + } + + /** + * @dev Implementation of {tryParseUint} that does not check bounds. Caller should make sure that + * `begin <= end <= input.length`. Other inputs would result in undefined behavior. + */ + function _tryParseUintUncheckedBounds( + string memory input, + uint256 begin, + uint256 end + ) private pure returns (bool success, uint256 value) { + bytes memory buffer = bytes(input); + + uint256 result = 0; + for (uint256 i = begin; i < end; ++i) { + uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i))); + if (chr > 9) return (false, 0); + result *= 10; + result += chr; + } + return (true, result); + } + + function _tryParseChr(bytes1 chr) private pure returns (uint8) { + uint8 value = uint8(chr); + + // Try to parse `chr`: + // - Case 1: [0-9] + // - Case 2: [a-f] + // - Case 3: [A-F] + // - otherwise not supported + unchecked { + if (value > 47 && value < 58) value -= 48; + else if (value > 96 && value < 103) value -= 87; + else if (value > 64 && value < 71) value -= 55; + else return type(uint8).max; + } + + return value; + } + + /** + * @dev Reads a bytes32 from a bytes array without bounds checking. + * + * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the + * assembly block as such would prevent some optimizations. + */ + function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) { + // This is not memory safe in the general case, but all calls to this private function are within bounds. + assembly ("memory-safe") { + value := mload(add(buffer, add(0x20, offset))) + } + } + +} diff --git a/src/tests/solidity_strings.rs b/src/tests/solidity_strings.rs new file mode 100644 index 0000000..f0c792b --- /dev/null +++ b/src/tests/solidity_strings.rs @@ -0,0 +1,123 @@ +// Copyright (C) 2024-2025 the DTVM authors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +/// This file contains test cases for the solidity strings library usage. +/// +/// The `Strings.sol` library is imported from the `@openzeppelin/contracts` package. +/// Url is https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol. +/// The library provides functions for string operations, such as converting a `uint256` to a string. +/// The test cases in this file are used to test the correctness of the library functions. +#[allow(unused)] +use super::test_helper::solidity_selector; +#[allow(unused)] +use super::test_helper::TestRuntime; +#[cfg(test)] +mod tests { + use super::*; + + // Embed the content of openzepplin_strings_full.sol file in the same directory + // into the OPEN_ZEPPLIN_STRINGS_SOL_CODE global variable. + const OPEN_ZEPPLIN_STRINGS_SOL_CODE: &str = include_str!("openzepplin_strings_full.sol"); + + #[test] + fn test_solidity_strings_to_string_1() { + let mut runtime = TestRuntime::new( + "test_solidity_strings_to_string_1", + "target/test_solidity_strings_to_string_1", + ); + runtime.clear_testdata(); + let yul_code = runtime.compile_solidity_to_yul( + &format!( + r#" + pragma solidity ^0.8.0; + {} + + contract TestContract {{ + function test() public returns (string memory) {{ + // test Strings.toString(uint256) + return Strings.toString(123456789); + }} + }} + "#, + OPEN_ZEPPLIN_STRINGS_SOL_CODE + ), + "TestContract", + ); + if let Err(err) = &yul_code { + eprintln!("compile to yul error: {err}"); + } + assert!(yul_code.is_ok()); + let yul_code = yul_code.unwrap(); + let _emited_bc = runtime.compile_test_yul(&yul_code).unwrap(); + runtime.set_enable_gas_meter(false); + runtime.deploy(&[]).unwrap(); + runtime.call(&solidity_selector("test()"), &[]).unwrap(); + + // The string encoding of 123456789 + runtime.assert_result("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000093132333435363738390000000000000000000000000000000000000000000000"); + } + + #[test] + fn test_solidity_strings_to_hex_string_uint() { + let mut runtime = TestRuntime::new( + "test_solidity_strings_to_hex_string_uint", + "target/test_solidity_strings_to_hex_string_uint", + ); + runtime.clear_testdata(); + let yul_code = runtime.compile_solidity_to_yul( + &format!( + r#" + pragma solidity ^0.8.0; + {} + contract TestContract {{ + function test() public pure returns (string memory) {{ + return Strings.toHexString(0xDEADBEEF); + }} + }} + "#, + OPEN_ZEPPLIN_STRINGS_SOL_CODE + ), + "TestContract", + ); + assert!(yul_code.is_ok()); + let yul_code = yul_code.unwrap(); + let _emited_bc = runtime.compile_test_yul(&yul_code).unwrap(); + runtime.set_enable_gas_meter(false); + runtime.deploy(&[]).unwrap(); + runtime.call(&solidity_selector("test()"), &[]).unwrap(); + // The string encoding of "0xDEADBEEF" + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a3078646561646265656600000000000000000000000000000000000000000000"); + } + + #[test] + fn test_solidity_strings_to_hex_string_address() { + let mut runtime = TestRuntime::new( + "test_solidity_strings_to_hex_string_address", + "target/test_solidity_strings_to_hex_string_address", + ); + runtime.clear_testdata(); + let yul_code = runtime.compile_solidity_to_yul( + &format!( + r#" + pragma solidity ^0.8.0; + {} + contract TestContract {{ + function test() public pure returns (string memory) {{ + return Strings.toHexString(0x1234567890123456789012345678901234567890); + }} + }} + "#, + OPEN_ZEPPLIN_STRINGS_SOL_CODE + ), + "TestContract", + ); + assert!(yul_code.is_ok()); + let yul_code = yul_code.unwrap(); + let _emited_bc = runtime.compile_test_yul(&yul_code).unwrap(); + runtime.set_enable_gas_meter(false); + runtime.deploy(&[]).unwrap(); + runtime.call(&solidity_selector("test()"), &[]).unwrap(); + // The string encoding of "0x1234567890123456789012345678901234567890" + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002a30783132333435363738393031323334353637383930313233343536373839303132333435363738393000000000000000000000000000000000000000000000"); + } +} diff --git a/src/tests/test_helper.rs b/src/tests/test_helper.rs index 553301f..2ff16d9 100644 --- a/src/tests/test_helper.rs +++ b/src/tests/test_helper.rs @@ -15,6 +15,7 @@ use rand::distr::Alphanumeric; use rand::Rng; use std::fs::File; use std::io::Write; +use std::path::Path; use std::process::Command; use tempfile::tempdir; @@ -134,6 +135,56 @@ impl TestRuntime { } } + #[allow(unused)] + pub fn compile_solidity_to_yul( + &mut self, + solidity_code: &str, + contract_name: &str, + ) -> Result { + // avoid using the invalid contract name(not strict check) + // this is because solc will generate yul files with basename of contract name + // but we don't known the name + assert!(solidity_code.contains(&format!("contract {contract_name}"))); + + // 1. create tmp file to store the solidity code + let tmp_dir = Path::new(&self.output_dir); + let sol_path = tmp_dir.join("input.sol"); + let yul_file_basename = &format!("{contract_name}.yul"); + let yul_path = tmp_dir.join(yul_file_basename); + println!( + "tmp_dir: {:?}, yul_path: {:?}", + tmp_dir.as_os_str(), + yul_path.as_os_str() + ); + + if !sol_path.exists() { + let mut sol_file = File::create(&sol_path).map_err(|e| e.to_string())?; + sol_file + .write_all(solidity_code.as_bytes()) + .map_err(|e| e.to_string())?; + } + // There are multiple output files, and the output file names are related to the Solidity contract name. + // 2. using `solc` to compile, + // eg. solc --ir --optimize-yul -o . --overwrite input.sol + let output = Command::new("solc") + .current_dir(tmp_dir) + .arg("--ir") + .arg("--optimize-yul") + .arg("--overwrite") + .arg("-o") + .arg(".") + .arg("input.sol") + .output() + .map_err(|e| e.to_string())?; + if !output.status.success() { + return Err(String::from_utf8_lossy(&output.stderr).to_string()); + } + // 3. read the generated yul file content + let yul_content = std::fs::read_to_string(&yul_path) + .map_err(|e| format!("Failed to read yul file: {}", e))?; + Ok(yul_content) + } + #[allow(unused)] pub fn set_sender(&mut self, sender: Option) { self.sender = sender; diff --git a/src/tests/var_redefine_tests.rs b/src/tests/var_redefine_tests.rs new file mode 100644 index 0000000..4d1dcbe --- /dev/null +++ b/src/tests/var_redefine_tests.rs @@ -0,0 +1,319 @@ +// Copyright (C) 2024-2025 the DTVM authors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused)] +use super::test_helper::solidity_selector; +#[allow(unused)] +use super::test_helper::TestRuntime; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_yul_var_redefine1() { + let mut runtime = TestRuntime::new("VarRedefineTest1", "target/test_yul_var_redefine1"); + let result = runtime.compile_test_yul( + r#" + object "VarRedefineTest1" { + code { + } + object "VarRedefineTest1_deployed" { + code { + function test_byte() -> r { + let index := 30 + let value := 23 + let value := 256 // error: value is redefined in the same scope + r := byte(index, value) + } + + let r := test_byte() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ); + assert!(result.is_err()); + let err_msg = result.unwrap_err().to_string(); + assert!(err_msg.contains("Variable 'value' is already defined in this scope")); + } + + #[test] + fn test_yul_var_redefine2() { + let mut runtime = TestRuntime::new("VarRedefineTest2", "target/test_yul_var_redefine2"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "VarRedefineTest2" { + code { + } + object "VarRedefineTest2_deployed" { + code { + function test_byte() -> r { + let index := 30 + let value := 23 + value := 256 // ok: value is reassigned in the same scope + r := byte(index, value) + } + + let r := test_byte() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_byte()"), &[]) + .unwrap(); + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000001"); + } + + #[test] + fn test_yul_var_redefine3() { + let mut runtime = TestRuntime::new("VarRedefineTest3", "target/test_yul_var_redefine3"); + let result = runtime.compile_test_yul( + r#" + object "VarRedefineTest3" { + code { + } + object "VarRedefineTest3_deployed" { + code { + function test_byte() -> r { + let index := 30 + let r := 256 // error: r is redefined in the same scope + r := byte(index, r) + } + + let r := test_byte() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ); + assert!(result.is_err()); + let err_msg = result.unwrap_err().to_string(); + assert!(err_msg.contains("Variable 'r' is already defined in this scope")); + } + + #[test] + fn test_yul_var_redefine4() { + let mut runtime = TestRuntime::new("VarRedefineTest4", "target/test_yul_var_redefine4"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "VarRedefineTest4" { + code { + } + object "VarRedefineTest4_deployed" { + code { + function test_byte() -> r { + let index := 30 + r := 256 // ok: r is assigned in the same scope + r := byte(index, r) // ok: r is reassigned in the same scope + } + + let r := test_byte() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_byte()"), &[]) + .unwrap(); + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000001"); + } + + #[test] + fn test_yul_var_redefine5() { + let mut runtime = TestRuntime::new("VarRedefineTest5", "target/test_yul_var_redefine5"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "VarRedefineTest5" { + code { + } + object "VarRedefineTest5_deployed" { + code { + function test_func1() -> r { + let index := 30 + let value := 256 + r := byte(index, value) + } + + function test_func2() -> r { // ok: r is defined in different scope + let index := 31 // ok: index is defined in different scope + let value := 3 // ok: value is defined in different scope + r := byte(index, value) + } + + let r := test_func2() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_func2()"), &[]) + .unwrap(); + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000003"); + } + + #[test] + fn test_yul_var_redefine6() { + let mut runtime = TestRuntime::new("VarRedefineTest6", "target/test_yul_var_redefine6"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "VarRedefineTest6" { + code { + } + object "VarRedefineTest6_deployed" { + code { + function test_func() -> value1, value2 { + { + let srcVal := 10 + value1 := srcVal + } + { + let srcVal := 20 // ok: srcVal is defined in different scope + value2 := srcVal + } + } + let r1, r2 := test_func() + mstore(0x00, r2) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_func()"), &[]) + .unwrap(); + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000014"); + } + + #[test] + fn test_yul_var_redefine7() { + let mut runtime = TestRuntime::new("VarRedefineTest7", "target/test_yul_var_redefine7"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "VarRedefineTest7" { + code { + } + object "VarRedefineTest7_deployed" { + code { + function test_func() -> result { + result := 1 + let offset := 1 + { + let offset := 5 // ok: offset is defined in different scope + result := add(result, offset) + } + } + let r := test_func() + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_func()"), &[]) + .unwrap(); + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000006"); + } + + #[test] + fn test_yul_var_redefine8() { + let mut runtime = TestRuntime::new("VarRedefineTest8", "target/test_yul_var_redefine8"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "VarRedefineTest8" { + code { + } + object "VarRedefineTest8_deployed" { + code { + function power(base, exponent) -> result { + result := 1 + for { let i := 0 } lt(i, exponent) { i := add(i, 1) } + { + result := mul(result, base) + } + } + let r := power(2, 2) + mstore(0x00, r) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime.call(&solidity_selector("power()"), &[]).unwrap(); + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000004"); + } + + #[test] + fn test_yul_var_redefine9() { + let mut runtime = TestRuntime::new("VarRedefineTest9", "target/test_yul_var_redefine9"); + let _emited_bc = runtime + .compile_test_yul( + r#" + object "VarRedefineTest9" { + code { + } + object "VarRedefineTest9_deployed" { + code { + function test_func() -> value1, value2 { + if gt(1, 2) { revert(0, 0) } + { + let srcVal := 10 + value1 := srcVal + } + { + let srcVal := 20 // ok: srcVal is defined in different scope + value2 := srcVal + } + } + let r1, r2 := test_func() + mstore(0x00, r2) + return(0x00, 0x20) + } + } + } + "#, + ) + .unwrap(); + runtime.deploy(&[]).unwrap(); + runtime + .call(&solidity_selector("test_func()"), &[]) + .unwrap(); + runtime.assert_result("0000000000000000000000000000000000000000000000000000000000000014"); + } +} diff --git a/src/yul2ir/context.rs b/src/yul2ir/context.rs index 2e00255..df88f63 100644 --- a/src/yul2ir/context.rs +++ b/src/yul2ir/context.rs @@ -23,7 +23,7 @@ use inkwell::values::{ }; use inkwell::{AddressSpace, IntPredicate}; use once_cell::sync::OnceCell; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::error::Error; use std::ops::Add; use std::{cell::RefCell, rc::Rc}; @@ -73,6 +73,7 @@ pub struct Yul2IRContext<'ctx> { pub functions_mapping: RefCell>>>, pub current_func_decls: RefCell>, + pub revert_zero_functions: RefCell>, // yul function name => yul low level function type pub yul_func_infer_types: RefCell>>, @@ -134,6 +135,7 @@ impl<'ctx> Yul2IRContext<'ctx> { vars_scopes: RefCell::new(vec![]), functions_mapping: RefCell::new(Default::default()), current_func_decls: RefCell::new(Default::default()), + revert_zero_functions: RefCell::new(Default::default()), yul_func_infer_types: RefCell::new(Default::default()), iden_id_gen: RefCell::new(0), exported_func_names: RefCell::new(vec![]), @@ -240,6 +242,10 @@ impl<'ctx> Yul2IRContext<'ctx> { } fn emit_code(&mut self, output_basename: &str) -> Result> { + if let Err(e) = self.transform() { + return Err(format!("Transform error: {}", e).into()); + } + self.transform().unwrap(); // Run LLVM pass on the LLVM module. self.run_llvm_passes(); @@ -357,9 +363,9 @@ impl<'ctx> Yul2IRContext<'ctx> { if let Some(res) = res.try_as_basic_value().left() { Ok(res) } else { - Err(ASTLoweringError { - message: format!("{FUNCTION_RETURN_VALUE_NOT_FOUND_MSG}: {name}"), - }) + Err(ASTLoweringError::FunctionReturnValueNotFound(format!( + "{FUNCTION_RETURN_VALUE_NOT_FOUND_MSG}: {name}" + ))) } } Err(err) => { @@ -415,9 +421,7 @@ impl<'ctx> Yul2IRContext<'ctx> { "u256" | "uint256" => Ok(self.u256_type().into()), "bytes32" => Ok(self.u256_type().into()), // bytes32 is stored as u256 in EVM "address" => Ok(self.u256_type().into()), // address is u160 but stored as u256 in EVM - _ => Err(ASTLoweringError { - message: format!("Unsupported type: {}", ty_name), - }), + _ => Err(ASTLoweringError::UnsupportedType(ty_name.to_string())), } } @@ -506,8 +510,8 @@ impl<'ctx> Yul2IRContext<'ctx> { } pub fn string_literal(&self, value: &str) -> IntValue<'ctx> { - if value.len() > 31 { - // panic!("String literal length exceeds 31 bytes: {}", value); + if value.len() > 32 { + // panic!("String literal length exceeds 32 bytes: {}", value); // String literals used in linker symbol, data offset, and data size instructions // don't need to be processed by string_literal function // After modifying the logic in instruction.rs, we can restore the panic here @@ -622,10 +626,15 @@ impl<'ctx> Yul2IRContext<'ctx> { } } - pub fn matches_log3_statement(&self, stmt: &Statement) -> Option> { + pub fn matches_function_call( + &self, + stmt: &Statement, + name: &str, + args_count: usize, + ) -> Option> { match stmt { Statement::FunctionCall(func_call) => { - if func_call.id.name == "log3" && func_call.arguments.len() == 5 { + if func_call.id.name == name && func_call.arguments.len() == args_count { Some(func_call.arguments.clone()) } else { None @@ -696,13 +705,21 @@ impl<'ctx> Yul2IRContext<'ctx> { var_low_level_value_type: YulLowLevelValueType, var_pointer: PointerValue<'ctx>, is_return_var: bool, - ) { - if let Some(last_var_scope) = self.vars_scopes.borrow_mut().last() { + ) -> Result<(), ASTLoweringError> { + if let Some(last_var_scope) = self.vars_scopes.borrow_mut().last_mut() { + if last_var_scope.vars.borrow().contains_key(iden) { + return Err(ASTLoweringError::DuplicateVariableDefinition(format!( + "Variable '{}' is already defined in this scope", + iden + ))); + } + last_var_scope.vars.borrow_mut().insert( iden.to_string(), (var_ty, var_low_level_value_type, var_pointer, is_return_var), ); } + Ok(()) } // return (var_type, var_low_level_value_type, var_pointer, is_return_var) @@ -825,9 +842,9 @@ impl<'ctx> Yul2IRContext<'ctx> { // is bytes32 pointer self.bytes32_pointer_as_u256(value) } else { - Err(ASTLoweringError { - message: format!("Unsupported type: {}", value.get_type()), - }) + Err(ASTLoweringError::UnsupportedType( + value.get_type().to_string(), + )) } } @@ -845,9 +862,9 @@ impl<'ctx> Yul2IRContext<'ctx> { let bytes32_val = self.try_into_bytes32(value)?; self.try_into_i64(&bytes32_val) } else { - Err(ASTLoweringError { - message: format!("Unsupported type: {}", value.get_type()), - }) + Err(ASTLoweringError::UnsupportedType( + value.get_type().to_string(), + )) } } @@ -902,9 +919,9 @@ impl<'ctx> Yul2IRContext<'ctx> { let bytes32_val = self.try_into_bytes32(value)?; self.try_into_i32(&bytes32_val) } else { - Err(ASTLoweringError { - message: format!("Unsupported type: {}", value.get_type()), - }) + Err(ASTLoweringError::UnsupportedType( + value.get_type().to_string(), + )) } } @@ -921,9 +938,9 @@ impl<'ctx> Yul2IRContext<'ctx> { let bytes32_val = self.try_into_bytes32(value)?; self.bytes32_as_u256(&bytes32_val) } else { - Err(ASTLoweringError { - message: format!("Unsupported type: {}", value.get_type()), - }) + Err(ASTLoweringError::UnsupportedType( + value.get_type().to_string(), + )) } } @@ -1046,9 +1063,9 @@ impl<'ctx> Yul2IRContext<'ctx> { let res = self.build_load(ret_ty, ret_ptr, "")?; Ok(res.into_int_value()) } else { - Err(ASTLoweringError { - message: format!("Unsupported type: {}", value.get_type()), - }) + Err(ASTLoweringError::UnsupportedType( + value.get_type().to_string(), + )) } } @@ -1064,9 +1081,9 @@ impl<'ctx> Yul2IRContext<'ctx> { let res = self.build_load(ret_ty, ret_ptr, "")?; Ok(res.into_int_value()) } else { - Err(ASTLoweringError { - message: format!("Unsupported type: {}", value.get_type()), - }) + Err(ASTLoweringError::UnsupportedType( + value.get_type().to_string(), + )) } } @@ -1085,9 +1102,9 @@ impl<'ctx> Yul2IRContext<'ctx> { let res = self.build_load(ret_ty, ret_ptr, "")?; Ok(res) } else { - Err(ASTLoweringError { - message: format!("Unsupported type: {}", value.get_type()), - }) + Err(ASTLoweringError::UnsupportedType( + value.get_type().to_string(), + )) } } @@ -1161,16 +1178,12 @@ impl<'ctx> Yul2IRContext<'ctx> { .builder .borrow_mut() .build_int_z_extend(int_value, target_int_ty, "") - .map_err(|e| ASTLoweringError { - message: e.to_string(), - }); + .map_err(|e| ASTLoweringError::BuilderError(e.to_string())); } self.builder .borrow_mut() .build_int_cast(int_value, target_int_ty, "") - .map_err(|e| ASTLoweringError { - message: e.to_string(), - }) + .map_err(|e| ASTLoweringError::BuilderError(e.to_string())) } #[allow(unused)] @@ -1277,9 +1290,7 @@ impl<'ctx> Yul2IRContext<'ctx> { self.builder .borrow_mut() .build_alloca(ty, name) - .map_err(|e| ASTLoweringError { - message: e.to_string(), - }) + .map_err(|e| ASTLoweringError::BuilderError(e.to_string())) } #[allow(dead_code)] @@ -1304,9 +1315,7 @@ impl<'ctx> Yul2IRContext<'ctx> { self.builder .borrow_mut() .build_load(pointee_ty, ptr, name) - .map_err(|e| ASTLoweringError { - message: e.to_string(), - }) + .map_err(|e| ASTLoweringError::BuilderError(e.to_string())) } pub fn get_value_pointer>( diff --git a/src/yul2ir/errors.rs b/src/yul2ir/errors.rs index d638911..091b767 100644 --- a/src/yul2ir/errors.rs +++ b/src/yul2ir/errors.rs @@ -1,16 +1,37 @@ // Copyright (C) 2024-2025 the DTVM authors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -#[derive(Debug, Clone, Default)] -pub struct ASTLoweringError { - #[allow(unused)] - pub message: String, +use std::fmt::Display; + +#[derive(Debug, Clone)] +pub enum ASTLoweringError { + BuilderError(String), + DuplicateVariableDefinition(String), + UnsupportedType(String), + FunctionReturnValueNotFound(String), } impl From for ASTLoweringError { fn from(err: inkwell::builder::BuilderError) -> ASTLoweringError { - ASTLoweringError { - message: err.to_string(), // Convert the error message to a string + ASTLoweringError::BuilderError(err.to_string()) + } +} + +impl Display for ASTLoweringError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ASTLoweringError::BuilderError(msg) => { + write!(f, "Builder error: {}", msg) + } + ASTLoweringError::DuplicateVariableDefinition(msg) => { + write!(f, "Variable definition error: {}", msg) + } + ASTLoweringError::UnsupportedType(msg) => { + write!(f, "Unsupported type: {}", msg) + } + ASTLoweringError::FunctionReturnValueNotFound(msg) => { + write!(f, "Function return value not found: {}", msg) + } } } } diff --git a/src/yul2ir/function_deduplicator.rs b/src/yul2ir/function_deduplicator.rs new file mode 100644 index 0000000..e99c334 --- /dev/null +++ b/src/yul2ir/function_deduplicator.rs @@ -0,0 +1,61 @@ +// Copyright (C) 2024-2025 the DTVM authors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::yul2ir::ast::FunctionDefinition; +use crate::yul2ir::transform::UNIFIED_REVERT_ERROR_ZERO; +use crate::yul2ir::{context::CompileResult, context::Yul2IRContext}; + +use ethereum_types::U256; +use inkwell::module::Linkage; +use std::rc::Rc; + +impl<'a> Yul2IRContext<'a> { + pub fn is_revert_zero_function(&self, function: &FunctionDefinition) -> bool { + if function.body.statements.len() != 1 { + return false; + } + + let stmt = &function.body.statements[0]; + let revert_params = self.matches_function_call(stmt, "revert", 2); + if let Some(params) = revert_params { + return self.matches_constant_literal(¶ms[0], U256::from(0)) + && self.matches_constant_literal(¶ms[1], U256::from(0)); + } + + false + } + + pub fn generate_unified_revert_zero(&self) -> CompileResult<'a> { + if self + .functions_mapping + .borrow() + .contains_key(UNIFIED_REVERT_ERROR_ZERO) + { + return self.ok_result(); + } + + let func_ty = self.llvm_context.void_type().fn_type(&[], false); + let function = self.llvm_module.borrow_mut().add_function( + UNIFIED_REVERT_ERROR_ZERO, + func_ty, + Some(Linkage::External), + ); + let entry_bb = self.llvm_context.append_basic_block(function, "entry"); + self.builder.borrow_mut().position_at_end(entry_bb); + self.build_void_call( + "wrapper_revert", + &[ + self.i32_type().const_zero().into(), + self.i32_type().const_zero().into(), + ], + )?; + self.builder.borrow_mut().build_return(None)?; + + self.functions.borrow_mut().push(Rc::new(function)); + self.functions_mapping + .borrow_mut() + .insert(UNIFIED_REVERT_ERROR_ZERO.to_string(), Rc::new(function)); + + self.ok_result() + } +} diff --git a/src/yul2ir/instruction.rs b/src/yul2ir/instruction.rs index e4d44e4..e7f6934 100644 --- a/src/yul2ir/instruction.rs +++ b/src/yul2ir/instruction.rs @@ -22,14 +22,12 @@ fn check_args_count( expected: usize, ) -> Result<(), ASTLoweringError> { if args.len() != expected { - return Err(ASTLoweringError { - message: format!( - "Instruction {:?} Expected {} arguments, but got {}", - instr, - expected, - args.len() - ), - }); + return Err(ASTLoweringError::BuilderError(format!( + "Instruction {:?} Expected {} arguments, but got {}", + instr, + expected, + args.len() + ))); } Ok(()) } @@ -594,10 +592,10 @@ impl<'a> Yul2IRContext<'a> { .builder .borrow_mut() .build_int_add(lhs, rhs, "add_result")?; - return Ok(YulLowLevelValue { + Ok(YulLowLevelValue { value_type: YulLowLevelValueType::from_int_type(result.get_type()), value: result.into(), - }); + }) } else if (self.is_bytes32_value(lhs) || self.is_bytes32_pointer_value(lhs)) && (self.is_bytes32_value(rhs) || self.is_bytes32_pointer_value(rhs)) { @@ -625,7 +623,7 @@ impl<'a> Yul2IRContext<'a> { value_type: YulLowLevelValueType::from_int_type(result.get_type()), value: result.into(), }); - }; + } } YulInstructionName::Sub => { check_args_count(&instr, &args, 2)?; diff --git a/src/yul2ir/mod.rs b/src/yul2ir/mod.rs index f026ab2..ac2e212 100644 --- a/src/yul2ir/mod.rs +++ b/src/yul2ir/mod.rs @@ -8,6 +8,7 @@ pub mod ast; pub mod config; pub mod context; pub mod errors; +pub mod function_deduplicator; pub mod infer; pub mod instruction; pub mod stdlib; diff --git a/src/yul2ir/transform.rs b/src/yul2ir/transform.rs index 5a1833c..203ba31 100644 --- a/src/yul2ir/transform.rs +++ b/src/yul2ir/transform.rs @@ -24,6 +24,8 @@ use inkwell::values::{BasicValue, BasicValueEnum, FunctionValue, IntValue, Point use super::yul_instruction::{YulLowLevelFunctionType, YulLowLevelValue, YulLowLevelValueType}; +pub const UNIFIED_REVERT_ERROR_ZERO: &str = "$unified_revert_error_zero"; + /// Checks if an object contains any sub-contracts. /// A sub-contract is defined as any nested object that is not a deployed contract /// (i.e., its name doesn't end with "_deployed"). @@ -48,8 +50,9 @@ pub fn has_sub_contract(object: &Object) -> bool { #[allow(unused)] impl<'a> Yul2IRContext<'a> { pub(crate) fn walk_block(&self, yul_func_name: &str, block: &Block) -> CompileResult<'a> { + let _scope_guard = ScopeGuard::new(self); for stmt in &block.statements { - self.walk_stmt(yul_func_name, stmt); + self.walk_stmt(yul_func_name, stmt)?; } self.ok_result() } @@ -195,23 +198,30 @@ impl<'a> Yul2IRContext<'a> { } fn walk_for(&self, yul_func_name: &str, r#for: &ast::For) -> CompileResult<'a> { - self.walk_block(yul_func_name, &r#for.init_block); + let _scope_guard = ScopeGuard::new(self); + + let _init_scope_guard = ScopeGuard::new(self); + for stmt in &r#for.init_block.statements { + self.walk_stmt(yul_func_name, stmt)?; + } let cur_func = self.current_function.borrow().clone().unwrap(); let cur_func_value = *cur_func.clone(); let cond_block = self .llvm_context .append_basic_block(cur_func_value, "for_cond"); - self.push_control_flow_continue_bb(cond_block); + let body_block = self .llvm_context .append_basic_block(cur_func_value, "for_body"); + + let update_block = self + .llvm_context + .append_basic_block(cur_func_value, "for_update"); + let end_block = self .llvm_context .append_basic_block(cur_func_value, "for_end"); - // Push the control flow end block onto the stack to facilitate break/continue in control flow - self.push_control_flow_end_bb(end_block); - self.builder .borrow_mut() .build_unconditional_branch(cond_block); @@ -232,8 +242,22 @@ impl<'a> Yul2IRContext<'a> { .build_conditional_branch(bool_cond_value, body_block, end_block); self.builder.borrow_mut().position_at_end(body_block); - self.walk_block(yul_func_name, &r#for.execution_block); - self.walk_block(yul_func_name, &r#for.post_block); + // Push the control flow end block onto the stack to facilitate break/continue in control flow + self.push_control_flow_end_bb(end_block); + self.push_control_flow_continue_bb(update_block); + + let _body_scope_guard = ScopeGuard::new(self); + self.walk_block(yul_func_name, &r#for.execution_block)?; + + self.builder + .borrow_mut() + .build_unconditional_branch(update_block); + + self.builder.borrow_mut().position_at_end(update_block); + + let _post_scope_guard = ScopeGuard::new(self); + self.walk_block(yul_func_name, &r#for.post_block)?; + self.builder .borrow_mut() .build_unconditional_branch(cond_block); @@ -316,10 +340,9 @@ impl<'a> Yul2IRContext<'a> { .collect::>>() } _ => { - return Err(ASTLoweringError { - message: "tuple variable assign value now only support function call" - .to_string(), - }); + return Err(ASTLoweringError::BuilderError( + "tuple variable assign value now only support function call".to_string(), + )); } }; @@ -497,7 +520,7 @@ impl<'a> Yul2IRContext<'a> { let var_low_level_value_type = YulLowLevelValueType::Bytes32Pointer; let ty = self.bytes32_pointer_type().as_basic_type_enum(); let llvm_var = self.fast_alloca(ty, &format!("var_{name}"))?; - self.set_var(&name, ty, var_low_level_value_type, llvm_var, false); + self.set_var(&name, ty, var_low_level_value_type, llvm_var, false)?; self.build_store(llvm_var, init_val_low_level.unwrap().value)?; return self.ok_result(); } @@ -563,7 +586,7 @@ impl<'a> Yul2IRContext<'a> { }; let llvm_var = self.fast_alloca(ty, &format!("var_{name}"))?; - self.set_var(&name, ty, var_low_level_value_type, llvm_var, false); + self.set_var(&name, ty, var_low_level_value_type, llvm_var, false)?; if init_val_low_level.is_some() && init_val_low_level.unwrap().value_type == YulLowLevelValueType::Bytes32Pointer @@ -610,10 +633,10 @@ impl<'a> Yul2IRContext<'a> { .collect::>>() } _ => { - return Err(ASTLoweringError { - message: "tuple variable declaration value now only support function call" + return Err(ASTLoweringError::BuilderError( + "tuple variable declaration value now only support function call" .to_string(), - }) + )); } }); } @@ -667,7 +690,7 @@ impl<'a> Yul2IRContext<'a> { new_var_low_level_value_type, new_var, false, - ); + )?; let item = match ty { Some(ty) => { @@ -755,6 +778,20 @@ impl<'a> Yul2IRContext<'a> { func_call: &ast::FunctionCall, ) -> CompileResult<'a> { let func_name = func_call.id.name.clone(); + let qualifier_func_name = self.get_func_decl_qualifier_name_by_str(&func_name); + + if self + .revert_zero_functions + .borrow() + .contains(&qualifier_func_name) + { + self.build_void_call(UNIFIED_REVERT_ERROR_ZERO, &[])?; + return Ok(YulLowLevelValue { + value_type: YulLowLevelValueType::I32, + value: self.i32_type().const_zero().into(), + }); + } + if let Some(instr) = parse_intrinsic_func_name(&func_name) { let yul_generated_expr = self.walk_yul_instruction( yul_func_name, @@ -832,12 +869,16 @@ impl<'a> Yul2IRContext<'a> { } } - let qualifier_func_name = self.get_func_decl_qualifier_name_by_str(&func_name); let infered_yul_func_ty = self .yul_func_infer_types .borrow() .get(&qualifier_func_name) - .unwrap() + .ok_or_else(|| { + ASTLoweringError::BuilderError(format!( + "Called function '{}' definition not found in module '{}'", + func_name, module_name + )) + })? .clone(); let mut call_args = vec![]; @@ -1040,7 +1081,7 @@ impl<'a> Yul2IRContext<'a> { } } - fn ok_result(&self) -> CompileResult<'a> { + pub fn ok_result(&self) -> CompileResult<'a> { Ok(YulLowLevelValue { value_type: YulLowLevelValueType::I32, value: self.i32_type().const_zero().into(), @@ -1241,7 +1282,7 @@ impl<'a> Yul2IRContext<'a> { return false; } // log3 - if self.matches_log3_statement(&stmts[17]).is_none() { + if self.matches_function_call(&stmts[17], "log3", 5).is_none() { return false; } true @@ -1348,6 +1389,13 @@ impl<'a> Yul2IRContext<'a> { .borrow_mut() .insert(qualifier_func_name.clone(), func_low_level_type); + if self.is_revert_zero_function(func_def) { + self.revert_zero_functions + .borrow_mut() + .insert(qualifier_func_name.clone()); + continue; + } + // Add function to module let function = self.llvm_module.borrow_mut().add_function( &qualifier_func_name, @@ -1507,6 +1555,8 @@ impl<'a> Yul2IRContext<'a> { *self.main_module.borrow_mut() = module_name.clone(); } + self.generate_unified_revert_zero()?; + for func in object .code .statements @@ -1721,7 +1771,7 @@ impl<'a> Yul2IRContext<'a> { param_low_level_value_type, param_var_pointer, false, - ); + )?; } // Declare return variables for (i, ret_info) in function.returns.iter().enumerate() { @@ -1751,7 +1801,7 @@ impl<'a> Yul2IRContext<'a> { ret_var_low_level_value_type, ret_var_pointer, true, - ); + )?; } if self.opts.enable_all_optimizers { diff --git a/src/yul2ir/usage.rs b/src/yul2ir/usage.rs index 021500e..8e126ff 100644 --- a/src/yul2ir/usage.rs +++ b/src/yul2ir/usage.rs @@ -8,7 +8,7 @@ use super::{ context::{UsageInfo, Yul2IRContext}, }; -impl<'a> Yul2IRContext<'a> { +impl Yul2IRContext<'_> { /// Variable Usage Analysis Functions (Free Functions) #[allow(unused)] fn analyze_expression_usage(expr: &Expression, usage_info: &mut HashMap) { diff --git a/src/yul2ir/var_scope.rs b/src/yul2ir/var_scope.rs index 5da0c26..affca13 100644 --- a/src/yul2ir/var_scope.rs +++ b/src/yul2ir/var_scope.rs @@ -45,7 +45,7 @@ impl<'a, 'b> ScopeGuard<'a, 'b> { } } -impl<'a, 'b> Drop for ScopeGuard<'a, 'b> { +impl Drop for ScopeGuard<'_, '_> { fn drop(&mut self) { self.context.exit_scope(); } diff --git a/stdlib/chain.c b/stdlib/chain.c index 528419a..e80727e 100644 --- a/stdlib/chain.c +++ b/stdlib/chain.c @@ -163,30 +163,35 @@ int32_t wrapper_calldata_size() { return (int32_t)size; } -void wrapper_caller(bytes32 *result) { - getCaller(12 + (ADDRESS_UINT)result); // address is 20 bytes - // clear first 12 bytes with zeros - - uint32_t *tmp_ptr = (uint32_t *)result; +static inline void clear_first_12_bytes(bytes32 *memory_ptr) { + uint32_t *tmp_ptr = (uint32_t *)memory_ptr; tmp_ptr[0] = 0; tmp_ptr[1] = 0; tmp_ptr[2] = 0; } +void wrapper_caller(bytes32 *result) { + getCaller(12 + (ADDRESS_UINT)result); // address is 20 bytes + clear_first_12_bytes(result); +} + void wrapper_current_contract(bytes32 *result) { getAddress(12 + (ADDRESS_UINT)result); // address is 20 bytes + clear_first_12_bytes(result); } void wrapper_origin(bytes32 *result) { getTxOrigin(12 + (ADDRESS_UINT)result); // address is 20 bytes + clear_first_12_bytes(result); } void wrapper_block_coin_base(bytes32 *result) { getBlockCoinbase(12 + (ADDRESS_UINT)result); // address is 20 bytes + clear_first_12_bytes(result); } void wrapper_block_prevRandao(bytes32 *result) { - getBlockPrevRandao(12 + (ADDRESS_UINT)result); // 32 bytes + getBlockPrevRandao((ADDRESS_UINT)result); // 32 bytes } void wrapper_callvalue(uint256_t *result) { diff --git a/tools/build_utils.sh b/tools/build_utils.sh new file mode 100755 index 0000000..9b216ba --- /dev/null +++ b/tools/build_utils.sh @@ -0,0 +1,56 @@ +#!/bin/bash +set -e + +setup_build_mode() { + local BUILD_MODE=${1:-release} + echo "Building in $BUILD_MODE mode" + + # --enable-little-endian-storage-load-store + YUL2WASM_EXTRA_ARGS="--verbose" + + # if env ENABLE_LITTLE_ENDIAN_STORAGE == "ON", then add --enable-little-endian-storage-load-store + if [ "$ENABLE_LITTLE_ENDIAN_STORAGE" == "ON" ]; then + YUL2WASM_EXTRA_ARGS="$YUL2WASM_EXTRA_ARGS --enable-little-endian-storage-load-store" + fi + + # Set the yul2wasm path based on the build mode + if [ "$BUILD_MODE" == "release" ]; then + YUL2WASM_PATH="../../target/release/yul2wasm" + else + YUL2WASM_PATH="../../target/debug/yul2wasm" + YUL2WASM_EXTRA_ARGS="$YUL2WASM_EXTRA_ARGS --debug" + fi + + export YUL2WASM_PATH + export YUL2WASM_EXTRA_ARGS +} + +compile_contract() { + local contract=$1 + local YUL_IR_PATH=$2 + echo "Compiling $contract..." + + $YUL2WASM_PATH --input $YUL_IR_PATH/$contract.sol/$contract.iropt \ + --output $YUL_IR_PATH/$contract.wasm \ + $YUL2WASM_EXTRA_ARGS + + wasm2wat -o $YUL_IR_PATH/$contract.wat $YUL_IR_PATH/$contract.wasm + + if [ -f "$YUL_IR_PATH/$contract.wasm" ]; then + echo "Successfully compiled $contract to $YUL_IR_PATH/$contract.wasm" + else + echo "Error: Failed to compile $contract" >&2 + exit 1 + fi +} + +compile_all_contracts() { + local contracts=("${!1}") + local YUL_IR_PATH=$2 + + for contract in "${contracts[@]}"; do + compile_contract "$contract" "$YUL_IR_PATH" + done + + echo "All contracts compiled successfully" +} diff --git a/tools/forge_test_utils.sh b/tools/forge_test_utils.sh new file mode 100755 index 0000000..3bba090 --- /dev/null +++ b/tools/forge_test_utils.sh @@ -0,0 +1,46 @@ +#!/bin/bash +set -e + +source ../examples/scripts/common.sh +ABI_ENCODE="../scripts/abi_encode.py" +MOCKCLI_PATH="/opt/chain_mockcli" + +DEPLOYER_SENDER=0x9988776655443322119900112233445566778899 + +cleanup() { + if [ -f test.db ]; then + rm -f test.db + fi +} + +deploy_contract() { + local wasm_file=$1 + local deploy_addr=$2 + echo "deploy contract: $wasm_file" + $MOCKCLI_PATH -f $wasm_file --action deploy -s $DEPLOYER_SENDER -t $deploy_addr -i 0x +} + +call_contract_function() { + local wasm_file=$1 + local deploy_addr=$2 + local function_name=$3 + local expected_output=$4 + echo "call contract $wasm_file function $function_name" + ABI_DATA=$($ABI_ENCODE "$function_name") + output=$($MOCKCLI_PATH -f $wasm_file -t $deploy_addr --action call --print-time --enable-gas-meter -s $DEPLOYER_SENDER -i $ABI_DATA) + run_cmd_and_grep "$output" "$expected_output" +} + +init_test() { + cleanup + + local wasm_vm_file=$1 + local WASM_TEST_VM_DEPLOY_ADDR=$2 + local contract_file=$3 + local DEPLOYER_INITIALIZER_ADDR=$4 + + deploy_contract "$wasm_vm_file" "$WASM_TEST_VM_DEPLOY_ADDR" + deploy_contract "$contract_file" "$DEPLOYER_INITIALIZER_ADDR" + + call_contract_function "$contract_file" "$DEPLOYER_INITIALIZER_ADDR" "setUp()" 'evm finish with result hex:' +}