Compare commits

..

2 Commits

Author SHA1 Message Date
pgherveou 20a3b30296 wip 2025-04-28 16:39:59 +02:00
pgherveou f44b2485bd lint 2025-04-24 16:34:06 +02:00
73 changed files with 5177 additions and 8136 deletions
+2 -2
View File
@@ -10,8 +10,8 @@ rustflags = [
"-Clink-arg=-sWASM_ASYNC_COMPILATION=0", "-Clink-arg=-sWASM_ASYNC_COMPILATION=0",
"-Clink-arg=-sDYNAMIC_EXECUTION=0", "-Clink-arg=-sDYNAMIC_EXECUTION=0",
"-Clink-arg=-sALLOW_TABLE_GROWTH=1", "-Clink-arg=-sALLOW_TABLE_GROWTH=1",
"-Clink-arg=--js-library=js/emscripten/embed/soljson_interface.js", "-Clink-arg=--js-library=js/embed/soljson_interface.js",
"-Clink-arg=--pre-js=js/emscripten/embed/pre.js", "-Clink-arg=--pre-js=js/embed/pre.js",
"-Clink-arg=-sSTACK_SIZE=128kb", "-Clink-arg=-sSTACK_SIZE=128kb",
"-Clink-arg=-sNODEJS_CATCH_EXIT=0" "-Clink-arg=-sNODEJS_CATCH_EXIT=0"
] ]
-1
View File
@@ -5,7 +5,6 @@ inputs:
required: false required: false
default: "3.1.64" default: "3.1.64"
runs: runs:
using: "composite" using: "composite"
steps: steps:
+1 -1
View File
@@ -19,7 +19,7 @@ runs:
shell: bash shell: bash
run: | run: |
mkdir -p solc mkdir -p solc
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.30/${SOLC_NAME} curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.29/${SOLC_NAME}
- name: Make Solc Executable - name: Make Solc Executable
if: ${{ runner.os == 'Windows' }} if: ${{ runner.os == 'Windows' }}
+49
View File
@@ -0,0 +1,49 @@
name: NPM Release
on:
release:
types: [released]
env:
CI: true
jobs:
publish:
name: Build & Publish to NPM
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22.x
- name: Install
run: yarn install --immutable
- name: update-resolc
run: yarn update-resolc
- name: Build
run: yarn build
- name: Set version
run: npm version --no-git-tag-version ${{github.event.release.tag_name}}
- name: npm pack
run: npm pack
- uses: actions/upload-artifact@v4
with:
name: package
path: 'parity-revive-*.tgz'
- uses: octokit/request-action@bbedc70b1981e610d89f1f8de88311a1fc02fb83
with:
route: POST /repos/paritytech/npm_publish_automation/actions/workflows/publish.yml/dispatches
ref: main
inputs: '${{ format(''{{ "repo": "{0}", "run_id": "{1}" }}'', github.repository, github.run_id) }}'
env:
GITHUB_TOKEN: ${{ secrets.NPM_PUBLISH_AUTOMATION_TOKEN }}
+9 -6
View File
@@ -37,7 +37,15 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
target: [x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl, wasm32-unknown-emscripten, aarch64-apple-darwin, x86_64-apple-darwin, x86_64-pc-windows-msvc] target:
[
x86_64-unknown-linux-gnu,
x86_64-unknown-linux-musl,
wasm32-unknown-emscripten,
aarch64-apple-darwin,
x86_64-apple-darwin,
x86_64-pc-windows-msvc,
]
include: include:
- target: x86_64-unknown-linux-gnu - target: x86_64-unknown-linux-gnu
builder-arg: gnu builder-arg: gnu
@@ -87,11 +95,6 @@ jobs:
run: | run: |
brew install ninja brew install ninja
- name: Install Dependencies
if: ${{ matrix.host == 'windows' }}
run: |
choco install ninja
- name: Install LLVM Builder - name: Install LLVM Builder
run: | run: |
cargo install --path crates/llvm-builder cargo install --path crates/llvm-builder
+1 -44
View File
@@ -181,7 +181,7 @@ jobs:
- name: Basic Sanity Check - name: Basic Sanity Check
run: | run: |
mkdir -p solc mkdir -p solc
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.30/soljson.js curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.29/soljson.js
node -e " node -e "
const soljson = require('solc/soljson'); const soljson = require('solc/soljson');
const createRevive = require('./target/wasm32-unknown-emscripten/release/resolc.js'); const createRevive = require('./target/wasm32-unknown-emscripten/release/resolc.js');
@@ -286,46 +286,3 @@ jobs:
resolc.wasm resolc.wasm
resolc_web.js resolc_web.js
checksums.txt checksums.txt
npm-release:
needs: [create-release]
runs-on: macos-14
environment: tags
steps:
- uses: actions/checkout@v4
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Set Up Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
- run: npm ci -w js/resolc
- name: Build
run: |
cp -f resolc.{wasm,js} js/resolc/src/resolc
npm -w js/resolc run build
- name: Set version
run: npm -w js/resolc version --no-git-tag-version ${{github.event.release.tag_name}}
- name: npm pack
run: npm -w js/resolc pack
- uses: actions/upload-artifact@v4
with:
name: npm_package
path: "parity-resolc-*.tgz"
- uses: octokit/request-action@bbedc70b1981e610d89f1f8de88311a1fc02fb83
with:
route: POST /repos/paritytech/npm_publish_automation/actions/workflows/publish.yml/dispatches
ref: main
inputs: '${{ format(''{{ "artifact_name": "npm_package", "repo": "{0}", "run_id": "{1}" }}'', github.repository, github.run_id) }}'
env:
GITHUB_TOKEN: ${{ secrets.NPM_PUBLISH_AUTOMATION_TOKEN }}
+3 -3
View File
@@ -4,9 +4,9 @@ on:
branches: ["main"] branches: ["main"]
types: [opened, synchronize] types: [opened, synchronize]
paths: paths:
- 'LLVM.lock' - "LLVM.lock"
- 'crates/llvm-builder/**' - "crates/llvm-builder/**"
- '.github/workflows/test-llvm-builder.yml' - ".github/workflows/test-llvm-builder.yml"
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+7 -12
View File
@@ -86,18 +86,13 @@ jobs:
- name: Install Node Packages - name: Install Node Packages
run: npm install run: npm install
- name: Test emscripten - name: Run Playwright tests
run: |
cd js
npx playwright install --with-deps
npx playwright test
- name: Test revive
run: | run: |
echo "Running tests for ${{ matrix.os }}" echo "Running tests for ${{ matrix.os }}"
npm run test:wasm npm run test:wasm
- name: Test @parity/resolc
run: |
echo "Running tests for ${{ matrix.os }}"
npm run -w js/resolc test
- name: Run Playwright tests
run: |
cd js/emscripten
npx playwright install --with-deps
npx playwright test
+1
View File
@@ -12,6 +12,7 @@ target-llvm
node_modules node_modules
artifacts artifacts
tmp tmp
package-lock.json
/*.html /*.html
/build /build
soljson.js soljson.js
-6
View File
@@ -1,6 +0,0 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true
}
-26
View File
@@ -6,38 +6,12 @@ This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee` Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
## v0.1.0
This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
### Added ### Added
### Changed ### Changed
### Fixed ### Fixed
## v0.1.0-dev.15
This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
### Added
- Move the npm package from paritytech/js-revive, into this repo. The package `@parity/resolc` will be deployed to npm for each release.
- Support for solc v0.8.30
### Changed
- By default, heavy size optimizations are applied.
### Fixed
- @parity/resolc: The solc dependency package is constrained to the latest supported version, preventing breaking the package ever time a new solc package was released.
- The resolc npm package no longer ignores the optimizer settings
## v0.1.0-dev.14 ## v0.1.0-dev.14
This is a development pre-release. This is a development pre-release.
Generated
+15 -15
View File
@@ -4553,7 +4553,7 @@ checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
[[package]] [[package]]
name = "lld-sys" name = "lld-sys"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@@ -8266,7 +8266,7 @@ dependencies = [
[[package]] [[package]]
name = "revive-benchmarks" name = "revive-benchmarks"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"alloy-primitives", "alloy-primitives",
"criterion", "criterion",
@@ -8278,18 +8278,18 @@ dependencies = [
[[package]] [[package]]
name = "revive-build-utils" name = "revive-build-utils"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
[[package]] [[package]]
name = "revive-builtins" name = "revive-builtins"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"revive-build-utils", "revive-build-utils",
] ]
[[package]] [[package]]
name = "revive-common" name = "revive-common"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"serde", "serde",
@@ -8299,7 +8299,7 @@ dependencies = [
[[package]] [[package]]
name = "revive-differential" name = "revive-differential"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"alloy-genesis", "alloy-genesis",
"alloy-primitives", "alloy-primitives",
@@ -8312,7 +8312,7 @@ dependencies = [
[[package]] [[package]]
name = "revive-integration" name = "revive-integration"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"alloy-primitives", "alloy-primitives",
"alloy-sol-types", "alloy-sol-types",
@@ -8328,7 +8328,7 @@ dependencies = [
[[package]] [[package]]
name = "revive-linker" name = "revive-linker"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"libc", "libc",
@@ -8340,7 +8340,7 @@ dependencies = [
[[package]] [[package]]
name = "revive-llvm-builder" name = "revive-llvm-builder"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assert_cmd", "assert_cmd",
@@ -8362,7 +8362,7 @@ dependencies = [
[[package]] [[package]]
name = "revive-llvm-context" name = "revive-llvm-context"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"hex", "hex",
@@ -8384,7 +8384,7 @@ dependencies = [
[[package]] [[package]]
name = "revive-runner" name = "revive-runner"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"alloy-primitives", "alloy-primitives",
"anyhow", "anyhow",
@@ -8403,7 +8403,7 @@ dependencies = [
[[package]] [[package]]
name = "revive-runtime-api" name = "revive-runtime-api"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"inkwell", "inkwell",
@@ -8413,7 +8413,7 @@ dependencies = [
[[package]] [[package]]
name = "revive-solc-json-interface" name = "revive-solc-json-interface"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"rayon", "rayon",
@@ -8425,7 +8425,7 @@ dependencies = [
[[package]] [[package]]
name = "revive-solidity" name = "revive-solidity"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
@@ -8452,7 +8452,7 @@ dependencies = [
[[package]] [[package]]
name = "revive-stdlib" name = "revive-stdlib"
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
dependencies = [ dependencies = [
"inkwell", "inkwell",
"revive-build-utils", "revive-build-utils",
+15 -15
View File
@@ -3,7 +3,7 @@ resolver = "2"
members = ["crates/*"] members = ["crates/*"]
[workspace.package] [workspace.package]
version = "0.1.0-dev.15" version = "0.1.0-dev.14"
authors = [ authors = [
"Cyrill Leutwiler <cyrill@parity.io>", "Cyrill Leutwiler <cyrill@parity.io>",
"Parity Technologies <admin@parity.io>", "Parity Technologies <admin@parity.io>",
@@ -14,20 +14,20 @@ repository = "https://github.com/paritytech/revive"
rust-version = "1.81.0" rust-version = "1.81.0"
[workspace.dependencies] [workspace.dependencies]
revive-benchmarks = { version = "0.1.0-dev.15", path = "crates/benchmarks" } revive-benchmarks = { version = "0.1.0-dev.14", path = "crates/benchmarks" }
revive-builtins = { version = "0.1.0-dev.15", path = "crates/builtins" } revive-builtins = { version = "0.1.0-dev.14", path = "crates/builtins" }
revive-common = { version = "0.1.0-dev.15", path = "crates/common" } revive-common = { version = "0.1.0-dev.14", path = "crates/common" }
revive-differential = { version = "0.1.0-dev.15", path = "crates/differential" } revive-differential = { version = "0.1.0-dev.14", path = "crates/differential" }
revive-integration = { version = "0.1.0-dev.15", path = "crates/integration" } revive-integration = { version = "0.1.0-dev.14", path = "crates/integration" }
revive-linker = { version = "0.1.0-dev.15", path = "crates/linker" } revive-linker = { version = "0.1.0-dev.14", path = "crates/linker" }
lld-sys = { version = "0.1.0-dev.15", path = "crates/lld-sys" } lld-sys = { version = "0.1.0-dev.14", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.1.0-dev.15", path = "crates/llvm-context" } revive-llvm-context = { version = "0.1.0-dev.14", path = "crates/llvm-context" }
revive-runtime-api = { version = "0.1.0-dev.15", path = "crates/runtime-api" } revive-runtime-api = { version = "0.1.0-dev.14", path = "crates/runtime-api" }
revive-runner = { version = "0.1.0-dev.15", path = "crates/runner" } revive-runner = { version = "0.1.0-dev.14", path = "crates/runner" }
revive-solc-json-interface = { version = "0.1.0-dev.15", path = "crates/solc-json-interface" } revive-solc-json-interface = { version = "0.1.0-dev.14", path = "crates/solc-json-interface" }
revive-solidity = { version = "0.1.0-dev.15", path = "crates/solidity" } revive-solidity = { version = "0.1.0-dev.14", path = "crates/solidity" }
revive-stdlib = { version = "0.1.0-dev.15", path = "crates/stdlib" } revive-stdlib = { version = "0.1.0-dev.14", path = "crates/stdlib" }
revive-build-utils = { version = "0.1.0-dev.15", path = "crates/build-utils" } revive-build-utils = { version = "0.1.0-dev.14", path = "crates/build-utils" }
hex = "0.4.3" hex = "0.4.3"
cc = "1.2" cc = "1.2"
+4 -1
View File
@@ -92,4 +92,7 @@ clean:
rm -rf node_modules ; \ rm -rf node_modules ; \
rm -rf crates/solidity/src/tests/cli-tests/artifacts ; \ rm -rf crates/solidity/src/tests/cli-tests/artifacts ; \
cargo uninstall revive-solidity ; \ cargo uninstall revive-solidity ; \
cargo uninstall revive-llvm-builder ; cargo uninstall revive-llvm-builder ; \
rm -f package-lock.json ; \
rm -rf js/dist ; \
rm -f js/src/resolc.{wasm,js}
+5 -1
View File
@@ -14,6 +14,7 @@ This is experimental software in active development and not ready just yet for p
Discussion around the development is hosted on the [Polkadot Forum](https://forum.polkadot.network/t/contracts-update-solidity-on-polkavm/6949#a-new-solidity-compiler-1). Discussion around the development is hosted on the [Polkadot Forum](https://forum.polkadot.network/t/contracts-update-solidity-on-polkavm/6949#a-new-solidity-compiler-1).
## Installation ## Installation
Please consult [the documentation](https://contracts.polkadot.io/revive_compiler/installation) for installation instructions. Please consult [the documentation](https://contracts.polkadot.io/revive_compiler/installation) for installation instructions.
## Building from source ## Building from source
@@ -30,11 +31,13 @@ Building revive requires a [stable Rust installation](https://rustup.rs/) and a
Download the [latest LLVM build](https://github.com/paritytech/revive/releases?q=LLVM+binaries+release&expanded=true) from our releases. Download the [latest LLVM build](https://github.com/paritytech/revive/releases?q=LLVM+binaries+release&expanded=true) from our releases.
> **MacOS** users need to clear the `downloaded` attribute from all binaries after extracting the archive: > **MacOS** users need to clear the `downloaded` attribute from all binaries after extracting the archive:
>
> ```sh > ```sh
> xattr -rc </path/to/the/extracted/archive>/target-llvm/gnu/target-final/bin/* > xattr -rc </path/to/the/extracted/archive>/target-llvm/gnu/target-final/bin/*
> ``` > ```
After extracting the archive, point `$LLVM_SYS_181_PREFIX` to it: After extracting the archive, point `$LLVM_SYS_181_PREFIX` to it:
```sh ```sh
export LLVM_SYS_181_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/target-final export LLVM_SYS_181_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/target-final
``` ```
@@ -44,7 +47,7 @@ export LLVM_SYS_181_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/targ
<details> <details>
<summary>Building from source</summary> <summary>Building from source</summary>
Use the provided [revive-llvm](crates/llvm-builder/README.md) utility to compile a compatible LLVM build locally and point `$LLVM_SYS_181_PREFIX` to the installation afterwards. Use the provided [revive-llvm](crates/llvm-builder/README.md) utility to compile a compatible LLVM build locally and point `$LLVM_SYS_181_PREFIX` to the installation afterwards.
The `Makefile` provides a shortcut target to obtain a compatible LLVM build: The `Makefile` provides a shortcut target to obtain a compatible LLVM build:
@@ -97,6 +100,7 @@ Please consult the [Makefile](Makefile) targets to learn how to run tests and be
Ensure that your branch passes `make test` locally when submitting a pull request. Ensure that your branch passes `make test` locally when submitting a pull request.
### Design overview ### Design overview
See the [relevant section in our documentation](https://contracts.polkadot.io/revive_compiler/architecture) to learn more about how the compiler works. See the [relevant section in our documentation](https://contracts.polkadot.io/revive_compiler/architecture) to learn more about how the compiler works.
[Frontend](https://github.com/matter-labs/era-compiler-solidity) and [code generator](https://github.com/matter-labs/era-compiler-llvm-context) are based of ZKSync `zksolc` (the project started as a fork of the era compiler). [Frontend](https://github.com/matter-labs/era-compiler-solidity) and [code generator](https://github.com/matter-labs/era-compiler-llvm-context) are based of ZKSync `zksolc` (the project started as a fork of the era compiler).
-4
View File
@@ -13,10 +13,6 @@ To create a new pre-release:
7. After the release is published, another workflow should start automatically and update json files in https://github.com/paritytech/resolc-bin. Check the changes. 7. After the release is published, another workflow should start automatically and update json files in https://github.com/paritytech/resolc-bin. Check the changes.
8. Update the [contract-docs](https://github.com/paritytech/contract-docs/) accordingly 8. Update the [contract-docs](https://github.com/paritytech/contract-docs/) accordingly
# `resolc` NPM package release
Will happen automatically.
# LLVM release # LLVM release
To create a new LLVM release, run "Release LLVM" workflow. Use current LLVM version as parameter, e.g. `18.1.8`. To create a new LLVM release, run "Release LLVM" workflow. Use current LLVM version as parameter, e.g. `18.1.8`.
+15 -15
View File
@@ -16,13 +16,13 @@
### Baseline ### Baseline
| | `EVM` | `PVMInterpreter` | | | `EVM` | `PVMInterpreter` |
|:--------|:-------------------------|:-------------------------------- | | :------ | :------------------------ | :------------------------------- |
| **`0`** | `10.08 us` (✅ **1.00x**) | `10.32 us` (✅ **1.02x slower**) | | **`0`** | `10.08 us` (✅ **1.00x**) | `10.32 us` (✅ **1.02x slower**) |
### OddPorduct ### OddPorduct
| | `EVM` | `PVMInterpreter` | | | `EVM` | `PVMInterpreter` |
|:-------------|:--------------------------|:-------------------------------- | | :----------- | :------------------------- | :------------------------------- |
| **`10000`** | `3.60 ms` (✅ **1.00x**) | `1.57 ms` (🚀 **2.28x faster**) | | **`10000`** | `3.60 ms` (✅ **1.00x**) | `1.57 ms` (🚀 **2.28x faster**) |
| **`100000`** | `34.72 ms` (✅ **1.00x**) | `14.82 ms` (🚀 **2.34x faster**) | | **`100000`** | `34.72 ms` (✅ **1.00x**) | `14.82 ms` (🚀 **2.34x faster**) |
| **`300000`** | `105.01 ms` (✅ **1.00x**) | `44.11 ms` (🚀 **2.38x faster**) | | **`300000`** | `105.01 ms` (✅ **1.00x**) | `44.11 ms` (🚀 **2.38x faster**) |
@@ -30,7 +30,7 @@
### TriangleNumber ### TriangleNumber
| | `EVM` | `PVMInterpreter` | | | `EVM` | `PVMInterpreter` |
|:-------------|:-------------------------|:-------------------------------- | | :----------- | :------------------------ | :------------------------------- |
| **`10000`** | `2.43 ms` (✅ **1.00x**) | `1.12 ms` (🚀 **2.17x faster**) | | **`10000`** | `2.43 ms` (✅ **1.00x**) | `1.12 ms` (🚀 **2.17x faster**) |
| **`100000`** | `24.20 ms` (✅ **1.00x**) | `10.86 ms` (🚀 **2.23x faster**) | | **`100000`** | `24.20 ms` (✅ **1.00x**) | `10.86 ms` (🚀 **2.23x faster**) |
| **`360000`** | `88.69 ms` (✅ **1.00x**) | `38.46 ms` (🚀 **2.31x faster**) | | **`360000`** | `88.69 ms` (✅ **1.00x**) | `38.46 ms` (🚀 **2.31x faster**) |
@@ -38,7 +38,7 @@
### FibonacciRecursive ### FibonacciRecursive
| | `EVM` | `PVMInterpreter` | | | `EVM` | `PVMInterpreter` |
|:---------|:--------------------------|:--------------------------------- | | :------- | :------------------------- | :-------------------------------- |
| **`12`** | `144.17 us` (✅ **1.00x**) | `150.85 us` (✅ **1.05x slower**) | | **`12`** | `144.17 us` (✅ **1.00x**) | `150.85 us` (✅ **1.05x slower**) |
| **`16`** | `938.71 us` (✅ **1.00x**) | `922.11 us` (✅ **1.02x faster**) | | **`16`** | `938.71 us` (✅ **1.00x**) | `922.11 us` (✅ **1.02x faster**) |
| **`20`** | `6.54 ms` (✅ **1.00x**) | `6.20 ms` (✅ **1.05x faster**) | | **`20`** | `6.54 ms` (✅ **1.00x**) | `6.20 ms` (✅ **1.05x faster**) |
@@ -47,27 +47,27 @@
### FibonacciIterative ### FibonacciIterative
| | `EVM` | `PVMInterpreter` | | | `EVM` | `PVMInterpreter` |
|:----------|:-------------------------|:-------------------------------- | | :-------- | :------------------------ | :------------------------------- |
| **`64`** | `23.00 us` (✅ **1.00x**) | `31.88 us` (❌ *1.39x slower*) | | **`64`** | `23.00 us` (✅ **1.00x**) | `31.88 us` (❌ _1.39x slower_) |
| **`128`** | `35.28 us` (✅ **1.00x**) | `42.43 us` (❌ *1.20x slower*) | | **`128`** | `35.28 us` (✅ **1.00x**) | `42.43 us` (❌ _1.20x slower_) |
| **`256`** | `60.12 us` (✅ **1.00x**) | `61.20 us` (✅ **1.02x slower**) | | **`256`** | `60.12 us` (✅ **1.00x**) | `61.20 us` (✅ **1.02x slower**) |
### FibonacciBinet ### FibonacciBinet
| | `EVM` | `PVMInterpreter` | | | `EVM` | `PVMInterpreter` |
|:----------|:-------------------------|:-------------------------------- | | :-------- | :------------------------ | :----------------------------- |
| **`64`** | `23.01 us` (✅ **1.00x**) | `47.74 us` (❌ *2.07x slower*) | | **`64`** | `23.01 us` (✅ **1.00x**) | `47.74 us` (❌ _2.07x slower_) |
| **`128`** | `25.44 us` (✅ **1.00x**) | `49.67 us` (❌ *1.95x slower*) | | **`128`** | `25.44 us` (✅ **1.00x**) | `49.67 us` (❌ _1.95x slower_) |
| **`256`** | `28.66 us` (✅ **1.00x**) | `53.01 us` (❌ *1.85x slower*) | | **`256`** | `28.66 us` (✅ **1.00x**) | `53.01 us` (❌ _1.85x slower_) |
### SHA1 ### SHA1
| | `EVM` | `PVMInterpreter` | | | `EVM` | `PVMInterpreter` |
|:----------|:--------------------------|:--------------------------------- | | :-------- | :------------------------- | :------------------------------ |
| **`1`** | `135.87 us` (✅ **1.00x**) | `243.75 us` (❌ *1.79x slower*) | | **`1`** | `135.87 us` (✅ **1.00x**) | `243.75 us` (❌ _1.79x slower_) |
| **`64`** | `258.45 us` (✅ **1.00x**) | `355.70 us` (❌ *1.38x slower*) | | **`64`** | `258.45 us` (✅ **1.00x**) | `355.70 us` (❌ _1.38x slower_) |
| **`512`** | `1.10 ms` (✅ **1.00x**) | `1.09 ms` (✅ **1.01x faster**) | | **`512`** | `1.10 ms` (✅ **1.00x**) | `1.09 ms` (✅ **1.01x faster**) |
--- ---
Made with [criterion-table](https://github.com/nu11ptr/criterion-table)
Made with [criterion-table](https://github.com/nu11ptr/criterion-table)
+23 -14
View File
@@ -6,6 +6,7 @@ Parity fork of the [Matter Labs zksync LLVM builder](https://github.com/matter-l
The LLVM compiler framework for revive must be built with our tool called `revive-llvm`. The LLVM compiler framework for revive must be built with our tool called `revive-llvm`.
This is because the revive compiler has requirements not fullfilled in upstream builds: This is because the revive compiler has requirements not fullfilled in upstream builds:
- Special builds for compiling the frontend into statically linked ELF binaries and also Wasm executables - Special builds for compiling the frontend into statically linked ELF binaries and also Wasm executables
- The RISC-V target (the PolkaVM target) - The RISC-V target (the PolkaVM target)
- The compiler-rt builtins for the PolkaVM target - The compiler-rt builtins for the PolkaVM target
@@ -17,20 +18,23 @@ Obtain a compatible build for your host platform from the release section of thi
<details> <details>
<summary>1. Install the system prerequisites.</summary> <summary>1. Install the system prerequisites.</summary>
* Linux (Debian): - Linux (Debian):
Install the following packages: Install the following packages:
```shell ```shell
apt install cmake ninja-build curl git libssl-dev pkg-config clang lld apt install cmake ninja-build curl git libssl-dev pkg-config clang lld
``` ```
* Linux (Arch):
- Linux (Arch):
Install the following packages: Install the following packages:
```shell ```shell
pacman -Syu which cmake ninja curl git pkg-config clang lld pacman -Syu which cmake ninja curl git pkg-config clang lld
``` ```
* MacOS: - MacOS:
* Install the [HomeBrew](https://brew.sh) package manager. * Install the [HomeBrew](https://brew.sh) package manager.
* Install the following packages: * Install the following packages:
@@ -40,24 +44,27 @@ Obtain a compatible build for your host platform from the release section of thi
``` ```
* Install your choice of a recent LLVM/[Clang](https://clang.llvm.org) compiler, e.g. via [Xcode](https://developer.apple.com/xcode/), [Apples Command Line Tools](https://developer.apple.com/library/archive/technotes/tn2339/_index.html), or your preferred package manager. * Install your choice of a recent LLVM/[Clang](https://clang.llvm.org) compiler, e.g. via [Xcode](https://developer.apple.com/xcode/), [Apples Command Line Tools](https://developer.apple.com/library/archive/technotes/tn2339/_index.html), or your preferred package manager.
</details>
</details>
<details> <details>
<summary>2. Install Rust.</summary> <summary>2. Install Rust.</summary>
* Follow the latest [official instructions](https://www.rust-lang.org/tools/install: - Follow the latest [official instructions](https://www.rust-lang.org/tools/install:
```shell `shell
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
. ${HOME}/.cargo/env . ${HOME}/.cargo/env
``` `
> Currently we are not pinned to any specific version of Rust, so just install the latest stable build for your platform. > Currently we are not pinned to any specific version of Rust, so just install the latest stable build for your platform.
</details>
</details>
<details> <details>
<summary>3. Install the revive LLVM framework builder.</summary> <summary>3. Install the revive LLVM framework builder.</summary>
* Install the builder using `cargo`: - Install the builder using `cargo`:
```shell ```shell
cargo install --git https://github.com/paritytech/revive-llvm-builder --force --locked cargo install --git https://github.com/paritytech/revive-llvm-builder --force --locked
``` ```
@@ -69,7 +76,7 @@ Obtain a compatible build for your host platform from the release section of thi
<details> <details>
<summary>4. (Optional) Create the `LLVM.lock` file.</summary> <summary>4. (Optional) Create the `LLVM.lock` file.</summary>
* The `LLVM.lock` dictates the LLVM source tree being used. - The `LLVM.lock` dictates the LLVM source tree being used.
A default `./LLVM.lock` pointing to the release used for development is already provided. A default `./LLVM.lock` pointing to the release used for development is already provided.
</details> </details>
@@ -77,7 +84,7 @@ Obtain a compatible build for your host platform from the release section of thi
<details> <details>
<summary>5. Build LLVM.</summary> <summary>5. Build LLVM.</summary>
* Clone and build the LLVM framework using the `revive-llvm` tool. - Clone and build the LLVM framework using the `revive-llvm` tool.
The clang and lld projects are required for the `resolc` Solidity frontend executable; they are enabled by default. LLVM assertions are also enabled by default. The clang and lld projects are required for the `resolc` Solidity frontend executable; they are enabled by default. LLVM assertions are also enabled by default.
@@ -96,6 +103,7 @@ Obtain a compatible build for your host platform from the release section of thi
## Supported target architectures ## Supported target architectures
The following target platforms are supported: The following target platforms are supported:
- Linux GNU (x86) - Linux GNU (x86)
- Linux MUSL (x86) - Linux MUSL (x86)
- MacOS (aarch64) - MacOS (aarch64)
@@ -105,11 +113,12 @@ The following target platforms are supported:
<details> <details>
<summary>Building for MUSL</summary> <summary>Building for MUSL</summary>
* Via a musl build we can build revive into fully static ELF binaries. - Via a musl build we can build revive into fully static ELF binaries.
Which is desirable for reproducible Solidity contracts builds. Which is desirable for reproducible Solidity contracts builds.
The resulting binary is also very portable, akin to the`solc` frontend binary distribution. The resulting binary is also very portable, akin to the`solc` frontend binary distribution.
Clone and build the LLVM framework using the `revive-llvm` tool: Clone and build the LLVM framework using the `revive-llvm` tool:
```shell ```shell
revive-llvm --target-env musl clone revive-llvm --target-env musl clone
revive-llvm --target-env musl build --enable-assertions --llvm-projects clang --llvm-projects lld revive-llvm --target-env musl build --enable-assertions --llvm-projects clang --llvm-projects lld
@@ -120,13 +129,13 @@ The following target platforms are supported:
<details> <details>
<summary>Building for Emscripten</summary> <summary>Building for Emscripten</summary>
* Via an emsdk build we can run revive in the browser and on node.js. - Via an emsdk build we can run revive in the browser and on node.js.
Clone and build the LLVM framework using the `revive-llvm` tool: Clone and build the LLVM framework using the `revive-llvm` tool:
```shell ```shell
revive-llvm --target-env emscripten clone revive-llvm --target-env emscripten clone
revive-llvm --target-env emscripten build --enable-assertions --llvm-projects clang --llvm-projects lld revive-llvm --target-env emscripten build --enable-assertions --llvm-projects clang --llvm-projects lld
``` ```
</details> </details>
+7 -1
View File
@@ -117,7 +117,13 @@ pub fn build(
log::info!("building compiler-rt for rv64emac"); log::info!("building compiler-rt for rv64emac");
crate::utils::check_presence("cmake")?; crate::utils::check_presence("cmake")?;
let generator = if cfg!(target_os = "windows") {
"Visual Studio 17 2022"
} else {
crate::utils::check_presence("ninja")?; crate::utils::check_presence("ninja")?;
"Ninja"
};
let llvm_module_compiler_rt = crate::LLVMPath::llvm_module_compiler_rt()?; let llvm_module_compiler_rt = crate::LLVMPath::llvm_module_compiler_rt()?;
let llvm_compiler_rt_build = crate::LLVMPath::llvm_build_compiler_rt()?; let llvm_compiler_rt_build = crate::LLVMPath::llvm_build_compiler_rt()?;
@@ -130,7 +136,7 @@ pub fn build(
"-B", "-B",
llvm_compiler_rt_build.to_string_lossy().as_ref(), llvm_compiler_rt_build.to_string_lossy().as_ref(),
"-G", "-G",
"Ninja", generator,
]) ])
.args(CMAKE_STATIC_ARGS) .args(CMAKE_STATIC_ARGS)
.args(cmake_dynamic_args(build_type, target_env)?) .args(cmake_dynamic_args(build_type, target_env)?)
@@ -234,7 +234,7 @@ impl TryFrom<&SolcStandardJsonInputSettingsOptimizer> for Settings {
fn try_from(value: &SolcStandardJsonInputSettingsOptimizer) -> Result<Self, Self::Error> { fn try_from(value: &SolcStandardJsonInputSettingsOptimizer) -> Result<Self, Self::Error> {
let mut result = match value.mode { let mut result = match value.mode {
Some(mode) => Self::try_from_cli(mode)?, Some(mode) => Self::try_from_cli(mode)?,
None => Self::size(), None => Self::cycles(),
}; };
if value.fallback_to_optimizing_for_size.unwrap_or_default() { if value.fallback_to_optimizing_for_size.unwrap_or_default() {
result.enable_fallback_to_size(); result.enable_fallback_to_size();
+1
View File
@@ -24,3 +24,4 @@ Set the `RUST_LOG` environment varibale to the `trace` level to see the full Pol
```bash ```bash
RUST_LOG=trace revive-runner -f mycontract.pvm -c a9059cbb000000000000000000000000f24ff3a9cf04c71dbc94d0b566f7a27b94566cac0000000000000000000000000000000000000000000000000000000000000000 RUST_LOG=trace revive-runner -f mycontract.pvm -c a9059cbb000000000000000000000000f24ff3a9cf04c71dbc94d0b566f7a27b94566cac0000000000000000000000000000000000000000000000000000000000000000
```
+1 -1
View File
@@ -129,7 +129,7 @@ fn main_inner() -> anyhow::Result<()> {
let mut optimizer_settings = match arguments.optimization { let mut optimizer_settings = match arguments.optimization {
Some(mode) => revive_llvm_context::OptimizerSettings::try_from_cli(mode)?, Some(mode) => revive_llvm_context::OptimizerSettings::try_from_cli(mode)?,
None => revive_llvm_context::OptimizerSettings::size(), None => revive_llvm_context::OptimizerSettings::cycles(),
}; };
if arguments.fallback_to_optimizing_for_size { if arguments.fallback_to_optimizing_for_size {
optimizer_settings.enable_fallback_to_size(); optimizer_settings.enable_fallback_to_size();
+1 -1
View File
@@ -19,7 +19,7 @@ use self::version::Version;
pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0); pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0);
/// The last supported version of `solc`. /// The last supported version of `solc`.
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 30); pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 29);
/// `--include-path` was introduced in solc `0.8.8` <https://github.com/ethereum/solidity/releases/tag/v0.8.8> /// `--include-path` was introduced in solc `0.8.8` <https://github.com/ethereum/solidity/releases/tag/v0.8.8>
pub const FIRST_INCLUDE_PATH_VERSION: semver::Version = semver::Version::new(0, 8, 8); pub const FIRST_INCLUDE_PATH_VERSION: semver::Version = semver::Version::new(0, 8, 8);
@@ -90,14 +90,10 @@
}, },
"outputSelection": { "outputSelection": {
"*": { "*": {
"": [ "": ["ast"]
"ast"
]
} }
}, },
"evmVersion": "berlin", "evmVersion": "berlin",
"remappings": [ "remappings": ["forge-std/=lib/forge-std/src/"]
"forge-std/=lib/forge-std/src/"
]
} }
} }
@@ -1,33 +1,33 @@
import * as path from 'path' import * as path from "path";
const outputDir = 'artifacts' const outputDir = "artifacts";
const binExtension = ':C.pvm' const binExtension = ":C.pvm";
const asmExtension = ':C.pvmasm' const asmExtension = ":C.pvmasm";
const llvmExtension = '.ll' const llvmExtension = ".ll";
const contractSolFilename = 'contract.sol' const contractSolFilename = "contract.sol";
const contractYulFilename = 'contract.yul' const contractYulFilename = "contract.yul";
const contractOptimizedLLVMFilename = contractSolFilename + '.C.optimized' const contractOptimizedLLVMFilename = contractSolFilename + ".C.optimized";
const contractUnoptimizedLLVMFilename = contractSolFilename + '.C.unoptimized' const contractUnoptimizedLLVMFilename = contractSolFilename + ".C.unoptimized";
const pathToOutputDir = path.join(__dirname, '..', outputDir) const pathToOutputDir = path.join(__dirname, "..", outputDir);
const pathToContracts = path.join(__dirname, '..', 'src', 'contracts') const pathToContracts = path.join(__dirname, "..", "src", "contracts");
const pathToBasicYulContract = path.join( const pathToBasicYulContract = path.join(
pathToContracts, pathToContracts,
'yul', "yul",
contractYulFilename contractYulFilename,
) );
const pathToBasicSolContract = path.join( const pathToBasicSolContract = path.join(
pathToContracts, pathToContracts,
'solidity', "solidity",
contractSolFilename contractSolFilename,
) );
const pathToSolBinOutputFile = path.join( const pathToSolBinOutputFile = path.join(
pathToOutputDir, pathToOutputDir,
contractSolFilename + binExtension contractSolFilename + binExtension,
) );
const pathToSolAsmOutputFile = path.join( const pathToSolAsmOutputFile = path.join(
pathToOutputDir, pathToOutputDir,
contractSolFilename + asmExtension contractSolFilename + asmExtension,
) );
export const paths = { export const paths = {
outputDir: outputDir, outputDir: outputDir,
@@ -44,4 +44,4 @@ export const paths = {
pathToBasicYulContract: pathToBasicYulContract, pathToBasicYulContract: pathToBasicYulContract,
pathToSolBinOutputFile: pathToSolBinOutputFile, pathToSolBinOutputFile: pathToSolBinOutputFile,
pathToSolAsmOutputFile: pathToSolAsmOutputFile, pathToSolAsmOutputFile: pathToSolAsmOutputFile,
} };
@@ -1,51 +1,51 @@
import * as shell from 'shelljs' import * as shell from "shelljs";
import * as fs from 'fs' import * as fs from "fs";
import { spawnSync } from 'child_process' import { spawnSync } from "child_process";
interface CommandResult { interface CommandResult {
output: string output: string;
exitCode: number exitCode: number;
} }
export const executeCommand = ( export const executeCommand = (
command: string, command: string,
stdin?: string stdin?: string,
): CommandResult => { ): CommandResult => {
if (stdin) { if (stdin) {
const process = spawnSync(command, [], { const process = spawnSync(command, [], {
input: stdin, input: stdin,
shell: true, shell: true,
encoding: 'utf8', encoding: "utf8",
maxBuffer: 30 * 1024 * 1024, maxBuffer: 30 * 1024 * 1024,
}) });
return { return {
exitCode: process.status || 0, exitCode: process.status || 0,
output: (process.stdout || process.stderr || '').toString(), output: (process.stdout || process.stderr || "").toString(),
} };
} }
const result = shell.exec(command, { silent: true, async: false }) const result = shell.exec(command, { silent: true, async: false });
return { return {
exitCode: result.code, exitCode: result.code,
output: result.stdout || result.stderr || '', output: result.stdout || result.stderr || "",
} };
} };
export const isFolderExist = (folder: string): boolean => { export const isFolderExist = (folder: string): boolean => {
return shell.test('-d', folder) return shell.test("-d", folder);
} };
export const isFileExist = ( export const isFileExist = (
pathToFileDir: string, pathToFileDir: string,
fileName: string, fileName: string,
fileExtension: string fileExtension: string,
): boolean => { ): boolean => {
return shell.ls(pathToFileDir).stdout.includes(fileName + fileExtension) return shell.ls(pathToFileDir).stdout.includes(fileName + fileExtension);
} };
export const isFileEmpty = (file: string): boolean => { export const isFileEmpty = (file: string): boolean => {
if (fs.existsSync(file)) { if (fs.existsSync(file)) {
return fs.readFileSync(file).length === 0 return fs.readFileSync(file).length === 0;
} }
} };
@@ -1,44 +1,44 @@
import { executeCommand } from '../src/helper' import { executeCommand } from "../src/helper";
import { paths } from '../src/entities' import { paths } from "../src/entities";
//id1746 //id1746
describe('Run with --asm by default', () => { describe("Run with --asm by default", () => {
const command = `resolc ${paths.pathToBasicSolContract} --asm` const command = `resolc ${paths.pathToBasicSolContract} --asm`;
const result = executeCommand(command) const result = executeCommand(command);
const commandInvalid = 'resolc --asm' const commandInvalid = "resolc --asm";
const resultInvalid = executeCommand(commandInvalid) const resultInvalid = executeCommand(commandInvalid);
it('Valid command exit code = 0', () => { it("Valid command exit code = 0", () => {
expect(result.exitCode).toBe(0) expect(result.exitCode).toBe(0);
}) });
it('--asm output is presented', () => { it("--asm output is presented", () => {
const expectedPatterns = [/(deploy)/i, /(call)/i, /(seal_return)/i] const expectedPatterns = [/(deploy)/i, /(call)/i, /(seal_return)/i];
for (const pattern of expectedPatterns) { for (const pattern of expectedPatterns) {
expect(result.output).toMatch(pattern) expect(result.output).toMatch(pattern);
} }
}) });
it('solc exit code == resolc exit code', () => { it("solc exit code == resolc exit code", () => {
const command = `solc ${paths.pathToBasicSolContract} --asm` const command = `solc ${paths.pathToBasicSolContract} --asm`;
const solcResult = executeCommand(command) const solcResult = executeCommand(command);
expect(solcResult.exitCode).toBe(result.exitCode) expect(solcResult.exitCode).toBe(result.exitCode);
}) });
it('run invalid: resolc --asm', () => { it("run invalid: resolc --asm", () => {
expect(resultInvalid.output).toMatch( expect(resultInvalid.output).toMatch(
/(No input sources specified|Compilation aborted)/i /(No input sources specified|Compilation aborted)/i,
) );
}) });
it('Invalid command exit code = 1', () => { it("Invalid command exit code = 1", () => {
expect(resultInvalid.exitCode).toBe(1) expect(resultInvalid.exitCode).toBe(1);
}) });
it('Invalid solc exit code == Invalid resolc exit code', () => { it("Invalid solc exit code == Invalid resolc exit code", () => {
const command = 'solc --asm' const command = "solc --asm";
const solcResult = executeCommand(command) const solcResult = executeCommand(command);
expect(solcResult.exitCode).toBe(resultInvalid.exitCode) expect(solcResult.exitCode).toBe(resultInvalid.exitCode);
}) });
}) });
@@ -3,239 +3,239 @@ import {
isFolderExist, isFolderExist,
isFileExist, isFileExist,
isFileEmpty, isFileEmpty,
} from '../src/helper' } from "../src/helper";
import { paths } from '../src/entities' import { paths } from "../src/entities";
import * as shell from 'shelljs' import * as shell from "shelljs";
import * as path from 'path' import * as path from "path";
//id1762 //id1762
describe('Run resolc without any options', () => { describe("Run resolc without any options", () => {
const command = 'resolc' const command = "resolc";
const result = executeCommand(command) const result = executeCommand(command);
it('Info with help is presented', () => { it("Info with help is presented", () => {
expect(result.output).toMatch(/(Usage: resolc)/i) expect(result.output).toMatch(/(Usage: resolc)/i);
}) });
it('Exit code = 1', () => { it("Exit code = 1", () => {
expect(result.exitCode).toBe(1) expect(result.exitCode).toBe(1);
}) });
it('solc exit code == resolc exit code', () => { it("solc exit code == resolc exit code", () => {
const command = 'solc' const command = "solc";
const solcResult = executeCommand(command) const solcResult = executeCommand(command);
expect(solcResult.exitCode).toBe(result.exitCode) expect(solcResult.exitCode).toBe(result.exitCode);
}) });
}) });
//#1713 //#1713
describe('Default run a command from the help', () => { describe("Default run a command from the help", () => {
const command = `resolc ${paths.pathToBasicSolContract} --overwrite -O3 --bin --output-dir "${paths.pathToOutputDir}"` // potential issue on resolc with full path on Windows cmd const command = `resolc ${paths.pathToBasicSolContract} --overwrite -O3 --bin --output-dir "${paths.pathToOutputDir}"`; // potential issue on resolc with full path on Windows cmd
const result = executeCommand(command) const result = executeCommand(command);
it('Compiler run successful', () => { it("Compiler run successful", () => {
expect(result.output).toMatch(/(Compiler run successful.)/i) expect(result.output).toMatch(/(Compiler run successful.)/i);
}) });
it('Exit code = 0', () => { it("Exit code = 0", () => {
expect(result.exitCode).toBe(0) expect(result.exitCode).toBe(0);
}) });
it('Output dir is created', () => { it("Output dir is created", () => {
expect(isFolderExist(paths.pathToOutputDir)).toBe(true) expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
}) });
xit('Output file is created', () => { xit("Output file is created", () => {
// a bug on windows // a bug on windows
expect( expect(
isFileExist( isFileExist(
paths.pathToOutputDir, paths.pathToOutputDir,
paths.contractSolFilename, paths.contractSolFilename,
paths.binExtension paths.binExtension,
) ),
).toBe(true) ).toBe(true);
}) });
it('the output file is not empty', () => { it("the output file is not empty", () => {
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false) expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
}) });
it("No 'Error'/'Warning'/'Fail' in the output", () => { it("No 'Error'/'Warning'/'Fail' in the output", () => {
expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i) expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i);
}) });
}) });
//#1818 //#1818
describe('Default run a command from the help', () => { describe("Default run a command from the help", () => {
const command = `resolc ${paths.pathToBasicSolContract} --overwrite -O3 --bin --asm --output-dir "${paths.pathToOutputDir}"` // potential issue on resolc with full path on Windows cmd const command = `resolc ${paths.pathToBasicSolContract} --overwrite -O3 --bin --asm --output-dir "${paths.pathToOutputDir}"`; // potential issue on resolc with full path on Windows cmd
const result = executeCommand(command) const result = executeCommand(command);
it('Compiler run successful', () => { it("Compiler run successful", () => {
expect(result.output).toMatch(/(Compiler run successful.)/i) expect(result.output).toMatch(/(Compiler run successful.)/i);
}) });
it('Exit code = 0', () => { it("Exit code = 0", () => {
expect(result.exitCode).toBe(0) expect(result.exitCode).toBe(0);
}) });
it('Output dir is created', () => { it("Output dir is created", () => {
expect(isFolderExist(paths.pathToOutputDir)).toBe(true) expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
}) });
xit('Output files are created', () => { xit("Output files are created", () => {
// a bug on windows // a bug on windows
expect( expect(
isFileExist( isFileExist(
paths.pathToOutputDir, paths.pathToOutputDir,
paths.contractSolFilename, paths.contractSolFilename,
paths.binExtension paths.binExtension,
) ),
).toBe(true) ).toBe(true);
expect( expect(
isFileExist( isFileExist(
paths.pathToOutputDir, paths.pathToOutputDir,
paths.contractSolFilename, paths.contractSolFilename,
paths.asmExtension paths.asmExtension,
) ),
).toBe(true) ).toBe(true);
}) });
it('the output files are not empty', () => { it("the output files are not empty", () => {
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false) expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false) expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false);
}) });
it("No 'Error'/'Warning'/'Fail' in the output", () => { it("No 'Error'/'Warning'/'Fail' in the output", () => {
expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i) expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i);
}) });
}) });
describe('Run resolc with source debug information', () => { describe("Run resolc with source debug information", () => {
const commands = [ const commands = [
`resolc -g ${paths.pathToBasicSolContract} --overwrite --bin --asm --output-dir "${paths.pathToOutputDir}"`, `resolc -g ${paths.pathToBasicSolContract} --overwrite --bin --asm --output-dir "${paths.pathToOutputDir}"`,
`resolc --disable-solc-optimizer -g ${paths.pathToBasicSolContract} --overwrite --bin --asm --output-dir "${paths.pathToOutputDir}"`, `resolc --disable-solc-optimizer -g ${paths.pathToBasicSolContract} --overwrite --bin --asm --output-dir "${paths.pathToOutputDir}"`,
] // potential issue on resolc with full path on Windows cmd`; ]; // potential issue on resolc with full path on Windows cmd`;
for (var idx in commands) { for (var idx in commands) {
const command = commands[idx] const command = commands[idx];
const result = executeCommand(command) const result = executeCommand(command);
it('Compiler run successful', () => { it("Compiler run successful", () => {
expect(result.output).toMatch(/(Compiler run successful.)/i) expect(result.output).toMatch(/(Compiler run successful.)/i);
}) });
it('Exit code = 0', () => { it("Exit code = 0", () => {
expect(result.exitCode).toBe(0) expect(result.exitCode).toBe(0);
}) });
it('Output dir is created', () => { it("Output dir is created", () => {
expect(isFolderExist(paths.pathToOutputDir)).toBe(true) expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
}) });
it('Output files are created', () => { it("Output files are created", () => {
// a bug on windows // a bug on windows
expect( expect(
isFileExist( isFileExist(
paths.pathToOutputDir, paths.pathToOutputDir,
paths.contractSolFilename, paths.contractSolFilename,
paths.binExtension paths.binExtension,
) ),
).toBe(true) ).toBe(true);
expect( expect(
isFileExist( isFileExist(
paths.pathToOutputDir, paths.pathToOutputDir,
paths.contractSolFilename, paths.contractSolFilename,
paths.asmExtension paths.asmExtension,
) ),
).toBe(true) ).toBe(true);
}) });
it('the output files are not empty', () => { it("the output files are not empty", () => {
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false) expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false) expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false);
}) });
it("No 'Error'/'Fail' in the output", () => { it("No 'Error'/'Fail' in the output", () => {
expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i) expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i);
}) });
} }
}) });
describe('Run resolc with source debug information, check LLVM debug-info', () => { describe("Run resolc with source debug information, check LLVM debug-info", () => {
const commands = [ const commands = [
`resolc -g ${paths.pathToBasicSolContract} --overwrite --debug-output-dir="${paths.pathToOutputDir}"`, `resolc -g ${paths.pathToBasicSolContract} --overwrite --debug-output-dir="${paths.pathToOutputDir}"`,
`resolc -g --disable-solc-optimizer ${paths.pathToBasicSolContract} --overwrite --debug-output-dir="${paths.pathToOutputDir}"`, `resolc -g --disable-solc-optimizer ${paths.pathToBasicSolContract} --overwrite --debug-output-dir="${paths.pathToOutputDir}"`,
] // potential issue on resolc with full path on Windows cmd`; ]; // potential issue on resolc with full path on Windows cmd`;
for (var idx in commands) { for (var idx in commands) {
const command = commands[idx] const command = commands[idx];
const result = executeCommand(command) const result = executeCommand(command);
it('Compiler run successful', () => { it("Compiler run successful", () => {
expect(result.output).toMatch(/(Compiler run successful.)/i) expect(result.output).toMatch(/(Compiler run successful.)/i);
}) });
it('Exit code = 0', () => { it("Exit code = 0", () => {
expect(result.exitCode).toBe(0) expect(result.exitCode).toBe(0);
}) });
it('Output dir is created', () => { it("Output dir is created", () => {
expect(isFolderExist(paths.pathToOutputDir)).toBe(true) expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
}) });
it('Output files are created', () => { it("Output files are created", () => {
// a bug on windows // a bug on windows
expect( expect(
isFileExist( isFileExist(
paths.pathToOutputDir, paths.pathToOutputDir,
paths.contractOptimizedLLVMFilename, paths.contractOptimizedLLVMFilename,
paths.llvmExtension paths.llvmExtension,
) ),
).toBe(true) ).toBe(true);
expect( expect(
isFileExist( isFileExist(
paths.pathToOutputDir, paths.pathToOutputDir,
paths.contractUnoptimizedLLVMFilename, paths.contractUnoptimizedLLVMFilename,
paths.llvmExtension paths.llvmExtension,
) ),
).toBe(true) ).toBe(true);
}) });
it('the output files are not empty', () => { it("the output files are not empty", () => {
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false) expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false) expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false);
}) });
it("No 'Error'/'Fail' in the output", () => { it("No 'Error'/'Fail' in the output", () => {
expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i) expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i);
}) });
} }
}) });
describe('Standard JSON compilation with path options', () => { describe("Standard JSON compilation with path options", () => {
const contractsDir = path.join(shell.tempdir(), 'contracts-test') const contractsDir = path.join(shell.tempdir(), "contracts-test");
const inputFile = path.join(__dirname, '..', 'src/contracts/compiled/1.json') const inputFile = path.join(__dirname, "..", "src/contracts/compiled/1.json");
beforeAll(() => { beforeAll(() => {
shell.mkdir('-p', contractsDir) shell.mkdir("-p", contractsDir);
const input = JSON.parse(shell.cat(inputFile).toString()) const input = JSON.parse(shell.cat(inputFile).toString());
Object.entries(input.sources).forEach( Object.entries(input.sources).forEach(
([sourcePath, source]: [string, any]) => { ([sourcePath, source]: [string, any]) => {
const filePath = path.join(contractsDir, sourcePath) const filePath = path.join(contractsDir, sourcePath);
shell.mkdir('-p', path.dirname(filePath)) shell.mkdir("-p", path.dirname(filePath));
shell.ShellString(source.content).to(filePath) shell.ShellString(source.content).to(filePath);
} },
) );
}) });
afterAll(() => { afterAll(() => {
shell.rm('-rf', contractsDir) shell.rm("-rf", contractsDir);
}) });
describe('Output with all path options', () => { describe("Output with all path options", () => {
let result: { exitCode: number; output: string } let result: { exitCode: number; output: string };
beforeAll(() => { beforeAll(() => {
const tempInputFile = path.join(contractsDir, 'temp-input.json') const tempInputFile = path.join(contractsDir, "temp-input.json");
shell.cp(inputFile, tempInputFile) shell.cp(inputFile, tempInputFile);
const inputContent = shell.cat(inputFile).toString() const inputContent = shell.cat(inputFile).toString();
const command = `resolc --standard-json --base-path "${contractsDir}" --include-path "${contractsDir}" --allow-paths "${contractsDir}"` const command = `resolc --standard-json --base-path "${contractsDir}" --include-path "${contractsDir}" --allow-paths "${contractsDir}"`;
result = executeCommand(command, inputContent) result = executeCommand(command, inputContent);
shell.rm(tempInputFile) shell.rm(tempInputFile);
}) });
it('Compiler run successful without emiting warnings', () => { it("Compiler run successful without emiting warnings", () => {
const parsedResults = JSON.parse(result.output) const parsedResults = JSON.parse(result.output);
expect( expect(
parsedResults.errors.filter( parsedResults.errors.filter(
(error: { type: string }) => error.type != 'Warning' (error: { type: string }) => error.type != "Warning",
) ),
).toEqual([]) ).toEqual([]);
}) });
}) });
}) });
@@ -1,39 +1,39 @@
import { executeCommand } from '../src/helper' import { executeCommand } from "../src/helper";
import { paths } from '../src/entities' import { paths } from "../src/entities";
//id1743 //id1743
describe('Run with --yul by default', () => { describe("Run with --yul by default", () => {
const command = `resolc ${paths.pathToBasicYulContract} --yul` const command = `resolc ${paths.pathToBasicYulContract} --yul`;
const result = executeCommand(command) const result = executeCommand(command);
const commandInvalid = 'resolc --yul' const commandInvalid = "resolc --yul";
const resultInvalid = executeCommand(commandInvalid) const resultInvalid = executeCommand(commandInvalid);
it('Valid command exit code = 0', () => { it("Valid command exit code = 0", () => {
expect(result.exitCode).toBe(0) expect(result.exitCode).toBe(0);
}) });
it('--yul output is presented', () => { it("--yul output is presented", () => {
expect(result.output).toMatch(/(Compiler run successful)/i) expect(result.output).toMatch(/(Compiler run successful)/i);
expect(result.output).toMatch(/(No output requested)/i) expect(result.output).toMatch(/(No output requested)/i);
}) });
xit('solc exit code == resolc exit code', () => { xit("solc exit code == resolc exit code", () => {
// unknown solc issue for datatype of the contract // unknown solc issue for datatype of the contract
const command = `solc ${paths.pathToBasicSolContract} --yul` const command = `solc ${paths.pathToBasicSolContract} --yul`;
const solcResult = executeCommand(command) const solcResult = executeCommand(command);
expect(solcResult.exitCode).toBe(result.exitCode) expect(solcResult.exitCode).toBe(result.exitCode);
}) });
it('run invalid: resolc --yul', () => { it("run invalid: resolc --yul", () => {
expect(resultInvalid.output).toMatch(/(The input file is missing)/i) expect(resultInvalid.output).toMatch(/(The input file is missing)/i);
}) });
it('Invalid command exit code = 1', () => { it("Invalid command exit code = 1", () => {
expect(resultInvalid.exitCode).toBe(1) expect(resultInvalid.exitCode).toBe(1);
}) });
it('Invalid solc exit code == Invalid resolc exit code', () => { it("Invalid solc exit code == Invalid resolc exit code", () => {
const command = 'solc --yul' const command = "solc --yul";
const solcResult = executeCommand(command) const solcResult = executeCommand(command);
expect(solcResult.exitCode).toBe(resultInvalid.exitCode) expect(solcResult.exitCode).toBe(resultInvalid.exitCode);
}) });
}) });
@@ -2,6 +2,6 @@
"compilerOptions": { "compilerOptions": {
"target": "ES6", "target": "ES6",
"module": "CommonJS", "module": "CommonJS",
"outDir": "./dist", "outDir": "./dist"
} }
} }
+104 -100
View File
@@ -1,9 +1,9 @@
import { executeCommand } from '../src/helper' import { executeCommand } from "../src/helper";
import { paths } from '../src/entities' import { paths } from "../src/entities";
describe('Set of --combined-json tests', () => { describe("Set of --combined-json tests", () => {
const zksolcCommand = 'zksolc' const zksolcCommand = "zksolc";
const solcCommand = 'solc' const solcCommand = "solc";
const json_args: string[] = [ const json_args: string[] = [
`abi`, `abi`,
`hashes`, `hashes`,
@@ -15,45 +15,49 @@ describe('Set of --combined-json tests', () => {
`asm`, `asm`,
`bin`, `bin`,
`bin-runtime`, `bin-runtime`,
] ];
//id1742:I //id1742:I
describe(`Run ${zksolcCommand} with just --combined-json`, () => { describe(`Run ${zksolcCommand} with just --combined-json`, () => {
const args = [`--combined-json`] const args = [`--combined-json`];
const result = executeCommand(zksolcCommand, args) const result = executeCommand(zksolcCommand, args);
it('Valid command exit code = 1', () => { it("Valid command exit code = 1", () => {
expect(result.exitCode).toBe(1) expect(result.exitCode).toBe(1);
}) });
it('--combined-json error is presented', () => { it("--combined-json error is presented", () => {
expect(result.output).toMatch(/(requires a value but none was supplied)/i) expect(result.output).toMatch(
}) /(requires a value but none was supplied)/i,
);
});
it('solc exit code == zksolc exit code', () => { it("solc exit code == zksolc exit code", () => {
const solcResult = executeCommand(solcCommand, args) const solcResult = executeCommand(solcCommand, args);
expect(solcResult.exitCode).toBe(result.exitCode) expect(solcResult.exitCode).toBe(result.exitCode);
}) });
}) });
//id1742:II //id1742:II
describe(`Run ${zksolcCommand} with Sol contract and --combined-json`, () => { describe(`Run ${zksolcCommand} with Sol contract and --combined-json`, () => {
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`] const args = [`${paths.pathToBasicSolContract}`, `--combined-json`];
const result = executeCommand(zksolcCommand, args) const result = executeCommand(zksolcCommand, args);
it('Valid command exit code = 1', () => { it("Valid command exit code = 1", () => {
expect(result.exitCode).toBe(1) expect(result.exitCode).toBe(1);
}) });
it('--combined-json error is presented', () => { it("--combined-json error is presented", () => {
expect(result.output).toMatch(/(requires a value but none was supplied)/i) expect(result.output).toMatch(
}) /(requires a value but none was supplied)/i,
);
});
it('solc exit code == zksolc exit code', () => { it("solc exit code == zksolc exit code", () => {
const solcResult = executeCommand(solcCommand, args) const solcResult = executeCommand(solcCommand, args);
expect(solcResult.exitCode).toBe(result.exitCode) expect(solcResult.exitCode).toBe(result.exitCode);
}) });
}) });
//id1742:III //id1742:III
for (let i = 0; i < json_args.length; i++) { for (let i = 0; i < json_args.length; i++) {
@@ -62,22 +66,22 @@ describe('Set of --combined-json tests', () => {
`${paths.pathToBasicSolContract}`, `${paths.pathToBasicSolContract}`,
`--combined-json`, `--combined-json`,
`${json_args[i]}`, `${json_args[i]}`,
] ];
const result = executeCommand(zksolcCommand, args) const result = executeCommand(zksolcCommand, args);
it('Valid command exit code = 0', () => { it("Valid command exit code = 0", () => {
expect(result.exitCode).toBe(0) expect(result.exitCode).toBe(0);
}) });
it('--combined-json error is presented', () => { it("--combined-json error is presented", () => {
expect(result.output).toMatch(/(contracts)/i) expect(result.output).toMatch(/(contracts)/i);
}) });
it('solc exit code == zksolc exit code', () => { it("solc exit code == zksolc exit code", () => {
const solcResult = executeCommand(solcCommand, args) const solcResult = executeCommand(solcCommand, args);
expect(solcResult.exitCode).toBe(result.exitCode) expect(solcResult.exitCode).toBe(result.exitCode);
}) });
}) });
} }
//id1829:I //id1829:I
@@ -87,22 +91,22 @@ describe('Set of --combined-json tests', () => {
`${paths.pathToBasicSolContract}`, `${paths.pathToBasicSolContract}`,
`--combined-json`, `--combined-json`,
`--${json_args[i]}`, `--${json_args[i]}`,
] ];
const result = executeCommand(zksolcCommand, args) const result = executeCommand(zksolcCommand, args);
it('Valid command exit code = 1', () => { it("Valid command exit code = 1", () => {
expect(result.exitCode).toBe(1) expect(result.exitCode).toBe(1);
}) });
it('--combined-json error is presented', () => { it("--combined-json error is presented", () => {
expect(result.output).toMatch(/(Invalid option|error)/i) expect(result.output).toMatch(/(Invalid option|error)/i);
}) });
it('solc exit code == zksolc exit code', () => { it("solc exit code == zksolc exit code", () => {
const solcResult = executeCommand(solcCommand, args) const solcResult = executeCommand(solcCommand, args);
expect(solcResult.exitCode).toBe(result.exitCode) expect(solcResult.exitCode).toBe(result.exitCode);
}) });
}) });
} }
//id1829:II //id1829:II
@@ -113,24 +117,24 @@ describe('Set of --combined-json tests', () => {
`--combined-json`, `--combined-json`,
`${json_args[i]}`, `${json_args[i]}`,
`${json_args[i]}`, `${json_args[i]}`,
] ];
const result = executeCommand(zksolcCommand, args) const result = executeCommand(zksolcCommand, args);
xit('Valid command exit code = 1', () => { xit("Valid command exit code = 1", () => {
expect(result.exitCode).toBe(1) expect(result.exitCode).toBe(1);
}) });
it('--combined-json error is presented', () => { it("--combined-json error is presented", () => {
expect(result.output).toMatch( expect(result.output).toMatch(
/(No such file or directory|cannot find the file specified)/i /(No such file or directory|cannot find the file specified)/i,
) // Hopefully we should have more precise message here! ); // Hopefully we should have more precise message here!
}) });
xit('solc exit code == zksolc exit code', () => { xit("solc exit code == zksolc exit code", () => {
const solcResult = executeCommand(solcCommand, args) const solcResult = executeCommand(solcCommand, args);
expect(solcResult.exitCode).toBe(result.exitCode) expect(solcResult.exitCode).toBe(result.exitCode);
}) });
}) });
} }
//id1829:III //id1829:III
@@ -142,22 +146,22 @@ describe('Set of --combined-json tests', () => {
`${json_args[i]}`, `${json_args[i]}`,
`--combined-json`, `--combined-json`,
`${json_args[i]}`, `${json_args[i]}`,
] ];
const result = executeCommand(zksolcCommand, args) const result = executeCommand(zksolcCommand, args);
it('Valid command exit code = 1', () => { it("Valid command exit code = 1", () => {
expect(result.exitCode).toBe(1) expect(result.exitCode).toBe(1);
}) });
it('--combined-json error is presented', () => { it("--combined-json error is presented", () => {
expect(result.output).toMatch(/(cannot be used multiple times)/i) expect(result.output).toMatch(/(cannot be used multiple times)/i);
}) });
it('solc exit code == zksolc exit code', () => { it("solc exit code == zksolc exit code", () => {
const solcResult = executeCommand(solcCommand, args) const solcResult = executeCommand(solcCommand, args);
expect(solcResult.exitCode).toBe(result.exitCode) expect(solcResult.exitCode).toBe(result.exitCode);
}) });
}) });
} }
//id1830 //id1830
@@ -167,22 +171,22 @@ describe('Set of --combined-json tests', () => {
`${paths.pathToBasicYulContract}`, `${paths.pathToBasicYulContract}`,
`--combined-json`, `--combined-json`,
`${json_args[i]}`, `${json_args[i]}`,
] ];
const result = executeCommand(zksolcCommand, args) const result = executeCommand(zksolcCommand, args);
it('Valid command exit code = 1', () => { it("Valid command exit code = 1", () => {
expect(result.exitCode).toBe(1) expect(result.exitCode).toBe(1);
}) });
it('--combined-json error is presented', () => { it("--combined-json error is presented", () => {
expect(result.output).toMatch(/(ParserError: Expected identifier)/i) expect(result.output).toMatch(/(ParserError: Expected identifier)/i);
}) });
asd asd;
it('solc exit code == zksolc exit code', () => { it("solc exit code == zksolc exit code", () => {
const solcResult = executeCommand(solcCommand, args) const solcResult = executeCommand(solcCommand, args);
expect(solcResult.exitCode).toBe(result.exitCode) expect(solcResult.exitCode).toBe(result.exitCode);
}) });
}) });
} }
}) });
-1
View File
@@ -1 +0,0 @@
../../../../target/wasm32-unknown-emscripten/release/resolc.wasm
-1
View File
@@ -1 +0,0 @@
../../../../target/wasm32-unknown-emscripten/release/resolc_web.js
-138
View File
@@ -1,138 +0,0 @@
import { expect } from 'chai'
import { compile } from '../examples/node/revive.js'
import { fileURLToPath } from 'url'
import path from 'path'
import fs from 'fs'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
function loadFixture(fixture) {
const fixturePath = path.resolve(__dirname, `../fixtures/${fixture}`)
return JSON.parse(fs.readFileSync(fixturePath, 'utf-8'))
}
describe('Compile Function Tests', function () {
it('should successfully compile valid Solidity code', async function () {
const standardInput = loadFixture('storage.json')
const result = await compile(standardInput)
expect(result).to.be.a('string')
const output = JSON.parse(result)
expect(output).to.have.property('contracts')
expect(output.contracts['fixtures/storage.sol']).to.have.property('Storage')
expect(output.contracts['fixtures/storage.sol'].Storage).to.have.property(
'abi'
)
expect(output.contracts['fixtures/storage.sol'].Storage).to.have.property(
'evm'
)
expect(
output.contracts['fixtures/storage.sol'].Storage.evm
).to.have.property('bytecode')
})
if (typeof globalThis.Bun == 'undefined') {
// Running this test with Bun on a Linux host causes:
// RuntimeError: Out of bounds memory access (evaluating 'getWasmTableEntry(index)(a1, a2, a3, a4, a5)')
// Once this issue is resolved, the test will be re-enabled.
it('should successfully compile large Solidity code', async function () {
const standardInput = loadFixture('token.json')
const result = await compile(standardInput)
expect(result).to.be.a('string')
const output = JSON.parse(result)
expect(output).to.have.property('contracts')
expect(output.contracts['fixtures/token.sol']).to.have.property('MyToken')
expect(output.contracts['fixtures/token.sol'].MyToken).to.have.property(
'abi'
)
expect(output.contracts['fixtures/token.sol'].MyToken).to.have.property(
'evm'
)
expect(
output.contracts['fixtures/token.sol'].MyToken.evm
).to.have.property('bytecode')
})
it('should successfully compile a valid Solidity contract that instantiates the token contracts', async function () {
const standardInput = loadFixture('instantiate_tokens.json')
const result = await compile(standardInput)
expect(result).to.be.a('string')
const output = JSON.parse(result)
expect(output).to.have.property('contracts')
expect(
output.contracts['fixtures/instantiate_tokens.sol']
).to.have.property('TokensFactory')
expect(
output.contracts['fixtures/instantiate_tokens.sol'].TokensFactory
).to.have.property('abi')
expect(
output.contracts['fixtures/instantiate_tokens.sol'].TokensFactory
).to.have.property('evm')
expect(
output.contracts['fixtures/instantiate_tokens.sol'].TokensFactory.evm
).to.have.property('bytecode')
})
}
it('should throw an error for invalid Solidity code', async function () {
const standardInput = loadFixture('invalid_contract_content.json')
const result = await compile(standardInput)
expect(result).to.be.a('string')
const output = JSON.parse(result)
expect(output).to.have.property('errors')
expect(output.errors).to.be.an('array')
expect(output.errors.length).to.be.greaterThan(0)
expect(output.errors[0].type).to.exist
expect(output.errors[0].type).to.contain('ParserError')
})
it('should return not found error for missing imports', async function () {
const standardInput = loadFixture('missing_import.json')
const result = await compile(standardInput)
const output = JSON.parse(result)
expect(output).to.have.property('errors')
expect(output.errors).to.be.an('array')
expect(output.errors.length).to.be.greaterThan(0)
expect(output.errors[0].message).to.exist
expect(output.errors[0].message).to.include(
'Source "nonexistent/console.sol" not found'
)
})
it('should successfully compile a valid Solidity contract that instantiates another contract', async function () {
const standardInput = loadFixture('instantiate.json')
const result = await compile(standardInput)
expect(result).to.be.a('string')
const output = JSON.parse(result)
expect(output).to.have.property('contracts')
expect(output.contracts['fixtures/instantiate.sol']).to.have.property(
'ChildContract'
)
expect(
output.contracts['fixtures/instantiate.sol'].ChildContract
).to.have.property('abi')
expect(
output.contracts['fixtures/instantiate.sol'].ChildContract
).to.have.property('evm')
expect(
output.contracts['fixtures/instantiate.sol'].ChildContract.evm
).to.have.property('bytecode')
expect(output.contracts['fixtures/instantiate.sol']).to.have.property(
'MainContract'
)
expect(
output.contracts['fixtures/instantiate.sol'].MainContract
).to.have.property('abi')
expect(
output.contracts['fixtures/instantiate.sol'].MainContract
).to.have.property('evm')
expect(
output.contracts['fixtures/instantiate.sol'].MainContract.evm
).to.have.property('bytecode')
})
})
+6
View File
@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": false,
"singleQuote": true
}
+5 -2
View File
@@ -1,7 +1,10 @@
# @parity/revive
Node.js module to compile Solidity contracts to Polkavm bytecode, using [Revive](https://github.com/paritytech/revive)
# Usage from Node.js # Usage from Node.js
```typescript ```typescript
import { compile } from "@parity/resolc";
const sources = { const sources = {
["contracts/1_Storage.sol"]: { ["contracts/1_Storage.sol"]: {
content: readFileSync("fixtures/storage.sol", "utf8"), content: readFileSync("fixtures/storage.sol", "utf8"),
@@ -13,5 +16,5 @@ const out = await compile(sources);
# Usage from shell # Usage from shell
```bash ```bash
npx @parity/resolc@latest --bin contracts/1_Storage.sol npx @parity/revive@latest --bin contracts/1_Storage.sol
``` ```
+8 -4
View File
@@ -24,14 +24,18 @@
"test": "npm run build && node ./dist/index.test.js" "test": "npm run build && node ./dist/index.test.js"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.14.0",
"@openzeppelin/contracts": "5.1.0", "@openzeppelin/contracts": "5.1.0",
"@types/node": "^22.14.1",
"eslint": "^9.14.0",
"globals": "^15.12.0", "globals": "^15.12.0",
"typescript": "^5.6.3" "typescript": "^5.6.3",
"typescript-eslint": "^8.13.0"
}, },
"dependencies": { "dependencies": {
"@types/node": "^22.9.0",
"commander": "^13.1.0", "commander": "^13.1.0",
"package-json": "^10.0.1", "package-json": "^10.0.1",
"solc": ">=0.8.0 <=0.8.30" "solc": "^0.8.29"
} },
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
} }
+5 -2
View File
@@ -169,7 +169,8 @@ async function main() {
writeFile( writeFile(
contractFileName + '.polkavm', contractFileName + '.polkavm',
Buffer.from( Buffer.from(
output.contracts[fileName][contractName].evm.bytecode.object, output.contracts[fileName][contractName].evm.bytecode
.object,
'hex' 'hex'
) )
) )
@@ -178,7 +179,9 @@ async function main() {
if (options.abi) { if (options.abi) {
writeFile( writeFile(
contractFileName + '.abi', contractFileName + '.abi',
toFormattedJson(output.contracts[fileName][contractName].abi) toFormattedJson(
output.contracts[fileName][contractName].abi
)
) )
} }
} }
+28 -12
View File
@@ -1,12 +1,22 @@
import { test } from 'node:test' import { test } from 'node:test'
import { readFileSync, existsSync } from 'node:fs' import { readFileSync } from 'node:fs'
import assert from 'node:assert' import assert from 'node:assert'
import { compile, tryResolveImport } from '.' import { compile, tryResolveImport } from '.'
import { resolve } from 'node:path' import { resolve } from 'node:path'
import { execSync } from 'node:child_process'
function isResolcInPath() {
try {
execSync('resolc --version', { stdio: 'ignore' })
return true
} catch {
return false
}
}
const compileOptions = [{}] const compileOptions = [{}]
if (existsSync('../../target/release/resolc')) { if (isResolcInPath()) {
compileOptions.push({ bin: '../../target/release/resolc' }) compileOptions.push({ bin: 'resolc' })
} }
for (const options of compileOptions) { for (const options of compileOptions) {
@@ -56,7 +66,9 @@ test('check Err from stderr', async () => {
assert(false, 'Expected error') assert(false, 'Expected error')
} catch (error) { } catch (error) {
assert( assert(
String(error).includes('Source file requires different compiler version') String(error).includes(
'Source file requires different compiler version'
)
) )
} }
}) })
@@ -71,15 +83,15 @@ test('resolve import', () => {
// scopped module with version // scopped module with version
{ {
file: '@openzeppelin/contracts@5.1.0/token/ERC20/ERC20.sol', file: '@openzeppelin/contracts@5.1.0/token/ERC20/ERC20.sol',
expected: require.resolve( expected: resolve(
'@openzeppelin/contracts/token/ERC20/ERC20.sol' 'node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol'
), ),
}, },
// scopped module without version // scopped module without version
{ {
file: '@openzeppelin/contracts/token/ERC20/ERC20.sol', file: '@openzeppelin/contracts/token/ERC20/ERC20.sol',
expected: require.resolve( expected: resolve(
'@openzeppelin/contracts/token/ERC20/ERC20.sol' 'node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol'
), ),
}, },
// scopped module with wrong version // scopped module with wrong version
@@ -89,13 +101,17 @@ test('resolve import', () => {
}, },
// module without version // module without version
{ {
file: '@openzeppelin/contracts/package.json', file: 'acorn/package.json',
expected: require.resolve('@openzeppelin/contracts/package.json'), expected: resolve('node_modules/acorn/package.json'),
}, },
// scopped module with version // scopped module with version
{ {
file: '@openzeppelin/contracts@5.1.0/package.json', file: 'acorn@8.14.0/package.json',
expected: require.resolve('@openzeppelin/contracts/package.json'), expected: resolve('node_modules/acorn/package.json'),
},
{
file: 'acorn@8.14.1/package.json',
expected: `Error: Version mismatch: Specified acorn@8.14.1, but installed version is 8.14.0`,
}, },
] ]
+3 -1
View File
@@ -138,7 +138,9 @@ export function tryResolveImport(importPath: string) {
let packageJsonPath let packageJsonPath
try { try {
packageJsonPath = require.resolve(path.join(basePackage, 'package.json')) packageJsonPath = require.resolve(
path.join(basePackage, 'package.json')
)
} catch { } catch {
throw new Error(`Could not resolve package ${basePackage}`) throw new Error(`Could not resolve package ${basePackage}`)
} }
+1 -1
View File
@@ -17,7 +17,7 @@
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"useUnknownInCatchVariables": true, "useUnknownInCatchVariables": true,
"types": ["node"], "types": ["node"],
"typeRoots": ["../../node_modules/@types", "./src"], "typeRoots": ["./node_modules/@types", "./src"],
"paths": { "paths": {
"#src/*": ["./src/*"] "#src/*": ["./src/*"]
}, },
+1 -1
View File
@@ -3,7 +3,7 @@ const path = require("path");
const { minify } = require("terser"); const { minify } = require("terser");
const SOLJSON_URI = const SOLJSON_URI =
"https://binaries.soliditylang.org/wasm/soljson-v0.8.30+commit.73712a01.js"; "https://binaries.soliditylang.org/wasm/soljson-v0.8.29+commit.ab55807c.js";
const RESOLC_WASM_URI = const RESOLC_WASM_URI =
process.env.RELEASE_RESOLC_WASM_URI || "http://127.0.0.1:8080/resolc.wasm"; process.env.RELEASE_RESOLC_WASM_URI || "http://127.0.0.1:8080/resolc.wasm";
const RESOLC_WASM_TARGET_DIR = path.join( const RESOLC_WASM_TARGET_DIR = path.join(
+1
View File
@@ -0,0 +1 @@
../../../target/wasm32-unknown-emscripten/release/resolc.wasm
+1
View File
@@ -0,0 +1 @@
../../../target/wasm32-unknown-emscripten/release/resolc_web.js
@@ -2,7 +2,7 @@
"name": "revive", "name": "revive",
"private": true, "private": true,
"dependencies": { "dependencies": {
"solc": ">=0.8.0 <=0.8.30" "solc": "^0.8.29"
}, },
"scripts": { "scripts": {
"example:web": "http-server ./examples/web/", "example:web": "http-server ./examples/web/",
+142
View File
@@ -0,0 +1,142 @@
import { expect } from "chai";
import { compile } from "../examples/node/revive.js";
import { fileURLToPath } from "url";
import path from "path";
import fs from "fs";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
function loadFixture(fixture) {
const fixturePath = path.resolve(__dirname, `../fixtures/${fixture}`);
return JSON.parse(fs.readFileSync(fixturePath, "utf-8"));
}
describe("Compile Function Tests", function () {
it("should successfully compile valid Solidity code", async function () {
const standardInput = loadFixture("storage.json");
const result = await compile(standardInput);
expect(result).to.be.a("string");
const output = JSON.parse(result);
expect(output).to.have.property("contracts");
expect(output.contracts["fixtures/storage.sol"]).to.have.property(
"Storage",
);
expect(output.contracts["fixtures/storage.sol"].Storage).to.have.property(
"abi",
);
expect(output.contracts["fixtures/storage.sol"].Storage).to.have.property(
"evm",
);
expect(
output.contracts["fixtures/storage.sol"].Storage.evm,
).to.have.property("bytecode");
});
if (typeof globalThis.Bun == "undefined") {
// Running this test with Bun on a Linux host causes:
// RuntimeError: Out of bounds memory access (evaluating 'getWasmTableEntry(index)(a1, a2, a3, a4, a5)')
// Once this issue is resolved, the test will be re-enabled.
it("should successfully compile large Solidity code", async function () {
const standardInput = loadFixture("token.json");
const result = await compile(standardInput);
expect(result).to.be.a("string");
const output = JSON.parse(result);
expect(output).to.have.property("contracts");
expect(output.contracts["fixtures/token.sol"]).to.have.property(
"MyToken",
);
expect(output.contracts["fixtures/token.sol"].MyToken).to.have.property(
"abi",
);
expect(output.contracts["fixtures/token.sol"].MyToken).to.have.property(
"evm",
);
expect(
output.contracts["fixtures/token.sol"].MyToken.evm,
).to.have.property("bytecode");
});
it("should successfully compile a valid Solidity contract that instantiates the token contracts", async function () {
const standardInput = loadFixture("instantiate_tokens.json");
const result = await compile(standardInput);
expect(result).to.be.a("string");
const output = JSON.parse(result);
expect(output).to.have.property("contracts");
expect(
output.contracts["fixtures/instantiate_tokens.sol"],
).to.have.property("TokensFactory");
expect(
output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory,
).to.have.property("abi");
expect(
output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory,
).to.have.property("evm");
expect(
output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory.evm,
).to.have.property("bytecode");
});
}
it("should throw an error for invalid Solidity code", async function () {
const standardInput = loadFixture("invalid_contract_content.json");
const result = await compile(standardInput);
expect(result).to.be.a("string");
const output = JSON.parse(result);
expect(output).to.have.property("errors");
expect(output.errors).to.be.an("array");
expect(output.errors.length).to.be.greaterThan(0);
expect(output.errors[0].type).to.exist;
expect(output.errors[0].type).to.contain("ParserError");
});
it("should return not found error for missing imports", async function () {
const standardInput = loadFixture("missing_import.json");
const result = await compile(standardInput);
const output = JSON.parse(result);
expect(output).to.have.property("errors");
expect(output.errors).to.be.an("array");
expect(output.errors.length).to.be.greaterThan(0);
expect(output.errors[0].message).to.exist;
expect(output.errors[0].message).to.include(
'Source "nonexistent/console.sol" not found',
);
});
it("should successfully compile a valid Solidity contract that instantiates another contract", async function () {
const standardInput = loadFixture("instantiate.json");
const result = await compile(standardInput);
expect(result).to.be.a("string");
const output = JSON.parse(result);
expect(output).to.have.property("contracts");
expect(output.contracts["fixtures/instantiate.sol"]).to.have.property(
"ChildContract",
);
expect(
output.contracts["fixtures/instantiate.sol"].ChildContract,
).to.have.property("abi");
expect(
output.contracts["fixtures/instantiate.sol"].ChildContract,
).to.have.property("evm");
expect(
output.contracts["fixtures/instantiate.sol"].ChildContract.evm,
).to.have.property("bytecode");
expect(output.contracts["fixtures/instantiate.sol"]).to.have.property(
"MainContract",
);
expect(
output.contracts["fixtures/instantiate.sol"].MainContract,
).to.have.property("abi");
expect(
output.contracts["fixtures/instantiate.sol"].MainContract,
).to.have.property("evm");
expect(
output.contracts["fixtures/instantiate.sol"].MainContract.evm,
).to.have.property("bytecode");
});
});
-6618
View File
File diff suppressed because it is too large Load Diff
+6 -11
View File
@@ -3,19 +3,14 @@
"private": true, "private": true,
"scripts": { "scripts": {
"test:cli": "npm run test -w crates/solidity/src/tests/cli-tests", "test:cli": "npm run test -w crates/solidity/src/tests/cli-tests",
"test:wasm": "npm run test:node -w js/emscripten", "test:wasm": "npm run test:node -w js/wasm",
"build:package": "npm run build:package -w js/emscripten", "build:package": "npm run build:package -w js/wasm",
"lint": "npx eslint 'js/**/*.{cjs,mjs,ts}' && npx prettier --check '**/*.{mjs,cjs,ts}'", "lint": "npx eslint 'js/**/*.{cjs,mjs,ts}' && npx prettier --check '**/*.{ts,json,yml,md}'",
"lint:fix": "npx prettier --write '**/*.{mjs,cjs,ts}'" "lint:fix": "npx prettier --write '**/*.{mjs,cjs,ts,json,yml,md}'"
}, },
"workspaces": [ "workspaces": [
"crates/solidity/src/tests/cli-tests", "crates/solidity/src/tests/cli-tests",
"js/emscripten", "js/wasm",
"js/resolc" "js/resolc"
], ]
"dependencies": {
"@eslint/js": "^9.14.0",
"eslint": "^9.14.0",
"typescript-eslint": "^8.13.0"
}
} }
+3635
View File
File diff suppressed because it is too large Load Diff