mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-24 18:18:02 +00:00
lint
This commit is contained in:
@@ -1,19 +1,18 @@
|
||||
name: "Get Emscripten SDK"
|
||||
inputs:
|
||||
version:
|
||||
description: ""
|
||||
required: false
|
||||
default: "3.1.64"
|
||||
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: install emsdk
|
||||
shell: bash
|
||||
run: |
|
||||
git clone https://github.com/emscripten-core/emsdk.git ./emsdk/
|
||||
cd emsdk
|
||||
git checkout tags/${{ inputs.version }}
|
||||
./emsdk install ${{ inputs.version }}
|
||||
./emsdk activate ${{ inputs.version }}
|
||||
name: "Get Emscripten SDK"
|
||||
inputs:
|
||||
version:
|
||||
description: ""
|
||||
required: false
|
||||
default: "3.1.64"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: install emsdk
|
||||
shell: bash
|
||||
run: |
|
||||
git clone https://github.com/emscripten-core/emsdk.git ./emsdk/
|
||||
cd emsdk
|
||||
git checkout tags/${{ inputs.version }}
|
||||
./emsdk install ${{ inputs.version }}
|
||||
./emsdk activate ${{ inputs.version }}
|
||||
|
||||
@@ -1,70 +1,70 @@
|
||||
# example:
|
||||
# - uses: ./.github/actions/get-llvm
|
||||
# with:
|
||||
# target: x86_64-unknown-linux-gnu
|
||||
|
||||
name: "Download LLVM"
|
||||
inputs:
|
||||
target:
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: find asset
|
||||
id: find
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
target: ${{ inputs.target }}
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
let page = 1;
|
||||
let releases = [];
|
||||
|
||||
let releasePrefix = "llvm-"
|
||||
let target = process.env.target
|
||||
|
||||
do {
|
||||
const res = await github.rest.repos.listReleases({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
per_page: 50,
|
||||
page,
|
||||
});
|
||||
|
||||
releases = res.data
|
||||
releases.sort((a, b) => {
|
||||
return (a.published_at < b.published_at) ? 1 : ((a.published_at > b.published_at) ? -1 : 0);
|
||||
});
|
||||
|
||||
let llvmLatestRelease = releases.find(release => {
|
||||
return release.tag_name.startsWith(releasePrefix);
|
||||
});
|
||||
if (llvmLatestRelease){
|
||||
let asset = llvmLatestRelease.assets.find(asset =>{
|
||||
return asset.name.includes(target);
|
||||
});
|
||||
if (!asset){
|
||||
core.setFailed(`Artifact for '${target}' not found in release ${llvmLatestRelease.tag_name} (${llvmLatestRelease.html_url})`);
|
||||
process.exit();
|
||||
}
|
||||
return asset.browser_download_url;
|
||||
}
|
||||
|
||||
page++;
|
||||
} while(releases.length > 0);
|
||||
|
||||
core.setFailed(`No LLVM releases with '${releasePrefix}' atifacts found! Please release LLVM before running this workflow.`);
|
||||
process.exit();
|
||||
|
||||
- name: download
|
||||
shell: bash
|
||||
run: |
|
||||
curl -sSLo llvm.tar.gz ${{ steps.find.outputs.result }}
|
||||
|
||||
- name: unpack
|
||||
shell: bash
|
||||
run: |
|
||||
tar -xf llvm.tar.gz
|
||||
rm llvm.tar.gz
|
||||
# example:
|
||||
# - uses: ./.github/actions/get-llvm
|
||||
# with:
|
||||
# target: x86_64-unknown-linux-gnu
|
||||
|
||||
name: "Download LLVM"
|
||||
inputs:
|
||||
target:
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: find asset
|
||||
id: find
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
target: ${{ inputs.target }}
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
let page = 1;
|
||||
let releases = [];
|
||||
|
||||
let releasePrefix = "llvm-"
|
||||
let target = process.env.target
|
||||
|
||||
do {
|
||||
const res = await github.rest.repos.listReleases({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
per_page: 50,
|
||||
page,
|
||||
});
|
||||
|
||||
releases = res.data
|
||||
releases.sort((a, b) => {
|
||||
return (a.published_at < b.published_at) ? 1 : ((a.published_at > b.published_at) ? -1 : 0);
|
||||
});
|
||||
|
||||
let llvmLatestRelease = releases.find(release => {
|
||||
return release.tag_name.startsWith(releasePrefix);
|
||||
});
|
||||
if (llvmLatestRelease){
|
||||
let asset = llvmLatestRelease.assets.find(asset =>{
|
||||
return asset.name.includes(target);
|
||||
});
|
||||
if (!asset){
|
||||
core.setFailed(`Artifact for '${target}' not found in release ${llvmLatestRelease.tag_name} (${llvmLatestRelease.html_url})`);
|
||||
process.exit();
|
||||
}
|
||||
return asset.browser_download_url;
|
||||
}
|
||||
|
||||
page++;
|
||||
} while(releases.length > 0);
|
||||
|
||||
core.setFailed(`No LLVM releases with '${releasePrefix}' atifacts found! Please release LLVM before running this workflow.`);
|
||||
process.exit();
|
||||
|
||||
- name: download
|
||||
shell: bash
|
||||
run: |
|
||||
curl -sSLo llvm.tar.gz ${{ steps.find.outputs.result }}
|
||||
|
||||
- name: unpack
|
||||
shell: bash
|
||||
run: |
|
||||
tar -xf llvm.tar.gz
|
||||
rm llvm.tar.gz
|
||||
|
||||
@@ -37,7 +37,15 @@ jobs:
|
||||
build:
|
||||
strategy:
|
||||
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:
|
||||
- target: x86_64-unknown-linux-gnu
|
||||
builder-arg: gnu
|
||||
|
||||
@@ -4,9 +4,9 @@ on:
|
||||
branches: ["main"]
|
||||
types: [opened, synchronize]
|
||||
paths:
|
||||
- 'LLVM.lock'
|
||||
- 'crates/llvm-builder/**'
|
||||
- '.github/workflows/test-llvm-builder.yml'
|
||||
- "LLVM.lock"
|
||||
- "crates/llvm-builder/**"
|
||||
- ".github/workflows/test-llvm-builder.yml"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/target
|
||||
/js/resolc/dist
|
||||
target-llvm
|
||||
*.dot
|
||||
.vscode/
|
||||
|
||||
+29
-3
@@ -19,13 +19,16 @@ This is a development pre-release.
|
||||
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
|
||||
|
||||
### Added
|
||||
- The `revive-runner` helper utility binary which helps to run contracts locally without a blockchain node.
|
||||
|
||||
- The `revive-runner` helper utility binary which helps to run contracts locally without a blockchain node.
|
||||
- Allow configuration of the EVM heap memory size and stack size via CLI flags and JSON input settings.
|
||||
|
||||
### Changed
|
||||
|
||||
- The default PVM stack memory size was increased from 16kb to 32kb.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Constructors avoid storing zero sized immutable data on exit.
|
||||
|
||||
## v0.1.0-dev.13
|
||||
@@ -35,16 +38,19 @@ This is a development pre-release.
|
||||
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
|
||||
|
||||
### Added
|
||||
|
||||
- Support for solc v0.8.29
|
||||
- Decouples the solc JSON-input-output type definitions from the Solidity fronted and expose them via a dedicated crate.
|
||||
- `--supported-solc-versions` for `resolc` binary to return a `semver` range of supported `solc` versions.
|
||||
- Support for passing LLVM command line options via the prcoess input or providing one or more `--llvm-arg='..'` resolc CLI flag. This allows more fine-grained control over the LLVM backend configuration.
|
||||
|
||||
### Changed
|
||||
|
||||
- Storage keys and values are big endian. This was a pre-mature optimization because for the contract itself it this is a no-op and thus not observable. However we should consider the storage layout as part of the contract ABI. The endianness of transient storage values are still kept as-is.
|
||||
- Running `resolc` using webkit is no longer supported.
|
||||
|
||||
### Fixed
|
||||
|
||||
- A missing byte swap for the create2 salt value.
|
||||
|
||||
## v0.1.0-dev.12
|
||||
@@ -54,10 +60,12 @@ This is a development pre-release.
|
||||
Supported `polkadot-sdk` rev: `21f6f0705e53c15aa2b8a5706b208200447774a9`
|
||||
|
||||
### Added
|
||||
|
||||
- Per file output selection for `--standard-json` mode.
|
||||
- The `ir` output selection option for `--standard-json` mode.
|
||||
|
||||
### Changed
|
||||
|
||||
- Improved code size: Large contracts compile to smaller code blobs when enabling aggressive size optimizations (`-Oz`).
|
||||
|
||||
### Fixed
|
||||
@@ -73,6 +81,7 @@ Supported `polkadot-sdk` rev: `274a781e8ca1a9432c7ec87593bd93214abbff50`
|
||||
### Changed
|
||||
|
||||
### Fixed
|
||||
|
||||
- A bug causing incorrect loads from the emulated EVM linear memory.
|
||||
- A missing integer truncate after switching to 64bit.
|
||||
|
||||
@@ -83,10 +92,12 @@ This is a development pre-release.
|
||||
Supported `polkadot-sdk` rev: `274a781e8ca1a9432c7ec87593bd93214abbff50`
|
||||
|
||||
### Added
|
||||
|
||||
- Support for the `coinbase` opcode.
|
||||
- The resolc web JS version.
|
||||
|
||||
### Changed
|
||||
|
||||
- Missing the `--overwrite` flag emits an error instead of a warning.
|
||||
- The `resolc` executable prints the help by default.
|
||||
- Removed support for legacy EVM assembly (EVMLA) translation.
|
||||
@@ -96,6 +107,7 @@ Supported `polkadot-sdk` rev: `274a781e8ca1a9432c7ec87593bd93214abbff50`
|
||||
If detected, the re-entrant call flag is not set and 0 deposit limit is endowed.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Solidity: Add the solc `--libraries` files to sources.
|
||||
- A data race in tests.
|
||||
- Fix `broken pipe` errors.
|
||||
@@ -109,9 +121,11 @@ This is a development pre-release.
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
- Syscalls with more than 6 arguments now pack them into registers.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Remove reloading of the resolc.js file (fix issue with relative path in web worker)
|
||||
|
||||
## v0.1.0-dev.8
|
||||
@@ -119,15 +133,18 @@ This is a development pre-release.
|
||||
This is a development pre-release.
|
||||
|
||||
### Added
|
||||
|
||||
- The `revive-llvm-builder` crate with the `revive-llvm` helper utility for streamlined management of the LLVM framework dependency.
|
||||
- Initial support for running `resolc` in the browser.
|
||||
|
||||
### Changed
|
||||
|
||||
- Suported contracts runtime is polkadot-sdk git version `d62a90c8c729acd98c7e9a5cab9803b8b211ffc5`.
|
||||
- The minimum supported Rust version is `1.81.0`.
|
||||
- Error out early instead of invoking `solc` with invalid base or include path flags.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Decouple the LLVM target dependency from the LLVM host dependency.
|
||||
- Do not error out if no files and no errors were produced. This aligns resolc closer to solc.
|
||||
- Fixes input normalization in the Wasm version.
|
||||
@@ -137,17 +154,20 @@ This is a development pre-release.
|
||||
This is a development pre-release.
|
||||
|
||||
### Added
|
||||
|
||||
- Implement the `GASPRICE` opcode.
|
||||
- Implement the `BASEFEE` opcode.
|
||||
- Implement the `GASLIMIT` opcode.
|
||||
|
||||
### Changed
|
||||
|
||||
- The `GAS` opcode now returns the remaining `ref_time`.
|
||||
- Contracts can now be supplied call data input of arbitrary size.
|
||||
- Some syscalls now return the value in a register, slightly improving emitted contract code.
|
||||
- Some syscalls now return the value in a register, slightly improving emitted contract code.
|
||||
- Calls forward maximum weight limits instead of 0, anticipating a change in polkadot-sdk where weight limits of 0 no longer interprets as uncapped limit.
|
||||
|
||||
### Fixed
|
||||
|
||||
- A linker bug which was preventing certain contracts from linking with the PVM linker.
|
||||
- JS: Fix encoding conversion from JS string (UTF-16) to UTF-8.
|
||||
- The git commit hash slug is always displayed in the version string.
|
||||
@@ -157,6 +177,7 @@ This is a development pre-release.
|
||||
This is a development pre-release.
|
||||
|
||||
# Added
|
||||
|
||||
- Implement the `BLOCKHASH` opcode.
|
||||
- Implement delegate calls.
|
||||
- Implement the `GASPRICE` opcode. Currently hard-coded to return `1`.
|
||||
@@ -164,21 +185,24 @@ This is a development pre-release.
|
||||
- Initial support for emitting debug info (opt in via the `-g` flag)
|
||||
|
||||
# Changed
|
||||
|
||||
- resolc now emits 64bit PolkaVM blobs, reducing contract code size and execution time.
|
||||
- The RISC-V bit-manipulation target feature (`zbb`) is enabled.
|
||||
|
||||
# Fixed
|
||||
- Compilation to Wasm (for usage in node and web browsers)
|
||||
|
||||
- Compilation to Wasm (for usage in node and web browsers)
|
||||
|
||||
## v0.1.0-dev.5
|
||||
|
||||
This is development pre-release.
|
||||
|
||||
# Added
|
||||
|
||||
- Implement the `CODESIZE` and `EXTCODESIZE` opcodes.
|
||||
|
||||
# Changed
|
||||
|
||||
- Include the full revive version in the contract metadata.
|
||||
|
||||
# Fixed
|
||||
@@ -188,9 +212,11 @@ This is development pre-release.
|
||||
This is development pre-release.
|
||||
|
||||
# Added
|
||||
|
||||
- Support the `ORIGIN` opcode.
|
||||
|
||||
# Changed
|
||||
|
||||
- Update polkavm to `v0.14.0`.
|
||||
- Enable the `a`, `fast-unaligned-access` and `xtheadcondmov` LLVM target features, decreasing the code size for some contracts.
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
## Installation
|
||||
|
||||
Please consult [the documentation](https://contracts.polkadot.io/revive_compiler/installation) for installation instructions.
|
||||
|
||||
## 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.
|
||||
|
||||
> **MacOS** users need to clear the `downloaded` attribute from all binaries after extracting the archive:
|
||||
>
|
||||
> ```sh
|
||||
> xattr -rc </path/to/the/extracted/archive>/target-llvm/gnu/target-final/bin/*
|
||||
> ```
|
||||
|
||||
After extracting the archive, point `$LLVM_SYS_181_PREFIX` to it:
|
||||
|
||||
```sh
|
||||
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>
|
||||
<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:
|
||||
|
||||
@@ -93,11 +96,12 @@ make test-wasm
|
||||
|
||||
## Development
|
||||
|
||||
Please consult the [Makefile](Makefile) targets to learn how to run tests and benchmarks.
|
||||
Please consult the [Makefile](Makefile) targets to learn how to run tests and benchmarks.
|
||||
Ensure that your branch passes `make test` locally when submitting a pull request.
|
||||
|
||||
### 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).
|
||||
|
||||
|
||||
+1
-1
@@ -18,4 +18,4 @@ To create a new pre-release:
|
||||
To create a new LLVM release, run "Release LLVM" workflow. Use current LLVM version as parameter, e.g. `18.1.8`.
|
||||
Version suffix will be resolved automatically.
|
||||
The workflows will create new GitHub release, and upload LLVM binaries.
|
||||
Next release of resolc will use newly created binaries.
|
||||
Next release of resolc will use newly created binaries.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/SECURITY.md
|
||||
https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/SECURITY.md
|
||||
|
||||
@@ -3,71 +3,71 @@
|
||||
## Table of Contents
|
||||
|
||||
- [Benchmark Results](#benchmark-results)
|
||||
- [Baseline](#baseline)
|
||||
- [OddPorduct](#oddporduct)
|
||||
- [TriangleNumber](#trianglenumber)
|
||||
- [FibonacciRecursive](#fibonaccirecursive)
|
||||
- [FibonacciIterative](#fibonacciiterative)
|
||||
- [FibonacciBinet](#fibonaccibinet)
|
||||
- [SHA1](#sha1)
|
||||
- [Baseline](#baseline)
|
||||
- [OddPorduct](#oddporduct)
|
||||
- [TriangleNumber](#trianglenumber)
|
||||
- [FibonacciRecursive](#fibonaccirecursive)
|
||||
- [FibonacciIterative](#fibonacciiterative)
|
||||
- [FibonacciBinet](#fibonaccibinet)
|
||||
- [SHA1](#sha1)
|
||||
|
||||
## Benchmark Results
|
||||
|
||||
### Baseline
|
||||
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
|:--------|:-------------------------|:-------------------------------- |
|
||||
| **`0`** | `10.08 us` (✅ **1.00x**) | `10.32 us` (✅ **1.02x slower**) |
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
| :------ | :------------------------ | :------------------------------- |
|
||||
| **`0`** | `10.08 us` (✅ **1.00x**) | `10.32 us` (✅ **1.02x slower**) |
|
||||
|
||||
### OddPorduct
|
||||
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
|:-------------|:--------------------------|:-------------------------------- |
|
||||
| **`10000`** | `3.60 ms` (✅ **1.00x**) | `1.57 ms` (🚀 **2.28x 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**) |
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
| :----------- | :------------------------- | :------------------------------- |
|
||||
| **`10000`** | `3.60 ms` (✅ **1.00x**) | `1.57 ms` (🚀 **2.28x 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**) |
|
||||
|
||||
### TriangleNumber
|
||||
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
|:-------------|:-------------------------|:-------------------------------- |
|
||||
| **`10000`** | `2.43 ms` (✅ **1.00x**) | `1.12 ms` (🚀 **2.17x 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**) |
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
| :----------- | :------------------------ | :------------------------------- |
|
||||
| **`10000`** | `2.43 ms` (✅ **1.00x**) | `1.12 ms` (🚀 **2.17x 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**) |
|
||||
|
||||
### FibonacciRecursive
|
||||
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
|:---------|:--------------------------|:--------------------------------- |
|
||||
| **`12`** | `144.17 us` (✅ **1.00x**) | `150.85 us` (✅ **1.05x slower**) |
|
||||
| **`16`** | `938.71 us` (✅ **1.00x**) | `922.11 us` (✅ **1.02x faster**) |
|
||||
| **`20`** | `6.54 ms` (✅ **1.00x**) | `6.20 ms` (✅ **1.05x faster**) |
|
||||
| **`24`** | `45.73 ms` (✅ **1.00x**) | `41.98 ms` (✅ **1.09x faster**) |
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
| :------- | :------------------------- | :-------------------------------- |
|
||||
| **`12`** | `144.17 us` (✅ **1.00x**) | `150.85 us` (✅ **1.05x slower**) |
|
||||
| **`16`** | `938.71 us` (✅ **1.00x**) | `922.11 us` (✅ **1.02x faster**) |
|
||||
| **`20`** | `6.54 ms` (✅ **1.00x**) | `6.20 ms` (✅ **1.05x faster**) |
|
||||
| **`24`** | `45.73 ms` (✅ **1.00x**) | `41.98 ms` (✅ **1.09x faster**) |
|
||||
|
||||
### FibonacciIterative
|
||||
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
|:----------|:-------------------------|:-------------------------------- |
|
||||
| **`64`** | `23.00 us` (✅ **1.00x**) | `31.88 us` (❌ *1.39x 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**) |
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
| :-------- | :------------------------ | :------------------------------- |
|
||||
| **`64`** | `23.00 us` (✅ **1.00x**) | `31.88 us` (❌ _1.39x 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**) |
|
||||
|
||||
### FibonacciBinet
|
||||
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
|:----------|:-------------------------|:-------------------------------- |
|
||||
| **`64`** | `23.01 us` (✅ **1.00x**) | `47.74 us` (❌ *2.07x 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*) |
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
| :-------- | :------------------------ | :----------------------------- |
|
||||
| **`64`** | `23.01 us` (✅ **1.00x**) | `47.74 us` (❌ _2.07x 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_) |
|
||||
|
||||
### SHA1
|
||||
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
|:----------|:--------------------------|:--------------------------------- |
|
||||
| **`1`** | `135.87 us` (✅ **1.00x**) | `243.75 us` (❌ *1.79x 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**) |
|
||||
| | `EVM` | `PVMInterpreter` |
|
||||
| :-------- | :------------------------- | :------------------------------ |
|
||||
| **`1`** | `135.87 us` (✅ **1.00x**) | `243.75 us` (❌ _1.79x 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**) |
|
||||
|
||||
---
|
||||
Made with [criterion-table](https://github.com/nu11ptr/criterion-table)
|
||||
|
||||
Made with [criterion-table](https://github.com/nu11ptr/criterion-table)
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
{
|
||||
"config": {
|
||||
"chainId": 420420420,
|
||||
"homesteadBlock": 0,
|
||||
"eip150Block": 0,
|
||||
"eip155Block": 0,
|
||||
"eip158Block": 0,
|
||||
"byzantiumBlock": 0,
|
||||
"constantinopleBlock": 0,
|
||||
"petersburgBlock": 0,
|
||||
"istanbulBlock": 0,
|
||||
"berlinBlock": 0,
|
||||
"londonBlock": 0,
|
||||
"arrowGlacierBlock": 0,
|
||||
"grayGlacierBlock": 0,
|
||||
"shanghaiTime": 0,
|
||||
"cancunTime": 0,
|
||||
"terminalTotalDifficulty": 0,
|
||||
"terminalTotalDifficultyPassed": true,
|
||||
"blobSchedule": {
|
||||
"cancun": {
|
||||
"target": 3,
|
||||
"max": 6,
|
||||
"baseFeeUpdateFraction": 3338477
|
||||
}
|
||||
}
|
||||
},
|
||||
"coinbase": "0xffffffffffffffffffffffffffffffffffffffff",
|
||||
"difficulty": "0x20000",
|
||||
"extraData": "",
|
||||
"gasLimit": "0xffffffff",
|
||||
"nonce": "0x0000000000000042",
|
||||
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"timestamp": "0x00",
|
||||
"alloc": {
|
||||
"0101010101010101010101010101010101010101": {
|
||||
"balance": "1000000000"
|
||||
},
|
||||
"0202020202020202020202020202020202020202": {
|
||||
"balance": "1000000000"
|
||||
},
|
||||
"0303030303030303030303030303030303030303": {
|
||||
"balance": "1000000000"
|
||||
}
|
||||
"config": {
|
||||
"chainId": 420420420,
|
||||
"homesteadBlock": 0,
|
||||
"eip150Block": 0,
|
||||
"eip155Block": 0,
|
||||
"eip158Block": 0,
|
||||
"byzantiumBlock": 0,
|
||||
"constantinopleBlock": 0,
|
||||
"petersburgBlock": 0,
|
||||
"istanbulBlock": 0,
|
||||
"berlinBlock": 0,
|
||||
"londonBlock": 0,
|
||||
"arrowGlacierBlock": 0,
|
||||
"grayGlacierBlock": 0,
|
||||
"shanghaiTime": 0,
|
||||
"cancunTime": 0,
|
||||
"terminalTotalDifficulty": 0,
|
||||
"terminalTotalDifficultyPassed": true,
|
||||
"blobSchedule": {
|
||||
"cancun": {
|
||||
"target": 3,
|
||||
"max": 6,
|
||||
"baseFeeUpdateFraction": 3338477
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"coinbase": "0xffffffffffffffffffffffffffffffffffffffff",
|
||||
"difficulty": "0x20000",
|
||||
"extraData": "",
|
||||
"gasLimit": "0xffffffff",
|
||||
"nonce": "0x0000000000000042",
|
||||
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"timestamp": "0x00",
|
||||
"alloc": {
|
||||
"0101010101010101010101010101010101010101": {
|
||||
"balance": "1000000000"
|
||||
},
|
||||
"0202020202020202020202020202020202020202": {
|
||||
"balance": "1000000000"
|
||||
},
|
||||
"0303030303030303030303030303030303030303": {
|
||||
"balance": "1000000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
"FibonacciIterative": 1497,
|
||||
"Flipper": 2099,
|
||||
"SHA1": 8243
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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`.
|
||||
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
|
||||
- The RISC-V target (the PolkaVM target)
|
||||
- The compiler-rt builtins for the PolkaVM target
|
||||
@@ -17,85 +18,92 @@ Obtain a compatible build for your host platform from the release section of thi
|
||||
<details>
|
||||
<summary>1. Install the system prerequisites.</summary>
|
||||
|
||||
* Linux (Debian):
|
||||
- Linux (Debian):
|
||||
|
||||
Install the following packages:
|
||||
```shell
|
||||
apt install cmake ninja-build curl git libssl-dev pkg-config clang lld
|
||||
```
|
||||
* Linux (Arch):
|
||||
Install the following packages:
|
||||
|
||||
Install the following packages:
|
||||
```shell
|
||||
pacman -Syu which cmake ninja curl git pkg-config clang lld
|
||||
```
|
||||
```shell
|
||||
apt install cmake ninja-build curl git libssl-dev pkg-config clang lld
|
||||
```
|
||||
|
||||
* MacOS:
|
||||
- Linux (Arch):
|
||||
|
||||
* Install the [HomeBrew](https://brew.sh) package manager.
|
||||
* Install the following packages:
|
||||
Install the following packages:
|
||||
|
||||
```shell
|
||||
brew install cmake ninja coreutils
|
||||
```
|
||||
```shell
|
||||
pacman -Syu which cmake ninja curl git pkg-config clang lld
|
||||
```
|
||||
|
||||
* Install your choice of a recent LLVM/[Clang](https://clang.llvm.org) compiler, e.g. via [Xcode](https://developer.apple.com/xcode/), [Apple’s Command Line Tools](https://developer.apple.com/library/archive/technotes/tn2339/_index.html), or your preferred package manager.
|
||||
</details>
|
||||
- MacOS:
|
||||
|
||||
* Install the [HomeBrew](https://brew.sh) package manager.
|
||||
* Install the following packages:
|
||||
|
||||
```shell
|
||||
brew install cmake ninja coreutils
|
||||
```
|
||||
|
||||
* Install your choice of a recent LLVM/[Clang](https://clang.llvm.org) compiler, e.g. via [Xcode](https://developer.apple.com/xcode/), [Apple’s Command Line Tools](https://developer.apple.com/library/archive/technotes/tn2339/_index.html), or your preferred package manager.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>2. Install Rust.</summary>
|
||||
|
||||
* Follow the latest [official instructions](https://www.rust-lang.org/tools/install:
|
||||
```shell
|
||||
- Follow the latest [official instructions](https://www.rust-lang.org/tools/install:
|
||||
`shell
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
. ${HOME}/.cargo/env
|
||||
```
|
||||
`
|
||||
|
||||
> Currently we are not pinned to any specific version of Rust, so just install the latest stable build for your platform.
|
||||
</details>
|
||||
> Currently we are not pinned to any specific version of Rust, so just install the latest stable build for your platform.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>3. Install the revive LLVM framework builder.</summary>
|
||||
|
||||
* Install the builder using `cargo`:
|
||||
```shell
|
||||
cargo install --git https://github.com/paritytech/revive-llvm-builder --force --locked
|
||||
```
|
||||
- Install the builder using `cargo`:
|
||||
|
||||
> The builder is not the LLVM framework itself, but a tool that clones its repository and runs a sequence of build commands. By default it is installed in `~/.cargo/bin/`, which is recommended to be added to your `$PATH`.
|
||||
```shell
|
||||
cargo install --git https://github.com/paritytech/revive-llvm-builder --force --locked
|
||||
```
|
||||
|
||||
> The builder is not the LLVM framework itself, but a tool that clones its repository and runs a sequence of build commands. By default it is installed in `~/.cargo/bin/`, which is recommended to be added to your `$PATH`.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>4. (Optional) Create the `LLVM.lock` file.</summary>
|
||||
|
||||
* The `LLVM.lock` dictates the LLVM source tree being used.
|
||||
A default `./LLVM.lock` pointing to the release used for development is already provided.
|
||||
- The `LLVM.lock` dictates the LLVM source tree being used.
|
||||
A default `./LLVM.lock` pointing to the release used for development is already provided.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<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.
|
||||
|
||||
```shell
|
||||
revive-llvm clone
|
||||
revive-llvm build --llvm-projects lld --llvm-projects clang
|
||||
```
|
||||
```shell
|
||||
revive-llvm clone
|
||||
revive-llvm build --llvm-projects lld --llvm-projects clang
|
||||
```
|
||||
|
||||
Build artifacts end up in the `./target-llvm/gnu/target-final/` directory by default.
|
||||
The `gnu` directory depends on the supported archticture and will either be `gnu`, `musl` or `emscripten`.
|
||||
You now need to export the final target directory `$LLVM_SYS_181_PREFIX`: `export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final`
|
||||
If built with the `--enable-tests` option, test tools will be in the `./target-llvm/gnu/build-final/` directory, along with copies of the build artifacts. For all supported build options, run `revive-llvm build --help`.
|
||||
Build artifacts end up in the `./target-llvm/gnu/target-final/` directory by default.
|
||||
The `gnu` directory depends on the supported archticture and will either be `gnu`, `musl` or `emscripten`.
|
||||
You now need to export the final target directory `$LLVM_SYS_181_PREFIX`: `export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final`
|
||||
If built with the `--enable-tests` option, test tools will be in the `./target-llvm/gnu/build-final/` directory, along with copies of the build artifacts. For all supported build options, run `revive-llvm build --help`.
|
||||
|
||||
</details>
|
||||
|
||||
## Supported target architectures
|
||||
|
||||
The following target platforms are supported:
|
||||
|
||||
- Linux GNU (x86)
|
||||
- Linux MUSL (x86)
|
||||
- MacOS (aarch64)
|
||||
@@ -105,28 +113,29 @@ The following target platforms are supported:
|
||||
<details>
|
||||
<summary>Building for MUSL</summary>
|
||||
|
||||
* Via a musl build we can build revive into fully static ELF binaries.
|
||||
Which is desirable for reproducible Solidity contracts builds.
|
||||
The resulting binary is also very portable, akin to the`solc` frontend binary distribution.
|
||||
- Via a musl build we can build revive into fully static ELF binaries.
|
||||
Which is desirable for reproducible Solidity contracts builds.
|
||||
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:
|
||||
```shell
|
||||
revive-llvm --target-env musl clone
|
||||
revive-llvm --target-env musl build --enable-assertions --llvm-projects clang --llvm-projects lld
|
||||
```
|
||||
Clone and build the LLVM framework using the `revive-llvm` tool:
|
||||
|
||||
```shell
|
||||
revive-llvm --target-env musl clone
|
||||
revive-llvm --target-env musl build --enable-assertions --llvm-projects clang --llvm-projects lld
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<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:
|
||||
```shell
|
||||
revive-llvm --target-env emscripten clone
|
||||
revive-llvm --target-env emscripten build --enable-assertions --llvm-projects clang --llvm-projects lld
|
||||
```
|
||||
Clone and build the LLVM framework using the `revive-llvm` tool:
|
||||
|
||||
```shell
|
||||
revive-llvm --target-env emscripten clone
|
||||
revive-llvm --target-env emscripten build --enable-assertions --llvm-projects clang --llvm-projects lld
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Inside the root `revive` repository directory, execute:
|
||||
make install-revive-runner
|
||||
```
|
||||
|
||||
Which will install the `revive-runner` using `cargo`.
|
||||
Which will install the `revive-runner` using `cargo`.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -24,3 +24,4 @@ Set the `RUST_LOG` environment varibale to the `trace` level to see the full Pol
|
||||
|
||||
```bash
|
||||
RUST_LOG=trace revive-runner -f mycontract.pvm -c a9059cbb000000000000000000000000f24ff3a9cf04c71dbc94d0b566f7a27b94566cac0000000000000000000000000000000000000000000000000000000000000000
|
||||
```
|
||||
|
||||
@@ -23,4 +23,4 @@
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.7.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,19 +1,33 @@
|
||||
import * as path from 'path';
|
||||
import * as path from "path";
|
||||
|
||||
const outputDir = 'artifacts';
|
||||
const binExtension = ':C.pvm';
|
||||
const asmExtension = ':C.pvmasm';
|
||||
const llvmExtension = '.ll';
|
||||
const contractSolFilename = 'contract.sol';
|
||||
const contractYulFilename = 'contract.yul';
|
||||
const contractOptimizedLLVMFilename = contractSolFilename + '.C.optimized';
|
||||
const contractUnoptimizedLLVMFilename = contractSolFilename + '.C.unoptimized';
|
||||
const pathToOutputDir = path.join(__dirname, '..', outputDir);
|
||||
const pathToContracts = path.join(__dirname, '..', 'src', 'contracts');
|
||||
const pathToBasicYulContract = path.join(pathToContracts, 'yul', contractYulFilename);
|
||||
const pathToBasicSolContract = path.join(pathToContracts, 'solidity', contractSolFilename);
|
||||
const pathToSolBinOutputFile = path.join(pathToOutputDir, contractSolFilename + binExtension);
|
||||
const pathToSolAsmOutputFile = path.join(pathToOutputDir, contractSolFilename + asmExtension);
|
||||
const outputDir = "artifacts";
|
||||
const binExtension = ":C.pvm";
|
||||
const asmExtension = ":C.pvmasm";
|
||||
const llvmExtension = ".ll";
|
||||
const contractSolFilename = "contract.sol";
|
||||
const contractYulFilename = "contract.yul";
|
||||
const contractOptimizedLLVMFilename = contractSolFilename + ".C.optimized";
|
||||
const contractUnoptimizedLLVMFilename = contractSolFilename + ".C.unoptimized";
|
||||
const pathToOutputDir = path.join(__dirname, "..", outputDir);
|
||||
const pathToContracts = path.join(__dirname, "..", "src", "contracts");
|
||||
const pathToBasicYulContract = path.join(
|
||||
pathToContracts,
|
||||
"yul",
|
||||
contractYulFilename,
|
||||
);
|
||||
const pathToBasicSolContract = path.join(
|
||||
pathToContracts,
|
||||
"solidity",
|
||||
contractSolFilename,
|
||||
);
|
||||
const pathToSolBinOutputFile = path.join(
|
||||
pathToOutputDir,
|
||||
contractSolFilename + binExtension,
|
||||
);
|
||||
const pathToSolAsmOutputFile = path.join(
|
||||
pathToOutputDir,
|
||||
contractSolFilename + asmExtension,
|
||||
);
|
||||
|
||||
export const paths = {
|
||||
outputDir: outputDir,
|
||||
|
||||
@@ -1,44 +1,51 @@
|
||||
import * as shell from 'shelljs';
|
||||
import * as fs from 'fs';
|
||||
import { spawnSync } from 'child_process';
|
||||
import * as shell from "shelljs";
|
||||
import * as fs from "fs";
|
||||
import { spawnSync } from "child_process";
|
||||
|
||||
interface CommandResult {
|
||||
output: string;
|
||||
exitCode: number;
|
||||
output: string;
|
||||
exitCode: number;
|
||||
}
|
||||
|
||||
export const executeCommand = (command: string, stdin?: string): CommandResult => {
|
||||
if (stdin) {
|
||||
const process = spawnSync(command, [], {
|
||||
input: stdin,
|
||||
shell: true,
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 30 * 1024 * 1024
|
||||
});
|
||||
export const executeCommand = (
|
||||
command: string,
|
||||
stdin?: string,
|
||||
): CommandResult => {
|
||||
if (stdin) {
|
||||
const process = spawnSync(command, [], {
|
||||
input: stdin,
|
||||
shell: true,
|
||||
encoding: "utf8",
|
||||
maxBuffer: 30 * 1024 * 1024,
|
||||
});
|
||||
|
||||
return {
|
||||
exitCode: process.status || 0,
|
||||
output: (process.stdout || process.stderr || '').toString()
|
||||
};
|
||||
}
|
||||
|
||||
const result = shell.exec(command, { silent: true, async: false });
|
||||
return {
|
||||
exitCode: result.code,
|
||||
output: result.stdout || result.stderr || ''
|
||||
exitCode: process.status || 0,
|
||||
output: (process.stdout || process.stderr || "").toString(),
|
||||
};
|
||||
}
|
||||
|
||||
const result = shell.exec(command, { silent: true, async: false });
|
||||
return {
|
||||
exitCode: result.code,
|
||||
output: result.stdout || result.stderr || "",
|
||||
};
|
||||
};
|
||||
|
||||
export const isFolderExist = (folder: string): boolean => {
|
||||
return shell.test('-d', folder);
|
||||
return shell.test("-d", folder);
|
||||
};
|
||||
|
||||
export const isFileExist = (pathToFileDir: string, fileName: string, fileExtension: string): boolean => {
|
||||
return shell.ls(pathToFileDir).stdout.includes(fileName + fileExtension);
|
||||
export const isFileExist = (
|
||||
pathToFileDir: string,
|
||||
fileName: string,
|
||||
fileExtension: string,
|
||||
): boolean => {
|
||||
return shell.ls(pathToFileDir).stdout.includes(fileName + fileExtension);
|
||||
};
|
||||
|
||||
export const isFileEmpty = (file: string): boolean => {
|
||||
if (fs.existsSync(file)) {
|
||||
return (fs.readFileSync(file).length === 0);
|
||||
}
|
||||
if (fs.existsSync(file)) {
|
||||
return fs.readFileSync(file).length === 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import {executeCommand} from "../src/helper";
|
||||
import { paths } from '../src/entities';
|
||||
|
||||
import { executeCommand } from "../src/helper";
|
||||
import { paths } from "../src/entities";
|
||||
|
||||
//id1746
|
||||
describe("Run with --asm by default", () => {
|
||||
const command = `resolc ${paths.pathToBasicSolContract} --asm`;
|
||||
const result = executeCommand(command);
|
||||
const commandInvalid = 'resolc --asm';
|
||||
const commandInvalid = "resolc --asm";
|
||||
const resultInvalid = executeCommand(commandInvalid);
|
||||
|
||||
it("Valid command exit code = 0", () => {
|
||||
@@ -28,16 +27,18 @@ describe("Run with --asm by default", () => {
|
||||
});
|
||||
|
||||
it("run invalid: resolc --asm", () => {
|
||||
expect(resultInvalid.output).toMatch(/(No input sources specified|Compilation aborted)/i);
|
||||
expect(resultInvalid.output).toMatch(
|
||||
/(No input sources specified|Compilation aborted)/i,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it("Invalid command exit code = 1", () => {
|
||||
expect(resultInvalid.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
it("Invalid solc exit code == Invalid resolc exit code", () => {
|
||||
const command = 'solc --asm';
|
||||
const command = "solc --asm";
|
||||
const solcResult = executeCommand(command);
|
||||
expect(solcResult.exitCode).toBe(resultInvalid.exitCode);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,191 +1,241 @@
|
||||
import { executeCommand, isFolderExist, isFileExist, isFileEmpty } from "../src/helper";
|
||||
import { paths } from '../src/entities';
|
||||
import * as shell from 'shelljs';
|
||||
import * as path from 'path';
|
||||
|
||||
import {
|
||||
executeCommand,
|
||||
isFolderExist,
|
||||
isFileExist,
|
||||
isFileEmpty,
|
||||
} from "../src/helper";
|
||||
import { paths } from "../src/entities";
|
||||
import * as shell from "shelljs";
|
||||
import * as path from "path";
|
||||
|
||||
//id1762
|
||||
describe("Run resolc without any options", () => {
|
||||
const command = 'resolc';
|
||||
const result = executeCommand(command);
|
||||
const command = "resolc";
|
||||
const result = executeCommand(command);
|
||||
|
||||
it("Info with help is presented", () => {
|
||||
expect(result.output).toMatch(/(Usage: resolc)/i);
|
||||
});
|
||||
it("Info with help is presented", () => {
|
||||
expect(result.output).toMatch(/(Usage: resolc)/i);
|
||||
});
|
||||
|
||||
it("Exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
it("Exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
it("solc exit code == resolc exit code", () => {
|
||||
const command = 'solc';
|
||||
const solcResult = executeCommand(command);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
it("solc exit code == resolc exit code", () => {
|
||||
const command = "solc";
|
||||
const solcResult = executeCommand(command);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//#1713
|
||||
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 result = executeCommand(command);
|
||||
|
||||
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);
|
||||
|
||||
it("Compiler run successful", () => {
|
||||
expect(result.output).toMatch(/(Compiler run successful.)/i);
|
||||
});
|
||||
it("Exit code = 0", () => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
it("Output dir is created", () => {
|
||||
expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
|
||||
});
|
||||
xit("Output file is created", () => { // a bug on windows
|
||||
expect(isFileExist(paths.pathToOutputDir, paths.contractSolFilename, paths.binExtension)).toBe(true);
|
||||
});
|
||||
it("the output file is not empty", () => {
|
||||
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
|
||||
});
|
||||
it("No 'Error'/'Warning'/'Fail' in the output", () => {
|
||||
expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i);
|
||||
});
|
||||
it("Compiler run successful", () => {
|
||||
expect(result.output).toMatch(/(Compiler run successful.)/i);
|
||||
});
|
||||
it("Exit code = 0", () => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
it("Output dir is created", () => {
|
||||
expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
|
||||
});
|
||||
xit("Output file is created", () => {
|
||||
// a bug on windows
|
||||
expect(
|
||||
isFileExist(
|
||||
paths.pathToOutputDir,
|
||||
paths.contractSolFilename,
|
||||
paths.binExtension,
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
it("the output file is not empty", () => {
|
||||
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
|
||||
});
|
||||
it("No 'Error'/'Warning'/'Fail' in the output", () => {
|
||||
expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i);
|
||||
});
|
||||
});
|
||||
|
||||
//#1818
|
||||
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 result = executeCommand(command);
|
||||
|
||||
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);
|
||||
|
||||
it("Compiler run successful", () => {
|
||||
expect(result.output).toMatch(/(Compiler run successful.)/i);
|
||||
});
|
||||
it("Exit code = 0", () => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
it("Output dir is created", () => {
|
||||
expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
|
||||
});
|
||||
xit("Output files are created", () => { // a bug on windows
|
||||
expect(isFileExist(paths.pathToOutputDir, paths.contractSolFilename, paths.binExtension)).toBe(true);
|
||||
expect(isFileExist(paths.pathToOutputDir, paths.contractSolFilename, paths.asmExtension)).toBe(true);
|
||||
});
|
||||
it("the output files are not empty", () => {
|
||||
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
|
||||
expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false);
|
||||
});
|
||||
it("No 'Error'/'Warning'/'Fail' in the output", () => {
|
||||
expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i);
|
||||
});
|
||||
it("Compiler run successful", () => {
|
||||
expect(result.output).toMatch(/(Compiler run successful.)/i);
|
||||
});
|
||||
it("Exit code = 0", () => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
it("Output dir is created", () => {
|
||||
expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
|
||||
});
|
||||
xit("Output files are created", () => {
|
||||
// a bug on windows
|
||||
expect(
|
||||
isFileExist(
|
||||
paths.pathToOutputDir,
|
||||
paths.contractSolFilename,
|
||||
paths.binExtension,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
isFileExist(
|
||||
paths.pathToOutputDir,
|
||||
paths.contractSolFilename,
|
||||
paths.asmExtension,
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
it("the output files are not empty", () => {
|
||||
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
|
||||
expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false);
|
||||
});
|
||||
it("No 'Error'/'Warning'/'Fail' in the output", () => {
|
||||
expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Run resolc with source debug information", () => {
|
||||
const commands = [
|
||||
`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}"`
|
||||
]; // potential issue on resolc with full path on Windows cmd`;
|
||||
const commands = [
|
||||
`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}"`,
|
||||
]; // potential issue on resolc with full path on Windows cmd`;
|
||||
|
||||
for (var idx in commands) {
|
||||
const command = commands[idx];
|
||||
const result = executeCommand(command);
|
||||
for (var idx in commands) {
|
||||
const command = commands[idx];
|
||||
const result = executeCommand(command);
|
||||
|
||||
it("Compiler run successful", () => {
|
||||
expect(result.output).toMatch(/(Compiler run successful.)/i);
|
||||
});
|
||||
it("Exit code = 0", () => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
it("Output dir is created", () => {
|
||||
expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
|
||||
});
|
||||
it("Output files are created", () => { // a bug on windows
|
||||
expect(isFileExist(paths.pathToOutputDir, paths.contractSolFilename, paths.binExtension)).toBe(true);
|
||||
expect(isFileExist(paths.pathToOutputDir, paths.contractSolFilename, paths.asmExtension)).toBe(true);
|
||||
});
|
||||
it("the output files are not empty", () => {
|
||||
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
|
||||
expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false);
|
||||
});
|
||||
it("No 'Error'/'Fail' in the output", () => {
|
||||
expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i);
|
||||
});
|
||||
}
|
||||
it("Compiler run successful", () => {
|
||||
expect(result.output).toMatch(/(Compiler run successful.)/i);
|
||||
});
|
||||
it("Exit code = 0", () => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
it("Output dir is created", () => {
|
||||
expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
|
||||
});
|
||||
it("Output files are created", () => {
|
||||
// a bug on windows
|
||||
expect(
|
||||
isFileExist(
|
||||
paths.pathToOutputDir,
|
||||
paths.contractSolFilename,
|
||||
paths.binExtension,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
isFileExist(
|
||||
paths.pathToOutputDir,
|
||||
paths.contractSolFilename,
|
||||
paths.asmExtension,
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
it("the output files are not empty", () => {
|
||||
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
|
||||
expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false);
|
||||
});
|
||||
it("No 'Error'/'Fail' in the output", () => {
|
||||
expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("Run resolc with source debug information, check LLVM debug-info", () => {
|
||||
const commands = [
|
||||
`resolc -g ${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`;
|
||||
const commands = [
|
||||
`resolc -g ${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`;
|
||||
|
||||
for (var idx in commands) {
|
||||
const command = commands[idx];
|
||||
const result = executeCommand(command);
|
||||
for (var idx in commands) {
|
||||
const command = commands[idx];
|
||||
const result = executeCommand(command);
|
||||
|
||||
it("Compiler run successful", () => {
|
||||
expect(result.output).toMatch(/(Compiler run successful.)/i);
|
||||
});
|
||||
it("Exit code = 0", () => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
it("Output dir is created", () => {
|
||||
expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
|
||||
});
|
||||
it("Output files are created", () => { // a bug on windows
|
||||
expect(isFileExist(paths.pathToOutputDir, paths.contractOptimizedLLVMFilename, paths.llvmExtension)).toBe(true);
|
||||
expect(isFileExist(paths.pathToOutputDir, paths.contractUnoptimizedLLVMFilename, paths.llvmExtension)).toBe(true);
|
||||
});
|
||||
it("the output files are not empty", () => {
|
||||
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
|
||||
expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false);
|
||||
});
|
||||
it("No 'Error'/'Fail' in the output", () => {
|
||||
expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i);
|
||||
});
|
||||
}
|
||||
it("Compiler run successful", () => {
|
||||
expect(result.output).toMatch(/(Compiler run successful.)/i);
|
||||
});
|
||||
it("Exit code = 0", () => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
it("Output dir is created", () => {
|
||||
expect(isFolderExist(paths.pathToOutputDir)).toBe(true);
|
||||
});
|
||||
it("Output files are created", () => {
|
||||
// a bug on windows
|
||||
expect(
|
||||
isFileExist(
|
||||
paths.pathToOutputDir,
|
||||
paths.contractOptimizedLLVMFilename,
|
||||
paths.llvmExtension,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
isFileExist(
|
||||
paths.pathToOutputDir,
|
||||
paths.contractUnoptimizedLLVMFilename,
|
||||
paths.llvmExtension,
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
it("the output files are not empty", () => {
|
||||
expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false);
|
||||
expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false);
|
||||
});
|
||||
it("No 'Error'/'Fail' in the output", () => {
|
||||
expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
describe("Standard JSON compilation with path options", () => {
|
||||
const contractsDir = path.join(shell.tempdir(), 'contracts-test');
|
||||
const inputFile = path.join(__dirname, '..', 'src/contracts/compiled/1.json');
|
||||
const contractsDir = path.join(shell.tempdir(), "contracts-test");
|
||||
const inputFile = path.join(__dirname, "..", "src/contracts/compiled/1.json");
|
||||
|
||||
beforeAll(() => {
|
||||
shell.mkdir("-p", contractsDir);
|
||||
|
||||
const input = JSON.parse(shell.cat(inputFile).toString());
|
||||
|
||||
Object.entries(input.sources).forEach(
|
||||
([sourcePath, source]: [string, any]) => {
|
||||
const filePath = path.join(contractsDir, sourcePath);
|
||||
shell.mkdir("-p", path.dirname(filePath));
|
||||
shell.ShellString(source.content).to(filePath);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
shell.rm("-rf", contractsDir);
|
||||
});
|
||||
|
||||
describe("Output with all path options", () => {
|
||||
let result: { exitCode: number; output: string };
|
||||
|
||||
beforeAll(() => {
|
||||
shell.mkdir('-p', contractsDir);
|
||||
const tempInputFile = path.join(contractsDir, "temp-input.json");
|
||||
shell.cp(inputFile, tempInputFile);
|
||||
const inputContent = shell.cat(inputFile).toString();
|
||||
|
||||
const input = JSON.parse(shell.cat(inputFile).toString());
|
||||
const command = `resolc --standard-json --base-path "${contractsDir}" --include-path "${contractsDir}" --allow-paths "${contractsDir}"`;
|
||||
|
||||
Object.entries(input.sources).forEach(([sourcePath, source]: [string, any]) => {
|
||||
const filePath = path.join(contractsDir, sourcePath);
|
||||
shell.mkdir('-p', path.dirname(filePath));
|
||||
shell.ShellString(source.content).to(filePath);
|
||||
});
|
||||
result = executeCommand(command, inputContent);
|
||||
|
||||
shell.rm(tempInputFile);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
shell.rm('-rf', contractsDir);
|
||||
it("Compiler run successful without emiting warnings", () => {
|
||||
const parsedResults = JSON.parse(result.output);
|
||||
expect(
|
||||
parsedResults.errors.filter(
|
||||
(error: { type: string }) => error.type != "Warning",
|
||||
),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
describe("Output with all path options", () => {
|
||||
let result: { exitCode: number; output: string };
|
||||
|
||||
beforeAll(() => {
|
||||
const tempInputFile = path.join(contractsDir, 'temp-input.json');
|
||||
shell.cp(inputFile, tempInputFile);
|
||||
const inputContent = shell.cat(inputFile).toString();
|
||||
|
||||
const command = `resolc --standard-json --base-path "${contractsDir}" --include-path "${contractsDir}" --allow-paths "${contractsDir}"`;
|
||||
|
||||
result = executeCommand(command, inputContent);
|
||||
|
||||
shell.rm(tempInputFile);
|
||||
|
||||
});
|
||||
|
||||
it("Compiler run successful without emiting warnings", () => {
|
||||
const parsedResults = JSON.parse(result.output)
|
||||
expect(parsedResults.errors.filter((error: { type: string; }) => error.type != 'Warning')).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import {executeCommand} from "../src/helper";
|
||||
import { paths } from '../src/entities';
|
||||
|
||||
import { executeCommand } from "../src/helper";
|
||||
import { paths } from "../src/entities";
|
||||
|
||||
//id1743
|
||||
describe("Run with --yul by default", () => {
|
||||
const command = `resolc ${paths.pathToBasicYulContract} --yul`;
|
||||
const result = executeCommand(command);
|
||||
const commandInvalid = 'resolc --yul';
|
||||
const commandInvalid = "resolc --yul";
|
||||
const resultInvalid = executeCommand(commandInvalid);
|
||||
|
||||
it("Valid command exit code = 0", () => {
|
||||
@@ -18,11 +17,11 @@ describe("Run with --yul by default", () => {
|
||||
expect(result.output).toMatch(/(No output requested)/i);
|
||||
});
|
||||
|
||||
|
||||
xit("solc exit code == resolc exit code", () => { // unknown solc issue for datatype of the contract
|
||||
const command = `solc ${paths.pathToBasicSolContract} --yul`;
|
||||
const solcResult = executeCommand(command);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
xit("solc exit code == resolc exit code", () => {
|
||||
// unknown solc issue for datatype of the contract
|
||||
const command = `solc ${paths.pathToBasicSolContract} --yul`;
|
||||
const solcResult = executeCommand(command);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
|
||||
it("run invalid: resolc --yul", () => {
|
||||
@@ -33,7 +32,7 @@ describe("Run with --yul by default", () => {
|
||||
});
|
||||
|
||||
it("Invalid solc exit code == Invalid resolc exit code", () => {
|
||||
const command = 'solc --yul';
|
||||
const command = "solc --yul";
|
||||
const solcResult = executeCommand(command);
|
||||
expect(solcResult.exitCode).toBe(resultInvalid.exitCode);
|
||||
});
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"module": "CommonJS",
|
||||
"outDir": "./dist",
|
||||
"outDir": "./dist"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,153 +1,192 @@
|
||||
import { executeCommand } from "../src/helper";
|
||||
import { paths } from '../src/entities';
|
||||
|
||||
import { paths } from "../src/entities";
|
||||
|
||||
describe("Set of --combined-json tests", () => {
|
||||
const zksolcCommand = 'zksolc';
|
||||
const solcCommand = 'solc';
|
||||
const json_args: string[] = [`abi`, `hashes`, `metadata`, `devdoc`, `userdoc`, `storage-layout`, `ast`, `asm`, `bin`, `bin-runtime`];
|
||||
const zksolcCommand = "zksolc";
|
||||
const solcCommand = "solc";
|
||||
const json_args: string[] = [
|
||||
`abi`,
|
||||
`hashes`,
|
||||
`metadata`,
|
||||
`devdoc`,
|
||||
`userdoc`,
|
||||
`storage-layout`,
|
||||
`ast`,
|
||||
`asm`,
|
||||
`bin`,
|
||||
`bin-runtime`,
|
||||
];
|
||||
|
||||
//id1742:I
|
||||
describe(`Run ${zksolcCommand} with just --combined-json`, () => {
|
||||
const args = [`--combined-json`];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
//id1742:I
|
||||
describe(`Run ${zksolcCommand} with just --combined-json`, () => {
|
||||
const args = [`--combined-json`];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
|
||||
it("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(/(requires a value but none was supplied)/i);
|
||||
});
|
||||
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
it("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
//id1742:II
|
||||
describe(`Run ${zksolcCommand} with Sol contract and --combined-json`, () => {
|
||||
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
|
||||
it("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(/(requires a value but none was supplied)/i);
|
||||
});
|
||||
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(
|
||||
/(requires a value but none was supplied)/i,
|
||||
);
|
||||
});
|
||||
|
||||
//id1742:III
|
||||
for (let i = 0; i < json_args.length; i++) {
|
||||
describe(`Run ${zksolcCommand} with Sol, --combined-json and ARG: ${json_args[i]}`, () => {
|
||||
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `${json_args[i]}`];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
|
||||
it("Valid command exit code = 0", () => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
//id1742:II
|
||||
describe(`Run ${zksolcCommand} with Sol contract and --combined-json`, () => {
|
||||
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(/(contracts)/i);
|
||||
});
|
||||
it("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
}
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(
|
||||
/(requires a value but none was supplied)/i,
|
||||
);
|
||||
});
|
||||
|
||||
//id1829:I
|
||||
for (let i = 0; i < json_args.length; i++) {
|
||||
describe(`Run ${zksolcCommand} with Sol, --combined-json and wrong ARG: --${json_args[i]}`, () => {
|
||||
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `--${json_args[i]}`];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
|
||||
it("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
//id1742:III
|
||||
for (let i = 0; i < json_args.length; i++) {
|
||||
describe(`Run ${zksolcCommand} with Sol, --combined-json and ARG: ${json_args[i]}`, () => {
|
||||
const args = [
|
||||
`${paths.pathToBasicSolContract}`,
|
||||
`--combined-json`,
|
||||
`${json_args[i]}`,
|
||||
];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(/(Invalid option|error)/i);
|
||||
});
|
||||
it("Valid command exit code = 0", () => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
}
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(/(contracts)/i);
|
||||
});
|
||||
|
||||
//id1829:II
|
||||
for (let i = 0; i < json_args.length; i++) {
|
||||
describe(`Run ${zksolcCommand} with Sol, --combined-json and multiple ARG: ${json_args[i]} ${json_args[i]}`, () => {
|
||||
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `${json_args[i]}`, `${json_args[i]}`];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
xit("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
//id1829:I
|
||||
for (let i = 0; i < json_args.length; i++) {
|
||||
describe(`Run ${zksolcCommand} with Sol, --combined-json and wrong ARG: --${json_args[i]}`, () => {
|
||||
const args = [
|
||||
`${paths.pathToBasicSolContract}`,
|
||||
`--combined-json`,
|
||||
`--${json_args[i]}`,
|
||||
];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(/(No such file or directory|cannot find the file specified)/i); // Hopefully we should have more precise message here!
|
||||
});
|
||||
it("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
xit("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
}
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(/(Invalid option|error)/i);
|
||||
});
|
||||
|
||||
//id1829:III
|
||||
for (let i = 0; i < json_args.length; i++) {
|
||||
describe(`Run ${zksolcCommand} with Sol, and multiple (--combined-json ${json_args[i]})`, () => {
|
||||
const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `${json_args[i]}`, `--combined-json`, `${json_args[i]}`];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
it("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
//id1829:II
|
||||
for (let i = 0; i < json_args.length; i++) {
|
||||
describe(`Run ${zksolcCommand} with Sol, --combined-json and multiple ARG: ${json_args[i]} ${json_args[i]}`, () => {
|
||||
const args = [
|
||||
`${paths.pathToBasicSolContract}`,
|
||||
`--combined-json`,
|
||||
`${json_args[i]}`,
|
||||
`${json_args[i]}`,
|
||||
];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(/(cannot be used multiple times)/i);
|
||||
});
|
||||
xit("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
}
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(
|
||||
/(No such file or directory|cannot find the file specified)/i,
|
||||
); // Hopefully we should have more precise message here!
|
||||
});
|
||||
|
||||
//id1830
|
||||
for (let i = 0; i < json_args.length; i++) {
|
||||
describe(`Run ${zksolcCommand} with Yul, and --combined-json ${json_args[i]}`, () => {
|
||||
const args = [`${paths.pathToBasicYulContract}`, `--combined-json`, `${json_args[i]}`];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
xit("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
it("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
//id1829:III
|
||||
for (let i = 0; i < json_args.length; i++) {
|
||||
describe(`Run ${zksolcCommand} with Sol, and multiple (--combined-json ${json_args[i]})`, () => {
|
||||
const args = [
|
||||
`${paths.pathToBasicSolContract}`,
|
||||
`--combined-json`,
|
||||
`${json_args[i]}`,
|
||||
`--combined-json`,
|
||||
`${json_args[i]}`,
|
||||
];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(/(ParserError: Expected identifier)/i);
|
||||
});
|
||||
asd
|
||||
it("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
}
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(/(cannot be used multiple times)/i);
|
||||
});
|
||||
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//id1830
|
||||
for (let i = 0; i < json_args.length; i++) {
|
||||
describe(`Run ${zksolcCommand} with Yul, and --combined-json ${json_args[i]}`, () => {
|
||||
const args = [
|
||||
`${paths.pathToBasicYulContract}`,
|
||||
`--combined-json`,
|
||||
`${json_args[i]}`,
|
||||
];
|
||||
const result = executeCommand(zksolcCommand, args);
|
||||
|
||||
it("Valid command exit code = 1", () => {
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
it("--combined-json error is presented", () => {
|
||||
expect(result.output).toMatch(/(ParserError: Expected identifier)/i);
|
||||
});
|
||||
asd;
|
||||
|
||||
it("solc exit code == zksolc exit code", () => {
|
||||
const solcResult = executeCommand(solcCommand, args);
|
||||
expect(solcResult.exitCode).toBe(result.exitCode);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../../target/wasm32-unknown-emscripten/release/resolc.js
|
||||
@@ -1 +0,0 @@
|
||||
../../../target/wasm32-unknown-emscripten/release/resolc.wasm
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources": {
|
||||
"fixtures/instantiate.sol": {
|
||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.2 <0.9.0;\ncontract ChildContract {\n constructor() {\n }\n}\ncontract MainContract {\n constructor() {\n ChildContract newContract = new ChildContract();\n }\n}"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": ["abi"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
# @parity/revive
|
||||
|
||||
Node.js module to compile Solidity contracts to Polkavm bytecode, using [Revive](https://github.com/paritytech/revive)
|
||||
|
||||
# Usage from Node.js
|
||||
|
||||
```typescript
|
||||
const sources = {
|
||||
["contracts/1_Storage.sol"]: {
|
||||
content: readFileSync("fixtures/storage.sol", "utf8"),
|
||||
}
|
||||
|
||||
const out = await compile(sources);
|
||||
```
|
||||
|
||||
# Usage from shell
|
||||
|
||||
```bash
|
||||
npx @parity/revive@latest --bin contracts/1_Storage.sol
|
||||
```
|
||||
@@ -0,0 +1,11 @@
|
||||
import globals from 'globals'
|
||||
import pluginJs from '@eslint/js'
|
||||
import tseslint from 'typescript-eslint'
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
{ files: ['**/*.{mjs,ts}'] },
|
||||
{ languageOptions: { globals: globals.browser } },
|
||||
pluginJs.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
]
|
||||
@@ -0,0 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^9999;
|
||||
|
||||
/**
|
||||
* @title Storage
|
||||
* @dev Store & retrieve value in a variable
|
||||
* @custom:dev-run-script ./scripts/deploy_with_ethers.ts
|
||||
*/
|
||||
contract BadPragma {
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.8.2 <0.9.0;
|
||||
|
||||
/**
|
||||
* @title Storage
|
||||
* @dev Store & retrieve value in a variable
|
||||
* @custom:dev-run-script ./scripts/deploy_with_ethers.ts
|
||||
*/
|
||||
contract Storage {
|
||||
|
||||
uint256 number;
|
||||
|
||||
/**
|
||||
* @dev Store value in variable
|
||||
* @param num value to store
|
||||
*/
|
||||
function store(uint256 num) public {
|
||||
number = num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return value
|
||||
* @return value of 'number'
|
||||
*/
|
||||
function retrieve() public view returns (uint256){
|
||||
return number;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// missing license and pragama
|
||||
/**
|
||||
* @title Storage
|
||||
* @dev Store & retrieve value in a variable
|
||||
* @custom:dev-run-script ./scripts/deploy_with_ethers.ts
|
||||
*/
|
||||
contract Storage {
|
||||
|
||||
uint256 number;
|
||||
|
||||
/**
|
||||
* @dev Store value in variable
|
||||
* @param num value to store
|
||||
*/
|
||||
function store(uint256 num) public {
|
||||
number = num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Return value
|
||||
* @return value of 'number'
|
||||
*/
|
||||
function retrieve() public view returns (uint256){
|
||||
return number;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Compatible with OpenZeppelin Contracts ^5.0.0
|
||||
pragma solidity ^0.8.22;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
|
||||
|
||||
contract MyToken is ERC20, Ownable, ERC20Permit {
|
||||
constructor(address initialOwner)
|
||||
ERC20("MyToken", "MTK")
|
||||
Ownable(initialOwner)
|
||||
ERC20Permit("MyToken")
|
||||
{
|
||||
_mint(msg.sender, 100 * 10 ** decimals());
|
||||
}
|
||||
|
||||
function mint(address to, uint256 amount) public onlyOwner {
|
||||
_mint(to, amount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@parity/resolc",
|
||||
"license": "Apache-2.0",
|
||||
"version": "0.0.0-updated-via-gh-releases",
|
||||
"author": "Parity <admin@parity.io> (https://parity.io)",
|
||||
"module": "index.ts",
|
||||
"types": "./dist/index.d.ts",
|
||||
"main": "./dist/index.js",
|
||||
"bin": {
|
||||
"resolc": "./dist/bin.js"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc && cp src/resolc/** dist/resolc",
|
||||
"test": "npm run build && node ./dist/index.test.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.14.0",
|
||||
"@openzeppelin/contracts": "5.1.0",
|
||||
"eslint": "^9.14.0",
|
||||
"globals": "^15.12.0",
|
||||
"tar": "^7.4.3",
|
||||
"typescript": "^5.6.3",
|
||||
"typescript-eslint": "^8.13.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "^22.9.0",
|
||||
"commander": "^13.1.0",
|
||||
"package-json": "^10.0.1",
|
||||
"solc": "^0.8.29"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
Executable
+203
@@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import * as commander from 'commander'
|
||||
import * as fs from 'fs'
|
||||
import * as os from 'os'
|
||||
import * as path from 'path'
|
||||
import * as resolc from '.'
|
||||
import { SolcInput } from '.'
|
||||
|
||||
async function main() {
|
||||
// hold on to any exception handlers that existed prior to this script running, we'll be adding them back at the end
|
||||
const originalUncaughtExceptionListeners =
|
||||
process.listeners('uncaughtException')
|
||||
// FIXME: remove annoying exception catcher of Emscripten
|
||||
// see https://github.com/chriseth/browser-solidity/issues/167
|
||||
process.removeAllListeners('uncaughtException')
|
||||
|
||||
const program = new commander.Command()
|
||||
|
||||
program.name('solcjs')
|
||||
program.version(resolc.version())
|
||||
program
|
||||
.option('--bin', 'Binary of the contracts in hex.')
|
||||
.option('--abi', 'ABI of the contracts.')
|
||||
.option(
|
||||
'--base-path <path>',
|
||||
'Root of the project source tree. ' +
|
||||
'The import callback will attempt to interpret all import paths as relative to this directory.'
|
||||
)
|
||||
.option(
|
||||
'--include-path <path...>',
|
||||
'Extra source directories available to the import callback. ' +
|
||||
'When using a package manager to install libraries, use this option to specify directories where packages are installed. ' +
|
||||
'Can be used multiple times to provide multiple locations.'
|
||||
)
|
||||
.option(
|
||||
'-o, --output-dir <output-directory>',
|
||||
'Output directory for the contracts.'
|
||||
)
|
||||
.option('-p, --pretty-json', 'Pretty-print all JSON output.', false)
|
||||
.option('-v, --verbose', 'More detailed console output.', false)
|
||||
.argument('<files...>')
|
||||
|
||||
program.parse(process.argv)
|
||||
const options = program.opts<{
|
||||
verbose: boolean
|
||||
abi: boolean
|
||||
bin: boolean
|
||||
outputDir?: string
|
||||
prettyJson: boolean
|
||||
basePath?: string
|
||||
includePath?: string[]
|
||||
}>()
|
||||
const files: string[] = program.args
|
||||
const destination = options.outputDir ?? '.'
|
||||
|
||||
function abort(msg: string) {
|
||||
console.error(msg || 'Error occurred')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
function withUnixPathSeparators(filePath: string) {
|
||||
// On UNIX-like systems forward slashes in paths are just a part of the file name.
|
||||
if (os.platform() !== 'win32') {
|
||||
return filePath
|
||||
}
|
||||
|
||||
return filePath.replace(/\\/g, '/')
|
||||
}
|
||||
|
||||
function makeSourcePathRelativeIfPossible(sourcePath: string) {
|
||||
const absoluteBasePath = options.basePath
|
||||
? path.resolve(options.basePath)
|
||||
: path.resolve('.')
|
||||
const absoluteIncludePaths = options.includePath
|
||||
? options.includePath.map((prefix: string) => {
|
||||
return path.resolve(prefix)
|
||||
})
|
||||
: []
|
||||
|
||||
// Compared to base path stripping logic in solc this is much simpler because path.resolve()
|
||||
// handles symlinks correctly (does not resolve them except in work dir) and strips .. segments
|
||||
// from paths going beyond root (e.g. `/../../a/b/c` -> `/a/b/c/`). It's simpler also because it
|
||||
// ignores less important corner cases: drive letters are not stripped from absolute paths on
|
||||
// Windows and UNC paths are not handled in a special way (at least on Linux). Finally, it has
|
||||
// very little test coverage so there might be more differences that we are just not aware of.
|
||||
const absoluteSourcePath = path.resolve(sourcePath)
|
||||
|
||||
for (const absolutePrefix of [absoluteBasePath].concat(
|
||||
absoluteIncludePaths
|
||||
)) {
|
||||
const relativeSourcePath = path.relative(
|
||||
absolutePrefix,
|
||||
absoluteSourcePath
|
||||
)
|
||||
|
||||
if (!relativeSourcePath.startsWith('../')) {
|
||||
return withUnixPathSeparators(relativeSourcePath)
|
||||
}
|
||||
}
|
||||
|
||||
// File is not located inside base path or include paths so use its absolute path.
|
||||
return withUnixPathSeparators(absoluteSourcePath)
|
||||
}
|
||||
|
||||
function toFormattedJson<T>(input: T) {
|
||||
return JSON.stringify(input, null, options.prettyJson ? 4 : 0)
|
||||
}
|
||||
|
||||
if (files.length === 0) {
|
||||
console.error('Must provide a file')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (!(options.bin || options.abi)) {
|
||||
abort('Invalid option selected, must specify either --bin or --abi')
|
||||
}
|
||||
|
||||
const sources: SolcInput = {}
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
try {
|
||||
sources[makeSourcePathRelativeIfPossible(files[i])] = {
|
||||
content: fs.readFileSync(files[i]).toString(),
|
||||
}
|
||||
} catch (e) {
|
||||
abort('Error reading ' + files[i] + ': ' + e)
|
||||
}
|
||||
}
|
||||
|
||||
if (options.verbose) {
|
||||
console.log('>>> Compiling:\n' + toFormattedJson(sources) + '\n')
|
||||
}
|
||||
|
||||
const output = await resolc.compile(sources)
|
||||
let hasError = false
|
||||
|
||||
if (!output) {
|
||||
abort('No output from compiler')
|
||||
} else if (output.errors) {
|
||||
for (const error in output.errors) {
|
||||
const message = output.errors[error]
|
||||
if (message.severity === 'warning') {
|
||||
console.log(message.formattedMessage)
|
||||
} else {
|
||||
console.error(message.formattedMessage)
|
||||
hasError = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fs.mkdirSync(destination, { recursive: true })
|
||||
|
||||
function writeFile(file: string, content: Buffer | string) {
|
||||
file = path.join(destination, file)
|
||||
fs.writeFile(file, content, function (err) {
|
||||
if (err) {
|
||||
console.error('Failed to write ' + file + ': ' + err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
for (const fileName in output.contracts) {
|
||||
for (const contractName in output.contracts[fileName]) {
|
||||
let contractFileName = fileName + ':' + contractName
|
||||
contractFileName = contractFileName.replace(/[:./\\]/g, '_')
|
||||
|
||||
if (options.bin) {
|
||||
writeFile(
|
||||
contractFileName + '.polkavm',
|
||||
Buffer.from(
|
||||
output.contracts[fileName][contractName].evm.bytecode
|
||||
.object,
|
||||
'hex'
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (options.abi) {
|
||||
writeFile(
|
||||
contractFileName + '.abi',
|
||||
toFormattedJson(
|
||||
output.contracts[fileName][contractName].abi
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Put back original exception handlers.
|
||||
originalUncaughtExceptionListeners.forEach(function (listener) {
|
||||
process.addListener('uncaughtException', listener)
|
||||
})
|
||||
|
||||
if (hasError) {
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -0,0 +1,132 @@
|
||||
import { test } from 'node:test'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import assert from 'node:assert'
|
||||
import { compile, tryResolveImport } from '.'
|
||||
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 = [{}]
|
||||
if (isResolcInPath()) {
|
||||
compileOptions.push({ bin: 'resolc' })
|
||||
}
|
||||
|
||||
for (const options of compileOptions) {
|
||||
test(`check Ok output with option ${JSON.stringify(options)}`, async () => {
|
||||
const contract = 'fixtures/token.sol'
|
||||
const sources = {
|
||||
[contract]: {
|
||||
content: readFileSync('fixtures/storage.sol', 'utf8'),
|
||||
},
|
||||
}
|
||||
|
||||
const out = await compile(sources, options)
|
||||
assert(out.contracts[contract].Storage.abi != null)
|
||||
assert(out.contracts[contract].Storage.evm.bytecode != null)
|
||||
})
|
||||
}
|
||||
|
||||
test('check Err output', async () => {
|
||||
const sources = {
|
||||
bad: {
|
||||
content: readFileSync('fixtures/storage_bad.sol', 'utf8'),
|
||||
},
|
||||
}
|
||||
|
||||
const out = await compile(sources)
|
||||
assert(
|
||||
out?.errors?.[0].message.includes(
|
||||
'SPDX license identifier not provided in source file'
|
||||
)
|
||||
)
|
||||
assert(
|
||||
out?.errors?.[1].message.includes(
|
||||
'Source file does not specify required compiler version'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
test('check Err from stderr', async () => {
|
||||
const sources = {
|
||||
bad: {
|
||||
content: readFileSync('fixtures/bad_pragma.sol', 'utf8'),
|
||||
},
|
||||
}
|
||||
|
||||
try {
|
||||
await compile(sources)
|
||||
assert(false, 'Expected error')
|
||||
} catch (error) {
|
||||
assert(
|
||||
String(error).includes(
|
||||
'Source file requires different compiler version'
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
test('resolve import', () => {
|
||||
const cases = [
|
||||
// local
|
||||
{
|
||||
file: './fixtures/storage.sol',
|
||||
expected: resolve('fixtures/storage.sol'),
|
||||
},
|
||||
// scopped module with version
|
||||
{
|
||||
file: '@openzeppelin/contracts@5.1.0/token/ERC20/ERC20.sol',
|
||||
expected: resolve(
|
||||
'node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol'
|
||||
),
|
||||
},
|
||||
// scopped module without version
|
||||
{
|
||||
file: '@openzeppelin/contracts/token/ERC20/ERC20.sol',
|
||||
expected: resolve(
|
||||
'node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol'
|
||||
),
|
||||
},
|
||||
// scopped module with wrong version
|
||||
{
|
||||
file: '@openzeppelin/contracts@4.8.3/token/ERC20/ERC20.sol',
|
||||
expected: `Error: Version mismatch: Specified @openzeppelin/contracts@4.8.3, but installed version is 5.1.0`,
|
||||
},
|
||||
// module without version
|
||||
{
|
||||
file: 'acorn/package.json',
|
||||
expected: resolve('node_modules/acorn/package.json'),
|
||||
},
|
||||
// scopped module with version
|
||||
{
|
||||
file: 'acorn@8.14.0/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`,
|
||||
},
|
||||
]
|
||||
|
||||
for (const { file, expected } of cases) {
|
||||
try {
|
||||
const resolved = tryResolveImport(file)
|
||||
assert(
|
||||
resolved === expected,
|
||||
`\nGot:\n${resolved}\nExpected:\n${expected}`
|
||||
)
|
||||
} catch (error) {
|
||||
assert(
|
||||
String(error) == expected,
|
||||
`\nGot:\n${String(error)}\nExpected:\n${expected}`
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,202 @@
|
||||
import solc from 'solc'
|
||||
import { spawn } from 'child_process'
|
||||
import { resolc, version as resolcVersion } from './resolc'
|
||||
import path from 'path'
|
||||
import { existsSync, readFileSync } from 'fs'
|
||||
|
||||
export type SolcInput = {
|
||||
[contractName: string]: {
|
||||
content: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SolcError = {
|
||||
component: string
|
||||
errorCode: string
|
||||
formattedMessage: string
|
||||
message: string
|
||||
severity: string
|
||||
sourceLocation?: {
|
||||
file: string
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
type: string
|
||||
}
|
||||
|
||||
export type SolcOutput = {
|
||||
contracts: {
|
||||
[contractPath: string]: {
|
||||
[contractName: string]: {
|
||||
abi: Array<{
|
||||
name: string
|
||||
inputs: Array<{ name: string; type: string }>
|
||||
outputs: Array<{ name: string; type: string }>
|
||||
stateMutability: string
|
||||
type: string
|
||||
}>
|
||||
evm: {
|
||||
bytecode: { object: string }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
errors?: Array<SolcError>
|
||||
}
|
||||
|
||||
export function resolveInputs(sources: SolcInput): SolcInput {
|
||||
const input = {
|
||||
language: 'Solidity',
|
||||
sources,
|
||||
settings: {
|
||||
outputSelection: {
|
||||
'*': {
|
||||
'*': ['evm.bytecode.object'],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const out = solc.compile(JSON.stringify(input), {
|
||||
import: (path: string) => {
|
||||
return {
|
||||
contents: readFileSync(tryResolveImport(path), 'utf8'),
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const output = JSON.parse(out) as {
|
||||
sources: { [fileName: string]: { id: number } }
|
||||
errors: Array<SolcError>
|
||||
}
|
||||
|
||||
if (output.errors && Object.keys(output.sources).length === 0) {
|
||||
throw new Error(output.errors[0].formattedMessage)
|
||||
}
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.keys(output.sources).map((fileName) => {
|
||||
return [
|
||||
fileName,
|
||||
sources[fileName] ?? {
|
||||
content: readFileSync(tryResolveImport(fileName), 'utf8'),
|
||||
},
|
||||
]
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
export function version(): string {
|
||||
const v = resolcVersion()
|
||||
return v.split(' ').pop() ?? v
|
||||
}
|
||||
|
||||
export async function compile(
|
||||
sources: SolcInput,
|
||||
option: { bin?: string } = {}
|
||||
): Promise<SolcOutput> {
|
||||
const input = JSON.stringify({
|
||||
language: 'Solidity',
|
||||
sources: resolveInputs(sources),
|
||||
settings: {
|
||||
optimizer: { enabled: true, runs: 200 },
|
||||
outputSelection: {
|
||||
'*': {
|
||||
'*': ['abi'],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if (option.bin) {
|
||||
return compileWithBin(input, option.bin)
|
||||
}
|
||||
|
||||
return resolc(input)
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve an import path to a file path.
|
||||
* @param importPath - The import path to resolve.
|
||||
*/
|
||||
export function tryResolveImport(importPath: string) {
|
||||
// resolve local path
|
||||
if (existsSync(importPath)) {
|
||||
return path.resolve(importPath)
|
||||
}
|
||||
|
||||
const importRegex = /^(@?[^@/]+(?:\/[^@/]+)?)(?:@([^/]+))?(\/.+)$/
|
||||
const match = importPath.match(importRegex)
|
||||
|
||||
if (!match) {
|
||||
throw new Error('Invalid import path format.')
|
||||
}
|
||||
|
||||
const basePackage = match[1] // "foo", "@scope/foo"
|
||||
const specifiedVersion = match[2] // "1.2.3" (optional)
|
||||
const relativePath = match[3] // "/path/to/file.sol"
|
||||
|
||||
let packageJsonPath
|
||||
try {
|
||||
packageJsonPath = require.resolve(
|
||||
path.join(basePackage, 'package.json')
|
||||
)
|
||||
} catch {
|
||||
throw new Error(`Could not resolve package ${basePackage}`)
|
||||
}
|
||||
|
||||
// Check if a version was specified and compare with the installed version
|
||||
if (specifiedVersion) {
|
||||
const installedVersion = JSON.parse(
|
||||
readFileSync(packageJsonPath, 'utf-8')
|
||||
).version
|
||||
|
||||
if (installedVersion !== specifiedVersion) {
|
||||
throw new Error(
|
||||
`Version mismatch: Specified ${basePackage}@${specifiedVersion}, but installed version is ${installedVersion}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const packageRoot = path.dirname(packageJsonPath)
|
||||
|
||||
// Construct full path to the requested file
|
||||
const resolvedPath = path.join(packageRoot, relativePath)
|
||||
if (existsSync(resolvedPath)) {
|
||||
return resolvedPath
|
||||
} else {
|
||||
throw new Error(`Resolved path ${resolvedPath} does not exist.`)
|
||||
}
|
||||
}
|
||||
function compileWithBin(input: string, bin: string): PromiseLike<SolcOutput> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const process = spawn(bin, ['--standard-json'])
|
||||
|
||||
let output = ''
|
||||
let error = ''
|
||||
|
||||
process.stdin.write(input)
|
||||
process.stdin.end()
|
||||
|
||||
process.stdout.on('data', (data) => {
|
||||
output += data.toString()
|
||||
})
|
||||
|
||||
process.stderr.on('data', (data) => {
|
||||
error += data.toString()
|
||||
})
|
||||
|
||||
process.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
try {
|
||||
const result: SolcOutput = JSON.parse(output)
|
||||
resolve(result)
|
||||
} catch {
|
||||
reject(new Error(`Failed to parse output`))
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`Process exited with code ${code}: ${error}`))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import soljson from 'solc/soljson'
|
||||
import Resolc from './resolc/resolc'
|
||||
import type { SolcOutput } from '.'
|
||||
|
||||
export function resolc(input: string): SolcOutput {
|
||||
const m = Resolc() as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
m.soljson = soljson
|
||||
m.writeToStdin(input)
|
||||
m.callMain(['--standard-json'])
|
||||
const err = m.readFromStderr()
|
||||
|
||||
if (err) {
|
||||
throw new Error(err)
|
||||
}
|
||||
|
||||
return JSON.parse(m.readFromStdout()) as SolcOutput
|
||||
}
|
||||
|
||||
export function version(): string {
|
||||
const m = Resolc() as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
m.soljson = soljson
|
||||
m.callMain(['--version'])
|
||||
const err = m.readFromStderr()
|
||||
|
||||
if (err) {
|
||||
throw new Error(err)
|
||||
}
|
||||
|
||||
return m.readFromStdout()
|
||||
}
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../../../target/wasm32-unknown-emscripten/release/resolc.js
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../../../target/wasm32-unknown-emscripten/release/resolc.wasm
|
||||
Vendored
+95
@@ -0,0 +1,95 @@
|
||||
declare module 'solc/soljson' {}
|
||||
|
||||
declare module 'solc' {
|
||||
// Basic types for input/output handling
|
||||
export interface CompileInput {
|
||||
language: string
|
||||
sources: {
|
||||
[fileName: string]: {
|
||||
content: string
|
||||
}
|
||||
}
|
||||
settings?: {
|
||||
optimizer?: {
|
||||
enabled: boolean
|
||||
runs: number
|
||||
}
|
||||
outputSelection: {
|
||||
[fileName: string]: {
|
||||
[contractName: string]: string[]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface CompileOutput {
|
||||
errors?: Array<{
|
||||
component: string
|
||||
errorCode: string
|
||||
formattedMessage: string
|
||||
message: string
|
||||
severity: string
|
||||
sourceLocation?: {
|
||||
file: string
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
type: string
|
||||
}>
|
||||
sources?: {
|
||||
[fileName: string]: {
|
||||
id: number
|
||||
ast: object
|
||||
}
|
||||
}
|
||||
contracts?: {
|
||||
[fileName: string]: {
|
||||
[contractName: string]: {
|
||||
abi: object[]
|
||||
evm: {
|
||||
bytecode: {
|
||||
object: string
|
||||
sourceMap: string
|
||||
linkReferences: {
|
||||
[fileName: string]: {
|
||||
[libraryName: string]: Array<{
|
||||
start: number
|
||||
length: number
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
deployedBytecode: {
|
||||
object: string
|
||||
sourceMap: string
|
||||
linkReferences: {
|
||||
[fileName: string]: {
|
||||
[libraryName: string]: Array<{
|
||||
start: number
|
||||
length: number
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main exported functions
|
||||
export function compile(
|
||||
input: string | CompileInput,
|
||||
options?: {
|
||||
import: (path: string) =>
|
||||
| {
|
||||
contents: string
|
||||
error?: undefined
|
||||
}
|
||||
| {
|
||||
error: string
|
||||
contents?: undefined
|
||||
}
|
||||
}
|
||||
): string
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"allowJs": true,
|
||||
"moduleResolution": "node",
|
||||
"module": "commonjs",
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2022"],
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"useUnknownInCatchVariables": true,
|
||||
"types": ["node"],
|
||||
"typeRoots": ["./node_modules/@types", "./src"],
|
||||
"paths": {
|
||||
"#src/*": ["./src/*"]
|
||||
},
|
||||
"plugins": []
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
+1213
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ const RESOLC_WASM_URI =
|
||||
process.env.RELEASE_RESOLC_WASM_URI || "http://127.0.0.1:8080/resolc.wasm";
|
||||
const RESOLC_WASM_TARGET_DIR = path.join(
|
||||
__dirname,
|
||||
"../target/wasm32-unknown-emscripten/release",
|
||||
"../../target/wasm32-unknown-emscripten/release",
|
||||
);
|
||||
const RESOLC_JS = path.join(RESOLC_WASM_TARGET_DIR, "resolc.js");
|
||||
const RESOLC_WEB_JS = path.join(RESOLC_WASM_TARGET_DIR, "resolc_web.js");
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../../../target/wasm32-unknown-emscripten/release/resolc.js
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../../../target/wasm32-unknown-emscripten/release/resolc.wasm
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources": {
|
||||
"fixtures/instantiate.sol": {
|
||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.8.2 <0.9.0;\ncontract ChildContract {\n constructor() {\n }\n}\ncontract MainContract {\n constructor() {\n ChildContract newContract = new ChildContract();\n }\n}"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": ["abi"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,9 +72,7 @@
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi"
|
||||
]
|
||||
"*": ["abi"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,15 +65,15 @@ describe("Compile Function Tests", function () {
|
||||
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"],
|
||||
).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");
|
||||
@@ -117,27 +117,26 @@ describe("Compile Function Tests", function () {
|
||||
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,
|
||||
).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,
|
||||
).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");
|
||||
});
|
||||
|
||||
});
|
||||
+15
-12
@@ -1,13 +1,16 @@
|
||||
{
|
||||
"name": "root",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test:cli": "npm run test -w crates/solidity/src/tests/cli-tests",
|
||||
"test:wasm": "npm run test:node -w js",
|
||||
"build:package": "npm run build:package -w js"
|
||||
},
|
||||
"workspaces": [
|
||||
"crates/solidity/src/tests/cli-tests",
|
||||
"js"
|
||||
]
|
||||
}
|
||||
"name": "root",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test:cli": "npm run test -w crates/solidity/src/tests/cli-tests",
|
||||
"test:wasm": "npm run test:node -w js/wasm",
|
||||
"build:package": "npm run build:package -w js/wasm",
|
||||
"lint": "npx eslint 'js/**/*.{cjs,mjs,ts}' && npx prettier --check '**/*.{ts,json,yml,md}'",
|
||||
"lint:fix": "npx prettier --write '**/*.{mjs,cjs,ts,json,yml,md}'"
|
||||
},
|
||||
"workspaces": [
|
||||
"crates/solidity/src/tests/cli-tests",
|
||||
"js/wasm",
|
||||
"js/resolc"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user