Compare commits

..

45 Commits

Author SHA1 Message Date
xermicus af8074cfde Merge branch 'main' into cl/optsize 2025-07-14 22:01:32 +02:00
xermicus a0396dd6d0 solc-json-interface: support for YUL optimizer details (#361)
- Add support for the YUL optimizer details in the standard json input
definition.
- Make optimizer settings optional. They can be omitted and solc will
pick default values ([see here for
reference](https://docs.soliditylang.org/en/latest/using-the-compiler.html#input-description)).

For example allows to use the
[`yul-phaser`](https://github.com/ethereum/solidity/blob/0917604a5ec7cff8bd40a1137f4fcb303fb90527/tools/yulPhaser/README.md?plain=1)
utility. I did a single search with slightly adjusted costs (just made
some educated guess) and after an hour or so this already found an
optimizer sequence
(`OESsShMxeoufcSTvlFxtelTfnfEvicdFxnsvopgCaIeLcnvsTtUrUgdVTUttaeUomccTTTuujsVVvVDvvueUrTjUOmjrrhuuTtj`)
which shrinks the size of the `EndpointV2.sol` from LayerZero by 10%.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: xermicus <cyrill@parity.io>
2025-07-14 11:25:45 +02:00
Alexander Samusev 141a8b752c Make nigthly version semver compliant (#360)
cc https://github.com/paritytech/revive/pull/357
2025-07-08 17:17:05 +02:00
Alexander Samusev 7c932f719b Generate nightly builds and json files (#357)
PR adds a nightly release pipeline.
Since the logic for the nightly build and release differs significantly
from the usual pipeline, I decided to put it in a separate file. The
same applies to the Python script that generates JSON files.

The nightly pipeline runs at 01:00 UTC every day, producing artefacts
and retaining them for 40 days if commits are made the day before it
runs.

cc https://github.com/paritytech/revive/issues/355
cc https://github.com/paritytech/devops/issues/4141
2025-07-07 17:46:55 +02:00
xermicus b238913a7d emit YUL builtins debug line info and fix debug info source file (#358)
This PR fixes and enhances debug info generation:
1. Adds line information for each lowered YUL builtin and the `if`
statement.
2. Fixes the debug info source path to match the YUL file of the
contract dumped to the `--debug-output-dir`.

This improves inspection of the generated code a lot. Excerpt from
`llvm-objdump -Sl /tmp/dbg/contracts_EndpointV2.sol.EndpointV2.so`:

```
; /tmp/dbg/contracts_EndpointV2.sol.EndpointV2.yul:203
;                 let _1 := memoryguard(0x80)
   13c3e: 3aa5b023      sd      a0, 0x3a0(a1)
   13c42: 38a5bc23      sd      a0, 0x398(a1)
   13c46: 38a5b823      sd      a0, 0x390(a1)
   13c4a: 08000513      li      a0, 0x80
   13c4e: 38a5b423      sd      a0, 0x388(a1)
; /tmp/dbg/contracts_EndpointV2.sol.EndpointV2.yul:204
;                 mstore(64, _1)
   13c52: 3885b503      ld      a0, 0x388(a1)
   13c56: 3905b603      ld      a2, 0x390(a1)
   13c5a: 3985b683      ld      a3, 0x398(a1)
   13c5e: 3a05b703      ld      a4, 0x3a0(a1)
   13c62: 38e5b023      sd      a4, 0x380(a1)
   13c66: 36d5bc23      sd      a3, 0x378(a1)
   13c6a: 36c5b823      sd      a2, 0x370(a1)
   13c6e: 36a5b423      sd      a0, 0x368(a1)
   13c72: 04000513      li      a0, 0x40
   13c76: 65d9          lui     a1, 0x16
   13c78: a605859b      addiw   a1, a1, -0x5a0
   13c7c: 95a6          add     a1, a1, s1
   13c7e: 00000097      auipc   ra, 0x0
   13c82: 000080e7      jalr    ra <__runtime+0x1de>

0000000000013c86 <.Lpcrel_hi27>:
; /tmp/dbg/contracts_EndpointV2.sol.EndpointV2.yul:205
;                 if iszero(lt(calldatasize(), 4))
   13c86: 00000517      auipc   a0, 0x0
   13c8a: 00053503      ld      a0, 0x0(a0)
   13c8e: 4108          lw      a0, 0x0(a0)
   13c90: 4591          li      a1, 0x4
   13c92: 06b56263      bltu    a0, a1, 0x13cf6 <.Lpcrel_hi27+0x70>
   13c96: a009          j       0x13c98 <.Lpcrel_hi27+0x12>
```

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-07-04 19:56:52 +02:00
Cyrill Leutwiler bb3b6ddb41 wip evm builtins
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-07-03 15:36:11 +02:00
Cyrill Leutwiler dfe56f9306 wip: args and returns
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-07-03 10:08:26 +02:00
Cyrill Leutwiler 63011b6d24 type fix
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-07-02 21:22:02 +02:00
Cyrill Leutwiler d40ef3e462 wip: variables
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-07-02 20:16:06 +02:00
xermicus ed608699af release resolc v0.3.0 (#354)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-06-28 12:32:48 +02:00
xermicus 75fc23c810 add the missing memset builtin (#353)
Closes  #350

- Add the missing `memset` builtin which was accidentally deleted in a
previous PR.
- Add a compilation test to ensure the `memset` builtin is present.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-06-28 12:01:34 +02:00
xermicus 486c9c28a1 new clippies (#352)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-06-28 11:48:24 +02:00
PG Herveou 7656c6a8b4 js: Add stats and override options (#348)
- Add `RESOLC_BIN` env variable to force use a binary compiler instead
of the wasm
- Add `--diff-stats` options to print file path 

e.g

```
~/github/redstone-oracles-monorepo main*
❯ npx @parity/resolc@latest --diff-stats \
  --base-path . \
  --include-path node_modules \
  --bin packages/evm-connector/contracts/samples/SampleWithEvents.sol
┌─────────┬──────────────────────────────────────────────────────────────────────────┬───────────────────────────────┬────────────┬────────────┬───────────┐
│ (index) │ file                                                                     │ contract                      │ polkavm    │ bin        │ diff      │
├─────────┼──────────────────────────────────────────────────────────────────────────┼───────────────────────────────┼────────────┼────────────┼───────────┤
│ 0       │ 'packages/evm-connector/contracts/core/CalldataExtractor.sol'            │ 'CalldataExtractor'           │ '4.31 kB'  │ '2.53 kB'  │ '70.12%'  │
│ 1       │ 'packages/evm-connector/contracts/core/RedstoneConstants.sol'            │ 'RedstoneConstants'           │ '0.80 kB'  │ '0.17 kB'  │ '368.18%' │
│ 2       │ 'packages/evm-connector/contracts/core/RedstoneDefaultsLib.sol'          │ 'RedstoneDefaultsLib'         │ '0.90 kB'  │ '0.31 kB'  │ '189.06%' │
│ 3       │ 'packages/evm-connector/contracts/libs/BitmapLib.sol'                    │ 'BitmapLib'                   │ '0.90 kB'  │ '0.31 kB'  │ '189.06%' │
│ 4       │ 'packages/evm-connector/contracts/libs/NumericArrayLib.sol'              │ 'NumericArrayLib'             │ '0.90 kB'  │ '0.31 kB'  │ '189.06%' │
│ 5       │ 'packages/evm-connector/contracts/libs/SignatureLib.sol'                 │ 'SignatureLib'                │ '0.90 kB'  │ '0.31 kB'  │ '189.06%' │
│ 6       │ 'packages/evm-connector/contracts/mocks/RedstoneConsumerNumericMock.sol' │ 'RedstoneConsumerNumericMock' │ '13.62 kB' │ '10.17 kB' │ '33.96%'  │
│ 7       │ 'packages/evm-connector/contracts/samples/SampleWithEvents.sol'          │ 'SampleWithEvents'            │ '29.34 kB' │ '15.60 kB' │ '88.03%'  │
└─────────┴──────────────────────────────────────────────────────────────────────────┴───────────────────────────────┴────────────┴────────────┴───────────┘
```
2025-06-19 12:17:09 +02:00
xermicus 8754d802fa llvm-context: bugfix PHI values in SAR builtin translation (#345)
Closes #344

Signed-off-by: xermicus <cyrill@parity.io>
2025-06-14 15:12:03 +02:00
PG Herveou 63f0266fff @parity/resolc fix sol file resolutions (#343)
second take on #339 

turns out that the resolve-pkg npm package was also failing to properly
resolve package with an exports field define in the package.json.

This fixes it and add a test case with such a package
2025-06-05 10:05:53 +02:00
xermicus e94432eaa0 ci: the resolc version dictates binary releases (#341)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-06-03 15:47:33 +02:00
xermicus 1fc3aa1554 release resolc v0.2.0 (#340)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-06-03 15:36:54 +02:00
Chris a77ab501c8 fix: exclude EVM bytecode from production solc requests (#338)
This is to address issue #320

## Introduced changes
- Added new_required_for_tests() method that includes EVM bytecode flags
- Modified new_required() to exclude evm.bytecode and
evm.deployedBytecode
- Updated test utilities to explicitly request EVM bytecode when needed

Signed-off-by: 0xf333 <0x333@tuta.io>
2025-06-03 10:43:52 +02:00
xermicus 8a3c587bbe solc-json-interface: do not unconditionally skip serialization of custom keys (#337)
The data structure can be used to build the JSON input for `resolc` too.
In that case serializing of provided custom options should not be
dismissed.

Makes the memory settings struct more modular as a drive-by.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-06-03 08:17:54 +02:00
PG Herveou 45b6a57cae Fix npm package resolution (#339)
Current approach fails with an 'ERR_PACKAGE_PATH_NOT_EXPORTED' error for
npm package that defines an exports field in the package.json

e.g:
> require.resolve('@redstone-finance/evm-connector/package.json')
will fail with
Uncaught:
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './package.json'
is not defined by "exports" in
/home/pg/github/evm-test-suite/eth-rpc/node_modules/@redstone-finance/evm-connector/package.json
  code: 'ERR_PACKAGE_PATH_NOT_EXPORTED'
2025-06-02 14:41:06 +02:00
xermicus 8a730f42cc update NPM package version (#336)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-28 08:15:41 +02:00
xermicus 413819facd do not use wildcard dependency in resolc crate (#335)
Do not use wildcard dependency in resolc crate. No sure why the publish
dry-run doesn't catch this.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-27 14:19:24 +02:00
xermicus fa0ad68279 make resolc crate publishable (#334)
- Fetching the commit SHA must not panic if not executed in a git
repository.
- Remove the license printer.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-27 14:13:12 +02:00
xermicus 004c71d5d5 add description to revive-differential (#333)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-27 13:26:05 +02:00
xermicus 4d659ac2a6 release resolc v0.1.0 (#332)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-27 12:06:42 +02:00
xermicus ed9dc60417 bump dependencies (#331)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-27 11:24:15 +02:00
xermicus 3b9144ef3b add installation instructions to the readme (#330)
Closes #294

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-27 10:23:42 +02:00
xermicus bd4e108bb0 resolc crate (#328)
- Factor the YUL crate out of `revive-solidity`.
- `revive-solidity` is in reality not a Solidity implementation but the
revive solidity compiler driver (`resolc`). By renaming we not only get
this straight but also a binary with the same name as the crate which
should be less confusing.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-27 09:48:43 +02:00
xermicus 090e3ac13c bugfix an env var in the release workflow (#329)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-27 09:29:25 +02:00
xermicus 3389865af7 solc-json-interface: make the input Cloneable (#323)
It helps external consumers working with the
`revive-solc-json-interface` crate.

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-21 10:03:32 +02:00
xermicus af39d506d9 update emsdk (#324)
Update Emscripten SDK to latest version `v4.0.9`.

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-21 07:01:41 +02:00
xermicus bb2f829361 expose custom PVM settings in the standard json interface (#318)
Exposes the following PolkaVM specific options via the standard json
interface:
- Heap size
- Stack size
- Whether to emit source level debug information

Additionally it is now forbidden to specify those as CLI option in
standard JSON mode. They are bytecode altering options and having
multiple ways to specify them creates unnecessary room for confusion:
The standard JSON input description should be sufficient and succint for
reproducible builds.

Closes #290

---------

Signed-off-by: xermicus <bigcyrill@hotmail.com>
2025-05-13 15:19:00 +02:00
xermicus 1b8fcc4649 Update the Rust version (#316)
- Update the Rust version to 1.85
- Update the package-lock.json
- Update the musl-cross docker image

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-09 20:00:58 +02:00
Cyrill Leutwiler 0e9e405f21 remove any git dependencies
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-09 17:26:20 +02:00
xermicus 722dd86c27 remove STATUS.md (#315)
This information is provided in the docs.

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-09 12:21:25 +02:00
PG Herveou 0421869e4b Replace release 0.1.0-dev.15 with 0.1.0-dev.16 (#314)
add missing patch and rename release
2025-05-08 15:26:10 +02:00
xermicus 32f55b976c update changelog (#313)
somehow went wrong

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-08 14:16:46 +02:00
PG Herveou 459a786299 v0.1.0-dev.15 release (#311)
Co-authored-by: xermicus <cyrill@parity.io>
2025-05-08 14:09:55 +02:00
xermicus fbaa45f283 support solc v0.8.30 (#308)
- Add support for solc `v0.8.30`. No changes in YUL or the binary
interface.
- Fix a semver bug in the NPM packages to correctly align their solc
dependencies with our last supported version.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-08 13:29:13 +02:00
xermicus f2fac85dae add npm package information to release checklist (#312)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-08 13:14:28 +02:00
PG Herveou b8f3073e29 Run lint:fix (#309) 2025-05-08 12:36:11 +02:00
xermicus 11d47d74ac apply size optimizations by default (#298)
So far if no optimization level was specified, optimizations for
execution time were applied. However, we currently are a bit limited on
code size. Add to that, this setting is not available in solc and people
generally ignore the docs, generating a lot of support requests.

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-07 15:35:48 +02:00
xermicus e3a9c95d32 llvm-builder: use the ninja generator for building the builtins on windows (#299)
The builtins build should use the Ninja generator (MSVC does not build a
valid archive).

Tested and verified here:
https://github.com/paritytech/revive-alex-workflowtest/releases/tag/untagged-f02d0f574bab8404fead

Closes #305

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-05-07 11:10:58 +02:00
PG Herveou a560b2d919 Fix npm-release job (#297)
follow up from #295
2025-04-30 21:48:11 +02:00
PG Herveou e07d0f0cb7 Move @parity/resolc from js-revive (#296)
- Move npm package from paritytech/js-revive 
- Rename package to `@parity/resolc`
2025-04-30 17:24:52 +02:00
216 changed files with 13794 additions and 8194 deletions
+2 -2
View File
@@ -10,8 +10,8 @@ rustflags = [
"-Clink-arg=-sWASM_ASYNC_COMPILATION=0",
"-Clink-arg=-sDYNAMIC_EXECUTION=0",
"-Clink-arg=-sALLOW_TABLE_GROWTH=1",
"-Clink-arg=--js-library=js/embed/soljson_interface.js",
"-Clink-arg=--pre-js=js/embed/pre.js",
"-Clink-arg=--js-library=js/emscripten/embed/soljson_interface.js",
"-Clink-arg=--pre-js=js/emscripten/embed/pre.js",
"-Clink-arg=-sSTACK_SIZE=128kb",
"-Clink-arg=-sNODEJS_CATCH_EXIT=0"
]
+19 -18
View File
@@ -1,18 +1,19 @@
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: "4.0.9"
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 }}
+70 -70
View File
@@ -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
+1 -1
View File
@@ -19,7 +19,7 @@ runs:
shell: bash
run: |
mkdir -p solc
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.29/${SOLC_NAME}
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.30/${SOLC_NAME}
- name: Make Solc Executable
if: ${{ runner.os == 'Windows' }}
+10
View File
@@ -1,3 +1,13 @@
#!/usr/bin/env python3
"""
This script generates JSON files for different platforms based on GitHub release data.
It fetches release information from a specified GitHub repository and tag,
parses the release assets, and generates JSON files for each platform with relevant metadata.
It also handles checksum files and updates a list.json file for each platform.
It requires the GITHUB_TOKEN environment variable to be set for authentication.
Usage:
python json_generator.py <repo> <tag>
"""
import os
import sys
import json
+155
View File
@@ -0,0 +1,155 @@
#!/usr/bin/env python3
"""
This script generates JSON files for different platforms based on GitHub data.
Requires the GITHUB_SHA, FIRST_SOLC_VERSION, LAST_SOLC_VERSION, TAG and FILEPATH environment variables to be set.
Usage:
python json_generator_nightly.py
"""
import os
import sys
import json
from datetime import datetime
def validate_env_variables():
"""Validate that environment variables are set."""
if "GITHUB_SHA" not in os.environ:
print("Error: GITHUB_SHA environment variable is not set.")
sys.exit(1)
if "FIRST_SOLC_VERSION" not in os.environ:
print("Error: FIRST_SOLC_VERSION environment variable is not set.")
sys.exit(1)
if "LAST_SOLC_VERSION" not in os.environ:
print("Error: LAST_SOLC_VERSION environment variable is not set.")
sys.exit(1)
if "TAG" not in os.environ:
print("Error: TAG environment variable is not set.")
sys.exit(1)
if "FILEPATH" not in os.environ:
print("Error: FILEPATH environment variable is not set.")
sys.exit(1)
def fetch_data_file():
"""
Fetch the data.json file with artifacts urls and sha256 checksums
and parse it into a single dictionary mapping artifact names to their URLs and SHAs.
"""
# read data.json file
artifacts_data = {}
data_file_path = os.environ["FILEPATH"]
if not os.path.exists(data_file_path):
print("Error: data.json file not found.")
sys.exit(1)
with open(data_file_path, 'r') as f:
try:
artifacts_data = json.load(f)
except json.JSONDecodeError:
print("Error: data.json file is not a valid JSON.")
sys.exit(1)
result = {}
for item in artifacts_data:
for key, value in item.items():
if key.endswith('_url'):
base_key = key.rsplit('_url', 1)[0]
if base_key not in result:
result[base_key] = {}
result[base_key]['url'] = value
elif key.endswith('_sha'):
base_key = key.rsplit('_sha', 1)[0]
if base_key not in result:
result[base_key] = {}
result[base_key]['sha'] = value
return result
def extract_build_hash():
"""Extract the first 8 characters of the commit hash."""
sha = os.environ.get("GITHUB_SHA")
return f"commit.{sha[:8]}"
def generate_asset_json_nightly(name, url, checksum):
"""Generate JSON for a specific asset."""
# Date in format YYYY-MM-DD
date = datetime.now().strftime("%Y.%-m.%-d")
last_version = os.environ.get("TAG").replace('v','')
version = f"{last_version}-nightly.{date}"
SHA = os.environ.get("GITHUB_SHA", "")[:8]
build = f"commit.{SHA}"
long_version = f"{version}+{build}"
return {
"name": name,
"version": version,
"build": build,
"longVersion": long_version,
"url": url,
"sha256": checksum,
"firstSolcVersion": os.environ.get("FIRST_SOLC_VERSION"),
"lastSolcVersion": os.environ.get("LAST_SOLC_VERSION")
}
def save_platform_json(platform_folder, asset_json):
"""Save asset JSON and update list.json for a specific platform."""
# Create platform folder if it doesn't exist
os.makedirs(platform_folder, exist_ok=True)
# Update or create list.json
list_file_path = os.path.join(platform_folder, "list.json")
if os.path.exists(list_file_path):
with open(list_file_path, 'r') as f:
try:
list_data = json.load(f)
except json.JSONDecodeError:
list_data = {"builds": [], "releases": {}, "latestRelease": ""}
else:
list_data = {"builds": [], "releases": {}, "latestRelease": ""}
# Remove any existing entry with the same path
list_data['builds'] = [
build for build in list_data['builds']
if build['version'] != asset_json['version']
]
# Add the new build
list_data['builds'].append(asset_json)
# Update releases
version = asset_json['version']
list_data['releases'][version] = f"{asset_json['name']}+{asset_json['longVersion']}"
# Update latest release
list_data['latestRelease'] = version
with open(list_file_path, 'w') as f:
json.dump(list_data, f, indent=4)
def main():
validate_env_variables()
data = fetch_data_file()
# Mapping of asset names to platform folders
platform_mapping = {
'resolc-x86_64-unknown-linux-musl': 'linux',
'resolc-universal-apple-darwin': 'macos',
'resolc-x86_64-pc-windows-msvc': 'windows',
'resolc-web.js': 'wasm'
}
# Process each asset
for asset in data.keys():
platform_name = platform_mapping.get(asset)
if platform_name:
platform_folder = os.path.join(platform_name)
asset_json = generate_asset_json_nightly(asset, data[asset]['url'], data[asset]['sha'])
save_platform_json(platform_folder, asset_json)
print(f"Processed {asset} for {platform_name}")
if __name__ == "__main__":
main()
-49
View File
@@ -1,49 +0,0 @@
name: NPM Release
on:
release:
types: [released]
env:
CI: true
jobs:
publish:
name: Build & Publish to NPM
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22.x
- name: Install
run: yarn install --immutable
- name: update-resolc
run: yarn update-resolc
- name: Build
run: yarn build
- name: Set version
run: npm version --no-git-tag-version ${{github.event.release.tag_name}}
- name: npm pack
run: npm pack
- uses: actions/upload-artifact@v4
with:
name: package
path: 'parity-revive-*.tgz'
- uses: octokit/request-action@bbedc70b1981e610d89f1f8de88311a1fc02fb83
with:
route: POST /repos/paritytech/npm_publish_automation/actions/workflows/publish.yml/dispatches
ref: main
inputs: '${{ format(''{{ "repo": "{0}", "run_id": "{1}" }}'', github.repository, github.run_id) }}'
env:
GITHUB_TOKEN: ${{ secrets.NPM_PUBLISH_AUTOMATION_TOKEN }}
+7 -10
View File
@@ -37,15 +37,7 @@ 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
@@ -95,9 +87,14 @@ jobs:
run: |
brew install ninja
- name: Install Dependencies
if: ${{ matrix.host == 'windows' }}
run: |
choco install ninja
- name: Install LLVM Builder
run: |
cargo install --path crates/llvm-builder
cargo install --locked --force --path crates/llvm-builder
- name: Clone LLVM
run: |
+385
View File
@@ -0,0 +1,385 @@
name: Nightly Release
on:
schedule:
# Run every day at 01:00 UTC
- cron: "0 1 * * *"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
RUST_MUSL_CROSS_IMAGE: messense/rust-musl-cross@sha256:c0154e992adb791c3b848dd008939d19862549204f8cb26f5ca7a00f629e6067
jobs:
# check if there were commits yesterday
check_commits:
runs-on: ubuntu-latest
outputs:
has_commits: ${{ steps.check_commits.outputs.has_commits }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch full history to check previous commits
ref: "main"
- name: Check for commits from yesterday
id: check_commits
run: |
# Get yesterday's date in YYYY-MM-DD format
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
echo "Checking for commits from: $YESTERDAY"
# Check if there were any commits yesterday
COMMIT_COUNT=$(git log --oneline --since="$YESTERDAY 00:00:00" --until="$YESTERDAY 23:59:59" | wc -l)
echo "Found $COMMIT_COUNT commits from yesterday"
if [ $COMMIT_COUNT -gt 0 ]; then
echo "has_commits=true" >> $GITHUB_OUTPUT
echo "✅ Found $COMMIT_COUNT commits from yesterday - continuing workflow"
else
echo "has_commits=false" >> $GITHUB_OUTPUT
echo "❌ No commits found from yesterday - skipping remaining steps"
echo "::notice::❌ No commits found from yesterday - skipping remaining steps"
fi
build:
# github actions matrix jobs don't support multiple outputs
# ugly workaround from https://github.com/orgs/community/discussions/17245#discussioncomment-11222880
if: ${{ needs.check_commits.outputs.has_commits == 'true' }}
outputs:
resolc-x86_64-unknown-linux-musl_url: ${{ steps.set-output.outputs.resolc-x86_64-unknown-linux-musl_url }}
resolc-x86_64-unknown-linux-musl_sha: ${{ steps.set-output.outputs.resolc-x86_64-unknown-linux-musl_sha }}
resolc-aarch64-apple-darwin_url: ${{ steps.set-output.outputs.resolc-aarch64-apple-darwin_url }}
resolc-aarch64-apple-darwin_sha: ${{ steps.set-output.outputs.resolc-aarch64-apple-darwin_sha }}
resolc-x86_64-apple-darwin_url: ${{ steps.set-output.outputs.resolc-x86_64-apple-darwin_url }}
resolc-x86_64-apple-darwin_sha: ${{ steps.set-output.outputs.resolc-x86_64-apple-darwin_sha }}
resolc-x86_64-pc-windows-msvc_url: ${{ steps.set-output.outputs.resolc-x86_64-pc-windows-msvc_url }}
resolc-x86_64-pc-windows-msvc_sha: ${{ steps.set-output.outputs.resolc-x86_64-pc-windows-msvc_sha }}
strategy:
matrix:
target:
[
x86_64-unknown-linux-musl,
aarch64-apple-darwin,
x86_64-apple-darwin,
x86_64-pc-windows-msvc,
]
include:
- target: x86_64-unknown-linux-musl
type: musl
runner: ubuntu-24.04
- target: aarch64-apple-darwin
type: native
runner: macos-14
- target: x86_64-apple-darwin
type: native
runner: macos-13
- target: x86_64-pc-windows-msvc
type: native
runner: windows-2022
runs-on: ${{ matrix.runner }}
needs: [check_commits]
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
# without this it will override our rust flags
rustflags: ""
cache-key: ${{ matrix.target }}
- name: Download LLVM
uses: ./.github/actions/get-llvm
with:
target: ${{ matrix.target }}
- name: Build
if: ${{ matrix.type == 'native' }}
shell: bash
run: |
export LLVM_SYS_181_PREFIX=$PWD/llvm-${{ matrix.target }}
make install-bin
mv target/release/resolc resolc-${{ matrix.target }} || mv target/release/resolc.exe resolc-${{ matrix.target }}.exe
- name: Build
if: ${{ matrix.type == 'musl' }}
run: |
docker run -v $PWD:/opt/revive $RUST_MUSL_CROSS_IMAGE /bin/bash -c "
cd /opt/revive
chown -R root:root .
apt update && apt upgrade -y && apt install -y pkg-config
export LLVM_SYS_181_PREFIX=/opt/revive/llvm-${{ matrix.target }}
make install-bin
mv target/${{ matrix.target }}/release/resolc resolc-${{ matrix.target }}
"
sudo chown -R $(id -u):$(id -g) .
- name: Install Solc
uses: ./.github/actions/get-solc
- name: Basic Sanity Check
shell: bash
run: |
result=$(./resolc-${{ matrix.target }} --bin crates/integration/contracts/flipper.sol)
echo $result
if [[ $result == *'0x50564d'* ]]; then exit 0; else exit 1; fi
- name: Upload artifacts (nightly)
uses: actions/upload-artifact@v4
id: artifact-upload-step
with:
name: resolc-${{ matrix.target }}
path: resolc-${{ matrix.target }}*
retention-days: 40
- name: Set output variables (nightly)
id: set-output
shell: bash
run: |
echo "Artifact URL is ${{ steps.artifact-upload-step.outputs.artifact-url }}"
echo "Artifact SHA is ${{ steps.artifact-upload-step.outputs.artifact-digest }}"
echo "resolc-${{ matrix.target }}_url=${{ steps.artifact-upload-step.outputs.artifact-url }}"
echo "resolc-${{ matrix.target }}_url=${{ steps.artifact-upload-step.outputs.artifact-url }}" >> "$GITHUB_OUTPUT"
echo "resolc-${{ matrix.target }}_sha=${{ steps.artifact-upload-step.outputs.artifact-digest }}"
echo "resolc-${{ matrix.target }}_sha=${{ steps.artifact-upload-step.outputs.artifact-digest }}" >> "$GITHUB_OUTPUT"
build-wasm:
runs-on: ubuntu-24.04
needs: [check_commits]
if: ${{ needs.check_commits.outputs.has_commits == 'true' }}
outputs:
resolc-web.js_url: ${{ steps.set-output.outputs.resolc_web_js_url }}
resolc-web.js_sha: ${{ steps.set-output.outputs.resolc_web_js_sha }}
env:
RELEASE_RESOLC_WASM_URI: https://github.com/paritytech/revive/releases/download/${{ github.ref_name }}/resolc.wasm
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
target: wasm32-unknown-emscripten
# without this it will override our rust flags
rustflags: ""
- name: Download Host LLVM
uses: ./.github/actions/get-llvm
with:
target: x86_64-unknown-linux-gnu
- name: Download Wasm LLVM
uses: ./.github/actions/get-llvm
with:
target: wasm32-unknown-emscripten
- name: Download EMSDK
uses: ./.github/actions/get-emsdk
- name: Build
run: |
export LLVM_SYS_181_PREFIX=$PWD/llvm-x86_64-unknown-linux-gnu
export REVIVE_LLVM_TARGET_PREFIX=$PWD/llvm-wasm32-unknown-emscripten
source emsdk/emsdk_env.sh
make install-wasm
chmod -x ./target/wasm32-unknown-emscripten/release/resolc.wasm
- name: Set Up Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
- name: Basic Sanity Check
run: |
mkdir -p solc
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.30/soljson.js
node -e "
const soljson = require('solc/soljson');
const createRevive = require('./target/wasm32-unknown-emscripten/release/resolc.js');
const compiler = createRevive();
compiler.soljson = soljson;
const standardJsonInput =
{
language: 'Solidity',
sources: {
'MyContract.sol': {
content: 'pragma solidity ^0.8.0; contract MyContract { function greet() public pure returns (string memory) { return \'Hello\'; } }',
},
},
settings: { optimizer: { enabled: false } }
};
compiler.writeToStdin(JSON.stringify(standardJsonInput));
compiler.callMain(['--standard-json']);
// Collect output
const stdout = compiler.readFromStdout();
const stderr = compiler.readFromStderr();
if (stderr) { console.error(stderr); process.exit(1); }
let out = JSON.parse(stdout);
let bytecode = out.contracts['MyContract.sol']['MyContract'].evm.bytecode.object
console.log(bytecode);
if(!bytecode.startsWith('50564d')) { process.exit(1); }
"
- name: Compress Artifact
run: |
mkdir -p resolc-wasm32-unknown-emscripten
mv ./target/wasm32-unknown-emscripten/release/resolc.js ./resolc-wasm32-unknown-emscripten/
mv ./target/wasm32-unknown-emscripten/release/resolc.wasm ./resolc-wasm32-unknown-emscripten/
mv ./target/wasm32-unknown-emscripten/release/resolc_web.js ./resolc-wasm32-unknown-emscripten/
# There is no way to upload several files as several artifacts with a single upload-artifact step
# It's needed to have resolc_web.js separately for night builds for resolc-bin repo
# https://github.com/actions/upload-artifact/issues/331
- name: Upload artifact resolc.js (nightly)
uses: actions/upload-artifact@v4
with:
name: resolc.js
path: resolc-wasm32-unknown-emscripten/resolc.js
retention-days: 40
- name: Upload artifacts resolc.wasm (nightly)
uses: actions/upload-artifact@v4
with:
name: resolc.wasm
path: resolc-wasm32-unknown-emscripten/resolc.wasm
retention-days: 40
- name: Upload artifacts resolc_web.js (nightly)
uses: actions/upload-artifact@v4
id: artifact-upload-step
with:
name: resolc_web.js
path: resolc-wasm32-unknown-emscripten/resolc_web.js
retention-days: 40
- name: Set output variables
id: set-output
env:
TARGET: resolc_web_js
run: |
echo "Artifact URL is ${{ steps.artifact-upload-step.outputs.artifact-url }}"
echo "Artifact SHA is ${{ steps.artifact-upload-step.outputs.artifact-digest }}"
echo "${TARGET}_url=${{ steps.artifact-upload-step.outputs.artifact-url }}"
echo "${TARGET}_url=${{ steps.artifact-upload-step.outputs.artifact-url }}" >> "$GITHUB_OUTPUT"
echo "${TARGET}_sha=${{ steps.artifact-upload-step.outputs.artifact-digest }}""
echo "${TARGET}_sha=${{ steps.artifact-upload-step.outputs.artifact-digest }}"" >> "$GITHUB_OUTPUT"
create-macos-fat-binary:
if: ${{ needs.check_commits.outputs.has_commits == 'true' }}
needs: [build]
outputs:
resolc-universal-apple-darwin_url: ${{ steps.set-output.outputs.resolc-universal-apple-darwin_url }}
resolc-universal-apple-darwin_sha: ${{ steps.set-output.outputs.resolc-universal-apple-darwin_sha }}
runs-on: macos-14
steps:
- uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Create macOS Fat Binary
run: |
lipo resolc-aarch64-apple-darwin resolc-x86_64-apple-darwin -create -output resolc-universal-apple-darwin
- name: Make Executable
run: |
chmod +x resolc-universal-apple-darwin
- uses: actions/upload-artifact@v4
id: artifact-upload-step
with:
name: resolc-universal-apple-darwin
path: resolc-universal-apple-darwin
retention-days: 40
- name: Set output variables
id: set-output
env:
TARGET: resolc-universal-apple-darwin
run: |
echo "Artifact URL is ${{ steps.artifact-upload-step.outputs.artifact-url }}"
echo "Artifact SHA is ${{ steps.artifact-upload-step.outputs.artifact-digest }}"
echo "${TARGET}_url=${{ steps.artifact-upload-step.outputs.artifact-url }}"
echo "${TARGET}_url=${{ steps.artifact-upload-step.outputs.artifact-url }}" >> "$GITHUB_OUTPUT"
echo "${TARGET}_sha=${{ steps.artifact-upload-step.outputs.artifact-digest }}""
echo "${TARGET}_sha=${{ steps.artifact-upload-step.outputs.artifact-digest }}"" >> "$GITHUB_OUTPUT"
generate-nightly-json:
runs-on: ubuntu-24.04
if: ${{ needs.check_commits.outputs.has_commits == 'true' }}
environment: tags
needs: [build-wasm, build, create-macos-fat-binary, check_commits]
steps:
- name: Checkout revive
uses: actions/checkout@v4
with:
path: revive
- name: Checkout resolc-bin
uses: actions/checkout@v4
with:
repository: paritytech/resolc-bin
path: resolc-bin
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
path: bins
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.REVIVE_JSON_APP_ID }}
private-key: ${{ secrets.REVIVE_JSON_APP_KEY }}
owner: paritytech
repositories: resolc-bin
- name: Generate JSON
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TOKEN: ${{ steps.app-token.outputs.token }}
APP_NAME: "paritytech-revive-json"
Green: "\e[32m"
NC: "\e[0m"
run: |
echo '[' > data.json
echo '${{ toJSON(needs.build.outputs) }}' >> data.json
echo ',' >> data.json
echo '${{ toJSON(needs.build-wasm.outputs) }}' >> data.json
echo ',' >> data.json
echo '${{ toJSON(needs.create-macos-fat-binary.outputs) }}' >> data.json
echo ']' >> data.json
chmod +x bins/resolc-x86_64-unknown-linux-musl
export FIRST_SOLC_VERSION=$(./bins/resolc-x86_64-unknown-linux-musl --supported-solc-versions | cut -f 1 -d "," | tr -d ">=")
export LAST_SOLC_VERSION=$(./bins/resolc-x86_64-unknown-linux-musl --supported-solc-versions | cut -f 2 -d "," | tr -d "<=")
export FILEPATH=$(readlink -f data.json)
export TAG=$(cd revive;gh release list --json name,isLatest --jq '.[] | select(.isLatest)|.name')
cd resolc-bin
mkdir -p nightly
cd nightly
python3 ../../revive/.github/scripts/json_generator_nightly.py
cd ..
git status
echo "${Green}Add new remote with gh app token${NC}"
git remote set-url origin $(git config remote.origin.url | sed "s/github.com/${APP_NAME}:${TOKEN}@github.com/g")
echo "${Green}Remove http section that causes issues with gh app auth token${NC}"
sed -i.bak '/\[http/d' ./.git/config
sed -i.bak '/extraheader/d' ./.git/config
git config user.email "ci@parity.io"
git config user.name "${APP_NAME}"
git add nightly/
git commit -m "Update nightly json"
git push origin main
echo "::notice::nightly info.list files were successfully published to https://github.com/paritytech/resolc-bin"
+45 -4
View File
@@ -14,7 +14,8 @@ concurrency:
env:
CARGO_TERM_COLOR: always
RUST_MUSL_CROSS_IMAGE: messense/rust-musl-cross@sha256:68b86bc7cb2867259e6b233415a665ff4469c28b57763e78c3bfea1c68091561
# if changed, dont forget to update the env var in release-nightly.yml
RUST_MUSL_CROSS_IMAGE: messense/rust-musl-cross@sha256:c0154e992adb791c3b848dd008939d19862549204f8cb26f5ca7a00f629e6067
jobs:
check-version-changed:
@@ -44,7 +45,7 @@ jobs:
exit 0
fi
export PKG_VER=v$(cat Cargo.toml | grep -A 5 package] | grep version | cut -d '=' -f 2 | tr -d '"' | tr -d " ")
export PKG_VER=v$(cat crates/resolc/Cargo.toml | grep -A 5 package] | grep version | cut -d '=' -f 2 | tr -d '"' | tr -d " ")
echo "Current tag $CURRENT_TAG"
echo "Package version $PKG_VER"
#
@@ -143,7 +144,7 @@ jobs:
runs-on: ubuntu-24.04
needs: [check-version-changed]
env:
RELEASE_RESOLC_WASM_URI: https://github.com/paritytech/revive-workflow-test/releases/download/${{ github.ref_name }}/resolc.wasm
RELEASE_RESOLC_WASM_URI: https://github.com/paritytech/revive/releases/download/${{ github.ref_name }}/resolc.wasm
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
@@ -181,7 +182,7 @@ jobs:
- name: Basic Sanity Check
run: |
mkdir -p solc
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.29/soljson.js
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.30/soljson.js
node -e "
const soljson = require('solc/soljson');
const createRevive = require('./target/wasm32-unknown-emscripten/release/resolc.js');
@@ -286,3 +287,43 @@ jobs:
resolc.wasm
resolc_web.js
checksums.txt
npm-release:
needs: [create-release]
runs-on: macos-14
environment: tags
steps:
- uses: actions/checkout@v4
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Set Up Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
- run: npm ci -w js/resolc
- name: Build
run: |
cp -f resolc.{wasm,js} js/resolc/src/resolc
npm -w js/resolc run build
- name: npm pack
run: npm -w js/resolc pack
- uses: actions/upload-artifact@v4
with:
name: npm_package
path: "parity-resolc-*.tgz"
- uses: octokit/request-action@bbedc70b1981e610d89f1f8de88311a1fc02fb83
with:
route: POST /repos/paritytech/npm_publish_automation/actions/workflows/publish.yml/dispatches
ref: main
inputs: '${{ format(''{{ "artifact_name": "npm_package", "repo": "{0}", "run_id": "{1}" }}'', github.repository, github.run_id) }}'
env:
GITHUB_TOKEN: ${{ secrets.NPM_PUBLISH_AUTOMATION_TOKEN }}
+3 -3
View File
@@ -4,9 +4,9 @@ on:
branches: ["main"]
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 }}
+12 -7
View File
@@ -86,13 +86,18 @@ jobs:
- name: Install Node Packages
run: npm install
- name: Run Playwright tests
run: |
cd js
npx playwright install --with-deps
npx playwright test
- name: Test revive
- name: Test emscripten
run: |
echo "Running tests for ${{ matrix.os }}"
npm run test:wasm
- name: Test @parity/resolc
run: |
echo "Running tests for ${{ matrix.os }}"
npm run -w js/resolc test
- name: Run Playwright tests
run: |
cd js/emscripten
npx playwright install --with-deps
npx playwright test
-1
View File
@@ -12,7 +12,6 @@ target-llvm
node_modules
artifacts
tmp
package-lock.json
/*.html
/build
soljson.js
+6
View File
@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true
}
+73
View File
@@ -4,14 +4,87 @@
This is a development pre-release.
Supported `polkadot-sdk` rev: `2503.0.1`
## v0.4.0
This is a development pre-release.
Supported `polkadot-sdk` rev: `2503.0.1`
### Added
- Line debug information per YUL builtin and for `if` statements.
- Support for the YUL optimizer details in the standard json input definition.
### Fixed
- The debug info source file matches the YUL path in `--debug-output-dir`, allowing tools to display the source line.
## v0.3.0
This is a development pre-release.
Supported `polkadot-sdk` rev: `2503.0.1`
### Fixed
- llvm-context: Bugfix the SAR YUL builtin translation.
- runtime-api: Add the missing `memset` builtin.
- npm package: Bugfix the exports field defined in the `package.json`.
## v0.2.0
This is a development pre-release.
Supported `polkadot-sdk` rev: `2503.0.1`
### Changed
- Removed the license printer from the `resolc` binary.
- EVM bytecode is no longer requested from solc (except in test utils) leading to less compilation work in the pipeline.
### Fixed
- solc-json-interface: Serializing of any custom key in the JSON input is only skipped if not provided.
- npm package resolution no longer fails with an 'ERR_PACKAGE_PATH_NOT_EXPORTED' error for packages defining exports fields in the `package.json`.
## v0.1.0
This is a development pre-release.
Supported `polkadot-sdk` rev: `2503.0.1`
### Added
- Add the PolkaVM heap size, stack size and debug info CLI compiler options to the standard JSON settings. This makes the standard JSON input succint for reproducible builds.
### Changed
- Supported `polkadot-sdk` version is now `2503.0.1`
- The `emsdk` version is now `4.0.9`
### Fixed
## v0.1.0-dev.16
This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
### Added
- Move the npm package from paritytech/js-revive, into this repo. The package `@parity/resolc` will be deployed to npm for each release.
- Support for solc v0.8.30
### Changed
- By default, heavy size optimizations are applied.
### Fixed
- @parity/resolc: The solc dependency package is constrained to the latest supported version, preventing breaking the package ever time a new solc package was released.
- The resolc npm package no longer ignores the optimizer settings
## v0.1.0-dev.14
This is a development pre-release.
Generated
+2072 -2230
View File
File diff suppressed because it is too large Load Diff
+41 -41
View File
@@ -3,7 +3,7 @@ resolver = "2"
members = ["crates/*"]
[workspace.package]
version = "0.1.0-dev.14"
version = "0.1.0"
authors = [
"Cyrill Leutwiler <cyrill@parity.io>",
"Parity Technologies <admin@parity.io>",
@@ -11,59 +11,60 @@ authors = [
license = "MIT/Apache-2.0"
edition = "2021"
repository = "https://github.com/paritytech/revive"
rust-version = "1.81.0"
rust-version = "1.85.0"
[workspace.dependencies]
revive-benchmarks = { version = "0.1.0-dev.14", path = "crates/benchmarks" }
revive-builtins = { version = "0.1.0-dev.14", path = "crates/builtins" }
revive-common = { version = "0.1.0-dev.14", path = "crates/common" }
revive-differential = { version = "0.1.0-dev.14", path = "crates/differential" }
revive-integration = { version = "0.1.0-dev.14", path = "crates/integration" }
revive-linker = { version = "0.1.0-dev.14", path = "crates/linker" }
lld-sys = { version = "0.1.0-dev.14", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.1.0-dev.14", path = "crates/llvm-context" }
revive-runtime-api = { version = "0.1.0-dev.14", path = "crates/runtime-api" }
revive-runner = { version = "0.1.0-dev.14", path = "crates/runner" }
revive-solc-json-interface = { version = "0.1.0-dev.14", path = "crates/solc-json-interface" }
revive-solidity = { version = "0.1.0-dev.14", path = "crates/solidity" }
revive-stdlib = { version = "0.1.0-dev.14", path = "crates/stdlib" }
revive-build-utils = { version = "0.1.0-dev.14", path = "crates/build-utils" }
resolc = { version = "0.3.0", path = "crates/resolc" }
revive-benchmarks = { version = "0.1.0", path = "crates/benchmarks" }
revive-builtins = { version = "0.1.0", path = "crates/builtins" }
revive-common = { version = "0.1.0", path = "crates/common" }
revive-differential = { version = "0.1.0", path = "crates/differential" }
revive-integration = { version = "0.1.1", path = "crates/integration" }
revive-linker = { version = "0.1.0", path = "crates/linker" }
lld-sys = { version = "0.1.0", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.3.0", path = "crates/llvm-context" }
revive-runtime-api = { version = "0.2.0", path = "crates/runtime-api" }
revive-runner = { version = "0.1.0", path = "crates/runner" }
revive-solc-json-interface = { version = "0.2.0", path = "crates/solc-json-interface" }
revive-stdlib = { version = "0.1.1", path = "crates/stdlib" }
revive-build-utils = { version = "0.1.0", path = "crates/build-utils" }
revive-yul = { version = "0.2.1", path = "crates/yul" }
hex = "0.4.3"
cc = "1.2"
libc = "0.2.169"
tempfile = "3.17"
libc = "0.2.172"
tempfile = "3.20"
anyhow = "1.0"
semver = { version = "1.0", features = ["serde"] }
itertools = "0.14"
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["arbitrary_precision"] }
regex = "1.10"
once_cell = "1.20"
regex = "1.11"
once_cell = "1.21"
num = "0.4.3"
sha1 = "0.10"
sha3 = "0.10"
thiserror = "2.0"
which = "7.0"
path-slash = "0.2"
rayon = "1.8"
rayon = "1.10"
clap = { version = "4", default-features = false, features = ["derive"] }
polkavm-common = "0.21.0"
polkavm-linker = "0.21.0"
polkavm-disassembler = "0.21.0"
polkavm = "0.21.0"
alloy-primitives = { version = "0.8.21", features = ["serde"] }
alloy-sol-types = "0.8.21"
alloy-genesis = "0.11.1"
alloy-serde = "0.11.1"
env_logger = { version = "0.11.6", default-features = false }
serde_stacker = "0.1.11"
criterion = { version = "0.5.1", features = ["html_reports"] }
log = { version = "0.4.25" }
git2 = { version = "0.20.0", default-features = false }
polkavm-common = "0.24.0"
polkavm-linker = "0.24.0"
polkavm-disassembler = "0.24.0"
polkavm = "0.24.0"
alloy-primitives = { version = "1.1", features = ["serde"] }
alloy-sol-types = "1.1"
alloy-genesis = "1.0"
alloy-serde = "1.0"
env_logger = { version = "0.11.8", default-features = false }
serde_stacker = "0.1.12"
criterion = { version = "0.6", features = ["html_reports"] }
log = { version = "0.4.27" }
git2 = { version = "0.20.2", default-features = false }
downloader = "0.2.8"
flate2 = "1.0.35"
fs_extra = "1.3.0"
flate2 = "1.1"
fs_extra = "1.3"
num_cpus = "1"
tar = "0.4"
toml = "0.8"
@@ -71,16 +72,15 @@ assert_cmd = "2.0"
assert_fs = "1.1"
# polkadot-sdk and friends
codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" }
codec = { version = "3.7.5", default-features = false, package = "parity-scale-codec" }
scale-info = { version = "2.11.6", default-features = false }
polkadot-sdk = { git = "https://github.com/paritytech/polkadot-sdk", rev = "c29e72a8628835e34deb6aa7db9a78a2e4eabcee" }
polkadot-sdk = { version = "2503.0.1" }
# llvm
[workspace.dependencies.inkwell]
git = "https://github.com/TheDan64/inkwell.git"
rev = "7b410298b6a93450adaa90b1841d5805a3038f12"
version = "0.6.0"
default-features = false
features = ["serde", "llvm18-0", "no-libffi-linking", "target-riscv"]
features = ["serde", "llvm18-1", "no-libffi-linking", "target-riscv"]
[profile.bench]
inherits = "release"
+2 -2
View File
@@ -1,4 +1,4 @@
FROM rust:1.84.0 AS llvm-builder
FROM rust:1.85.0 AS llvm-builder
WORKDIR /opt/revive
RUN apt update && \
@@ -11,7 +11,7 @@ RUN make install-llvm-builder
RUN revive-llvm --target-env musl clone
RUN revive-llvm --target-env musl build --llvm-projects lld --llvm-projects clang
FROM messense/rust-musl-cross@sha256:68b86bc7cb2867259e6b233415a665ff4469c28b57763e78c3bfea1c68091561 AS resolc-builder
FROM messense/rust-musl-cross@sha256:c0154e992adb791c3b848dd008939d19862549204f8cb26f5ca7a00f629e6067 AS resolc-builder
WORKDIR /opt/revive
RUN apt update && \
+10 -13
View File
@@ -11,7 +11,7 @@
machete \
test \
test-integration \
test-solidity \
test-resolc \
test-workspace \
test-cli \
test-wasm \
@@ -24,24 +24,24 @@
install: install-bin install-npm
install-bin:
cargo install --locked --path crates/solidity
cargo install --force --locked --path crates/resolc
install-npm:
npm install && npm fund
install-wasm: install-npm
cargo build --target wasm32-unknown-emscripten -p revive-solidity --release --no-default-features
cargo build --target wasm32-unknown-emscripten -p resolc --release --no-default-features
npm run build:package
install-llvm-builder:
cargo install --path crates/llvm-builder
cargo install --force --locked --path crates/llvm-builder
install-llvm: install-llvm-builder
revive-llvm clone
revive-llvm build --llvm-projects lld --llvm-projects clang
install-revive-runner:
cargo install --path crates/runner --no-default-features --locked
cargo install --locked --force --path crates/runner --no-default-features
format:
cargo fmt --all --check
@@ -58,8 +58,8 @@ test: format clippy machete test-cli test-workspace install-revive-runner
test-integration: install-bin
cargo test --package revive-integration
test-solidity: install
cargo test --package revive-solidity
test-resolc: install
cargo test --package resolc
test-workspace: install
cargo test --workspace --exclude revive-llvm-builder
@@ -90,9 +90,6 @@ clean:
cargo clean ; \
revive-llvm clean ; \
rm -rf node_modules ; \
rm -rf crates/solidity/src/tests/cli-tests/artifacts ; \
cargo uninstall revive-solidity ; \
cargo uninstall revive-llvm-builder ; \
rm -f package-lock.json ; \
rm -rf js/dist ; \
rm -f js/src/resolc.{wasm,js}
rm -rf crates/resolc/src/tests/cli-tests/artifacts ; \
cargo uninstall resolc ; \
cargo uninstall revive-llvm-builder ;
+40 -9
View File
@@ -14,8 +14,39 @@ 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
Building Solidity contracts for PolkaVM requires installing the following two compilers:
- `resolc`: The revive Solidity compiler YUL frontend and PolkaVM code generator (provided by this repository).
- `solc`: The [Ethereum Solidity reference compiler](https://github.com/ethereum/solidity/) implemenation.`resolc` uses `solc` during the compilation process, please refer to the [Ethereum Solidity documentation](https://docs.soliditylang.org/en/latest/installing-solidity.html) for installation instructions.
Please consult [the documentation](https://contracts.polkadot.io/revive_compiler/installation) for installation instructions.
### `resolc` binary releases
`resolc` is distributed as a standalone binary (with `solc` as the only external dependency). Please download one of our [binary releases](https://github.com/paritytech/revive/releases) for your target platform and mind the platform specific instructions below.
<details>
<summary>MacOS users</summary>
> **MacOS** users need to clear the `downloaded` attribute from the binary and set the executable flag.
> ```sh
> xattr -rc resolc-universal-apple-darwin
> chmod +x resolc-universal-apple-darwin
> ```
</details>
<details>
<summary>Linux users</summary>
> **Linux** users need to set the executable flag.
> ```sh
> chmod +x resolc-x86_64-unknown-linux-musl
> ```
</details>
### `resolc` NPM package
We distribute the revive compiler as [node.js module](https://www.npmjs.com/package/@parity/resolc) and [hardhat plugin](https://www.npmjs.com/package/@parity/hardhat-polkadot-resolc).
Note: The `solc` dependency is bundled via NPM packaging and defaults to the latest supported version.
## Building from source
@@ -31,13 +62,11 @@ 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
```
@@ -47,7 +76,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:
@@ -96,14 +125,11 @@ 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.
[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).
See the [relevant section in our documentation](https://contracts.polkadot.io/revive_compiler/architecture) to learn more about how the compiler works.
### Tests
@@ -113,3 +139,8 @@ Once Geth is installed, you can run the tests using the following command:
```sh
make test
```
# Acknowledgements
The revive compiler project, after some early experiments with EVM bytecode translations, decided to fork the `era-compiler` framework.
[Frontend](https://github.com/matter-labs/era-compiler-solidity), [code generator](https://github.com/matter-labs/era-compiler-llvm-context) and some supporting libraries are based of ZKSync `zksolc`. I'd like to express my gratitude and thank the original authors for providing a useable code base under a generous license.
+12 -4
View File
@@ -4,18 +4,26 @@ Prior to the first stable release we neither have formal release processes nor d
To create a new pre-release:
1. Create a release PR which updates the `-dev.X` versions in the workspace `Cargo.toml` and updates the `CHANGELOG.md` accordingly.
1. Create a release PR which, if necessary:
- Updates the versions in the workspace `Cargo.toml`
- Updates the version in each crate `Cargo.toml`
- Updates the version of the NPM package in `js/resolc/package.json`
- Updates the `CHANGELOG.md` to reflect all observable changes
2. If the CI passes, merge the release PR.
3. Push a tag that has the same `-dev.X` version as in `Cargo.toml`
3. Push a `vX.Y.Z` tag that has the same version as in `Cargo.toml`
4. The release workflow will attempt to build and publish a new pre-release if the latest tag does match the cargo package version.
5. Wait for the `Release` workflow to finish. It should create the pre-release with the same `-dev.X` name.
5. Wait for the `Release` workflow to finish. It should create the pre-release with the same name.
6. Check that pre-release was created on the [Releases page](https://github.com/paritytech/revive/releases) with all artifacts.
7. After the release is published, another workflow should start automatically and update json files in https://github.com/paritytech/resolc-bin. Check the changes.
8. Update the [contract-docs](https://github.com/paritytech/contract-docs/) accordingly
# `resolc` NPM package release
Will happen automatically.
# LLVM 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
View File
@@ -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
-30
View File
@@ -1,30 +0,0 @@
# Known issues
The following is known and we are either working on it or it is a hard limitation. Please do not open a new issue.
## Release
`0.1.0-dev-2`
## Missing features
- [Libraries with public functions are not supported](https://github.com/paritytech/revive/issues/91)
- [Automatic import resolution is not supported](https://github.com/paritytech/revive/issues/98)
- The emulated EVM linear contract memory is limited to 64kb in size. Will be fixed with support for metered dynamic memory.
- [The contract calldata is currently limited to 1kb in size](https://github.com/paritytech/revive/issues/57)
- [EIP-4844 opcodes are not supported](https://github.com/paritytech/revive/issues/64)
- [Delegate calls are not supported](https://github.com/paritytech/revive/issues/67)
- [The `blockhash` opcode is not supported](https://github.com/paritytech/revive/issues/61)
- [The `extcodesize` opcode is not supported](https://github.com/paritytech/revive/issues/58)
- [The `origin` opcode is not supported](https://github.com/paritytech/revive/issues/59)
- [Gas limits for contract calls are ignored](https://github.com/paritytech/revive/issues/60)
- [Gas related opcodes are not supported](https://github.com/paritytech/revive/issues/60)
- IPFS metadata hashes are not supported
- [Compiled contract artifacts can exceed the pallet static memory limit and fail to deploy](https://github.com/paritytech/revive/issues/96).
- [Transfers to inexistant accounts will fail if the transferred value lies below the ED.](https://github.com/paritytech/revive/issues/83) Will be fixed in the pallet to make the ED completely transparent for contracts.
## Wontfix
Please consult our documentation to learn more about Solidity and EVM features likely to remain unsupported (and why they will not be supported).
TODO: Insert link to the relevant documentation section.
+42 -42
View File
@@ -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)
+2 -1
View File
@@ -1,5 +1,6 @@
[package]
name = "revive-differential"
description = "utilities for differential testing the revive compiler against EVM"
version.workspace = true
license.workspace = true
edition.workspace = true
@@ -13,4 +14,4 @@ serde = { workspace = true }
serde_json = { workspace = true }
alloy-primitives = { workspace = true, features = ["serde"] }
alloy-genesis = { workspace = true }
alloy-serde = { workspace = true }
alloy-serde = { workspace = true }
+44 -44
View File
@@ -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"
"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
}
}
},
"0202020202020202020202020202020202020202": {
"balance": "1000000000"
},
"0303030303030303030303030303030303030303": {
"balance": "1000000000"
"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"
}
}
}
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "revive-integration"
version.workspace = true
version = "0.1.1"
license.workspace = true
edition.workspace = true
repository.workspace = true
@@ -13,7 +13,7 @@ alloy-sol-types = { workspace = true }
hex = { workspace = true }
serde_json = { workspace = true }
revive-solidity = { workspace = true }
resolc = { workspace = true }
revive-runner = { workspace = true }
revive-llvm-context = { workspace = true }
+1 -1
View File
@@ -7,4 +7,4 @@
"FibonacciIterative": 1497,
"Flipper": 2099,
"SHA1": 8243
}
}
+49
View File
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "SAR"
}
}
}
}
]
}
*/
contract SAR {
constructor() payable {
assert(sar(0x03, 0x01) == 0x01);
assert(
sar(
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,
0x01
) == 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
);
assert(
sar(
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,
0xff
) == 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
);
assert(
sar(
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,
0x100
) == 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
);
}
function sar(uint256 a, uint256 b) public pure returns (uint256 c) {
assembly {
c := sar(b, a)
}
}
}
+1 -1
View File
@@ -1,8 +1,8 @@
use alloy_primitives::{Address, Bytes, I256, U256};
use alloy_sol_types::{sol, SolCall, SolConstructor};
use resolc::test_utils::*;
use revive_llvm_context::OptimizerSettings;
use revive_solidity::test_utils::*;
#[derive(Clone)]
pub struct Contract {
+1
View File
@@ -60,6 +60,7 @@ test_spec!(mload, "MLoad", "MLoad.sol");
test_spec!(delegate_no_contract, "DelegateCaller", "DelegateCaller.sol");
test_spec!(function_type, "FunctionType", "FunctionType.sol");
test_spec!(layout_at, "LayoutAt", "LayoutAt.sol");
test_spec!(shift_arithmetic_right, "SAR", "SAR.sol");
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
vec![Instantiate {
+1 -1
View File
@@ -6,7 +6,7 @@ authors = [
"Anton Baliasnikov <aba@matterlabs.dev>",
"Cyrill Leutwiler <cyrill@parity.io>",
]
version.workspace = true
version = "0.2.0"
license.workspace = true
edition.workspace = true
repository.workspace = true
+55 -64
View File
@@ -6,7 +6,6 @@ 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
@@ -18,92 +17,85 @@ 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:
Install the following packages:
```shell
apt install cmake ninja-build curl git libssl-dev pkg-config clang lld
```
* Linux (Arch):
```shell
apt install cmake ninja-build curl git libssl-dev pkg-config clang lld
```
Install the following packages:
```shell
pacman -Syu which cmake ninja curl git pkg-config clang lld
```
- Linux (Arch):
* MacOS:
Install the following packages:
* Install the [HomeBrew](https://brew.sh) package manager.
* Install the following packages:
```shell
pacman -Syu which cmake ninja curl git pkg-config clang lld
```
```shell
brew install cmake ninja coreutils
```
- 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/), [Apples Command Line Tools](https://developer.apple.com/library/archive/technotes/tn2339/_index.html), or your preferred package manager.
</details>
* Install your choice of a recent LLVM/[Clang](https://clang.llvm.org) compiler, e.g. via [Xcode](https://developer.apple.com/xcode/), [Apples Command Line Tools](https://developer.apple.com/library/archive/technotes/tn2339/_index.html), or your preferred package manager.
</details>
<details>
<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`:
* Install the builder using `cargo`:
```shell
cargo install --git https://github.com/paritytech/revive-llvm-builder --force --locked
```
```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`.
> 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)
@@ -113,29 +105,28 @@ 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>
+1 -1
View File
@@ -22,7 +22,7 @@ impl std::str::FromStr for BuildType {
"Release" => Ok(Self::Release),
"RelWithDebInfo" => Ok(Self::RelWithDebInfo),
"MinSizeRel" => Ok(Self::MinSizeRel),
value => Err(format!("Unsupported build type: `{}`", value)),
value => Err(format!("Unsupported build type: `{value}`")),
}
}
}
+2 -8
View File
@@ -117,13 +117,7 @@ pub fn build(
log::info!("building compiler-rt for rv64emac");
crate::utils::check_presence("cmake")?;
let generator = if cfg!(target_os = "windows") {
"Visual Studio 17 2022"
} else {
crate::utils::check_presence("ninja")?;
"Ninja"
};
crate::utils::check_presence("ninja")?;
let llvm_module_compiler_rt = crate::LLVMPath::llvm_module_compiler_rt()?;
let llvm_compiler_rt_build = crate::LLVMPath::llvm_build_compiler_rt()?;
@@ -136,7 +130,7 @@ pub fn build(
"-B",
llvm_compiler_rt_build.to_string_lossy().as_ref(),
"-G",
generator,
"Ninja",
])
.args(CMAKE_STATIC_ARGS)
.args(cmake_dynamic_args(build_type, target_env)?)
+1 -1
View File
@@ -16,7 +16,7 @@ impl std::str::FromStr for CcacheVariant {
match value {
"ccache" => Ok(Self::Ccache),
"sccache" => Ok(Self::Sccache),
value => Err(format!("Unsupported ccache variant: `{}`", value)),
value => Err(format!("Unsupported ccache variant: `{value}`")),
}
}
}
+13 -14
View File
@@ -127,23 +127,22 @@ pub fn build(
sanitizer: Option<sanitizer::Sanitizer>,
enable_valgrind: bool,
) -> anyhow::Result<()> {
log::trace!("build type: {:?}", build_type);
log::trace!("target env: {:?}", target_env);
log::trace!("targets: {:?}", targets);
log::trace!("llvm projects: {:?}", llvm_projects);
log::trace!("enable rtti: {:?}", enable_rtti);
log::trace!("default target: {:?}", default_target);
log::trace!("eneable tests: {:?}", enable_tests);
log::trace!("enable_coverage: {:?}", enable_coverage);
log::trace!("extra args: {:?}", extra_args);
log::trace!("sanitzer: {:?}", sanitizer);
log::trace!("enable valgrind: {:?}", enable_valgrind);
log::trace!("build type: {build_type:?}");
log::trace!("target env: {target_env:?}");
log::trace!("targets: {targets:?}");
log::trace!("llvm projects: {llvm_projects:?}");
log::trace!("enable rtti: {enable_rtti:?}");
log::trace!("default target: {default_target:?}");
log::trace!("eneable tests: {enable_tests:?}");
log::trace!("enable_coverage: {enable_coverage:?}");
log::trace!("extra args: {extra_args:?}");
log::trace!("sanitzer: {sanitizer:?}");
log::trace!("enable valgrind: {enable_valgrind:?}");
if !PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE).exists() {
log::error!(
"LLVM project source directory {} does not exist (run `revive-llvm --target-env {} clone`)",
LLVMPath::DIRECTORY_LLVM_SOURCE,
target_env
"LLVM project source directory {} does not exist (run `revive-llvm --target-env {target_env} clone`)",
LLVMPath::DIRECTORY_LLVM_SOURCE
)
}
+1 -1
View File
@@ -22,7 +22,7 @@ impl std::str::FromStr for LLVMProject {
"lld" => Ok(Self::LLD),
"lldb" => Ok(Self::LLDB),
"mlir" => Ok(Self::MLIR),
value => Err(format!("Unsupported LLVM project to enable: `{}`", value)),
value => Err(format!("Unsupported LLVM project to enable: `{value}`")),
}
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ impl TryFrom<&PathBuf> for Lock {
fn try_from(path: &PathBuf) -> Result<Self, Self::Error> {
let mut config_str = String::new();
let mut config_file =
File::open(path).with_context(|| format!("Error opening {:?} file", path))?;
File::open(path).with_context(|| format!("Error opening {path:?} file"))?;
config_file.read_to_string(&mut config_str)?;
Ok(toml::from_str(&config_str)?)
}
+1 -1
View File
@@ -29,7 +29,7 @@ impl FromStr for Platform {
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"PolkaVM" => Ok(Self::PolkaVM),
value => Err(format!("Unsupported platform: `{}`", value)),
value => Err(format!("Unsupported platform: `{value}`")),
}
}
}
+2 -2
View File
@@ -69,8 +69,8 @@ fn main_inner() -> anyhow::Result<()> {
})
.collect();
log::debug!("extra_args: {:#?}", extra_args);
log::debug!("extra_args_unescaped: {:#?}", extra_args_unescaped);
log::debug!("extra_args: {extra_args:#?}");
log::debug!("extra_args_unescaped: {extra_args_unescaped:#?}");
if let Some(ccache_variant) = ccache_variant {
revive_llvm_builder::utils::check_presence(ccache_variant.to_string().as_str())?;
+1 -1
View File
@@ -30,7 +30,7 @@ impl std::str::FromStr for Sanitizer {
"thread" => Ok(Self::Thread),
"dataflow" => Ok(Self::DataFlow),
"address;undefined" => Ok(Self::AddressUndefined),
value => Err(format!("Unsupported sanitizer: `{}`", value)),
value => Err(format!("Unsupported sanitizer: `{value}`")),
}
}
}
+1 -1
View File
@@ -20,7 +20,7 @@ impl std::str::FromStr for TargetEnv {
"gnu" => Ok(Self::GNU),
"musl" => Ok(Self::MUSL),
"emscripten" => Ok(Self::Emscripten),
value => Err(format!("Unsupported target environment: `{}`", value)),
value => Err(format!("Unsupported target environment: `{value}`")),
}
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ impl std::str::FromStr for TargetTriple {
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"polkavm" => Ok(Self::PolkaVM),
value => Err(format!("Unsupported target triple: `{}`", value)),
value => Err(format!("Unsupported target triple: `{value}`")),
}
}
}
+3 -3
View File
@@ -38,7 +38,7 @@ pub const MUSL_SNAPSHOTS_URL: &str = "https://git.musl-libc.org/cgit/musl/snapsh
pub const EMSDK_SOURCE_URL: &str = "https://github.com/emscripten-core/emsdk.git";
/// The emscripten SDK version.
pub const EMSDK_VERSION: &str = "3.1.64";
pub const EMSDK_VERSION: &str = "4.0.9";
/// The subprocess runner.
///
@@ -92,7 +92,7 @@ pub fn unpack_tar(filename: PathBuf, path: &str) -> anyhow::Result<()> {
pub fn download_musl(name: &str) -> anyhow::Result<()> {
log::info!("downloading musl {name}");
let tar_file_name = format!("{name}.tar.gz");
let url = format!("{}/{tar_file_name}", MUSL_SNAPSHOTS_URL);
let url = format!("{MUSL_SNAPSHOTS_URL}/{tar_file_name}");
let target_path = crate::llvm_path::DIRECTORY_LLVM_TARGET
.get()
.unwrap()
@@ -223,6 +223,6 @@ pub fn install_emsdk() -> anyhow::Result<()> {
/// The LLVM target directory default path.
pub fn directory_target_llvm(target_env: crate::target_env::TargetEnv) -> PathBuf {
crate::llvm_path::DIRECTORY_LLVM_TARGET
.get_or_init(|| PathBuf::from(format!("./target-llvm/{}/", target_env)))
.get_or_init(|| PathBuf::from(format!("./target-llvm/{target_env}/")))
.clone()
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "revive-llvm-context"
version.workspace = true
version = "0.3.0"
license.workspace = true
edition.workspace = true
repository.workspace = true
+39 -4
View File
@@ -2,6 +2,7 @@
pub mod ir_type;
use std::path::Path;
use std::path::PathBuf;
use serde::Deserialize;
@@ -16,6 +17,14 @@ pub struct DebugConfig {
pub output_directory: Option<PathBuf>,
/// Whether debug info should be emitted.
pub emit_debug_info: bool,
/// The YUL debug output file path.
///
/// Is expected to be configured when running in YUL mode.
pub contract_path: Option<PathBuf>,
/// The YUL input file path.
///
/// Is expected to be configured when not running in YUL mode.
pub yul_path: Option<PathBuf>,
}
impl DebugConfig {
@@ -24,15 +33,41 @@ impl DebugConfig {
Self {
output_directory,
emit_debug_info,
contract_path: None,
yul_path: None,
}
}
/// Set the current YUL path.
pub fn set_yul_path(&mut self, yul_path: &Path) {
self.yul_path = yul_path.to_path_buf().into();
}
/// Set the current contract path.
pub fn set_contract_path(&mut self, contract_path: &str) {
self.contract_path = self.yul_source_path(contract_path);
}
/// Returns with the following precedence:
/// 1. The YUL source path if it was configured.
/// 2. The source YUL path from the debug output dir if it was configured.
/// 3. `None` if there is no debug output directory.
pub fn yul_source_path(&self, contract_path: &str) -> Option<PathBuf> {
if let Some(path) = self.yul_path.as_ref() {
return Some(path.clone());
}
self.output_directory.as_ref().map(|output_directory| {
let mut file_path = output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::Yul);
file_path.push(full_file_name);
file_path
})
}
/// Dumps the Yul IR.
pub fn dump_yul(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
if let Some(output_directory) = self.output_directory.as_ref() {
let mut file_path = output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::Yul);
file_path.push(full_file_name);
if let Some(file_path) = self.yul_source_path(contract_path) {
std::fs::write(file_path, code)?;
}
+1 -2
View File
@@ -5,7 +5,6 @@ use std::sync::OnceLock;
pub use self::debug_config::ir_type::IRType as DebugConfigIR;
pub use self::debug_config::DebugConfig;
pub use self::memory::MemoryConfig;
pub use self::optimizer::settings::size_level::SizeLevel as OptimizerSettingsSizeLevel;
pub use self::optimizer::settings::Settings as OptimizerSettings;
pub use self::optimizer::Optimizer;
@@ -20,6 +19,7 @@ pub use self::polkavm::context::function::declaration::Declaration as PolkaVMFun
pub use self::polkavm::context::function::intrinsics::Intrinsics as PolkaVMIntrinsicFunction;
pub use self::polkavm::context::function::llvm_runtime::LLVMRuntime as PolkaVMLLVMRuntime;
pub use self::polkavm::context::function::r#return::Return as PolkaVMFunctionReturn;
pub use self::polkavm::context::function::runtime::arithmetics::Addition as PolkaVMAdditionFunction;
pub use self::polkavm::context::function::runtime::arithmetics::Division as PolkaVMDivisionFunction;
pub use self::polkavm::context::function::runtime::arithmetics::Remainder as PolkaVMRemainderFunction;
pub use self::polkavm::context::function::runtime::arithmetics::SignedDivision as PolkaVMSignedDivisionFunction;
@@ -76,7 +76,6 @@ pub use self::target_machine::target::Target;
pub use self::target_machine::TargetMachine;
pub(crate) mod debug_config;
pub(crate) mod memory;
pub(crate) mod optimizer;
pub(crate) mod polkavm;
pub(crate) mod target_machine;
-21
View File
@@ -1,21 +0,0 @@
//! The compile time PolkaVM memory configuration settings.
use serde::{Deserialize, Serialize};
/// The PolkaVM memory configuration.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct MemoryConfig {
/// The emulated EVM linear heap memory size in bytes.
pub heap_size: u32,
/// The PVM stack size in bytes.
pub stack_size: u32,
}
impl Default for MemoryConfig {
fn default() -> Self {
Self {
heap_size: 64 * 1024,
stack_size: 32 * 1024,
}
}
}
@@ -234,7 +234,7 @@ impl TryFrom<&SolcStandardJsonInputSettingsOptimizer> for Settings {
fn try_from(value: &SolcStandardJsonInputSettingsOptimizer) -> Result<Self, Self::Error> {
let mut result = match value.mode {
Some(mode) => Self::try_from_cli(mode)?,
None => Self::cycles(),
None => Self::size(),
};
if value.fallback_to_optimizing_for_size.unwrap_or_default() {
result.enable_fallback_to_size();
@@ -51,11 +51,20 @@ pub struct DebugInfo<'ctx> {
impl<'ctx> DebugInfo<'ctx> {
/// A shortcut constructor.
pub fn new(module: &inkwell::module::Module<'ctx>) -> Self {
pub fn new(
module: &inkwell::module::Module<'ctx>,
debug_config: &crate::debug_config::DebugConfig,
) -> Self {
let module_name = module.get_name().to_string_lossy();
let yul_name = debug_config
.contract_path
.as_ref()
.map(|path| path.display().to_string());
let (builder, compile_unit) = module.create_debug_info_builder(
true,
inkwell::debug_info::DWARFSourceLanguage::C,
module.get_name().to_string_lossy().as_ref(),
yul_name.as_deref().unwrap_or_else(|| module_name.as_ref()),
"",
"",
false,
@@ -7,7 +7,7 @@ pub mod r#return;
pub mod runtime;
pub mod yul_data;
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use inkwell::debug_info::AsDIScope;
@@ -29,6 +29,10 @@ pub struct Function<'ctx> {
declaration: Declaration<'ctx>,
/// The stack representation.
stack: HashMap<String, Pointer<'ctx>>,
/// The stack variables buffer.
stack_variables: inkwell::values::GlobalValue<'ctx>,
/// The stack variable names to slot mapping.
stack_slots: BTreeMap<String, usize>,
/// The return value entity.
r#return: Return<'ctx>,
@@ -53,6 +57,7 @@ impl<'ctx> Function<'ctx> {
name: String,
declaration: Declaration<'ctx>,
r#return: Return<'ctx>,
stack_variables: inkwell::values::GlobalValue<'ctx>,
entry_block: inkwell::basic_block::BasicBlock<'ctx>,
return_block: inkwell::basic_block::BasicBlock<'ctx>,
@@ -61,6 +66,8 @@ impl<'ctx> Function<'ctx> {
name,
declaration,
stack: HashMap::with_capacity(Self::STACK_HASHMAP_INITIAL_CAPACITY),
stack_variables,
stack_slots: BTreeMap::new(),
r#return,
entry_block,
@@ -279,4 +286,45 @@ impl<'ctx> Function<'ctx> {
.as_mut()
.expect("The Yul data must have been initialized")
}
/// Returns the stack variables global value.
pub fn stack_variables(&self) -> inkwell::values::GlobalValue<'ctx> {
self.stack_variables
}
/// Returns the slot for the given variable name.
pub fn stack_variable_slot(&mut self, name: String) -> usize {
let len = self.stack_slots.len();
*self.stack_slots.entry(name).or_insert_with(|| len)
}
/// References the stack variable `name`.
pub fn stack_variable_pointer<D: crate::PolkaVMDependency + Clone>(
&mut self,
name: String,
context: &mut super::Context<'ctx, D>,
) -> Pointer<'ctx> {
if let Some(pointer) = self.get_stack_pointer(&name) {
return pointer;
}
let pointer_name = format!("var_{}", &name);
let slot = self.stack_variable_slot(name);
Pointer::new(
context.word_type(),
Default::default(),
unsafe {
context.builder().build_gep(
context.word_type().array_type(0),
self.stack_variables().as_pointer_value(),
&[
context.xlen_type().const_zero(),
context.xlen_type().const_int(slot as u64, false),
],
&pointer_name,
)
}
.unwrap(),
)
}
}
@@ -7,6 +7,65 @@ use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::polkavm::WriteLLVM;
/// Implements the division operator according to the EVM specification.
pub struct Addition;
impl<D> RuntimeFunction<D> for Addition
where
D: Dependency + Clone,
{
const NAME: &'static str = "__revive_addition";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.void_type().fn_type(
&[
context.llvm().ptr_type(Default::default()).into(),
context.llvm().ptr_type(Default::default()).into(),
context.llvm().ptr_type(Default::default()).into(),
],
false,
)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<inkwell::values::BasicValueEnum<'ctx>>> {
let result_pointer = Self::paramater(context, 0).into_pointer_value();
let operand_1 = Self::paramater(context, 1).into_pointer_value();
let operand_2 = Self::paramater(context, 2).into_pointer_value();
let operand_1 = context
.builder()
.build_load(context.word_type(), operand_1, "operand_1")?
.into_int_value();
let operand_2 = context
.builder()
.build_load(context.word_type(), operand_2, "operand_2")?
.into_int_value();
let result = context
.builder()
.build_int_add(operand_1, operand_2, "addition_result")?;
context.builder().build_store(result_pointer, result)?;
Ok(None)
}
}
impl<D> WriteLLVM<D> for Addition
where
D: Dependency + Clone,
{
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::declare(self, context)
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
/// Implements the division operator according to the EVM specification.
pub struct Division;
@@ -1,6 +1,7 @@
//! The entry function.
use inkwell::types::BasicType;
use revive_solc_json_interface::PolkaVMDefaultHeapMemorySize;
use crate::polkavm::context::address_space::AddressSpace;
use crate::polkavm::context::function::runtime;
@@ -38,9 +39,12 @@ impl Entry {
context.xlen_type().const_zero(),
);
let heap_memory_type = context
.byte_type()
.array_type(context.memory_config.heap_size);
let heap_memory_type = context.byte_type().array_type(
context
.memory_config
.heap_size
.unwrap_or(PolkaVMDefaultHeapMemorySize),
);
context.set_global(
crate::polkavm::GLOBAL_HEAP_MEMORY,
heap_memory_type,
+41 -7
View File
@@ -25,8 +25,10 @@ use inkwell::debug_info::AsDIScope;
use inkwell::debug_info::DIScope;
use inkwell::types::BasicType;
use inkwell::values::BasicValue;
use revive_solc_json_interface::PolkaVMDefaultHeapMemorySize;
use revive_solc_json_interface::PolkaVMDefaultStackMemorySize;
use revive_solc_json_interface::SolcStandardJsonInputSettingsPolkaVMMemory;
use crate::memory::MemoryConfig;
use crate::optimizer::settings::Settings as OptimizerSettings;
use crate::optimizer::Optimizer;
use crate::polkavm::DebugConfig;
@@ -88,7 +90,7 @@ where
/// The extra LLVM arguments that were used during target initialization.
llvm_arguments: &'ctx [String],
/// The PVM memory configuration.
memory_config: MemoryConfig,
memory_config: SolcStandardJsonInputSettingsPolkaVMMemory,
/// The project dependency manager. It can be any entity implementing the trait.
/// The manager is used to get information about contracts and their dependencies during
@@ -228,18 +230,24 @@ where
include_metadata_hash: bool,
debug_config: DebugConfig,
llvm_arguments: &'ctx [String],
memory_config: MemoryConfig,
memory_config: SolcStandardJsonInputSettingsPolkaVMMemory,
) -> Self {
Self::set_data_layout(llvm, &module);
Self::link_stdlib_module(llvm, &module);
Self::link_polkavm_imports(llvm, &module);
Self::set_polkavm_stack_size(llvm, &module, memory_config.stack_size);
Self::set_polkavm_stack_size(
llvm,
&module,
memory_config
.stack_size
.unwrap_or(PolkaVMDefaultStackMemorySize),
);
Self::set_module_flags(llvm, &module);
let intrinsics = Intrinsics::new(llvm, &module);
let llvm_runtime = LLVMRuntime::new(llvm, &module, &optimizer);
let debug_info = debug_config.emit_debug_info.then(|| {
let debug_info = DebugInfo::new(&module);
let debug_info = DebugInfo::new(&module, &debug_config);
debug_info.initialize_module(llvm, &module);
debug_info
});
@@ -495,10 +503,17 @@ where
}
};
let stack_variables = format!("__vars_{name}");
self.declare_global(
&stack_variables,
self.word_type().array_type(0),
Default::default(),
);
let function = Function::new(
name.to_owned(),
FunctionDeclaration::new(r#type, value),
r#return,
self.get_global(&stack_variables).unwrap().value,
entry_block,
return_block,
);
@@ -1263,6 +1278,20 @@ where
where
T: BasicType<'ctx>,
{
let argument_types: Vec<inkwell::types::BasicMetadataTypeEnum> =
vec![self.llvm().ptr_type(Default::default()).into(); return_values_size]
.into_iter()
.chain(
argument_types
.as_slice()
.iter()
.map(T::as_basic_type_enum)
.map(inkwell::types::BasicMetadataTypeEnum::from),
)
.collect();
self.void_type().fn_type(&argument_types.as_slice(), false)
/*
let argument_types: Vec<inkwell::types::BasicMetadataTypeEnum> = argument_types
.as_slice()
.iter()
@@ -1279,6 +1308,7 @@ where
.structure_type(vec![self.word_type().as_basic_type_enum(); size].as_slice())
.fn_type(argument_types.as_slice(), false),
}
*/
}
/// Modifies the call site value, setting the default attributes.
@@ -1443,7 +1473,11 @@ where
}
pub fn heap_size(&self) -> inkwell::values::IntValue<'ctx> {
self.xlen_type()
.const_int(self.memory_config.heap_size as u64, false)
self.xlen_type().const_int(
self.memory_config
.heap_size
.unwrap_or(PolkaVMDefaultHeapMemorySize) as u64,
false,
)
}
}
@@ -8,6 +8,7 @@ use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
pub mod heap;
//pub mod stack;
pub mod storage;
/// The LLVM pointer.
@@ -0,0 +1,111 @@
//! The revive simulated EVM stack variable functions.
use inkwell::values::BasicValueEnum;
use crate::polkavm::context::runtime::RuntimeFunction;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::polkavm::WriteLLVM;
/// Load a word size value from a heap pointer.
pub struct DeclareVariable;
impl<D> RuntimeFunction<D> for DeclareVariable
where
D: Dependency + Clone,
{
const NAME: &'static str = "__revive_declare_variable";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context
.llvm
.ptr_type(Default::default())
.fn_type(&[context.xlen_type().into()], false)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
let offset = Self::paramater(context, 0).into_int_value();
let length = context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false);
let pointer = context.build_heap_gep(offset, length)?;
let value = context
.builder()
.build_load(context.word_type(), pointer.value, "value")?;
context
.basic_block()
.get_last_instruction()
.expect("Always exists")
.set_alignment(revive_common::BYTE_LENGTH_BYTE as u32)
.expect("Alignment is valid");
let swapped_value = context.build_byte_swap(value)?;
Ok(Some(swapped_value))
}
}
impl<D> WriteLLVM<D> for LoadWord
where
D: Dependency + Clone,
{
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::declare(self, context)
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
/// Store a word size value through a heap pointer.
pub struct StoreWord;
impl<D> RuntimeFunction<D> for StoreWord
where
D: Dependency + Clone,
{
const NAME: &'static str = "__revive_store_heap_word";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.void_type().fn_type(
&[context.xlen_type().into(), context.word_type().into()],
false,
)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
let offset = Self::paramater(context, 0).into_int_value();
let length = context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false);
let pointer = context.build_heap_gep(offset, length)?;
let value = context.build_byte_swap(Self::paramater(context, 1))?;
context
.builder()
.build_store(pointer.value, value)?
.set_alignment(revive_common::BYTE_LENGTH_BYTE as u32)
.expect("Alignment is valid");
Ok(None)
}
}
impl<D> WriteLLVM<D> for StoreWord
where
D: Dependency + Clone,
{
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::declare(self, context)
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
@@ -5,6 +5,7 @@ use inkwell::values::BasicValue;
use crate::polkavm::context::runtime::RuntimeFunction;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::PolkaVMAdditionFunction;
use crate::PolkaVMDivisionFunction;
use crate::PolkaVMRemainderFunction;
use crate::PolkaVMSignedDivisionFunction;
@@ -13,16 +14,20 @@ use crate::PolkaVMSignedRemainderFunction;
/// Translates the arithmetic addition.
pub fn addition<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
binding: inkwell::values::PointerValue<'ctx>,
operand_1: inkwell::values::PointerValue<'ctx>,
operand_2: inkwell::values::PointerValue<'ctx>,
) -> anyhow::Result<()>
where
D: Dependency + Clone,
{
Ok(context
.builder()
.build_int_add(operand_1, operand_2, "addition_result")?
.as_basic_value_enum())
let declaration = <PolkaVMAdditionFunction as RuntimeFunction<D>>::declaration(context);
context.build_call(
declaration,
&[binding.into(), operand_1.into(), operand_2.into()],
"add",
);
Ok(())
}
/// Translates the arithmetic subtraction.
@@ -204,7 +204,7 @@ where
&context.word_type().const_all_ones(),
overflow_negative_block,
),
(&context.word_const(0), overflow_block),
(&context.word_const(0), overflow_positive_block),
]);
Ok(result.as_basic_value())
}
+4 -4
View File
@@ -7,12 +7,12 @@ pub mod evm;
pub use self::r#const::*;
use crate::debug_config::DebugConfig;
use crate::memory::MemoryConfig;
use crate::optimizer::settings::Settings as OptimizerSettings;
use anyhow::Context as AnyhowContext;
use polkavm_common::program::ProgramBlob;
use polkavm_disassembler::{Disassembler, DisassemblyFormat};
use revive_solc_json_interface::SolcStandardJsonInputSettingsPolkaVMMemory;
use sha3::Digest;
use self::context::build::Build;
@@ -37,7 +37,7 @@ pub fn build_assembly_text(
let mut disassembled_code = Vec::new();
disassembler
.disassemble_into(&mut disassembled_code)
.with_context(|| format!("Failed to disassemble contract: {}", contract_path))?;
.with_context(|| format!("Failed to disassemble contract: {contract_path}"))?;
let assembly_text = String::from_utf8(disassembled_code).with_context(|| {
format!("Failed to convert disassembled code to string for contract: {contract_path}")
@@ -91,7 +91,7 @@ pub trait Dependency {
include_metadata_hash: bool,
debug_config: DebugConfig,
llvm_arguments: &[String],
memory_config: MemoryConfig,
memory_config: SolcStandardJsonInputSettingsPolkaVMMemory,
) -> anyhow::Result<String>;
/// Resolves a full contract path.
@@ -113,7 +113,7 @@ impl Dependency for DummyDependency {
_include_metadata_hash: bool,
_debug_config: DebugConfig,
_llvm_arguments: &[String],
_memory_config: MemoryConfig,
_memory_config: SolcStandardJsonInputSettingsPolkaVMMemory,
) -> anyhow::Result<String> {
Ok(String::new())
}
@@ -1,6 +1,6 @@
[package]
name = "revive-solidity"
version.workspace = true
name = "resolc"
version = "0.3.0"
license.workspace = true
edition.workspace = true
repository.workspace = true
@@ -18,33 +18,30 @@ path = "src/resolc/main.rs"
doctest = false
[dependencies]
clap = { workspace = true }
thiserror = { workspace = true }
anyhow = { workspace = true }
which = { workspace = true }
clap = { workspace = true }
hex = { workspace = true }
inkwell = { workspace = true }
once_cell = { workspace = true }
path-slash = { workspace = true }
rayon = { workspace = true, optional = true }
semver = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
semver = { workspace = true }
once_cell = { workspace = true }
regex = { workspace = true }
hex = { workspace = true }
num = { workspace = true }
sha3 = { workspace = true }
inkwell = { workspace = true }
which = { workspace = true }
revive-common = { workspace = true }
revive-llvm-context = { workspace = true }
revive-solc-json-interface = { workspace = true, features = ["resolc"] }
revive-yul = { workspace = true }
[target.'cfg(target_env = "musl")'.dependencies]
mimalloc = { version = "*", default-features = false }
mimalloc = { version = "0.1.46", default-features = false }
[target.'cfg(target_os = "emscripten")'.dependencies]
libc = { workspace = true }
inkwell = { workspace = true, features = ["target-riscv", "llvm18-0-no-llvm-linking"]}
inkwell = { workspace = true, features = ["target-riscv", "llvm18-1-no-llvm-linking"]}
[build-dependencies]
git2 = { workspace = true, default-features = false }
+11
View File
@@ -0,0 +1,11 @@
fn main() {
match git2::Repository::open("../..") {
Ok(repo) => {
let head = repo.head().expect("should have head");
let commit = head.peel_to_commit().expect("should have commit");
let id = &commit.id().to_string()[..7];
println!("cargo:rustc-env=GIT_COMMIT_HASH={id}");
}
Err(_) => println!("cargo:rustc-env=GIT_COMMIT_HASH=unknown"),
};
}
@@ -7,7 +7,6 @@ pub(crate) mod process;
pub(crate) mod project;
pub(crate) mod solc;
pub(crate) mod version;
pub(crate) mod yul;
pub use self::build::contract::Contract as ContractBuild;
pub use self::build::Build;
@@ -45,6 +44,8 @@ use revive_solc_json_interface::ResolcWarning;
use revive_solc_json_interface::SolcStandardJsonInput;
use revive_solc_json_interface::SolcStandardJsonInputLanguage;
use revive_solc_json_interface::SolcStandardJsonInputSettingsOptimizer;
use revive_solc_json_interface::SolcStandardJsonInputSettingsPolkaVM;
use revive_solc_json_interface::SolcStandardJsonInputSettingsPolkaVMMemory;
use revive_solc_json_interface::SolcStandardJsonInputSettingsSelection;
/// Runs the Yul mode.
@@ -53,9 +54,9 @@ pub fn yul<T: Compiler>(
solc: &mut T,
optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig,
mut debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
memory_config: SolcStandardJsonInputSettingsPolkaVMMemory,
) -> anyhow::Result<Build> {
let path = match input_files.len() {
1 => input_files.first().expect("Always exists"),
@@ -76,6 +77,7 @@ pub fn yul<T: Compiler>(
let solc_validator = Some(&*solc);
let project = Project::try_from_yul_path(path, solc_validator)?;
debug_config.set_yul_path(path);
let build = project.compile(
optimizer_settings,
include_metadata_hash,
@@ -94,7 +96,7 @@ pub fn llvm_ir(
include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
memory_config: SolcStandardJsonInputSettingsPolkaVMMemory,
) -> anyhow::Result<Build> {
let path = match input_files.len() {
1 => input_files.first().expect("Always exists"),
@@ -135,7 +137,7 @@ pub fn standard_output<T: Compiler>(
suppressed_warnings: Option<Vec<ResolcWarning>>,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
memory_config: SolcStandardJsonInputSettingsPolkaVMMemory,
) -> anyhow::Result<Build> {
let solc_version = solc.version()?;
@@ -154,6 +156,10 @@ pub fn standard_output<T: Compiler>(
),
None,
suppressed_warnings,
Some(SolcStandardJsonInputSettingsPolkaVM::new(
Some(memory_config),
debug_config.emit_debug_info,
)),
)?;
let source_code_files = solc_input
@@ -208,9 +214,8 @@ pub fn standard_json<T: Compiler>(
base_path: Option<String>,
include_paths: Vec<String>,
allow_paths: Option<String>,
debug_config: revive_llvm_context::DebugConfig,
mut debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
) -> anyhow::Result<()> {
let solc_version = solc.version()?;
@@ -224,6 +229,9 @@ pub fn standard_json<T: Compiler>(
let optimizer_settings =
revive_llvm_context::OptimizerSettings::try_from(&solc_input.settings.optimizer)?;
let polkavm_settings = solc_input.settings.polkavm.unwrap_or_default();
debug_config.emit_debug_info = polkavm_settings.debug_information.unwrap_or_default();
let include_metadata_hash = match solc_input.settings.metadata {
Some(ref metadata) => metadata.bytecode_hash != Some(MetadataHash::None),
None => true,
@@ -258,7 +266,9 @@ pub fn standard_json<T: Compiler>(
include_metadata_hash,
debug_config,
llvm_arguments,
memory_config,
polkavm_settings
.memory_config
.unwrap_or_else(SolcStandardJsonInputSettingsPolkaVMMemory::default),
)?;
build.write_to_standard_json(&mut solc_output, &solc_version)?;
}
@@ -286,7 +296,7 @@ pub fn combined_json<T: Compiler>(
output_directory: Option<PathBuf>,
overwrite: bool,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
memory_config: SolcStandardJsonInputSettingsPolkaVMMemory,
) -> anyhow::Result<()> {
let build = standard_output(
input_files,
@@ -1,6 +1,7 @@
//! Process for compiling a single compilation unit.
//! The input data.
use revive_solc_json_interface::SolcStandardJsonInputSettingsPolkaVMMemory;
use serde::Deserialize;
use serde::Serialize;
@@ -23,7 +24,7 @@ pub struct Input {
/// The extra LLVM arguments give used for manual control.
pub llvm_arguments: Vec<String>,
/// The PVM memory configuration.
pub memory_config: revive_llvm_context::MemoryConfig,
pub memory_config: SolcStandardJsonInputSettingsPolkaVMMemory,
}
impl Input {
@@ -35,7 +36,7 @@ impl Input {
optimizer_settings: revive_llvm_context::OptimizerSettings,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: Vec<String>,
memory_config: revive_llvm_context::MemoryConfig,
memory_config: SolcStandardJsonInputSettingsPolkaVMMemory,
) -> Self {
Self {
contract,
@@ -8,7 +8,7 @@ use std::collections::HashSet;
use serde::Deserialize;
use serde::Serialize;
use crate::yul::parser::statement::object::Object;
use revive_yul::parser::statement::object::Object;
use self::llvm_ir::LLVMIR;
use self::yul::Yul;
@@ -5,7 +5,7 @@ use std::collections::HashSet;
use serde::Deserialize;
use serde::Serialize;
use crate::yul::parser::statement::object::Object;
use revive_yul::parser::statement::object::Object;
/// The contract Yul source code.
#[derive(Debug, Serialize, Deserialize, Clone)]
@@ -5,6 +5,7 @@ pub mod metadata;
use std::collections::HashSet;
use revive_solc_json_interface::SolcStandardJsonInputSettingsPolkaVMMemory;
use serde::Deserialize;
use serde::Serialize;
use sha3::Digest;
@@ -76,9 +77,9 @@ impl Contract {
project: Project,
optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig,
mut debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
memory_config: SolcStandardJsonInputSettingsPolkaVMMemory,
) -> anyhow::Result<ContractBuild> {
let llvm = inkwell::context::Context::create();
let optimizer = revive_llvm_context::Optimizer::new(optimizer_settings);
@@ -116,6 +117,7 @@ impl Contract {
_ => llvm.create_module(self.path.as_str()),
};
debug_config.set_contract_path(&self.path);
let mut context = revive_llvm_context::PolkaVMContext::new(
&llvm,
module,
@@ -9,11 +9,14 @@ use std::path::Path;
#[cfg(feature = "parallel")]
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use revive_solc_json_interface::SolcStandardJsonOutput;
use serde::Deserialize;
use serde::Serialize;
use sha3::Digest;
use revive_solc_json_interface::SolcStandardJsonOutput;
use revive_yul::lexer::Lexer;
use revive_yul::parser::statement::object::Object;
use crate::build::contract::Contract as ContractBuild;
use crate::build::Build;
use crate::missing_libraries::MissingLibraries;
@@ -22,8 +25,6 @@ use crate::process::Process;
use crate::project::contract::ir::IR;
use crate::solc::version::Version as SolcVersion;
use crate::solc::Compiler;
use crate::yul::lexer::Lexer;
use crate::yul::parser::statement::object::Object;
use self::contract::Contract;
@@ -67,7 +68,7 @@ impl Project {
include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
memory_config: revive_solc_json_interface::SolcStandardJsonInputSettingsPolkaVMMemory,
) -> anyhow::Result<Build> {
let project = self.clone();
#[cfg(feature = "parallel")]
@@ -154,8 +155,8 @@ impl Project {
.iter()
.flat_map(|(file, names)| {
names
.iter()
.map(|(name, _address)| format!("{file}:{name}"))
.keys()
.map(|name| format!("{file}:{name}"))
.collect::<HashSet<String>>()
})
.collect::<HashSet<String>>();
@@ -321,7 +322,7 @@ impl revive_llvm_context::PolkaVMDependency for Project {
include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
memory_config: revive_llvm_context::MemoryConfig,
memory_config: revive_solc_json_interface::SolcStandardJsonInputSettingsPolkaVMMemory,
) -> anyhow::Result<String> {
let contract_path = project.resolve_path(identifier)?;
let contract = project
@@ -23,10 +23,6 @@ pub struct Arguments {
#[arg(long = "supported-solc-versions")]
pub supported_solc_versions: bool,
/// Print the licence and exit.
#[arg(long = "license")]
pub license: bool,
/// Specify the input paths and remappings.
/// If an argument contains a '=', it is considered a remapping.
/// Multiple Solidity files can be passed in the default Solidity mode.
@@ -185,8 +181,8 @@ pub struct Arguments {
/// 1.Increasing the heap size will increase startup costs.
/// 2.The heap size contributes to the total memory size a contract can use,
/// which includes the contracts code size
#[arg(long = "heap-size", default_value = "65536")]
pub heap_size: u32,
#[arg(long = "heap-size")]
pub heap_size: Option<u32>,
/// The contracts total stack size in bytes.
///
@@ -200,8 +196,8 @@ pub struct Arguments {
/// 1.Increasing the heap size will increase startup costs.
/// 2.The stack size contributes to the total memory size a contract can use,
/// which includes the contracts code size
#[arg(long = "stack-size", default_value = "32768")]
pub stack_size: u32,
#[arg(long = "stack-size")]
pub stack_size: Option<u32>,
}
impl Arguments {
@@ -330,6 +326,22 @@ impl Arguments {
if self.metadata_hash.is_some() {
anyhow::bail!("Metadata hash mode must specified in standard JSON input settings.");
}
if self.heap_size.is_some() {
anyhow::bail!(
"Heap size must be specified in standard JSON input polkavm memory settings."
);
}
if self.stack_size.is_some() {
anyhow::bail!(
"Stack size must be specified in standard JSON input polkavm memory settings."
);
}
if self.emit_source_debug_info {
anyhow::bail!(
"Debug info must be requested in standard JSON input polkavm settings."
);
}
}
Ok(())
@@ -5,7 +5,7 @@ pub mod arguments;
use std::io::Write;
use std::str::FromStr;
use revive_solidity::Process;
use resolc::Process;
use self::arguments::Arguments;
@@ -36,7 +36,7 @@ fn main_inner() -> anyhow::Result<()> {
std::io::stdout(),
"{} version {}",
env!("CARGO_PKG_DESCRIPTION"),
revive_solidity::ResolcVersion::default().long
resolc::ResolcVersion::default().long
)?;
return Ok(());
}
@@ -45,20 +45,12 @@ fn main_inner() -> anyhow::Result<()> {
writeln!(
std::io::stdout(),
">={},<={}",
revive_solidity::SolcFirstSupportedVersion,
revive_solidity::SolcLastSupportedVersion,
resolc::SolcFirstSupportedVersion,
resolc::SolcLastSupportedVersion,
)?;
return Ok(());
}
if arguments.license {
let license_mit = include_str!("../../../../LICENSE-MIT");
let license_apache = include_str!("../../../../LICENSE-APACHE");
writeln!(std::io::stdout(), "{}\n{}\n", license_mit, license_apache)?;
return Ok(());
}
#[cfg(feature = "parallel")]
rayon::ThreadPoolBuilder::new()
.stack_size(RAYON_WORKER_STACK_SIZE)
@@ -71,20 +63,20 @@ fn main_inner() -> anyhow::Result<()> {
let mut infile = std::fs::File::open(fname)?;
#[cfg(target_os = "emscripten")]
{
return revive_solidity::WorkerProcess::run(Some(&mut infile));
return resolc::WorkerProcess::run(Some(&mut infile));
}
#[cfg(not(target_os = "emscripten"))]
{
return revive_solidity::NativeProcess::run(Some(&mut infile));
return resolc::NativeProcess::run(Some(&mut infile));
}
}
#[cfg(target_os = "emscripten")]
{
return revive_solidity::WorkerProcess::run(None);
return resolc::WorkerProcess::run(None);
}
#[cfg(not(target_os = "emscripten"))]
{
return revive_solidity::NativeProcess::run(None);
return resolc::NativeProcess::run(None);
}
}
@@ -111,14 +103,16 @@ fn main_inner() -> anyhow::Result<()> {
let mut solc = {
#[cfg(target_os = "emscripten")]
{
revive_solidity::SoljsonCompiler
resolc::SoljsonCompiler
}
#[cfg(not(target_os = "emscripten"))]
{
revive_solidity::SolcCompiler::new(arguments.solc.unwrap_or_else(|| {
revive_solidity::SolcCompiler::DEFAULT_EXECUTABLE_NAME.to_owned()
}))?
resolc::SolcCompiler::new(
arguments
.solc
.unwrap_or_else(|| resolc::SolcCompiler::DEFAULT_EXECUTABLE_NAME.to_owned()),
)?
}
};
@@ -129,7 +123,7 @@ fn main_inner() -> anyhow::Result<()> {
let mut optimizer_settings = match arguments.optimization {
Some(mode) => revive_llvm_context::OptimizerSettings::try_from_cli(mode)?,
None => revive_llvm_context::OptimizerSettings::cycles(),
None => revive_llvm_context::OptimizerSettings::size(),
};
if arguments.fallback_to_optimizing_for_size {
optimizer_settings.enable_fallback_to_size();
@@ -148,13 +142,13 @@ fn main_inner() -> anyhow::Result<()> {
None => true,
};
let memory_config = revive_llvm_context::MemoryConfig {
heap_size: arguments.heap_size,
stack_size: arguments.stack_size,
};
let memory_config = revive_solc_json_interface::SolcStandardJsonInputSettingsPolkaVMMemory::new(
arguments.heap_size,
arguments.stack_size,
);
let build = if arguments.yul {
revive_solidity::yul(
resolc::yul(
input_files.as_slice(),
&mut solc,
optimizer_settings,
@@ -164,7 +158,7 @@ fn main_inner() -> anyhow::Result<()> {
memory_config,
)
} else if arguments.llvm_ir {
revive_solidity::llvm_ir(
resolc::llvm_ir(
input_files.as_slice(),
optimizer_settings,
include_metadata_hash,
@@ -173,7 +167,7 @@ fn main_inner() -> anyhow::Result<()> {
memory_config,
)
} else if arguments.standard_json {
revive_solidity::standard_json(
resolc::standard_json(
&mut solc,
arguments.detect_missing_libraries,
arguments.base_path,
@@ -181,11 +175,10 @@ fn main_inner() -> anyhow::Result<()> {
arguments.allow_paths,
debug_config,
&arguments.llvm_arguments,
memory_config,
)?;
return Ok(());
} else if let Some(format) = arguments.combined_json {
revive_solidity::combined_json(
resolc::combined_json(
format,
input_files.as_slice(),
arguments.libraries,
@@ -207,7 +200,7 @@ fn main_inner() -> anyhow::Result<()> {
)?;
return Ok(());
} else {
revive_solidity::standard_output(
resolc::standard_output(
input_files.as_slice(),
arguments.libraries,
&mut solc,
@@ -247,9 +240,7 @@ fn main_inner() -> anyhow::Result<()> {
writeln!(
std::io::stdout(),
"Contract `{}` assembly:\n\n{}",
path,
assembly_text
"Contract `{path}` assembly:\n\n{assembly_text}"
)?;
}
if arguments.output_binary {
@@ -19,7 +19,7 @@ use self::version::Version;
pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0);
/// The last supported version of `solc`.
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 29);
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 30);
/// `--include-path` was introduced in solc `0.8.8` <https://github.com/ethereum/solidity/releases/tag/v0.8.8>
pub const FIRST_INCLUDE_PATH_VERSION: semver::Version = semver::Version::new(0, 8, 8);
@@ -45,8 +45,6 @@ impl Compiler for SolcCompiler {
include_paths: Vec<String>,
allow_paths: Option<String>,
) -> anyhow::Result<SolcStandardJsonOutput> {
let version = self.version()?.validate(&include_paths)?.default;
let mut command = std::process::Command::new(self.executable.as_str());
command.stdin(std::process::Stdio::piped());
command.stdout(std::process::Stdio::piped());
@@ -65,7 +63,7 @@ impl Compiler for SolcCompiler {
command.arg(allow_paths);
}
input.normalize(&version);
input.normalize();
let suppressed_warnings = input.suppressed_warnings.take().unwrap_or_default();
@@ -40,8 +40,7 @@ impl Compiler for SoljsonCompiler {
anyhow::bail!("configuring allow paths is not supported with solJson")
}
let version = self.version()?.validate(&include_paths)?.default;
input.normalize(&version);
input.normalize();
let suppressed_warnings = input.suppressed_warnings.take().unwrap_or_default();
@@ -89,7 +89,7 @@ pub fn build_solidity_with_options(
sources.clone(),
libraries.clone(),
remappings,
SolcStandardJsonInputSettingsSelection::new_required(),
SolcStandardJsonInputSettingsSelection::new_required_for_tests(),
SolcStandardJsonInputSettingsOptimizer::new(
solc_optimizer_enabled,
optimizer_settings.middle_end_as_string().chars().last(),
@@ -98,6 +98,7 @@ pub fn build_solidity_with_options(
),
None,
None,
None,
)?;
let mut output = solc.standard_json(input, None, vec![], None)?;
@@ -153,7 +154,7 @@ pub fn build_solidity_with_options_evm(
sources.clone(),
libraries.clone(),
remappings,
SolcStandardJsonInputSettingsSelection::new_required(),
SolcStandardJsonInputSettingsSelection::new_required_for_tests(),
SolcStandardJsonInputSettingsOptimizer::new(
solc_optimizer_enabled,
None,
@@ -162,6 +163,7 @@ pub fn build_solidity_with_options_evm(
),
None,
None,
None,
)?;
let mut output = solc.standard_json(input, None, vec![], None)?;
@@ -209,10 +211,11 @@ pub fn build_solidity_and_detect_missing_libraries(
sources.clone(),
libraries.clone(),
None,
SolcStandardJsonInputSettingsSelection::new_required(),
SolcStandardJsonInputSettingsSelection::new_required_for_tests(),
SolcStandardJsonInputSettingsOptimizer::new(true, None, &solc_version.default, false),
None,
None,
None,
)?;
let mut output = solc.standard_json(input, None, vec![], None)?;
@@ -282,10 +285,11 @@ pub fn check_solidity_warning(
sources.clone(),
libraries,
None,
SolcStandardJsonInputSettingsSelection::new_required(),
SolcStandardJsonInputSettingsSelection::new_required_for_tests(),
SolcStandardJsonInputSettingsOptimizer::new(true, None, &solc_version.default, false),
None,
suppressed_warnings,
None,
)?;
let output = solc.standard_json(input, None, vec![], None)?;
@@ -357,7 +361,7 @@ fn compile_evm(
.expect("source should compile");
let object = &contracts
.get(contract_name)
.unwrap_or_else(|| panic!("contract '{}' didn't produce bin-runtime", contract_name));
.unwrap_or_else(|| panic!("contract '{contract_name}' didn't produce bin-runtime"));
let code = if runtime {
object.1.object.as_str()
} else {
@@ -23,4 +23,4 @@
"ts-jest": "^29.2.5",
"typescript": "^5.7.3"
}
}
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,22 @@
object "Test" {
code {
function allocate(size) -> ptr {
ptr := mload(0x40)
if iszero(ptr) { ptr := 0x60 }
mstore(0x40, add(ptr, size))
}
let size := datasize("Test_deployed")
let offset := allocate(size)
datacopy(offset, dataoffset("Test_deployed"), size)
return(offset, size)
}
object "Test_deployed" {
code {
{
let test:=0x5
mstore(2,signextend(0x8,0x0))
mstore(8,lt(0xc,test))
}
return(0, 65536)
}}}
@@ -1,33 +1,38 @@
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 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,
);
'yul',
contractYulFilename
)
const pathToMemsetYulContract = path.join(
pathToContracts,
'yul',
'memset.yul'
)
const pathToBasicSolContract = path.join(
pathToContracts,
"solidity",
contractSolFilename,
);
'solidity',
contractSolFilename
)
const pathToSolBinOutputFile = path.join(
pathToOutputDir,
contractSolFilename + binExtension,
);
contractSolFilename + binExtension
)
const pathToSolAsmOutputFile = path.join(
pathToOutputDir,
contractSolFilename + asmExtension,
);
contractSolFilename + asmExtension
)
export const paths = {
outputDir: outputDir,
@@ -42,6 +47,7 @@ export const paths = {
pathToContracts: pathToContracts,
pathToBasicSolContract: pathToBasicSolContract,
pathToBasicYulContract: pathToBasicYulContract,
pathToMemsetYulContract: pathToMemsetYulContract,
pathToSolBinOutputFile: pathToSolBinOutputFile,
pathToSolAsmOutputFile: pathToSolAsmOutputFile,
};
}
@@ -1,51 +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,
stdin?: string
): CommandResult => {
if (stdin) {
const process = spawnSync(command, [], {
input: stdin,
shell: true,
encoding: "utf8",
encoding: 'utf8',
maxBuffer: 30 * 1024 * 1024,
});
})
return {
exitCode: process.status || 0,
output: (process.stdout || process.stderr || "").toString(),
};
output: (process.stdout || process.stderr || '').toString(),
}
}
const result = shell.exec(command, { silent: true, async: false });
const result = shell.exec(command, { silent: true, async: false })
return {
exitCode: result.code,
output: result.stdout || result.stderr || "",
};
};
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,
fileExtension: string
): boolean => {
return shell.ls(pathToFileDir).stdout.includes(fileName + fileExtension);
};
return shell.ls(pathToFileDir).stdout.includes(fileName + fileExtension)
}
export const isFileEmpty = (file: string): boolean => {
if (fs.existsSync(file)) {
return fs.readFileSync(file).length === 0;
return fs.readFileSync(file).length === 0
}
};
}
@@ -0,0 +1,44 @@
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 resultInvalid = executeCommand(commandInvalid)
it('Valid command exit code = 0', () => {
expect(result.exitCode).toBe(0)
})
it('--asm output is presented', () => {
const expectedPatterns = [/(deploy)/i, /(call)/i, /(seal_return)/i]
for (const pattern of expectedPatterns) {
expect(result.output).toMatch(pattern)
}
})
it('solc exit code == resolc exit code', () => {
const command = `solc ${paths.pathToBasicSolContract} --asm`
const solcResult = executeCommand(command)
expect(solcResult.exitCode).toBe(result.exitCode)
})
it('run invalid: resolc --asm', () => {
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 solcResult = executeCommand(command)
expect(solcResult.exitCode).toBe(resultInvalid.exitCode)
})
})
@@ -0,0 +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'
//id1762
describe('Run resolc without any options', () => {
const command = 'resolc'
const result = executeCommand(command)
it('Info with help is presented', () => {
expect(result.output).toMatch(/(Usage: resolc)/i)
})
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)
})
})
//#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)
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)
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`;
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)
})
}
})
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`;
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)
})
}
})
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')
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(() => {
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([])
})
})
})
@@ -0,0 +1,18 @@
import { executeCommand } from '../src/helper'
import { paths } from '../src/entities'
describe('tests for the memset builtin to be present', () => {
// -O3 is required to reproduce.
const command = `resolc ${paths.pathToMemsetYulContract} --yul -O3`
const result = executeCommand(command)
it('Valid command exit code = 0', () => {
expect(result.exitCode).toBe(0)
})
it('--yul output is presented', () => {
expect(result.output).toMatch(/(Compiler run successful)/i)
expect(result.output).toMatch(/(No output requested)/i)
})
})
@@ -0,0 +1,39 @@
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 resultInvalid = executeCommand(commandInvalid)
it('Valid command exit code = 0', () => {
expect(result.exitCode).toBe(0)
})
it('--yul output is presented', () => {
expect(result.output).toMatch(/(Compiler run successful)/i)
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)
})
it('run invalid: resolc --yul', () => {
expect(resultInvalid.output).toMatch(/(The input file is missing)/i)
})
it('Invalid command exit code = 1', () => {
expect(resultInvalid.exitCode).toBe(1)
})
it('Invalid solc exit code == Invalid resolc exit code', () => {
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",
}
}

Some files were not shown because too many files have changed in this diff Show More