Compare commits

...

27 Commits

Author SHA1 Message Date
Alexander Samusev 9ddddc989d Merge branch 'main' into as-release-json 2025-04-07 13:24:07 +02:00
alvicsam 5992ad0043 nit 2025-04-07 13:11:09 +02:00
alvicsam 2fd96f6188 updated release.md 2025-04-07 11:18:19 +02:00
xermicus 7d8fa75a0f storage keys and values should be big endian (#277)
Storage keys and values are big endian. Keeping them LE was a pre-mature
optimization because for the contract itself it this is a no-op and thus
not observable. However we should consider the storage layout as part of
the contract ABI. The endianness of transient storage values are still
kept as-is.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-07 10:34:44 +02:00
dependabot[bot] 80f94b5c76 Bump openssl from 0.10.71 to 0.10.72 (#278)
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.71
to 0.10.72.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/sfackler/rust-openssl/releases">openssl's
releases</a>.</em></p>
<blockquote>
<h2>openssl-v0.10.72</h2>
<h2>What's Changed</h2>
<ul>
<li>make set_rsa_oaep_md visible to boringssl config by <a
href="https://github.com/frncs-rss"><code>@​frncs-rss</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2372">sfackler/rust-openssl#2372</a></li>
<li>Fix typo in openssl-sys build script by <a
href="https://github.com/rushilmehra"><code>@​rushilmehra</code></a> in
<a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2375">sfackler/rust-openssl#2375</a></li>
<li>Unify the two BoringSSL codepaths a bit and simplify init by <a
href="https://github.com/davidben"><code>@​davidben</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2377">sfackler/rust-openssl#2377</a></li>
<li>pkey_ctx: Fix link to the corresponding OpenSSL function by <a
href="https://github.com/Jakuje"><code>@​Jakuje</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2378">sfackler/rust-openssl#2378</a></li>
<li>fix test on MSRV by <a
href="https://github.com/alex"><code>@​alex</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2383">sfackler/rust-openssl#2383</a></li>
<li>Add support for AWS-LC to openssl and openssl-sys crates by <a
href="https://github.com/skmcgrail"><code>@​skmcgrail</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/1805">sfackler/rust-openssl#1805</a></li>
<li>Enable additional capabilities for AWS-LC by <a
href="https://github.com/skmcgrail"><code>@​skmcgrail</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2386">sfackler/rust-openssl#2386</a></li>
<li>Use --experimental with bindgen-cli with aws-lc build by <a
href="https://github.com/skmcgrail"><code>@​skmcgrail</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2389">sfackler/rust-openssl#2389</a></li>
<li>Fixed two UAFs and bumped versions for release by <a
href="https://github.com/alex"><code>@​alex</code></a> in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2390">sfackler/rust-openssl#2390</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Jakuje"><code>@​Jakuje</code></a> made
their first contribution in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/2378">sfackler/rust-openssl#2378</a></li>
<li><a href="https://github.com/skmcgrail"><code>@​skmcgrail</code></a>
made their first contribution in <a
href="https://redirect.github.com/sfackler/rust-openssl/pull/1805">sfackler/rust-openssl#1805</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.71...openssl-v0.10.72">https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.71...openssl-v0.10.72</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/87085bd67896b7f92e6de35d081f607a334beae4"><code>87085bd</code></a>
Merge pull request <a
href="https://redirect.github.com/sfackler/rust-openssl/issues/2390">#2390</a>
from alex/uaf-fix</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/d1a12e21573e95727b2e38b8b65273cb389be7e4"><code>d1a12e2</code></a>
Fixed two UAFs and bumped versions for release</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/7c7b2e6c9f95e77e56ab37af70b16de75beff387"><code>7c7b2e6</code></a>
Merge pull request <a
href="https://redirect.github.com/sfackler/rust-openssl/issues/2389">#2389</a>
from skmcgrail/aws-lc-follow-up</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/34a477bff20cbe43492915338d3c12597430c345"><code>34a477b</code></a>
Use --experimental with bindgen-cli with aws-lc build</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/d4bf0710640e4725b8b237968040aef3e5f4ab9a"><code>d4bf071</code></a>
Merge pull request <a
href="https://redirect.github.com/sfackler/rust-openssl/issues/2386">#2386</a>
from skmcgrail/aws-lc-follow-up</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/a86bf670c4cba3ee5531838b52419356791d966e"><code>a86bf67</code></a>
Remove comment</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/705dbfb2ee3f2d7151ff313d840bf558435d4379"><code>705dbfb</code></a>
Fix test</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/e0df413d46a89303c42e15bf7d4566193b242466"><code>e0df413</code></a>
Skip final call for LibreSSL 4.1.0 for CCM mode</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/2f1164b5e838d3665dd10a9fac19e22174289ea3"><code>2f1164b</code></a>
Enable additional capabilities for AWS-LC</li>
<li><a
href="https://github.com/sfackler/rust-openssl/commit/dde9ffb36071249ff98474eec853fd830aea44f5"><code>dde9ffb</code></a>
Merge pull request <a
href="https://redirect.github.com/sfackler/rust-openssl/issues/1805">#1805</a>
from skmcgrail/aws-lc-support-final</li>
<li>Additional commits viewable in <a
href="https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.71...openssl-v0.10.72">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=openssl&package-manager=cargo&previous-version=0.10.71&new-version=0.10.72)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/paritytech/revive/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-05 12:25:52 +02:00
alvicsam 06d324259c revert mimalloc to * 2025-04-04 14:24:47 +02:00
alvicsam 7669320e31 downgrade lockfile 2025-04-04 13:04:58 +02:00
alvicsam ea0ff27c6f use --locked 2025-04-04 12:52:24 +02:00
alvicsam 60e41a9210 upd cargo.lock 2025-04-04 12:47:49 +02:00
alvicsam 0089d58d85 downgrade mimalloc crate 2025-04-04 12:37:43 +02:00
Alexander Samusev 09c8f64eef Merge branch 'main' into as-release-json 2025-04-04 11:20:14 +02:00
alvicsam 4e6c562fac rename the releaseworkflow 2025-04-04 11:17:26 +02:00
alvicsam 12a8685f11 fix notice 2025-04-04 11:14:08 +02:00
alvicsam ce1766dc64 skip check in PRs 2025-04-04 11:11:05 +02:00
alvicsam 2c1097ef36 rm my ref from workflow 2025-04-04 10:46:05 +02:00
alvicsam a5ad9a917a add environment to generate_versions 2025-04-04 10:39:33 +02:00
alvicsam c929dc9b03 ci: update release flow and publish list.json 2025-04-03 15:32:26 +02:00
xermicus dab29bc89b bugfix missing byte swap for the create2 salt value (#272)
Found in https://github.com/paritytech/contract-issues/issues/45, thanks
@albertov19 and @sekisamu

---------

Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-03 15:20:22 +02:00
xermicus 313c033261 fix Rust 1.86.0 clippy (#273)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-03 15:03:49 +02:00
xermicus 87c1d7a8be Suport passing arbitrary llvm arguments (#271)
- Support for passing LLVM command line options via the prcoess input or
providing one or more `--llvm-arg='..'` resolc CLI flag. This allows
more fine-grained control over the LLVM backend configuration.
- Make LLVM initialization idempotent.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-04-03 13:21:00 +02:00
xermicus 8a98346a9c Fix CI badge link (#270) 2025-04-01 07:52:39 +02:00
Alexander Samusev 1b4d2c6bb8 ci: modify release according to #162 (#269)
PR modifies release workflow according to changes requested in
https://github.com/paritytech/revive/issues/162#issuecomment-2751287953
2025-03-26 12:06:51 +01:00
xermicus 004b8ac16c Update release.yml (#265)
The Release workflow used to work with a fetch-depth: 0 - not sure why this is required but yolo-ing it in for a test
2025-03-20 20:07:04 +01:00
xermicus 497dae2494 factor out solc JSON interface crate (#264)
The differential testing framework will make a second consumer. There
seems to be no re-usable Rust crate for this. But we already have
everything here, just needs a small refactor to make it fully re-usable.

- Mostly decouple the solc JSON-input-output interface types from the
`solidity` frontend crate
- Expose the JSON-input-output interface types in a dedicated crate

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-03-20 17:11:40 +01:00
Pavlo Khrystenko 36ea69b50f Add --supported-solc-versions CLI command (#260)
### Description 

Adds `--supported-solc-versions` cli command to return a semver range of
supported `solc` versions.
Is a hack until #162 is implemented.

---------

Co-authored-by: xermicus <cyrill@parity.io>
2025-03-19 16:07:48 +01:00
xermicus 2bbc5d713d remove support for webkit (#262)
Signed-off-by: xermicus <cyrill@parity.io>
2025-03-18 15:00:55 +01:00
xermicus 4a9b651235 Support solc v0.8.29 (#261)
No observable changes w.r.t. YUL compilation.
- Mark solc v0.8.29 as the latest supported version
- Add integration test for solc v0.8.29 specific feature
- Use the latest version on CI
- Drive-by fix linter complaints and a two types in the CI yaml files

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: xermicus <cyrill@parity.io>
2025-03-18 13:01:15 +01:00
73 changed files with 1091 additions and 426 deletions
+2 -1
View File
@@ -1,4 +1,5 @@
name: "Install Solidity Compiler" name: "Install Solidity Compiler"
description: "Installs the Ethereum solc Solidity compiler frontend executable"
runs: runs:
using: "composite" using: "composite"
@@ -18,7 +19,7 @@ runs:
shell: bash shell: bash
run: | run: |
mkdir -p solc mkdir -p solc
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.28/${SOLC_NAME} curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.29/${SOLC_NAME}
- name: Make Solc Executable - name: Make Solc Executable
if: ${{ runner.os == 'Windows' }} if: ${{ runner.os == 'Windows' }}
+119
View File
@@ -0,0 +1,119 @@
import os
import sys
import json
import requests
from datetime import datetime
def validate_github_token():
"""Validate that GITHUB_TOKEN environment variable is set."""
if 'GITHUB_TOKEN' not in os.environ:
print("Error: GITHUB_TOKEN environment variable is not set.")
sys.exit(1)
def fetch_release_data(repo, tag):
"""Fetch release data from GitHub API."""
url = f"https://api.github.com/repos/{repo}/releases/tags/{tag}"
headers = {
'Authorization': f"Bearer {os.environ['GITHUB_TOKEN']}",
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28'
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"Error fetching release data: {e}")
sys.exit(1)
def extract_build_hash(target_commitish):
"""Extract the first 8 characters of the commit hash."""
return f"commit.{target_commitish[:8]}"
def generate_asset_json(release_data, asset):
"""Generate JSON for a specific asset."""
version = release_data['tag_name'].lstrip('v')
build = extract_build_hash(release_data['target_commitish'])
long_version = f"{version}+{build}"
path = f"{asset['name']}+{long_version}"
return {
"path": path,
"name": asset['name'],
"version": version,
"build": build,
"longVersion": long_version,
"url": asset['browser_download_url'],
"firstSolcVersion": os.environ["FIRST_SOLC_VERSION"],
"lastSolcVersion": os.environ["LAST_SOLC_VERSION"]
}
def save_platform_json(platform_folder, asset_json, tag):
"""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['path'] != asset_json['path']
]
# Add the new build
list_data['builds'].append(asset_json)
# Update releases
version = asset_json['version']
list_data['releases'][version] = asset_json['path']
# 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 arguments
if len(sys.argv) != 3:
print("Usage: python script.py <repo> <tag>")
sys.exit(1)
repo, tag = sys.argv[1], sys.argv[2]
# Validate GitHub token
validate_github_token()
# Fetch release data
release_data = fetch_release_data(repo, tag)
# 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.exe': 'windows',
'resolc_web.js': 'wasm'
}
# Process each asset
for asset in release_data['assets']:
platform_name = platform_mapping.get(asset['name'])
if platform_name:
platform_folder = os.path.join(platform_name)
asset_json = generate_asset_json(release_data, asset)
save_platform_json(platform_folder, asset_json, tag)
print(f"Processed {asset['name']} for {platform_name}")
if __name__ == "__main__":
main()
+64
View File
@@ -0,0 +1,64 @@
name: Generate JSON for resolc-bin
on:
release:
types: [published]
jobs:
generateJson:
runs-on: ubuntu-latest
if: contains(github.event.release.tag_name, 'llvm') == false
environment: tags
env:
# the token is needed for json_generator.py
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
path: tmp
- name: Checkout
uses: actions/checkout@v4
with:
repository: paritytech/resolc-bin
path: resolc-bin
- 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 and push
env:
TOKEN: ${{ steps.app-token.outputs.token }}
APP_NAME: "paritytech-revive-json"
Green: "\e[32m"
NC: "\e[0m"
run: |
sudo apt-get update && sudo apt-get install -y wget
wget https://github.com/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/resolc-x86_64-unknown-linux-musl
chmod +x resolc-x86_64-unknown-linux-musl
export FIRST_SOLC_VERSION=$(./resolc-x86_64-unknown-linux-musl --supported-solc-versions | cut -f 1 -d "," | tr -d ">=")
export LAST_SOLC_VERSION=$(./resolc-x86_64-unknown-linux-musl --supported-solc-versions | cut -f 2 -d "," | tr -d "<=")
cd resolc-bin
python ../tmp/.github/scripts/json_generator.py ${GITHUB_REPOSITORY} ${{ github.event.release.tag_name }}
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 .
git commit -m "Update json"
git push origin main
echo "::notice::info.list files were successfully published to https://github.com/paritytech/resolc-bin"
+60 -44
View File
@@ -1,11 +1,12 @@
name: Release name: Build & Release
on: on:
push: push:
branches: ["main"] branches: ["main"]
tags:
- "v*"
pull_request: pull_request:
branches: ["main"] branches: ["main"]
types: [opened, synchronize, labled, unlabled] types: [opened, synchronize, labeled, unlabeled]
workflow_dispatch:
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -17,40 +18,44 @@ env:
jobs: jobs:
check-version-changed: check-version-changed:
if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'release-test')
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: write contents: write
env:
CURRENT_TAG: ${{ github.ref_name }}
outputs: outputs:
TAG: ${{ steps.versions.outputs.TAG }}
PKG_VER: ${{ steps.versions.outputs.PKG_VER }}
RELEASE_NOTES: ${{ steps.versions.outputs.RELEASE_NOTES }} RELEASE_NOTES: ${{ steps.versions.outputs.RELEASE_NOTES }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
fetch-tags: true
- name: Check Versions # Check that tag and version in Cargo.toml match
- name: Check versions
id: versions id: versions
run: | run: |
export CURRENT_TAG=$(git describe --tags --abbrev=0 --exclude "llvm-*") if [[ $CURRENT_TAG == 'main' ]];
then
echo "::notice::Tag $CURRENT_TAG is not a release tag, skipping the check in the main branch";
exit 0
fi
if [[ $CURRENT_TAG != "v"* ]];
then
echo "::notice::Tag $CURRENT_TAG is not a release tag, skipping the check in a PR";
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 Cargo.toml | grep -A 5 package] | grep version | cut -d '=' -f 2 | tr -d '"' | tr -d " ")
echo "Current tag $CURRENT_TAG" echo "Current tag $CURRENT_TAG"
echo "Package version $PKG_VER" echo "Package version $PKG_VER"
# #
echo "PKG_VER=$PKG_VER" >> $GITHUB_OUTPUT if [[ $CURRENT_TAG != $PKG_VER ]];
if [[ $CURRENT_TAG == $PKG_VER ]];
then then
echo "Tag is up to date. Nothing to do."; echo "::error::Tag $CURRENT_TAG doesn't match package version $PKG_VER in Cargo.toml, please fix";
export TAG=old; exit 1
else
echo "Tag was updated.";
export TAG=new;
fi fi
echo "TAG=$TAG" >> $GITHUB_OUTPUT
# Generating release notes early, in order to avoid checkout at the last step # Generating release notes early, in order to avoid checkout at the last step
export RELEASE_NOTES="$(sed '/^## '${PKG_VER}'/,/^## v/!d' CHANGELOG.md | sed -e '1d' -e '$d')" export RELEASE_NOTES="$(sed '/^## '${CURRENT_TAG}'/,/^## v/!d' CHANGELOG.md | sed -e '1d' -e '$d')"
echo "Release notes:" echo "Release notes:"
echo "$RELEASE_NOTES" echo "$RELEASE_NOTES"
@@ -62,7 +67,13 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
target: [x86_64-unknown-linux-musl, aarch64-apple-darwin, x86_64-apple-darwin, x86_64-pc-windows-msvc] target:
[
x86_64-unknown-linux-musl,
aarch64-apple-darwin,
x86_64-apple-darwin,
x86_64-pc-windows-msvc,
]
include: include:
- target: x86_64-unknown-linux-musl - target: x86_64-unknown-linux-musl
type: musl type: musl
@@ -76,14 +87,13 @@ jobs:
- target: x86_64-pc-windows-msvc - target: x86_64-pc-windows-msvc
type: native type: native
runner: windows-2022 runner: windows-2022
if: ${{ needs.check-version-changed.outputs.TAG == 'new' }}
runs-on: ${{ matrix.runner }} runs-on: ${{ matrix.runner }}
needs: [check-version-changed] needs: [check-version-changed]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
# without this it will override our rust flags # without this it will override our rust flags
rustflags: "" rustflags: ""
cache-key: ${{ matrix.target }} cache-key: ${{ matrix.target }}
@@ -130,9 +140,10 @@ jobs:
retention-days: 1 retention-days: 1
build-wasm: build-wasm:
if: ${{ needs.check-version-changed.outputs.TAG == 'new' }}
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
needs: [check-version-changed] needs: [check-version-changed]
env:
RELEASE_RESOLC_WASM_URI: https://github.com/paritytech/revive-workflow-test/releases/download/${{ github.ref_name }}/resolc.wasm
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
@@ -165,12 +176,12 @@ jobs:
- name: Set Up Node.js - name: Set Up Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: "20" node-version: "20"
- name: Basic Sanity Check - name: Basic Sanity Check
run: | run: |
mkdir -p solc mkdir -p solc
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.28/soljson.js curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.29/soljson.js
node -e " node -e "
const soljson = require('solc/soljson'); const soljson = require('solc/soljson');
const createRevive = require('./target/wasm32-unknown-emscripten/release/resolc.js'); const createRevive = require('./target/wasm32-unknown-emscripten/release/resolc.js');
@@ -207,23 +218,22 @@ jobs:
- name: Compress Artifact - name: Compress Artifact
run: | run: |
tar -czf $(pwd)/resolc-wasm32-unknown-emscripten.tar.gz -C ./target/wasm32-unknown-emscripten/release/ \ mkdir -p resolc-wasm32-unknown-emscripten
resolc.js \ mv ./target/wasm32-unknown-emscripten/release/resolc.js ./resolc-wasm32-unknown-emscripten/
resolc.wasm \ mv ./target/wasm32-unknown-emscripten/release/resolc.wasm ./resolc-wasm32-unknown-emscripten/
resolc_web.js mv ./target/wasm32-unknown-emscripten/release/resolc_web.js ./resolc-wasm32-unknown-emscripten/
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: resolc-wasm32-unknown-emscripten name: resolc-wasm32-unknown-emscripten
path: resolc-wasm32-unknown-emscripten.tar.gz path: resolc-wasm32-unknown-emscripten/*
retention-days: 1 retention-days: 1
create-release: create-release:
if: github.event_name != 'pull_request' if: startsWith(github.ref_name, 'v')
needs: [check-version-changed, build-wasm] needs: [check-version-changed, build-wasm]
runs-on: macos-14 runs-on: macos-14
permissions: environment: tags
contents: write
steps: steps:
- name: Download Artifacts - name: Download Artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@@ -234,13 +244,16 @@ jobs:
run: | run: |
lipo resolc-aarch64-apple-darwin resolc-x86_64-apple-darwin -create -output resolc-universal-apple-darwin lipo resolc-aarch64-apple-darwin resolc-x86_64-apple-darwin -create -output resolc-universal-apple-darwin
- name: Compress Artifacts - name: Make Executable
run: | run: |
chmod +x resolc-x86_64-unknown-linux-musl chmod +x resolc-x86_64-unknown-linux-musl
chmod +x resolc-universal-apple-darwin chmod +x resolc-universal-apple-darwin
tar -czf resolc-x86_64-unknown-linux-musl.tar.gz resolc-x86_64-unknown-linux-musl
tar -czf resolc-universal-apple-darwin.tar.gz resolc-universal-apple-darwin - uses: actions/create-github-app-token@v1
zip -j resolc-x86_64-pc-windows-msvc.zip resolc-x86_64-pc-windows-msvc.exe id: app-token
with:
app-id: ${{ secrets.REVIVE_RELEASE_APP_ID }}
private-key: ${{ secrets.REVIVE_RELEASE_APP_KEY }}
- name: create-release - name: create-release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
@@ -251,12 +264,15 @@ jobs:
## Note for macOS Users ## Note for macOS Users
The macOS binary is unsigned and it needs to be made runnable using `xattr -c resolc-universal-apple-darwin`. The macOS binary is unsigned and it needs to be made runnable using `xattr -c resolc-universal-apple-darwin`.
tag_name: ${{ needs.check-version-changed.outputs.PKG_VER }} tag_name: ${{ github.ref_name }}
name: ${{ needs.check-version-changed.outputs.PKG_VER }} name: ${{ github.ref_name }}
draft: true prerelease: true
token: ${{ steps.app-token.outputs.token }}
target_commitish: ${{ github.sha }} target_commitish: ${{ github.sha }}
files: | files: |
resolc-x86_64-unknown-linux-musl.tar.gz resolc-x86_64-unknown-linux-musl
resolc-universal-apple-darwin.tar.gz resolc-universal-apple-darwin
resolc-wasm32-unknown-emscripten.tar.gz resolc-x86_64-pc-windows-msvc.exe
resolc-x86_64-pc-windows-msvc.zip resolc.js
resolc.wasm
resolc_web.js
+13
View File
@@ -6,6 +6,19 @@ This is a development pre-release.
Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee` Supported `polkadot-sdk` rev:`c29e72a8628835e34deb6aa7db9a78a2e4eabcee`
### Added
- Support for solc v0.8.29
- Decouples the solc JSON-input-output type definitions from the Solidity fronted and expose them via a dedicated crate.
- `--supported-solc-versions` for `resolc` binary to return a `semver` range of supported `solc` versions.
- Support for passing LLVM command line options via the prcoess input or providing one or more `--llvm-arg='..'` resolc CLI flag. This allows more fine-grained control over the LLVM backend configuration.
### Changed
- Storage keys and values are big endian. This was a pre-mature optimization because for the contract itself it this is a no-op and thus not observable. However we should consider the storage layout as part of the contract ABI. The endianness of transient storage values are still kept as-is.
- Runner `resolc` using webkit is no longer supported.
### Fixed
- A missing byte swap for the create2 salt value.
## v0.1.0-dev.12 ## v0.1.0-dev.12
This is a development pre-release. This is a development pre-release.
Generated
+19 -4
View File
@@ -4965,9 +4965,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.71" version = "0.10.72"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
dependencies = [ dependencies = [
"bitflags 2.8.0", "bitflags 2.8.0",
"cfg-if", "cfg-if",
@@ -4997,9 +4997,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.106" version = "0.9.107"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@@ -8368,12 +8368,14 @@ dependencies = [
"hex", "hex",
"inkwell", "inkwell",
"itertools 0.14.0", "itertools 0.14.0",
"libc",
"num", "num",
"polkavm-common 0.21.0", "polkavm-common 0.21.0",
"polkavm-disassembler", "polkavm-disassembler",
"revive-common", "revive-common",
"revive-linker", "revive-linker",
"revive-runtime-api", "revive-runtime-api",
"revive-solc-json-interface",
"revive-stdlib", "revive-stdlib",
"semver 1.0.25", "semver 1.0.25",
"serde", "serde",
@@ -8406,6 +8408,18 @@ dependencies = [
"revive-common", "revive-common",
] ]
[[package]]
name = "revive-solc-json-interface"
version = "0.1.0-dev.12"
dependencies = [
"anyhow",
"rayon",
"revive-common",
"semver 1.0.25",
"serde",
"serde_json",
]
[[package]] [[package]]
name = "revive-solidity" name = "revive-solidity"
version = "0.1.0-dev.12" version = "0.1.0-dev.12"
@@ -8424,6 +8438,7 @@ dependencies = [
"regex", "regex",
"revive-common", "revive-common",
"revive-llvm-context", "revive-llvm-context",
"revive-solc-json-interface",
"semver 1.0.25", "semver 1.0.25",
"serde", "serde",
"serde_json", "serde_json",
+1
View File
@@ -24,6 +24,7 @@ lld-sys = { version = "0.1.0-dev.12", path = "crates/lld-sys" }
revive-llvm-context = { version = "0.1.0-dev.12", path = "crates/llvm-context" } revive-llvm-context = { version = "0.1.0-dev.12", path = "crates/llvm-context" }
revive-runtime-api = { version = "0.1.0-dev.12", path = "crates/runtime-api" } revive-runtime-api = { version = "0.1.0-dev.12", path = "crates/runtime-api" }
revive-runner = { version = "0.1.0-dev.12", path = "crates/runner" } revive-runner = { version = "0.1.0-dev.12", path = "crates/runner" }
revive-solc-json-interface = { version = "0.1.0-dev.12", path = "crates/solc-json-interface" }
revive-solidity = { version = "0.1.0-dev.12", path = "crates/solidity" } revive-solidity = { version = "0.1.0-dev.12", path = "crates/solidity" }
revive-stdlib = { version = "0.1.0-dev.12", path = "crates/stdlib" } revive-stdlib = { version = "0.1.0-dev.12", path = "crates/stdlib" }
revive-build-utils = { version = "0.1.0-dev.12", path = "crates/build-utils" } revive-build-utils = { version = "0.1.0-dev.12", path = "crates/build-utils" }
+1 -1
View File
@@ -23,7 +23,7 @@
install: install-bin install-npm install: install-bin install-npm
install-bin: install-bin:
cargo install --path crates/solidity cargo install --locked --path crates/solidity
install-npm: install-npm:
npm install && npm fund npm install && npm fund
+1 -1
View File
@@ -1,4 +1,4 @@
![CI](https://github.com/paritytech/revive/actions/workflows/rust.yml/badge.svg) ![CI](https://github.com/paritytech/revive/actions/workflows/test.yml/badge.svg)
[![Docs](https://img.shields.io/badge/Docs-contracts.polkadot.io-brightgreen.svg)](https://contracts.polkadot.io/revive_compiler/) [![Docs](https://img.shields.io/badge/Docs-contracts.polkadot.io-brightgreen.svg)](https://contracts.polkadot.io/revive_compiler/)
# revive # revive
+8 -5
View File
@@ -4,11 +4,14 @@ Prior to the first stable release we neither have formal release processes nor d
To create a new pre-release: 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. Add the `release-test` label to trigger the release workflows. 1. Create a release PR which updates the `-dev.X` versions in the workspace `Cargo.toml` and updates the `CHANGELOG.md` accordingly.
2. If the CI passes, merge the release PR. The release workflow will attempt to build and publish a new release whenever the latest git tag does not match the cargo package version. 2. If the CI passes, merge the release PR.
3. Wait for the `Release` workflow to finish. If the workflow fails after the `build-linux-all` step, check if a tag has been created and delete it before restarting or pushing updates. Note: It's more convenient to debug the release workflow in a fork (the fork has to be under the `paritytech` org to access `parity-large` runners). 3. Push a tag that has the same `-dev.X` version as in `Cargo.toml`
4. Check draft release on [Releases page](https://github.com/paritytech/revive/releases) and publish (should contain `resolc.js`, `resolc.wasm`, `resolc-web.js`, and `resolc-static-linux` release assets) 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. Update the [contract-docs](https://github.com/paritytech/contract-docs/) accordingly 5. Wait for the `Release` workflow to finish. It should create the pre-release with the same `-dev.X` 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
# LLVM release # LLVM release
+3 -3
View File
@@ -2,9 +2,9 @@
"Baseline": 1443, "Baseline": 1443,
"Computation": 2788, "Computation": 2788,
"DivisionArithmetics": 9748, "DivisionArithmetics": 9748,
"ERC20": 19203, "ERC20": 19150,
"Events": 2201, "Events": 2201,
"FibonacciIterative": 2041, "FibonacciIterative": 2041,
"Flipper": 2632, "Flipper": 2691,
"SHA1": 8958 "SHA1": 8997
} }
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
contract Predicted {
uint public salt;
constructor(uint _salt) {
salt = _salt;
}
}
contract AddressPredictor {
constructor(uint _salt, bytes memory _bytecode) payable {
address deployed = address(new Predicted{salt: bytes32(_salt)}(_salt));
address predicted = predictAddress(_salt, _bytecode);
assert(deployed == predicted);
}
function predictAddress(
uint _foo,
bytes memory _bytecode
) public view returns (address predicted) {
bytes32 addr = keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
bytes32(_foo),
keccak256(abi.encodePacked(_bytecode, abi.encode(_foo)))
)
);
predicted = address(uint160(uint(addr)));
}
}
+52
View File
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.29;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "LayoutAt"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "a7a0d537"
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "15393349"
}
}
]
}
*/
contract LayoutAt layout at 0xDEADBEEF + 0xCAFEBABE {
uint[3] public something;
constructor() payable {
something[0] = 1337;
something[1] = 42;
something[2] = 69;
}
function slotOfSomething() public pure returns (uint ret) {
assembly {
ret := something.slot
}
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ pragma solidity ^0.8;
"Instantiated": 0 "Instantiated": 0
}, },
"key": "0000000000000000000000000000000000000000000000000000000000000000", "key": "0000000000000000000000000000000000000000000000000000000000000000",
"expected": "0100000000000000000000000000000000000000000000000000000000000000" "expected": "0000000000000000000000000000000000000000000000000000000000000001"
} }
}, },
{ {
+11
View File
@@ -250,6 +250,17 @@ sol!(
); );
case!("Storage.sol", Storage, transientCall, storage_transient, value: U256); case!("Storage.sol", Storage, transientCall, storage_transient, value: U256);
sol!(
contract Predicted {
constructor(uint _foo);
}
contract AddressPredictor {
constructor(uint _foo, bytes memory _bytecode) payable;
}
);
case!("AddressPredictor.sol", Predicted, constructorCall, predicted_constructor, salt: U256);
case!("AddressPredictor.sol", AddressPredictor, constructorCall, address_predictor_constructor, salt: U256, bytecode: Bytes);
impl Contract { impl Contract {
pub fn build(calldata: Vec<u8>, name: &'static str, code: &str) -> Self { pub fn build(calldata: Vec<u8>, name: &'static str, code: &str) -> Self {
Self { Self {
+29
View File
@@ -59,6 +59,7 @@ test_spec!(function_pointer, "FunctionPointer", "FunctionPointer.sol");
test_spec!(mload, "MLoad", "MLoad.sol"); test_spec!(mload, "MLoad", "MLoad.sol");
test_spec!(delegate_no_contract, "DelegateCaller", "DelegateCaller.sol"); test_spec!(delegate_no_contract, "DelegateCaller", "DelegateCaller.sol");
test_spec!(function_type, "FunctionType", "FunctionType.sol"); test_spec!(function_type, "FunctionType", "FunctionType.sol");
test_spec!(layout_at, "LayoutAt", "LayoutAt.sol");
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> { fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
vec![Instantiate { vec![Instantiate {
@@ -485,3 +486,31 @@ fn transfer_denies_reentrancy() {
} }
.run(); .run();
} }
#[test]
fn create2_salt() {
let salt = U256::from(777);
let predicted = Contract::predicted_constructor(salt).pvm_runtime;
let predictor = Contract::address_predictor_constructor(salt, predicted.clone().into());
Specs {
actions: vec![
Upload {
origin: TestAddress::Alice,
code: Code::Bytes(predicted),
storage_deposit_limit: None,
},
Instantiate {
origin: TestAddress::Alice,
value: 0,
gas_limit: Some(GAS_LIMIT),
storage_deposit_limit: None,
code: Code::Bytes(predictor.pvm_runtime),
data: predictor.calldata,
salt: OptionalHex::default(),
},
],
differential: false,
..Default::default()
}
.run();
}
+2
View File
@@ -22,6 +22,7 @@ num = { workspace = true }
hex = { workspace = true } hex = { workspace = true }
sha3 = { workspace = true } sha3 = { workspace = true }
inkwell = { workspace = true } inkwell = { workspace = true }
libc = { workspace = true }
polkavm-disassembler = { workspace = true } polkavm-disassembler = { workspace = true }
polkavm-common = { workspace = true } polkavm-common = { workspace = true }
@@ -29,3 +30,4 @@ revive-common = { workspace = true }
revive-runtime-api = { workspace = true } revive-runtime-api = { workspace = true }
revive-linker = { workspace = true } revive-linker = { workspace = true }
revive-stdlib = { workspace = true } revive-stdlib = { workspace = true }
revive-solc-json-interface = { workspace = true }
+39 -8
View File
@@ -1,9 +1,7 @@
//! The LLVM context library. //! The LLVM context library.
pub(crate) mod debug_config; use std::ffi::CString;
pub(crate) mod optimizer; use std::sync::OnceLock;
pub(crate) mod polkavm;
pub(crate) mod target_machine;
pub use self::debug_config::ir_type::IRType as DebugConfigIR; pub use self::debug_config::ir_type::IRType as DebugConfigIR;
pub use self::debug_config::DebugConfig; pub use self::debug_config::DebugConfig;
@@ -38,7 +36,9 @@ pub use self::polkavm::context::function::Function as PolkaVMFunction;
pub use self::polkavm::context::global::Global as PolkaVMGlobal; pub use self::polkavm::context::global::Global as PolkaVMGlobal;
pub use self::polkavm::context::pointer::heap::LoadWord as PolkaVMLoadHeapWordFunction; pub use self::polkavm::context::pointer::heap::LoadWord as PolkaVMLoadHeapWordFunction;
pub use self::polkavm::context::pointer::heap::StoreWord as PolkaVMStoreHeapWordFunction; pub use self::polkavm::context::pointer::heap::StoreWord as PolkaVMStoreHeapWordFunction;
pub use self::polkavm::context::pointer::storage::LoadTransientWord as PolkaVMLoadTransientStorageWordFunction;
pub use self::polkavm::context::pointer::storage::LoadWord as PolkaVMLoadStorageWordFunction; pub use self::polkavm::context::pointer::storage::LoadWord as PolkaVMLoadStorageWordFunction;
pub use self::polkavm::context::pointer::storage::StoreTransientWord as PolkaVMStoreTransientStorageWordFunction;
pub use self::polkavm::context::pointer::storage::StoreWord as PolkaVMStoreStorageWordFunction; pub use self::polkavm::context::pointer::storage::StoreWord as PolkaVMStoreStorageWordFunction;
pub use self::polkavm::context::pointer::Pointer as PolkaVMPointer; pub use self::polkavm::context::pointer::Pointer as PolkaVMPointer;
pub use self::polkavm::context::r#loop::Loop as PolkaVMLoop; pub use self::polkavm::context::r#loop::Loop as PolkaVMLoop;
@@ -66,7 +66,6 @@ pub use self::polkavm::evm::memory as polkavm_evm_memory;
pub use self::polkavm::evm::r#return as polkavm_evm_return; pub use self::polkavm::evm::r#return as polkavm_evm_return;
pub use self::polkavm::evm::return_data as polkavm_evm_return_data; pub use self::polkavm::evm::return_data as polkavm_evm_return_data;
pub use self::polkavm::evm::storage as polkavm_evm_storage; pub use self::polkavm::evm::storage as polkavm_evm_storage;
pub use self::polkavm::metadata_hash::MetadataHash as PolkaVMMetadataHash;
pub use self::polkavm::r#const as polkavm_const; pub use self::polkavm::r#const as polkavm_const;
pub use self::polkavm::Dependency as PolkaVMDependency; pub use self::polkavm::Dependency as PolkaVMDependency;
pub use self::polkavm::DummyDependency as PolkaVMDummyDependency; pub use self::polkavm::DummyDependency as PolkaVMDummyDependency;
@@ -75,9 +74,41 @@ pub use self::polkavm::WriteLLVM as PolkaVMWriteLLVM;
pub use self::target_machine::target::Target; pub use self::target_machine::target::Target;
pub use self::target_machine::TargetMachine; pub use self::target_machine::TargetMachine;
/// Initializes the target machine. pub(crate) mod debug_config;
pub fn initialize_target(target: Target) { pub(crate) mod optimizer;
pub(crate) mod polkavm;
pub(crate) mod target_machine;
static DID_INITIALIZE: OnceLock<()> = OnceLock::new();
/// Initializes the LLVM compiler backend.
///
/// This is a no-op if called subsequentially.
///
/// `llvm_arguments` are passed as-is to the LLVM CL options parser.
pub fn initialize_llvm(target: Target, name: &str, llvm_arguments: &[String]) {
let Ok(_) = DID_INITIALIZE.set(()) else {
return; // Tests don't go through a recursive process
};
let argv = [name.to_string()]
.iter()
.chain(llvm_arguments)
.map(|arg| CString::new(arg.as_bytes()).unwrap())
.collect::<Vec<_>>();
let argv: Vec<*const libc::c_char> = argv.iter().map(|arg| arg.as_ptr()).collect();
let overview = CString::new("").unwrap();
unsafe {
inkwell::llvm_sys::support::LLVMParseCommandLineOptions(
argv.len() as i32,
argv.as_ptr(),
overview.as_ptr(),
);
}
inkwell::support::enable_llvm_pretty_stack_trace();
match target { match target {
Target::PVM => self::polkavm::initialize_target(), Target::PVM => inkwell::targets::Target::initialize_riscv(&Default::default()),
} }
} }
@@ -2,6 +2,7 @@
pub mod size_level; pub mod size_level;
use revive_solc_json_interface::SolcStandardJsonInputSettingsOptimizer;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
@@ -226,3 +227,18 @@ impl std::fmt::Display for Settings {
) )
} }
} }
impl TryFrom<&SolcStandardJsonInputSettingsOptimizer> for Settings {
type Error = anyhow::Error;
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(),
};
if value.fallback_to_optimizing_for_size.unwrap_or_default() {
result.enable_fallback_to_size();
}
Ok(result)
}
}
@@ -83,6 +83,8 @@ where
current_function: Option<Rc<RefCell<Function<'ctx>>>>, current_function: Option<Rc<RefCell<Function<'ctx>>>>,
/// The loop context stack. /// The loop context stack.
loop_stack: Vec<Loop<'ctx>>, loop_stack: Vec<Loop<'ctx>>,
/// The extra LLVM arguments that were used during target initialization.
llvm_arguments: &'ctx [String],
/// The project dependency manager. It can be any entity implementing the trait. /// 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 /// The manager is used to get information about contracts and their dependencies during
@@ -223,6 +225,7 @@ where
dependency_manager: Option<D>, dependency_manager: Option<D>,
include_metadata_hash: bool, include_metadata_hash: bool,
debug_config: DebugConfig, debug_config: DebugConfig,
llvm_arguments: &'ctx [String],
) -> Self { ) -> Self {
Self::set_data_layout(llvm, &module); Self::set_data_layout(llvm, &module);
Self::link_stdlib_module(llvm, &module); Self::link_stdlib_module(llvm, &module);
@@ -250,6 +253,7 @@ where
functions: HashMap::with_capacity(Self::FUNCTIONS_HASHMAP_INITIAL_CAPACITY), functions: HashMap::with_capacity(Self::FUNCTIONS_HASHMAP_INITIAL_CAPACITY),
current_function: None, current_function: None,
loop_stack: Vec::with_capacity(Self::LOOP_STACK_INITIAL_CAPACITY), loop_stack: Vec::with_capacity(Self::LOOP_STACK_INITIAL_CAPACITY),
llvm_arguments,
dependency_manager, dependency_manager,
include_metadata_hash, include_metadata_hash,
@@ -639,6 +643,7 @@ where
self.optimizer.settings().to_owned(), self.optimizer.settings().to_owned(),
self.include_metadata_hash, self.include_metadata_hash,
self.debug_config.clone(), self.debug_config.clone(),
self.llvm_arguments,
) )
}) })
} }
@@ -17,47 +17,20 @@ where
const NAME: &'static str = "__revive_load_storage_word"; const NAME: &'static str = "__revive_load_storage_word";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> { fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.word_type().fn_type( context
&[context.xlen_type().into(), context.word_type().into()], .word_type()
false, .fn_type(&[context.word_type().into()], false)
)
} }
fn emit_body<'ctx>( fn emit_body<'ctx>(
&self, &self,
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> { ) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
let is_transient = Self::paramater(context, 0); Ok(Some(emit_load(
let key_value = Self::paramater(context, 1); context,
Self::paramater(context, 0),
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer"); false,
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer"); )?))
let length_pointer = context.build_alloca_at_entry(context.xlen_type(), "length_pointer");
context
.builder()
.build_store(key_pointer.value, key_value)?;
context.build_store(value_pointer, context.word_const(0))?;
context.build_store(
length_pointer,
context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false),
)?;
let arguments = [
is_transient,
key_pointer.to_int(context).into(),
context.xlen_type().const_all_ones().into(),
value_pointer.to_int(context).into(),
length_pointer.to_int(context).into(),
];
context.build_runtime_call(revive_runtime_api::polkavm_imports::GET_STORAGE, &arguments);
// We do not to check the return value: Solidity assumes infallible loads.
// If a key doesn't exist the "zero" value is returned (ensured by above write).
Ok(Some(context.build_load(value_pointer, "storage_value")?))
} }
} }
@@ -74,6 +47,42 @@ where
} }
} }
/// Load a word size value from a transient storage pointer.
pub struct LoadTransientWord;
impl<D> RuntimeFunction<D> for LoadTransientWord
where
D: Dependency + Clone,
{
const NAME: &'static str = "__revive_load_transient_storage_word";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context
.word_type()
.fn_type(&[context.word_type().into()], false)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
Ok(Some(emit_load(context, Self::paramater(context, 0), true)?))
}
}
impl<D> WriteLLVM<D> for LoadTransientWord
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 storage pointer. /// Store a word size value through a storage pointer.
pub struct StoreWord; pub struct StoreWord;
@@ -85,11 +94,7 @@ where
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> { fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.void_type().fn_type( context.void_type().fn_type(
&[ &[context.word_type().into(), context.word_type().into()],
context.xlen_type().into(),
context.word_type().into(),
context.word_type().into(),
],
false, false,
) )
} }
@@ -98,24 +103,12 @@ where
&self, &self,
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> { ) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
let is_transient = Self::paramater(context, 0); emit_store(
let key = Self::paramater(context, 1); context,
let value = Self::paramater(context, 2); Self::paramater(context, 0),
Self::paramater(context, 1),
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer"); false,
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer"); )?;
context.build_store(key_pointer, key)?;
context.build_store(value_pointer, value)?;
let arguments = [
is_transient,
key_pointer.to_int(context).into(),
context.xlen_type().const_all_ones().into(),
value_pointer.to_int(context).into(),
context.integer_const(crate::polkavm::XLEN, 32).into(),
];
context.build_runtime_call(revive_runtime_api::polkavm_imports::SET_STORAGE, &arguments);
Ok(None) Ok(None)
} }
@@ -133,3 +126,122 @@ where
<Self as RuntimeFunction<_>>::emit(&self, context) <Self as RuntimeFunction<_>>::emit(&self, context)
} }
} }
/// Store a word size value through a transient storage pointer.
pub struct StoreTransientWord;
impl<D> RuntimeFunction<D> for StoreTransientWord
where
D: Dependency + Clone,
{
const NAME: &'static str = "__revive_store_transient_storage_word";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.void_type().fn_type(
&[context.word_type().into(), context.word_type().into()],
false,
)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<BasicValueEnum<'ctx>>> {
emit_store(
context,
Self::paramater(context, 0),
Self::paramater(context, 1),
true,
)?;
Ok(None)
}
}
impl<D> WriteLLVM<D> for StoreTransientWord
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)
}
}
fn emit_load<'ctx, D: Dependency + Clone>(
context: &mut Context<'ctx, D>,
mut key: BasicValueEnum<'ctx>,
transient: bool,
) -> anyhow::Result<BasicValueEnum<'ctx>> {
if !transient {
key = context.build_byte_swap(key)?;
}
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer");
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
let length_pointer = context.build_alloca_at_entry(context.xlen_type(), "length_pointer");
context.builder().build_store(key_pointer.value, key)?;
context.build_store(value_pointer, context.word_const(0))?;
context.build_store(
length_pointer,
context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false),
)?;
let is_transient = context.xlen_type().const_int(transient as u64, false);
let arguments = [
is_transient.into(),
key_pointer.to_int(context).into(),
context.xlen_type().const_all_ones().into(),
value_pointer.to_int(context).into(),
length_pointer.to_int(context).into(),
];
context.build_runtime_call(revive_runtime_api::polkavm_imports::GET_STORAGE, &arguments);
// We do not to check the return value: Solidity assumes infallible loads.
// If a key doesn't exist the "zero" value is returned (ensured by above write).
let value = context.build_load(value_pointer, "storage_value")?;
Ok(if transient {
value
} else {
context.build_byte_swap(value)?
})
}
fn emit_store<'ctx, D: Dependency + Clone>(
context: &mut Context<'ctx, D>,
mut key: BasicValueEnum<'ctx>,
mut value: BasicValueEnum<'ctx>,
transient: bool,
) -> anyhow::Result<()> {
if !transient {
key = context.build_byte_swap(key)?;
value = context.build_byte_swap(value)?;
}
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer");
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
context.build_store(key_pointer, key)?;
context.build_store(value_pointer, value)?;
let is_transient = context.xlen_type().const_int(transient as u64, false);
let arguments = [
is_transient.into(),
key_pointer.to_int(context).into(),
context.xlen_type().const_all_ones().into(),
value_pointer.to_int(context).into(),
context.integer_const(crate::polkavm::XLEN, 32).into(),
];
context.build_runtime_call(revive_runtime_api::polkavm_imports::SET_STORAGE, &arguments);
Ok(())
}
@@ -10,12 +10,20 @@ pub fn create_context(
llvm: &inkwell::context::Context, llvm: &inkwell::context::Context,
optimizer_settings: OptimizerSettings, optimizer_settings: OptimizerSettings,
) -> Context<DummyDependency> { ) -> Context<DummyDependency> {
crate::polkavm::initialize_target(); crate::initialize_llvm(crate::Target::PVM, "resolc", Default::default());
let module = llvm.create_module("test"); let module = llvm.create_module("test");
let optimizer = Optimizer::new(optimizer_settings); let optimizer = Optimizer::new(optimizer_settings);
Context::<DummyDependency>::new(llvm, module, optimizer, None, true, Default::default()) Context::<DummyDependency>::new(
llvm,
module,
optimizer,
None,
true,
Default::default(),
Default::default(),
)
} }
#[test] #[test]
@@ -32,6 +32,7 @@ where
let salt_pointer = match salt { let salt_pointer = match salt {
Some(salt) => { Some(salt) => {
let salt_pointer = context.build_alloca_at_entry(context.word_type(), "salt_pointer"); let salt_pointer = context.build_alloca_at_entry(context.word_type(), "salt_pointer");
let salt = context.build_byte_swap(salt.into())?;
context.build_store(salt_pointer, salt)?; context.build_store(salt_pointer, salt)?;
salt_pointer salt_pointer
} }
+13 -20
View File
@@ -4,7 +4,9 @@ use crate::polkavm::context::runtime::RuntimeFunction;
use crate::polkavm::context::Context; use crate::polkavm::context::Context;
use crate::polkavm::Dependency; use crate::polkavm::Dependency;
use crate::PolkaVMLoadStorageWordFunction; use crate::PolkaVMLoadStorageWordFunction;
use crate::PolkaVMLoadTransientStorageWordFunction;
use crate::PolkaVMStoreStorageWordFunction; use crate::PolkaVMStoreStorageWordFunction;
use crate::PolkaVMStoreTransientStorageWordFunction;
/// Translates the storage load. /// Translates the storage load.
pub fn load<'ctx, D>( pub fn load<'ctx, D>(
@@ -16,7 +18,7 @@ where
{ {
let name = <PolkaVMLoadStorageWordFunction as RuntimeFunction<D>>::NAME; let name = <PolkaVMLoadStorageWordFunction as RuntimeFunction<D>>::NAME;
let declaration = <PolkaVMLoadStorageWordFunction as RuntimeFunction<D>>::declaration(context); let declaration = <PolkaVMLoadStorageWordFunction as RuntimeFunction<D>>::declaration(context);
let arguments = [context.xlen_type().const_zero().into(), position.into()]; let arguments = [position.into()];
Ok(context Ok(context
.build_call(declaration, &arguments, "storage_load") .build_call(declaration, &arguments, "storage_load")
.unwrap_or_else(|| panic!("runtime function {name} should return a value"))) .unwrap_or_else(|| panic!("runtime function {name} should return a value")))
@@ -32,11 +34,7 @@ where
D: Dependency + Clone, D: Dependency + Clone,
{ {
let declaration = <PolkaVMStoreStorageWordFunction as RuntimeFunction<D>>::declaration(context); let declaration = <PolkaVMStoreStorageWordFunction as RuntimeFunction<D>>::declaration(context);
let arguments = [ let arguments = [position.into(), value.into()];
context.xlen_type().const_zero().into(),
position.into(),
value.into(),
];
context.build_call(declaration, &arguments, "storage_store"); context.build_call(declaration, &arguments, "storage_store");
Ok(()) Ok(())
} }
@@ -49,14 +47,12 @@ pub fn transient_load<'ctx, D>(
where where
D: Dependency + Clone, D: Dependency + Clone,
{ {
let name = <PolkaVMLoadStorageWordFunction as RuntimeFunction<D>>::NAME; let name = <PolkaVMLoadTransientStorageWordFunction as RuntimeFunction<D>>::NAME;
let declaration = <PolkaVMLoadStorageWordFunction as RuntimeFunction<D>>::declaration(context); let arguments = [position.into()];
let arguments = [ let declaration =
context.xlen_type().const_int(1, false).into(), <PolkaVMLoadTransientStorageWordFunction as RuntimeFunction<D>>::declaration(context);
position.into(),
];
Ok(context Ok(context
.build_call(declaration, &arguments, "storage_load") .build_call(declaration, &arguments, "transient_storage_load")
.unwrap_or_else(|| panic!("runtime function {name} should return a value"))) .unwrap_or_else(|| panic!("runtime function {name} should return a value")))
} }
@@ -69,12 +65,9 @@ pub fn transient_store<'ctx, D>(
where where
D: Dependency + Clone, D: Dependency + Clone,
{ {
let declaration = <PolkaVMStoreStorageWordFunction as RuntimeFunction<D>>::declaration(context); let declaration =
let arguments = [ <PolkaVMStoreTransientStorageWordFunction as RuntimeFunction<D>>::declaration(context);
context.xlen_type().const_int(1, false).into(), let arguments = [position.into(), value.into()];
position.into(), context.build_call(declaration, &arguments, "transient_storage_store");
value.into(),
];
context.build_call(declaration, &arguments, "storage_store");
Ok(()) Ok(())
} }
+2 -6
View File
@@ -3,7 +3,6 @@
pub mod r#const; pub mod r#const;
pub mod context; pub mod context;
pub mod evm; pub mod evm;
pub mod metadata_hash;
pub use self::r#const::*; pub use self::r#const::*;
@@ -18,11 +17,6 @@ use sha3::Digest;
use self::context::build::Build; use self::context::build::Build;
use self::context::Context; use self::context::Context;
/// Initializes the PolkaVM target machine.
pub fn initialize_target() {
inkwell::targets::Target::initialize_riscv(&Default::default());
}
/// Builds PolkaVM assembly text. /// Builds PolkaVM assembly text.
pub fn build_assembly_text( pub fn build_assembly_text(
contract_path: &str, contract_path: &str,
@@ -95,6 +89,7 @@ pub trait Dependency {
optimizer_settings: OptimizerSettings, optimizer_settings: OptimizerSettings,
include_metadata_hash: bool, include_metadata_hash: bool,
debug_config: DebugConfig, debug_config: DebugConfig,
llvm_arguments: &[String],
) -> anyhow::Result<String>; ) -> anyhow::Result<String>;
/// Resolves a full contract path. /// Resolves a full contract path.
@@ -115,6 +110,7 @@ impl Dependency for DummyDependency {
_optimizer_settings: OptimizerSettings, _optimizer_settings: OptimizerSettings,
_include_metadata_hash: bool, _include_metadata_hash: bool,
_debug_config: DebugConfig, _debug_config: DebugConfig,
_llvm_arguments: &[String],
) -> anyhow::Result<String> { ) -> anyhow::Result<String> {
Ok(String::new()) Ok(String::new())
} }
+2 -6
View File
@@ -106,14 +106,10 @@ impl SpecsAction {
}; };
for (key, expected) in storage { for (key, expected) in storage {
let mut key = **key;
let mut expected = **expected;
key.reverse();
expected.reverse();
actions.push(Self::VerifyStorage { actions.push(Self::VerifyStorage {
contract: account_pvm.clone(), contract: account_pvm.clone(),
key, key: **key,
expected, expected: **expected,
}); });
} }
+23
View File
@@ -0,0 +1,23 @@
[package]
name = "revive-solc-json-interface"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
rust-version.workspace = true
description = "Rust bindings for the solc standard JSON and combined JSON interface"
[features]
default = ["parallel"]
parallel = ["rayon"]
resolc = [] # The resolc binary adds a bunch of custom fields to the format
[dependencies]
revive-common = { workspace = true }
anyhow = { workspace = true }
rayon = { workspace = true, optional = true }
semver = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
+27
View File
@@ -0,0 +1,27 @@
//! This crates provides (de)serializable Rust types for interacting
//! `solc` via the [JSON-input-output][0] interface.
//!
//! [0]: https://docs.soliditylang.org/en/latest/using-the-compiler.html#compiler-input-and-output-json-description
pub use self::combined_json::contract::Contract as CombinedJsonContract;
pub use self::standard_json::input::language::Language as SolcStandardJsonInputLanguage;
pub use self::standard_json::input::settings::metadata::Metadata as SolcStandardJsonInputSettingsMetadata;
pub use self::standard_json::input::settings::metadata_hash::MetadataHash as SolcStandardJsonInputSettingsMetadataHash;
pub use self::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
pub use self::standard_json::input::settings::selection::file::flag::Flag as SolcStandardJsonInputSettingsSelectionFileFlag;
pub use self::standard_json::input::settings::selection::file::File as SolcStandardJsonInputSettingsSelectionFile;
pub use self::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
pub use self::standard_json::input::settings::Settings as SolcStandardJsonInputSettings;
pub use self::standard_json::input::source::Source as SolcStandardJsonInputSource;
pub use self::standard_json::input::Input as SolcStandardJsonInput;
pub use self::standard_json::output::contract::evm::bytecode::Bytecode as SolcStandardJsonOutputContractEVMBytecode;
pub use self::standard_json::output::contract::evm::EVM as SolcStandardJsonOutputContractEVM;
pub use self::standard_json::output::contract::Contract as SolcStandardJsonOutputContract;
pub use self::standard_json::output::Output as SolcStandardJsonOutput;
#[cfg(feature = "resolc")]
pub use self::warning::Warning as ResolcWarning;
pub mod combined_json;
pub mod standard_json;
#[cfg(feature = "resolc")]
pub mod warning;
@@ -8,14 +8,15 @@ use std::collections::BTreeMap;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::path::PathBuf; use std::path::PathBuf;
#[cfg(feature = "parallel")] #[cfg(all(feature = "parallel", feature = "resolc"))]
use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::iter::{IntoParallelIterator, ParallelIterator};
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use crate::solc::standard_json::input::settings::metadata::Metadata as SolcStandardJsonInputSettingsMetadata; use crate::standard_json::input::settings::metadata::Metadata as SolcStandardJsonInputSettingsMetadata;
use crate::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer; use crate::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
use crate::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection; use crate::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
#[cfg(feature = "resolc")]
use crate::warning::Warning; use crate::warning::Warning;
use self::language::Language; use self::language::Language;
@@ -33,6 +34,7 @@ pub struct Input {
/// The compiler settings. /// The compiler settings.
pub settings: Settings, pub settings: Settings,
/// The suppressed warnings. /// The suppressed warnings.
#[cfg(feature = "resolc")]
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub suppressed_warnings: Option<Vec<Warning>>, pub suppressed_warnings: Option<Vec<Warning>>,
} }
@@ -60,7 +62,7 @@ impl Input {
output_selection: SolcStandardJsonInputSettingsSelection, output_selection: SolcStandardJsonInputSettingsSelection,
optimizer: SolcStandardJsonInputSettingsOptimizer, optimizer: SolcStandardJsonInputSettingsOptimizer,
metadata: Option<SolcStandardJsonInputSettingsMetadata>, metadata: Option<SolcStandardJsonInputSettingsMetadata>,
suppressed_warnings: Option<Vec<Warning>>, #[cfg(feature = "resolc")] suppressed_warnings: Option<Vec<Warning>>,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
let mut paths: BTreeSet<PathBuf> = paths.iter().cloned().collect(); let mut paths: BTreeSet<PathBuf> = paths.iter().cloned().collect();
let libraries = Settings::parse_libraries(library_map)?; let libraries = Settings::parse_libraries(library_map)?;
@@ -89,12 +91,14 @@ impl Input {
optimizer, optimizer,
metadata, metadata,
), ),
#[cfg(feature = "resolc")]
suppressed_warnings, suppressed_warnings,
}) })
} }
/// A shortcut constructor from source code. /// A shortcut constructor from source code.
/// Only for the integration test purposes. /// Only for the integration test purposes.
#[cfg(feature = "resolc")]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn try_from_sources( pub fn try_from_sources(
evm_version: Option<revive_common::EVMVersion>, evm_version: Option<revive_common::EVMVersion>,
@@ -3,18 +3,20 @@
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use crate::standard_json::input::settings::metadata_hash::MetadataHash;
/// The `solc --standard-json` input settings metadata. /// The `solc --standard-json` input settings metadata.
#[derive(Debug, Default, Serialize, Deserialize)] #[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Metadata { pub struct Metadata {
/// The bytecode hash mode. /// The bytecode hash mode.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub bytecode_hash: Option<revive_llvm_context::PolkaVMMetadataHash>, pub bytecode_hash: Option<MetadataHash>,
} }
impl Metadata { impl Metadata {
/// A shortcut constructor. /// A shortcut constructor.
pub fn new(bytecode_hash: revive_llvm_context::PolkaVMMetadataHash) -> Self { pub fn new(bytecode_hash: MetadataHash) -> Self {
Self { Self {
bytecode_hash: Some(bytecode_hash), bytecode_hash: Some(bytecode_hash),
} }
@@ -1,6 +1,7 @@
//! The `solc --standard-json` input settings. //! The `solc --standard-json` input settings.
pub mod metadata; pub mod metadata;
pub mod metadata_hash;
pub mod optimizer; pub mod optimizer;
pub mod selection; pub mod selection;
@@ -49,18 +49,3 @@ impl Optimizer {
}; };
} }
} }
impl TryFrom<&Optimizer> for revive_llvm_context::OptimizerSettings {
type Error = anyhow::Error;
fn try_from(value: &Optimizer) -> Result<Self, Self::Error> {
let mut result = match value.mode {
Some(mode) => Self::try_from_cli(mode)?,
None => Self::cycles(),
};
if value.fallback_to_optimizing_for_size.unwrap_or_default() {
result.enable_fallback_to_size();
}
Ok(result)
}
}
@@ -0,0 +1,4 @@
//! The `solc <input>.sol --standard-json` interface input and output.
pub mod input;
pub mod output;
@@ -0,0 +1,71 @@
//! The `solc --standard-json` output.
pub mod contract;
pub mod error;
pub mod source;
use std::collections::BTreeMap;
use serde::Deserialize;
use serde::Serialize;
#[cfg(feature = "resolc")]
use crate::warning::Warning;
use self::contract::Contract;
use self::error::Error as SolcStandardJsonOutputError;
use self::source::Source;
/// The `solc --standard-json` output.
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct Output {
/// The file-contract hashmap.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub contracts: Option<BTreeMap<String, BTreeMap<String, Contract>>>,
/// The source code mapping data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sources: Option<BTreeMap<String, Source>>,
/// The compilation errors and warnings.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub errors: Option<Vec<SolcStandardJsonOutputError>>,
/// The `solc` compiler version.
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
/// The `solc` compiler long version.
#[serde(skip_serializing_if = "Option::is_none")]
pub long_version: Option<String>,
/// The `resolc` compiler version.
#[serde(skip_serializing_if = "Option::is_none")]
pub revive_version: Option<String>,
}
impl Output {
/// Traverses the AST and returns the list of additional errors and warnings.
#[cfg(feature = "resolc")]
pub fn preprocess_ast(&mut self, suppressed_warnings: &[Warning]) -> anyhow::Result<()> {
let sources = match self.sources.as_ref() {
Some(sources) => sources,
None => return Ok(()),
};
let mut messages = Vec::new();
for (path, source) in sources.iter() {
if let Some(ast) = source.ast.as_ref() {
let mut polkavm_messages = Source::get_messages(ast, suppressed_warnings);
for message in polkavm_messages.iter_mut() {
message.push_contract_path(path.as_str());
}
messages.extend(polkavm_messages);
}
}
self.errors = match self.errors.take() {
Some(mut errors) => {
errors.extend(messages);
Some(errors)
}
None => Some(messages),
};
Ok(())
}
}
@@ -3,7 +3,8 @@
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use crate::solc::standard_json::output::error::Error as SolcStandardJsonOutputError; use crate::standard_json::output::error::Error as SolcStandardJsonOutputError;
#[cfg(feature = "resolc")]
use crate::warning::Warning; use crate::warning::Warning;
/// The `solc --standard-json` output source. /// The `solc --standard-json` output source.
@@ -131,6 +132,7 @@ impl Source {
} }
/// Returns the list of messages for some specific parts of the AST. /// Returns the list of messages for some specific parts of the AST.
#[cfg(feature = "resolc")]
pub fn get_messages( pub fn get_messages(
ast: &serde_json::Value, ast: &serde_json::Value,
suppressed_warnings: &[Warning], suppressed_warnings: &[Warning],
@@ -194,7 +196,7 @@ impl Source {
_ => None, _ => None,
}, },
) )
.last() .next_back()
.ok_or_else(|| anyhow::anyhow!("The last contract not found in the AST")) .ok_or_else(|| anyhow::anyhow!("The last contract not found in the AST"))
} }
} }
@@ -1,26 +1,22 @@
//! The compiler warning. //! `resolc` custom compiler warnings.
//!
//! The revive compiler adds warnings only applicable when compilng
//! to the revive stack on Polkadot to the output.
use std::str::FromStr; use std::str::FromStr;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
/// The compiler warning. // The `resolc` custom compiler warning.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Warning { pub enum Warning {
/// The warning for eponymous feature.
EcRecover, EcRecover,
/// The warning for eponymous feature.
SendTransfer, SendTransfer,
/// The warning for eponymous feature.
ExtCodeSize, ExtCodeSize,
/// The warning for eponymous feature.
TxOrigin, TxOrigin,
/// The warning for eponymous feature.
BlockTimestamp, BlockTimestamp,
/// The warning for eponymous feature.
BlockNumber, BlockNumber,
/// The warning for eponymous feature.
BlockHash, BlockHash,
} }
+1
View File
@@ -37,6 +37,7 @@ inkwell = { workspace = true }
revive-common = { workspace = true } revive-common = { workspace = true }
revive-llvm-context = { workspace = true } revive-llvm-context = { workspace = true }
revive-solc-json-interface = { workspace = true, features = ["resolc"] }
[target.'cfg(target_env = "musl")'.dependencies] [target.'cfg(target_env = "musl")'.dependencies]
mimalloc = { version = "*", default-features = false } mimalloc = { version = "*", default-features = false }
+3 -4
View File
@@ -5,12 +5,11 @@ use std::fs::File;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
use revive_solc_json_interface::CombinedJsonContract;
use revive_solc_json_interface::SolcStandardJsonOutputContract;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use crate::solc::combined_json::contract::Contract as CombinedJsonContract;
use crate::solc::standard_json::output::contract::Contract as StandardJsonOutputContract;
/// The Solidity contract build. /// The Solidity contract build.
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Contract { pub struct Contract {
@@ -131,7 +130,7 @@ impl Contract {
/// Writes the contract text assembly and bytecode to the standard JSON. /// Writes the contract text assembly and bytecode to the standard JSON.
pub fn write_to_standard_json( pub fn write_to_standard_json(
self, self,
standard_json_contract: &mut StandardJsonOutputContract, standard_json_contract: &mut SolcStandardJsonOutputContract,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
standard_json_contract.metadata = Some(self.metadata_json); standard_json_contract.metadata = Some(self.metadata_json);
+4 -3
View File
@@ -5,8 +5,9 @@ pub mod contract;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::path::Path; use std::path::Path;
use crate::solc::combined_json::CombinedJson; use revive_solc_json_interface::combined_json::CombinedJson;
use crate::solc::standard_json::output::Output as StandardJsonOutput; use revive_solc_json_interface::SolcStandardJsonOutput;
use crate::solc::version::Version as SolcVersion; use crate::solc::version::Version as SolcVersion;
use crate::ResolcVersion; use crate::ResolcVersion;
@@ -66,7 +67,7 @@ impl Build {
/// Writes all contracts assembly and bytecode to the standard JSON. /// Writes all contracts assembly and bytecode to the standard JSON.
pub fn write_to_standard_json( pub fn write_to_standard_json(
mut self, mut self,
standard_json: &mut StandardJsonOutput, standard_json: &mut SolcStandardJsonOutput,
solc_version: &SolcVersion, solc_version: &SolcVersion,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let contracts = match standard_json.contracts.as_mut() { let contracts = match standard_json.contracts.as_mut() {
+58 -31
View File
@@ -7,7 +7,6 @@ pub(crate) mod process;
pub(crate) mod project; pub(crate) mod project;
pub(crate) mod solc; pub(crate) mod solc;
pub(crate) mod version; pub(crate) mod version;
pub(crate) mod warning;
pub(crate) mod yul; pub(crate) mod yul;
pub use self::build::contract::Contract as ContractBuild; pub use self::build::contract::Contract as ContractBuild;
@@ -23,29 +22,16 @@ pub use self::process::Process;
pub use self::project::contract::Contract as ProjectContract; pub use self::project::contract::Contract as ProjectContract;
pub use self::project::Project; pub use self::project::Project;
pub use self::r#const::*; pub use self::r#const::*;
pub use self::solc::combined_json::contract::Contract as SolcCombinedJsonContract;
pub use self::solc::combined_json::CombinedJson as SolcCombinedJson;
#[cfg(not(target_os = "emscripten"))] #[cfg(not(target_os = "emscripten"))]
pub use self::solc::solc_compiler::SolcCompiler; pub use self::solc::solc_compiler::SolcCompiler;
#[cfg(target_os = "emscripten")] #[cfg(target_os = "emscripten")]
pub use self::solc::soljson_compiler::SoljsonCompiler; pub use self::solc::soljson_compiler::SoljsonCompiler;
pub use self::solc::standard_json::input::language::Language as SolcStandardJsonInputLanguage;
pub use self::solc::standard_json::input::settings::metadata::Metadata as SolcStandardJsonInputSettingsMetadata;
pub use self::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
pub use self::solc::standard_json::input::settings::selection::file::flag::Flag as SolcStandardJsonInputSettingsSelectionFileFlag;
pub use self::solc::standard_json::input::settings::selection::file::File as SolcStandardJsonInputSettingsSelectionFile;
pub use self::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
pub use self::solc::standard_json::input::settings::Settings as SolcStandardJsonInputSettings;
pub use self::solc::standard_json::input::source::Source as SolcStandardJsonInputSource;
pub use self::solc::standard_json::input::Input as SolcStandardJsonInput;
pub use self::solc::standard_json::output::contract::evm::bytecode::Bytecode as SolcStandardJsonOutputContractEVMBytecode;
pub use self::solc::standard_json::output::contract::evm::EVM as SolcStandardJsonOutputContractEVM;
pub use self::solc::standard_json::output::contract::Contract as SolcStandardJsonOutputContract;
pub use self::solc::standard_json::output::Output as SolcStandardJsonOutput;
pub use self::solc::version::Version as SolcVersion; pub use self::solc::version::Version as SolcVersion;
pub use self::solc::Compiler; pub use self::solc::Compiler;
pub use self::solc::FIRST_SUPPORTED_VERSION as SolcFirstSupportedVersion;
pub use self::solc::LAST_SUPPORTED_VERSION as SolcLastSupportedVersion;
pub use self::version::Version as ResolcVersion; pub use self::version::Version as ResolcVersion;
pub use self::warning::Warning;
#[cfg(not(target_os = "emscripten"))] #[cfg(not(target_os = "emscripten"))]
pub mod test_utils; pub mod test_utils;
pub mod tests; pub mod tests;
@@ -54,6 +40,13 @@ use std::collections::BTreeSet;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use revive_solc_json_interface::standard_json::input::settings::metadata_hash::MetadataHash;
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::SolcStandardJsonInputSettingsSelection;
/// Runs the Yul mode. /// Runs the Yul mode.
pub fn yul<T: Compiler>( pub fn yul<T: Compiler>(
input_files: &[PathBuf], input_files: &[PathBuf],
@@ -61,6 +54,7 @@ pub fn yul<T: Compiler>(
optimizer_settings: revive_llvm_context::OptimizerSettings, optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool, include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig, debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
) -> anyhow::Result<Build> { ) -> anyhow::Result<Build> {
let path = match input_files.len() { let path = match input_files.len() {
1 => input_files.first().expect("Always exists"), 1 => input_files.first().expect("Always exists"),
@@ -81,7 +75,12 @@ pub fn yul<T: Compiler>(
let solc_validator = Some(&*solc); let solc_validator = Some(&*solc);
let project = Project::try_from_yul_path(path, solc_validator)?; let project = Project::try_from_yul_path(path, solc_validator)?;
let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?; let build = project.compile(
optimizer_settings,
include_metadata_hash,
debug_config,
llvm_arguments,
)?;
Ok(build) Ok(build)
} }
@@ -92,6 +91,7 @@ pub fn llvm_ir(
optimizer_settings: revive_llvm_context::OptimizerSettings, optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool, include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig, debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
) -> anyhow::Result<Build> { ) -> anyhow::Result<Build> {
let path = match input_files.len() { let path = match input_files.len() {
1 => input_files.first().expect("Always exists"), 1 => input_files.first().expect("Always exists"),
@@ -104,7 +104,12 @@ pub fn llvm_ir(
let project = Project::try_from_llvm_ir_path(path)?; let project = Project::try_from_llvm_ir_path(path)?;
let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?; let build = project.compile(
optimizer_settings,
include_metadata_hash,
debug_config,
llvm_arguments,
)?;
Ok(build) Ok(build)
} }
@@ -123,8 +128,9 @@ pub fn standard_output<T: Compiler>(
include_paths: Vec<String>, include_paths: Vec<String>,
allow_paths: Option<String>, allow_paths: Option<String>,
remappings: Option<BTreeSet<String>>, remappings: Option<BTreeSet<String>>,
suppressed_warnings: Option<Vec<Warning>>, suppressed_warnings: Option<Vec<ResolcWarning>>,
debug_config: revive_llvm_context::DebugConfig, debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
) -> anyhow::Result<Build> { ) -> anyhow::Result<Build> {
let solc_version = solc.version()?; let solc_version = solc.version()?;
@@ -152,7 +158,7 @@ pub fn standard_output<T: Compiler>(
.collect(); .collect();
let libraries = solc_input.settings.libraries.clone().unwrap_or_default(); let libraries = solc_input.settings.libraries.clone().unwrap_or_default();
let mut solc_output = solc.standard_json(solc_input, base_path, include_paths, allow_paths)?; let solc_output = solc.standard_json(solc_input, base_path, include_paths, allow_paths)?;
if let Some(errors) = solc_output.errors.as_deref() { if let Some(errors) = solc_output.errors.as_deref() {
let mut has_errors = false; let mut has_errors = false;
@@ -170,10 +176,20 @@ pub fn standard_output<T: Compiler>(
} }
} }
let project = let project = Project::try_from_standard_json_output(
solc_output.try_to_project(source_code_files, libraries, &solc_version, &debug_config)?; &solc_output,
source_code_files,
libraries,
&solc_version,
&debug_config,
)?;
let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?; let build = project.compile(
optimizer_settings,
include_metadata_hash,
debug_config,
llvm_arguments,
)?;
Ok(build) Ok(build)
} }
@@ -186,6 +202,7 @@ pub fn standard_json<T: Compiler>(
include_paths: Vec<String>, include_paths: Vec<String>,
allow_paths: Option<String>, allow_paths: Option<String>,
debug_config: revive_llvm_context::DebugConfig, debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let solc_version = solc.version()?; let solc_version = solc.version()?;
@@ -200,9 +217,7 @@ pub fn standard_json<T: Compiler>(
revive_llvm_context::OptimizerSettings::try_from(&solc_input.settings.optimizer)?; revive_llvm_context::OptimizerSettings::try_from(&solc_input.settings.optimizer)?;
let include_metadata_hash = match solc_input.settings.metadata { let include_metadata_hash = match solc_input.settings.metadata {
Some(ref metadata) => { Some(ref metadata) => metadata.bytecode_hash != Some(MetadataHash::None),
metadata.bytecode_hash != Some(revive_llvm_context::PolkaVMMetadataHash::None)
}
None => true, None => true,
}; };
@@ -218,14 +233,24 @@ pub fn standard_json<T: Compiler>(
} }
} }
let project = let project = Project::try_from_standard_json_output(
solc_output.try_to_project(source_code_files, libraries, &solc_version, &debug_config)?; &solc_output,
source_code_files,
libraries,
&solc_version,
&debug_config,
)?;
if detect_missing_libraries { if detect_missing_libraries {
let missing_libraries = project.get_missing_libraries(); let missing_libraries = project.get_missing_libraries();
missing_libraries.write_to_standard_json(&mut solc_output, &solc_version)?; missing_libraries.write_to_standard_json(&mut solc_output, &solc_version)?;
} else { } else {
let build = project.compile(optimizer_settings, include_metadata_hash, debug_config)?; let build = project.compile(
optimizer_settings,
include_metadata_hash,
debug_config,
llvm_arguments,
)?;
build.write_to_standard_json(&mut solc_output, &solc_version)?; build.write_to_standard_json(&mut solc_output, &solc_version)?;
} }
serde_json::to_writer(std::io::stdout(), &solc_output)?; serde_json::to_writer(std::io::stdout(), &solc_output)?;
@@ -247,10 +272,11 @@ pub fn combined_json<T: Compiler>(
include_paths: Vec<String>, include_paths: Vec<String>,
allow_paths: Option<String>, allow_paths: Option<String>,
remappings: Option<BTreeSet<String>>, remappings: Option<BTreeSet<String>>,
suppressed_warnings: Option<Vec<Warning>>, suppressed_warnings: Option<Vec<ResolcWarning>>,
debug_config: revive_llvm_context::DebugConfig, debug_config: revive_llvm_context::DebugConfig,
output_directory: Option<PathBuf>, output_directory: Option<PathBuf>,
overwrite: bool, overwrite: bool,
llvm_arguments: &[String],
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let build = standard_output( let build = standard_output(
input_files, input_files,
@@ -266,6 +292,7 @@ pub fn combined_json<T: Compiler>(
remappings, remappings,
suppressed_warnings, suppressed_warnings,
debug_config, debug_config,
llvm_arguments,
)?; )?;
let mut combined_json = solc.combined_json(input_files, format.as_str())?; let mut combined_json = solc.combined_json(input_files, format.as_str())?;
+3 -2
View File
@@ -3,7 +3,8 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::HashSet; use std::collections::HashSet;
use crate::solc::standard_json::output::Output as StandardJsonOutput; use revive_solc_json_interface::SolcStandardJsonOutput;
use crate::solc::version::Version as SolcVersion; use crate::solc::version::Version as SolcVersion;
use crate::ResolcVersion; use crate::ResolcVersion;
@@ -22,7 +23,7 @@ impl MissingLibraries {
/// Writes the missing libraries to the standard JSON. /// Writes the missing libraries to the standard JSON.
pub fn write_to_standard_json( pub fn write_to_standard_json(
mut self, mut self,
standard_json: &mut StandardJsonOutput, standard_json: &mut SolcStandardJsonOutput,
solc_version: &SolcVersion, solc_version: &SolcVersion,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let contracts = match standard_json.contracts.as_mut() { let contracts = match standard_json.contracts.as_mut() {
+4
View File
@@ -20,6 +20,8 @@ pub struct Input {
pub optimizer_settings: revive_llvm_context::OptimizerSettings, pub optimizer_settings: revive_llvm_context::OptimizerSettings,
/// The debug output config. /// The debug output config.
pub debug_config: revive_llvm_context::DebugConfig, pub debug_config: revive_llvm_context::DebugConfig,
/// The extra LLVM arguments give used for manual control.
pub llvm_arguments: Vec<String>,
} }
impl Input { impl Input {
@@ -30,6 +32,7 @@ impl Input {
include_metadata_hash: bool, include_metadata_hash: bool,
optimizer_settings: revive_llvm_context::OptimizerSettings, optimizer_settings: revive_llvm_context::OptimizerSettings,
debug_config: revive_llvm_context::DebugConfig, debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: Vec<String>,
) -> Self { ) -> Self {
Self { Self {
contract, contract,
@@ -37,6 +40,7 @@ impl Input {
include_metadata_hash, include_metadata_hash,
optimizer_settings, optimizer_settings,
debug_config, debug_config,
llvm_arguments,
} }
} }
} }
+8
View File
@@ -37,11 +37,19 @@ pub trait Process {
} }
let input: Input = revive_common::deserialize_from_slice(buffer.as_slice())?; let input: Input = revive_common::deserialize_from_slice(buffer.as_slice())?;
revive_llvm_context::initialize_llvm(
revive_llvm_context::Target::PVM,
crate::DEFAULT_EXECUTABLE_NAME,
&input.llvm_arguments,
);
let result = input.contract.compile( let result = input.contract.compile(
input.project, input.project,
input.optimizer_settings, input.optimizer_settings,
input.include_metadata_hash, input.include_metadata_hash,
input.debug_config, input.debug_config,
&input.llvm_arguments,
); );
match result { match result {
@@ -18,6 +18,8 @@ pub struct Metadata {
pub revive_version: String, pub revive_version: String,
/// The PolkaVM compiler optimizer settings. /// The PolkaVM compiler optimizer settings.
pub optimizer_settings: revive_llvm_context::OptimizerSettings, pub optimizer_settings: revive_llvm_context::OptimizerSettings,
/// The extra LLVM arguments give used for manual control.
pub llvm_arguments: Vec<String>,
} }
impl Metadata { impl Metadata {
@@ -27,6 +29,7 @@ impl Metadata {
solc_version: String, solc_version: String,
revive_pallet_version: Option<semver::Version>, revive_pallet_version: Option<semver::Version>,
optimizer_settings: revive_llvm_context::OptimizerSettings, optimizer_settings: revive_llvm_context::OptimizerSettings,
llvm_arguments: Vec<String>,
) -> Self { ) -> Self {
Self { Self {
solc_metadata, solc_metadata,
@@ -34,6 +37,7 @@ impl Metadata {
revive_pallet_version, revive_pallet_version,
revive_version: ResolcVersion::default().long, revive_version: ResolcVersion::default().long,
optimizer_settings, optimizer_settings,
llvm_arguments,
} }
} }
} }
@@ -77,6 +77,7 @@ impl Contract {
optimizer_settings: revive_llvm_context::OptimizerSettings, optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool, include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig, debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
) -> anyhow::Result<ContractBuild> { ) -> anyhow::Result<ContractBuild> {
let llvm = inkwell::context::Context::create(); let llvm = inkwell::context::Context::create();
let optimizer = revive_llvm_context::Optimizer::new(optimizer_settings); let optimizer = revive_llvm_context::Optimizer::new(optimizer_settings);
@@ -89,6 +90,7 @@ impl Contract {
version.long.clone(), version.long.clone(),
version.l2_revision.clone(), version.l2_revision.clone(),
optimizer.settings().to_owned(), optimizer.settings().to_owned(),
llvm_arguments.to_vec(),
); );
let metadata_json = serde_json::to_value(&metadata).expect("Always valid"); let metadata_json = serde_json::to_value(&metadata).expect("Always valid");
let metadata_hash: Option<[u8; revive_common::BYTE_LENGTH_WORD]> = if include_metadata_hash let metadata_hash: Option<[u8; revive_common::BYTE_LENGTH_WORD]> = if include_metadata_hash
@@ -120,6 +122,7 @@ impl Contract {
Some(project), Some(project),
include_metadata_hash, include_metadata_hash,
debug_config, debug_config,
llvm_arguments,
); );
context.set_solidity_data(revive_llvm_context::PolkaVMContextSolidityData::default()); context.set_solidity_data(revive_llvm_context::PolkaVMContextSolidityData::default());
match self.ir { match self.ir {
+68
View File
@@ -9,6 +9,7 @@ use std::path::Path;
#[cfg(feature = "parallel")] #[cfg(feature = "parallel")]
use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::iter::{IntoParallelIterator, ParallelIterator};
use revive_solc_json_interface::SolcStandardJsonOutput;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use sha3::Digest; use sha3::Digest;
@@ -65,6 +66,7 @@ impl Project {
optimizer_settings: revive_llvm_context::OptimizerSettings, optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool, include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig, debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
) -> anyhow::Result<Build> { ) -> anyhow::Result<Build> {
let project = self.clone(); let project = self.clone();
#[cfg(feature = "parallel")] #[cfg(feature = "parallel")]
@@ -80,6 +82,7 @@ impl Project {
include_metadata_hash, include_metadata_hash,
optimizer_settings.clone(), optimizer_settings.clone(),
debug_config.clone(), debug_config.clone(),
llvm_arguments.to_vec(),
); );
let process_output = { let process_output = {
#[cfg(target_os = "emscripten")] #[cfg(target_os = "emscripten")]
@@ -243,6 +246,69 @@ impl Project {
BTreeMap::new(), BTreeMap::new(),
)) ))
} }
/// Converts the `solc` JSON output into a convenient project.
pub fn try_from_standard_json_output(
output: &SolcStandardJsonOutput,
source_code_files: BTreeMap<String, String>,
libraries: BTreeMap<String, BTreeMap<String, String>>,
solc_version: &SolcVersion,
debug_config: &revive_llvm_context::DebugConfig,
) -> anyhow::Result<Self> {
let files = match output.contracts.as_ref() {
Some(files) => files,
None => match &output.errors {
Some(errors) if errors.iter().any(|e| e.severity == "error") => {
anyhow::bail!(serde_json::to_string_pretty(errors).expect("Always valid"));
}
_ => &BTreeMap::new(),
},
};
let mut project_contracts = BTreeMap::new();
for (path, contracts) in files.iter() {
for (name, contract) in contracts.iter() {
let full_path = format!("{path}:{name}");
let ir_optimized = match contract.ir_optimized.to_owned() {
Some(ir_optimized) => ir_optimized,
None => continue,
};
if ir_optimized.is_empty() {
continue;
}
debug_config.dump_yul(full_path.as_str(), ir_optimized.as_str())?;
let mut lexer = Lexer::new(ir_optimized.to_owned());
let object = Object::parse(&mut lexer, None).map_err(|error| {
anyhow::anyhow!("Contract `{}` parsing error: {:?}", full_path, error)
})?;
let source = IR::new_yul(ir_optimized.to_owned(), object);
let source_code = source_code_files
.get(path.as_str())
.ok_or_else(|| anyhow::anyhow!("Source code for path `{}` not found", path))?;
let source_hash = sha3::Keccak256::digest(source_code.as_bytes()).into();
let project_contract = Contract::new(
full_path.clone(),
source_hash,
solc_version.to_owned(),
source,
contract.metadata.to_owned(),
);
project_contracts.insert(full_path, project_contract);
}
}
Ok(Project::new(
solc_version.to_owned(),
project_contracts,
libraries,
))
}
} }
impl revive_llvm_context::PolkaVMDependency for Project { impl revive_llvm_context::PolkaVMDependency for Project {
@@ -252,6 +318,7 @@ impl revive_llvm_context::PolkaVMDependency for Project {
optimizer_settings: revive_llvm_context::OptimizerSettings, optimizer_settings: revive_llvm_context::OptimizerSettings,
include_metadata_hash: bool, include_metadata_hash: bool,
debug_config: revive_llvm_context::DebugConfig, debug_config: revive_llvm_context::DebugConfig,
llvm_arguments: &[String],
) -> anyhow::Result<String> { ) -> anyhow::Result<String> {
let contract_path = project.resolve_path(identifier)?; let contract_path = project.resolve_path(identifier)?;
let contract = project let contract = project
@@ -271,6 +338,7 @@ impl revive_llvm_context::PolkaVMDependency for Project {
optimizer_settings, optimizer_settings,
include_metadata_hash, include_metadata_hash,
debug_config, debug_config,
llvm_arguments,
) )
.map_err(|error| { .map_err(|error| {
anyhow::anyhow!( anyhow::anyhow!(
+14
View File
@@ -19,6 +19,10 @@ pub struct Arguments {
#[arg(long = "version")] #[arg(long = "version")]
pub version: bool, pub version: bool,
/// Print supported `solc` versions and exit.
#[arg(long = "supported-solc-versions")]
pub supported_solc_versions: bool,
/// Print the licence and exit. /// Print the licence and exit.
#[arg(long = "license")] #[arg(long = "license")]
pub license: bool, pub license: bool,
@@ -162,6 +166,10 @@ pub struct Arguments {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
#[arg(long = "recursive-process-input")] #[arg(long = "recursive-process-input")]
pub recursive_process_input: Option<String>, pub recursive_process_input: Option<String>,
#[arg(long = "llvm-arg")]
/// These are passed to LLVM as the command line to allow manual control.
pub llvm_arguments: Vec<String>,
} }
impl Arguments { impl Arguments {
@@ -171,6 +179,12 @@ impl Arguments {
anyhow::bail!("No other options are allowed while getting the compiler version."); anyhow::bail!("No other options are allowed while getting the compiler version.");
} }
if self.supported_solc_versions && std::env::args().count() > 2 {
anyhow::bail!(
"No other options are allowed while getting the supported `solc` versions."
);
}
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
if self.recursive_process_input.is_some() && !self.recursive_process { if self.recursive_process_input.is_some() && !self.recursive_process {
anyhow::bail!("--process-input can be only used when --recursive-process is given"); anyhow::bail!("--process-input can be only used when --recursive-process is given");
+20 -5
View File
@@ -41,6 +41,16 @@ fn main_inner() -> anyhow::Result<()> {
return Ok(()); return Ok(());
} }
if arguments.supported_solc_versions {
writeln!(
std::io::stdout(),
">={},<={}",
revive_solidity::SolcFirstSupportedVersion,
revive_solidity::SolcLastSupportedVersion,
)?;
return Ok(());
}
if arguments.license { if arguments.license {
let license_mit = include_str!("../../../../LICENSE-MIT"); let license_mit = include_str!("../../../../LICENSE-MIT");
let license_apache = include_str!("../../../../LICENSE-APACHE"); let license_apache = include_str!("../../../../LICENSE-APACHE");
@@ -54,8 +64,6 @@ fn main_inner() -> anyhow::Result<()> {
.stack_size(RAYON_WORKER_STACK_SIZE) .stack_size(RAYON_WORKER_STACK_SIZE)
.build_global() .build_global()
.expect("Thread pool configuration failure"); .expect("Thread pool configuration failure");
inkwell::support::enable_llvm_pretty_stack_trace();
revive_llvm_context::initialize_target(revive_llvm_context::Target::PVM); // TODO: pass from CLI
if arguments.recursive_process { if arguments.recursive_process {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@@ -94,7 +102,7 @@ fn main_inner() -> anyhow::Result<()> {
let (input_files, remappings) = arguments.split_input_files_and_remappings()?; let (input_files, remappings) = arguments.split_input_files_and_remappings()?;
let suppressed_warnings = match arguments.suppress_warnings { let suppressed_warnings = match arguments.suppress_warnings {
Some(warnings) => Some(revive_solidity::Warning::try_from_strings( Some(warnings) => Some(revive_solc_json_interface::ResolcWarning::try_from_strings(
warnings.as_slice(), warnings.as_slice(),
)?), )?),
None => None, None => None,
@@ -132,8 +140,10 @@ fn main_inner() -> anyhow::Result<()> {
let include_metadata_hash = match arguments.metadata_hash { let include_metadata_hash = match arguments.metadata_hash {
Some(metadata_hash) => { Some(metadata_hash) => {
let metadata = let metadata =
revive_llvm_context::PolkaVMMetadataHash::from_str(metadata_hash.as_str())?; revive_solc_json_interface::SolcStandardJsonInputSettingsMetadataHash::from_str(
metadata != revive_llvm_context::PolkaVMMetadataHash::None metadata_hash.as_str(),
)?;
metadata != revive_solc_json_interface::SolcStandardJsonInputSettingsMetadataHash::None
} }
None => true, None => true,
}; };
@@ -145,6 +155,7 @@ fn main_inner() -> anyhow::Result<()> {
optimizer_settings, optimizer_settings,
include_metadata_hash, include_metadata_hash,
debug_config, debug_config,
&arguments.llvm_arguments,
) )
} else if arguments.llvm_ir { } else if arguments.llvm_ir {
revive_solidity::llvm_ir( revive_solidity::llvm_ir(
@@ -152,6 +163,7 @@ fn main_inner() -> anyhow::Result<()> {
optimizer_settings, optimizer_settings,
include_metadata_hash, include_metadata_hash,
debug_config, debug_config,
&arguments.llvm_arguments,
) )
} else if arguments.standard_json { } else if arguments.standard_json {
revive_solidity::standard_json( revive_solidity::standard_json(
@@ -161,6 +173,7 @@ fn main_inner() -> anyhow::Result<()> {
arguments.include_paths, arguments.include_paths,
arguments.allow_paths, arguments.allow_paths,
debug_config, debug_config,
&arguments.llvm_arguments,
)?; )?;
return Ok(()); return Ok(());
} else if let Some(format) = arguments.combined_json { } else if let Some(format) = arguments.combined_json {
@@ -181,6 +194,7 @@ fn main_inner() -> anyhow::Result<()> {
debug_config, debug_config,
arguments.output_directory, arguments.output_directory,
arguments.overwrite, arguments.overwrite,
&arguments.llvm_arguments,
)?; )?;
return Ok(()); return Ok(());
} else { } else {
@@ -198,6 +212,7 @@ fn main_inner() -> anyhow::Result<()> {
remappings, remappings,
suppressed_warnings, suppressed_warnings,
debug_config, debug_config,
&arguments.llvm_arguments,
) )
}?; }?;
+7 -8
View File
@@ -1,26 +1,25 @@
//! The Solidity compiler. //! The Solidity compiler.
pub mod combined_json;
#[cfg(not(target_os = "emscripten"))] #[cfg(not(target_os = "emscripten"))]
pub mod solc_compiler; pub mod solc_compiler;
#[cfg(target_os = "emscripten")] #[cfg(target_os = "emscripten")]
pub mod soljson_compiler; pub mod soljson_compiler;
pub mod standard_json;
pub mod version; pub mod version;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use self::combined_json::CombinedJson; use revive_solc_json_interface::combined_json::CombinedJson;
use self::standard_json::input::Input as StandardJsonInput; use revive_solc_json_interface::SolcStandardJsonInput;
use self::standard_json::output::Output as StandardJsonOutput; use revive_solc_json_interface::SolcStandardJsonOutput;
use self::version::Version; use self::version::Version;
/// The first version of `solc` with the support of standard JSON interface. /// The first version of `solc` with the support of standard JSON interface.
pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0); pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0);
/// The last supported version of `solc`. /// The last supported version of `solc`.
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 28); pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 29);
/// `--include-path` was introduced in solc `0.8.8` <https://github.com/ethereum/solidity/releases/tag/v0.8.8> /// `--include-path` was introduced in solc `0.8.8` <https://github.com/ethereum/solidity/releases/tag/v0.8.8>
pub const FIRST_INCLUDE_PATH_VERSION: semver::Version = semver::Version::new(0, 8, 8); pub const FIRST_INCLUDE_PATH_VERSION: semver::Version = semver::Version::new(0, 8, 8);
@@ -30,11 +29,11 @@ pub trait Compiler {
/// Compiles the Solidity `--standard-json` input into Yul IR. /// Compiles the Solidity `--standard-json` input into Yul IR.
fn standard_json( fn standard_json(
&mut self, &mut self,
input: StandardJsonInput, input: SolcStandardJsonInput,
base_path: Option<String>, base_path: Option<String>,
include_paths: Vec<String>, include_paths: Vec<String>,
allow_paths: Option<String>, allow_paths: Option<String>,
) -> anyhow::Result<StandardJsonOutput>; ) -> anyhow::Result<SolcStandardJsonOutput>;
/// The `solc --combined-json abi,hashes...` mirror. /// The `solc --combined-json abi,hashes...` mirror.
fn combined_json( fn combined_json(
+7 -6
View File
@@ -4,9 +4,10 @@ use std::io::Write;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use crate::solc::combined_json::CombinedJson; use revive_solc_json_interface::combined_json::CombinedJson;
use crate::solc::standard_json::input::Input as StandardJsonInput; use revive_solc_json_interface::SolcStandardJsonInput;
use crate::solc::standard_json::output::Output as StandardJsonOutput; use revive_solc_json_interface::SolcStandardJsonOutput;
use crate::solc::version::Version; use crate::solc::version::Version;
use super::Compiler; use super::Compiler;
@@ -39,11 +40,11 @@ impl Compiler for SolcCompiler {
/// Compiles the Solidity `--standard-json` input into Yul IR. /// Compiles the Solidity `--standard-json` input into Yul IR.
fn standard_json( fn standard_json(
&mut self, &mut self,
mut input: StandardJsonInput, mut input: SolcStandardJsonInput,
base_path: Option<String>, base_path: Option<String>,
include_paths: Vec<String>, include_paths: Vec<String>,
allow_paths: Option<String>, allow_paths: Option<String>,
) -> anyhow::Result<StandardJsonOutput> { ) -> anyhow::Result<SolcStandardJsonOutput> {
let version = self.version()?.validate(&include_paths)?.default; let version = self.version()?.validate(&include_paths)?.default;
let mut command = std::process::Command::new(self.executable.as_str()); let mut command = std::process::Command::new(self.executable.as_str());
@@ -93,7 +94,7 @@ impl Compiler for SolcCompiler {
); );
} }
let mut output: StandardJsonOutput = let mut output: SolcStandardJsonOutput =
revive_common::deserialize_from_slice(output.stdout.as_slice()).map_err(|error| { revive_common::deserialize_from_slice(output.stdout.as_slice()).map_err(|error| {
anyhow::anyhow!( anyhow::anyhow!(
"{} subprocess output parsing error: {}\n{}", "{} subprocess output parsing error: {}\n{}",
+8 -7
View File
@@ -3,9 +3,10 @@
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use crate::solc::combined_json::CombinedJson; use revive_solc_json_interface::combined_json::CombinedJson;
use crate::solc::standard_json::input::Input as StandardJsonInput; use revive_solc_json_interface::SolcStandardJsonInput;
use crate::solc::standard_json::output::Output as StandardJsonOutput; use revive_solc_json_interface::SolcStandardJsonOutput;
use crate::solc::version::Version; use crate::solc::version::Version;
use anyhow::Context; use anyhow::Context;
use std::ffi::{c_char, c_void, CStr, CString}; use std::ffi::{c_char, c_void, CStr, CString};
@@ -24,11 +25,11 @@ impl Compiler for SoljsonCompiler {
/// Compiles the Solidity `--standard-json` input into Yul IR. /// Compiles the Solidity `--standard-json` input into Yul IR.
fn standard_json( fn standard_json(
&mut self, &mut self,
mut input: StandardJsonInput, mut input: SolcStandardJsonInput,
base_path: Option<String>, base_path: Option<String>,
include_paths: Vec<String>, include_paths: Vec<String>,
allow_paths: Option<String>, allow_paths: Option<String>,
) -> anyhow::Result<StandardJsonOutput> { ) -> anyhow::Result<SolcStandardJsonOutput> {
if !include_paths.is_empty() { if !include_paths.is_empty() {
anyhow::bail!("configuring include paths is not supported with solJson") anyhow::bail!("configuring include paths is not supported with solJson")
} }
@@ -46,8 +47,8 @@ impl Compiler for SoljsonCompiler {
let input_json = serde_json::to_string(&input).expect("Always valid"); let input_json = serde_json::to_string(&input).expect("Always valid");
let out = Self::compile_standard_json(input_json)?; let out = Self::compile_standard_json(input_json)?;
let mut output: StandardJsonOutput = revive_common::deserialize_from_slice(out.as_bytes()) let mut output: SolcStandardJsonOutput =
.map_err(|error| { revive_common::deserialize_from_slice(out.as_bytes()).map_err(|error| {
anyhow::anyhow!( anyhow::anyhow!(
"Soljson output parsing error: {}\n{}", "Soljson output parsing error: {}\n{}",
error, error,
@@ -1,4 +0,0 @@
//! The `solc <input>.sol --standard-json`.
pub mod input;
pub mod output;
@@ -1,138 +0,0 @@
//! The `solc --standard-json` output.
pub mod contract;
pub mod error;
pub mod source;
use std::collections::BTreeMap;
use serde::Deserialize;
use serde::Serialize;
use sha3::Digest;
use crate::project::contract::ir::IR as ProjectContractIR;
use crate::project::contract::Contract as ProjectContract;
use crate::project::Project;
use crate::solc::version::Version as SolcVersion;
use crate::warning::Warning;
use crate::yul::lexer::Lexer;
use crate::yul::parser::statement::object::Object;
use self::contract::Contract;
use self::error::Error as SolcStandardJsonOutputError;
use self::source::Source;
/// The `solc --standard-json` output.
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct Output {
/// The file-contract hashmap.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub contracts: Option<BTreeMap<String, BTreeMap<String, Contract>>>,
/// The source code mapping data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sources: Option<BTreeMap<String, Source>>,
/// The compilation errors and warnings.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub errors: Option<Vec<SolcStandardJsonOutputError>>,
/// The `solc` compiler version.
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
/// The `solc` compiler long version.
#[serde(skip_serializing_if = "Option::is_none")]
pub long_version: Option<String>,
/// The `resolc` compiler version.
#[serde(skip_serializing_if = "Option::is_none")]
pub revive_version: Option<String>,
}
impl Output {
/// Converts the `solc` JSON output into a convenient project.
pub fn try_to_project(
&mut self,
source_code_files: BTreeMap<String, String>,
libraries: BTreeMap<String, BTreeMap<String, String>>,
solc_version: &SolcVersion,
debug_config: &revive_llvm_context::DebugConfig,
) -> anyhow::Result<Project> {
let files = match self.contracts.as_ref() {
Some(files) => files,
None => match &self.errors {
Some(errors) if errors.iter().any(|e| e.severity == "error") => {
anyhow::bail!(serde_json::to_string_pretty(errors).expect("Always valid"));
}
_ => &BTreeMap::new(),
},
};
let mut project_contracts = BTreeMap::new();
for (path, contracts) in files.iter() {
for (name, contract) in contracts.iter() {
let full_path = format!("{path}:{name}");
let ir_optimized = match contract.ir_optimized.to_owned() {
Some(ir_optimized) => ir_optimized,
None => continue,
};
if ir_optimized.is_empty() {
continue;
}
debug_config.dump_yul(full_path.as_str(), ir_optimized.as_str())?;
let mut lexer = Lexer::new(ir_optimized.to_owned());
let object = Object::parse(&mut lexer, None).map_err(|error| {
anyhow::anyhow!("Contract `{}` parsing error: {:?}", full_path, error)
})?;
let source = ProjectContractIR::new_yul(ir_optimized.to_owned(), object);
let source_code = source_code_files
.get(path.as_str())
.ok_or_else(|| anyhow::anyhow!("Source code for path `{}` not found", path))?;
let source_hash = sha3::Keccak256::digest(source_code.as_bytes()).into();
let project_contract = ProjectContract::new(
full_path.clone(),
source_hash,
solc_version.to_owned(),
source,
contract.metadata.to_owned(),
);
project_contracts.insert(full_path, project_contract);
}
}
Ok(Project::new(
solc_version.to_owned(),
project_contracts,
libraries,
))
}
/// Traverses the AST and returns the list of additional errors and warnings.
pub fn preprocess_ast(&mut self, suppressed_warnings: &[Warning]) -> anyhow::Result<()> {
let sources = match self.sources.as_ref() {
Some(sources) => sources,
None => return Ok(()),
};
let mut messages = Vec::new();
for (path, source) in sources.iter() {
if let Some(ast) = source.ast.as_ref() {
let mut polkavm_messages = Source::get_messages(ast, suppressed_warnings);
for message in polkavm_messages.iter_mut() {
message.push_contract_path(path.as_str());
}
messages.extend(polkavm_messages);
}
}
self.errors = match self.errors.take() {
Some(mut errors) => {
errors.extend(messages);
Some(errors)
}
None => Some(messages),
};
Ok(())
}
}
+44 -15
View File
@@ -7,17 +7,17 @@ use std::sync::Mutex;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use revive_llvm_context::OptimizerSettings; use revive_llvm_context::OptimizerSettings;
use revive_solc_json_interface::standard_json::output::contract::evm::bytecode::Bytecode;
use revive_solc_json_interface::standard_json::output::contract::evm::bytecode::DeployedBytecode;
use revive_solc_json_interface::warning::Warning;
use revive_solc_json_interface::SolcStandardJsonInput;
use revive_solc_json_interface::SolcStandardJsonInputSettingsOptimizer;
use revive_solc_json_interface::SolcStandardJsonInputSettingsSelection;
use revive_solc_json_interface::SolcStandardJsonOutput;
use crate::project::Project; use crate::project::Project;
use crate::solc::solc_compiler::SolcCompiler; use crate::solc::solc_compiler::SolcCompiler;
use crate::solc::standard_json::input::settings::optimizer::Optimizer as SolcStandardJsonInputSettingsOptimizer;
use crate::solc::standard_json::input::settings::selection::Selection as SolcStandardJsonInputSettingsSelection;
use crate::solc::standard_json::input::Input as SolcStandardJsonInput;
use crate::solc::standard_json::output::contract::evm::bytecode::Bytecode;
use crate::solc::standard_json::output::contract::evm::bytecode::DeployedBytecode;
use crate::solc::standard_json::output::Output as SolcStandardJsonOutput;
use crate::solc::Compiler; use crate::solc::Compiler;
use crate::warning::Warning;
static PVM_BLOB_CACHE: Lazy<Mutex<HashMap<CachedBlob, Vec<u8>>>> = Lazy::new(Default::default); static PVM_BLOB_CACHE: Lazy<Mutex<HashMap<CachedBlob, Vec<u8>>>> = Lazy::new(Default::default);
static EVM_BLOB_CACHE: Lazy<Mutex<HashMap<CachedBlob, Vec<u8>>>> = Lazy::new(Default::default); static EVM_BLOB_CACHE: Lazy<Mutex<HashMap<CachedBlob, Vec<u8>>>> = Lazy::new(Default::default);
@@ -73,7 +73,11 @@ pub fn build_solidity_with_options(
check_dependencies(); check_dependencies();
inkwell::support::enable_llvm_pretty_stack_trace(); inkwell::support::enable_llvm_pretty_stack_trace();
revive_llvm_context::initialize_target(revive_llvm_context::Target::PVM); revive_llvm_context::initialize_llvm(
revive_llvm_context::Target::PVM,
crate::DEFAULT_EXECUTABLE_NAME,
&[],
);
let _ = crate::process::native_process::EXECUTABLE let _ = crate::process::native_process::EXECUTABLE
.set(PathBuf::from(crate::r#const::DEFAULT_EXECUTABLE_NAME)); .set(PathBuf::from(crate::r#const::DEFAULT_EXECUTABLE_NAME));
@@ -98,9 +102,16 @@ pub fn build_solidity_with_options(
let mut output = solc.standard_json(input, None, vec![], None)?; let mut output = solc.standard_json(input, None, vec![], None)?;
let project = output.try_to_project(sources, libraries, &solc_version, &DEBUG_CONFIG)?; let project = Project::try_from_standard_json_output(
&output,
sources,
libraries,
&solc_version,
&DEBUG_CONFIG,
)?;
let build: crate::Build = project.compile(optimizer_settings, false, DEBUG_CONFIG)?; let build: crate::Build =
project.compile(optimizer_settings, false, DEBUG_CONFIG, Default::default())?;
build.write_to_standard_json(&mut output, &solc_version)?; build.write_to_standard_json(&mut output, &solc_version)?;
Ok(output) Ok(output)
@@ -116,7 +127,11 @@ pub fn build_solidity_with_options_evm(
check_dependencies(); check_dependencies();
inkwell::support::enable_llvm_pretty_stack_trace(); inkwell::support::enable_llvm_pretty_stack_trace();
revive_llvm_context::initialize_target(revive_llvm_context::Target::PVM); revive_llvm_context::initialize_llvm(
revive_llvm_context::Target::PVM,
crate::DEFAULT_EXECUTABLE_NAME,
&[],
);
let _ = crate::process::native_process::EXECUTABLE let _ = crate::process::native_process::EXECUTABLE
.set(PathBuf::from(crate::r#const::DEFAULT_EXECUTABLE_NAME)); .set(PathBuf::from(crate::r#const::DEFAULT_EXECUTABLE_NAME));
@@ -168,7 +183,11 @@ pub fn build_solidity_and_detect_missing_libraries(
check_dependencies(); check_dependencies();
inkwell::support::enable_llvm_pretty_stack_trace(); inkwell::support::enable_llvm_pretty_stack_trace();
revive_llvm_context::initialize_target(revive_llvm_context::Target::PVM); revive_llvm_context::initialize_llvm(
revive_llvm_context::Target::PVM,
crate::DEFAULT_EXECUTABLE_NAME,
&[],
);
let _ = crate::process::native_process::EXECUTABLE let _ = crate::process::native_process::EXECUTABLE
.set(PathBuf::from(crate::r#const::DEFAULT_EXECUTABLE_NAME)); .set(PathBuf::from(crate::r#const::DEFAULT_EXECUTABLE_NAME));
@@ -188,7 +207,13 @@ pub fn build_solidity_and_detect_missing_libraries(
let mut output = solc.standard_json(input, None, vec![], None)?; let mut output = solc.standard_json(input, None, vec![], None)?;
let project = output.try_to_project(sources, libraries, &solc_version, &DEBUG_CONFIG)?; let project = Project::try_from_standard_json_output(
&output,
sources,
libraries,
&solc_version,
&DEBUG_CONFIG,
)?;
let missing_libraries = project.get_missing_libraries(); let missing_libraries = project.get_missing_libraries();
missing_libraries.write_to_standard_json(&mut output, &solc.version()?)?; missing_libraries.write_to_standard_json(&mut output, &solc.version()?)?;
@@ -201,7 +226,11 @@ pub fn build_yul(source_code: &str) -> anyhow::Result<()> {
check_dependencies(); check_dependencies();
inkwell::support::enable_llvm_pretty_stack_trace(); inkwell::support::enable_llvm_pretty_stack_trace();
revive_llvm_context::initialize_target(revive_llvm_context::Target::PVM); revive_llvm_context::initialize_llvm(
revive_llvm_context::Target::PVM,
crate::DEFAULT_EXECUTABLE_NAME,
&[],
);
let optimizer_settings = revive_llvm_context::OptimizerSettings::none(); let optimizer_settings = revive_llvm_context::OptimizerSettings::none();
let project = Project::try_from_yul_string::<SolcCompiler>( let project = Project::try_from_yul_string::<SolcCompiler>(
@@ -209,7 +238,7 @@ pub fn build_yul(source_code: &str) -> anyhow::Result<()> {
source_code, source_code,
None, None,
)?; )?;
let _build = project.compile(optimizer_settings, false, DEBUG_CONFIG)?; let _build = project.compile(optimizer_settings, false, DEBUG_CONFIG, Default::default())?;
Ok(()) Ok(())
} }
+1 -1
View File
@@ -4,7 +4,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use crate::warning::Warning; use revive_solc_json_interface::warning::Warning;
pub const ECRECOVER_TEST_SOURCE: &str = r#" pub const ECRECOVER_TEST_SOURCE: &str = r#"
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
@@ -192,6 +192,8 @@ where
revive_llvm_context::PolkaVMStoreHeapWordFunction.declare(context)?; revive_llvm_context::PolkaVMStoreHeapWordFunction.declare(context)?;
revive_llvm_context::PolkaVMLoadStorageWordFunction.declare(context)?; revive_llvm_context::PolkaVMLoadStorageWordFunction.declare(context)?;
revive_llvm_context::PolkaVMStoreStorageWordFunction.declare(context)?; revive_llvm_context::PolkaVMStoreStorageWordFunction.declare(context)?;
revive_llvm_context::PolkaVMLoadTransientStorageWordFunction.declare(context)?;
revive_llvm_context::PolkaVMStoreTransientStorageWordFunction.declare(context)?;
revive_llvm_context::PolkaVMWordToPointerFunction.declare(context)?; revive_llvm_context::PolkaVMWordToPointerFunction.declare(context)?;
revive_llvm_context::PolkaVMExitFunction.declare(context)?; revive_llvm_context::PolkaVMExitFunction.declare(context)?;
@@ -242,6 +244,8 @@ where
revive_llvm_context::PolkaVMStoreHeapWordFunction.into_llvm(context)?; revive_llvm_context::PolkaVMStoreHeapWordFunction.into_llvm(context)?;
revive_llvm_context::PolkaVMLoadStorageWordFunction.into_llvm(context)?; revive_llvm_context::PolkaVMLoadStorageWordFunction.into_llvm(context)?;
revive_llvm_context::PolkaVMStoreStorageWordFunction.into_llvm(context)?; revive_llvm_context::PolkaVMStoreStorageWordFunction.into_llvm(context)?;
revive_llvm_context::PolkaVMLoadTransientStorageWordFunction.into_llvm(context)?;
revive_llvm_context::PolkaVMStoreTransientStorageWordFunction.into_llvm(context)?;
revive_llvm_context::PolkaVMWordToPointerFunction.into_llvm(context)?; revive_llvm_context::PolkaVMWordToPointerFunction.into_llvm(context)?;
revive_llvm_context::PolkaVMExitFunction.into_llvm(context)?; revive_llvm_context::PolkaVMExitFunction.into_llvm(context)?;
+3 -2
View File
@@ -3,8 +3,9 @@ const path = require("path");
const { minify } = require("terser"); const { minify } = require("terser");
const SOLJSON_URI = const SOLJSON_URI =
"https://binaries.soliditylang.org/wasm/soljson-v0.8.28+commit.7893614a.js"; "https://binaries.soliditylang.org/wasm/soljson-v0.8.29+commit.ab55807c.js";
const RESOLC_WASM_URI = "http://127.0.0.1:8080/resolc.wasm"; const RESOLC_WASM_URI =
process.env.RELEASE_RESOLC_WASM_URI || "http://127.0.0.1:8080/resolc.wasm";
const RESOLC_WASM_TARGET_DIR = path.join( const RESOLC_WASM_TARGET_DIR = path.join(
__dirname, __dirname,
"../target/wasm32-unknown-emscripten/release", "../target/wasm32-unknown-emscripten/release",
+2 -2
View File
@@ -2,7 +2,7 @@
"name": "revive", "name": "revive",
"private": true, "private": true,
"dependencies": { "dependencies": {
"solc": "^0.8.28" "solc": "^0.8.29"
}, },
"scripts": { "scripts": {
"example:web": "http-server ./examples/web/", "example:web": "http-server ./examples/web/",
@@ -21,4 +21,4 @@
"prettier": "^3.4.2", "prettier": "^3.4.2",
"terser": "^5.37.0" "terser": "^5.37.0"
} }
} }
-5
View File
@@ -35,11 +35,6 @@ module.exports = defineConfig({
name: "firefox", name: "firefox",
use: { ...devices["Desktop Firefox"] }, use: { ...devices["Desktop Firefox"] },
}, },
{
name: "webkit",
use: { ...devices["Desktop Safari"] },
},
], ],
/* Run your local dev server before starting the tests */ /* Run your local dev server before starting the tests */