mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-14 18:01:05 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ddddc989d | |||
| 5992ad0043 | |||
| 2fd96f6188 | |||
| 7d8fa75a0f | |||
| 80f94b5c76 | |||
| 06d324259c | |||
| 7669320e31 | |||
| ea0ff27c6f | |||
| 60e41a9210 | |||
| 0089d58d85 | |||
| 09c8f64eef | |||
| 4e6c562fac | |||
| 12a8685f11 | |||
| ce1766dc64 | |||
| 2c1097ef36 | |||
| a5ad9a917a | |||
| c929dc9b03 | |||
| dab29bc89b | |||
| 313c033261 | |||
| 87c1d7a8be | |||
| 8a98346a9c | |||
| 1b4d2c6bb8 | |||
| 004b8ac16c | |||
| 497dae2494 | |||
| 36ea69b50f | |||
| 2bbc5d713d | |||
| 4a9b651235 |
@@ -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' }}
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -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"
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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",
|
||||||
|
|||||||
@@ -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" }
|
||||||
|
|||||||
@@ -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,4 +1,4 @@
|
|||||||

|

|
||||||
[](https://contracts.polkadot.io/revive_compiler/)
|
[](https://contracts.polkadot.io/revive_compiler/)
|
||||||
|
|
||||||
# revive
|
# revive
|
||||||
|
|||||||
+8
-5
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ pragma solidity ^0.8;
|
|||||||
"Instantiated": 0
|
"Instantiated": 0
|
||||||
},
|
},
|
||||||
"key": "0000000000000000000000000000000000000000000000000000000000000000",
|
"key": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"expected": "0100000000000000000000000000000000000000000000000000000000000000"
|
"expected": "0000000000000000000000000000000000000000000000000000000000000001"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 }
|
||||||
@@ -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;
|
||||||
+9
-5
@@ -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>,
|
||||||
+4
-2
@@ -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
@@ -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;
|
||||||
|
|
||||||
-15
@@ -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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-2
@@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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 }
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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,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() {
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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!(
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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,
|
||||||
)
|
)
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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{}",
|
||||||
|
|||||||
@@ -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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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",
|
||||||
|
|||||||
+1
-1
@@ -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/",
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
Reference in New Issue
Block a user