Compare commits

...

9 Commits

Author SHA1 Message Date
kvpanch 4ab11a09a9 Merge branch 'main' into kvpanch/llvm_21 2025-12-16 07:13:09 -05:00
xermicus 9446132608 Emit consume_all_gas in invalid and bounds checks (#433)
Closes #374

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-12-16 10:04:51 +01:00
kvp c952471647 Update code base to use LLVM 21 2025-12-15 18:34:58 -05:00
xermicus 91bd1b0b4e Do not build the book during test (#432)
Avoid spurious changes in the build output directory.
2025-12-15 14:16:03 +01:00
xermicus e568a924ae update to polkadot-sdk unstable2507 (#431)
Support for `polkadot-sdk` release `unstable2507`. This release will be
deployed to Kusama and is supposed the first one on Polkadot.

---------

Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-12-15 14:02:48 +01:00
xermicus 11f82c8488 Support solc v0.8.31 (#430)
- Support for solc v0.8.31.
- Support for the `clz` Yul builtin.

---------

Signed-off-by: xermicus <cyrill@parity.io>
2025-12-05 15:25:13 +01:00
kvpanch d0c10e6d5c Update ubuntu's source list to use nobel (#425)
This helps to install clang-18 and not clang-15. Latter cannot be used
anymore to build new LLVM due to some missed clang option.
2025-12-03 21:28:48 -05:00
xermicus 45ceab7dc7 Additional bounds check in sbrk (#428)
Close #356

Signed-off-by: xermicus <cyrill@parity.io>
2025-12-03 16:00:19 +01:00
xermicus a9ccb1f9b4 small docs fixes (#426)
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2025-12-02 18:01:01 +01:00
78 changed files with 1601 additions and 1288 deletions
+56 -36
View File
@@ -26,11 +26,14 @@ runs:
# Extract version from branch name (e.g., "18.x" from "release/18.x") # Extract version from branch name (e.g., "18.x" from "release/18.x")
VERSION_PREFIX=$(echo "$BRANCH" | sed 's|release/||' | sed 's|\.x$||') VERSION_PREFIX=$(echo "$BRANCH" | sed 's|release/||' | sed 's|\.x$||')
echo "Detected LLVM version prefix from submodule branch: $VERSION_PREFIX" echo "Detected LLVM version prefix from submodule branch: $VERSION_PREFIX"
# Special case: pin LLVM 18 to specific version 18.1.8 # Special case: pin LLVM 18 to specific version 18.1.8
if [ "$VERSION_PREFIX" = "18" ]; then if [ "$VERSION_PREFIX" = "18" ]; then
echo "Using pinned version for LLVM 18: llvm-18.1.8" echo "Using pinned version for LLVM 18: llvm-18.1.8"
echo "version_prefix=llvm-18.1.8" >> $GITHUB_OUTPUT echo "version_prefix=llvm-18.1.8" >> $GITHUB_OUTPUT
elif [ "$VERSION_PREFIX" = "21" ]; then
echo "Using pinned version for LLVM 21: llvm-21.1.6"
echo "version_prefix=llvm-21.1.6" >> $GITHUB_OUTPUT
else else
echo "version_prefix=llvm-$VERSION_PREFIX" >> $GITHUB_OUTPUT echo "version_prefix=llvm-$VERSION_PREFIX" >> $GITHUB_OUTPUT
fi fi
@@ -42,7 +45,7 @@ runs:
echo "Using explicitly provided version: ${{ inputs.version }}" echo "Using explicitly provided version: ${{ inputs.version }}"
echo "version_prefix=${{ inputs.version }}" >> $GITHUB_OUTPUT echo "version_prefix=${{ inputs.version }}" >> $GITHUB_OUTPUT
fi fi
- name: find asset - name: find asset
id: find id: find
uses: actions/github-script@v7 uses: actions/github-script@v7
@@ -53,12 +56,15 @@ runs:
result-encoding: string result-encoding: string
script: | script: |
let page = 1; let page = 1;
let releases = []; let allReleases = [];
let target = process.env.target let target = process.env.target
let versionPrefix = process.env.version_prefix let versionPrefix = process.env.version_prefix
do { // Fetch all releases from all pages
core.info('Fetching releases from revive repository...');
let hasMorePages = true;
while (hasMorePages) {
const res = await github.rest.repos.listReleases({ const res = await github.rest.repos.listReleases({
owner: context.repo.owner, owner: context.repo.owner,
repo: context.repo.repo, repo: context.repo.repo,
@@ -66,43 +72,57 @@ runs:
page, page,
}); });
releases = res.data if (res.data.length > 0) {
releases.sort((a, b) => { core.info(`Page ${page}: Fetched ${res.data.length} releases`);
return (a.published_at < b.published_at) ? 1 : ((a.published_at > b.published_at) ? -1 : 0); allReleases.push(...res.data);
}); page++;
let llvmRelease;
if (versionPrefix) {
// Search for latest release matching the version prefix
llvmRelease = releases.find(release => {
return release.tag_name.startsWith(versionPrefix);
});
if (llvmRelease) {
core.info(`Found LLVM release matching prefix '${versionPrefix}': ${llvmRelease.tag_name}`);
}
} else { } else {
// Find latest LLVM release hasMorePages = false;
llvmRelease = releases.find(release => {
return release.tag_name.startsWith('llvm-');
});
if (llvmRelease) {
core.info(`Found latest LLVM version: ${llvmRelease.tag_name}`);
}
} }
}
if (llvmRelease){ core.info(`Total releases fetched: ${allReleases.length}`);
let asset = llvmRelease.assets.find(asset =>{
return asset.name.includes(target); // Sort all releases by publication date (newest first)
}); allReleases.sort((a, b) => {
if (!asset){ return (a.published_at < b.published_at) ? 1 : ((a.published_at > b.published_at) ? -1 : 0);
core.setFailed(`Artifact for '${target}' not found in release ${llvmRelease.tag_name} (${llvmRelease.html_url})`); });
process.exit();
} // Debug: Print all LLVM releases
return asset.browser_download_url; const llvmReleases = allReleases.filter(r => r.tag_name.startsWith('llvm-'));
core.info(`Found ${llvmReleases.length} LLVM releases in total:`);
llvmReleases.forEach(r => {
core.info(` - ${r.tag_name} (published: ${r.published_at})`);
});
// Find the appropriate LLVM release
let llvmRelease;
if (versionPrefix) {
// Search for latest release matching the version prefix
llvmRelease = llvmReleases.find(release => {
return release.tag_name.startsWith(versionPrefix);
});
if (llvmRelease) {
core.info(`Selected LLVM release matching prefix '${versionPrefix}': ${llvmRelease.tag_name}`);
} }
} else {
// Find latest LLVM release (first in sorted list)
llvmRelease = llvmReleases[0];
if (llvmRelease) {
core.info(`Selected latest LLVM version: ${llvmRelease.tag_name}`);
}
}
page++; if (llvmRelease) {
} while(releases.length > 0); let asset = llvmRelease.assets.find(asset => {
return asset.name.includes(target);
});
if (!asset) {
core.setFailed(`Artifact for '${target}' not found in release ${llvmRelease.tag_name} (${llvmRelease.html_url})`);
process.exit();
}
return asset.browser_download_url;
}
if (versionPrefix) { if (versionPrefix) {
core.setFailed(`No LLVM releases matching prefix '${versionPrefix}' found! Please check the version.`); core.setFailed(`No LLVM releases matching prefix '${versionPrefix}' found! Please check the version.`);
+1 -1
View File
@@ -19,7 +19,7 @@ runs:
shell: bash shell: bash
run: | run: |
mkdir -p solc mkdir -p solc
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.30/${SOLC_NAME} curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.31/${SOLC_NAME}
- name: Make Solc Executable - name: Make Solc Executable
if: ${{ runner.os == 'Windows' }} if: ${{ runner.os == 'Windows' }}
+4 -1
View File
@@ -25,9 +25,12 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: { fetch-depth: 0 } with: { fetch-depth: 0 }
- name: Install mdBook - name: Install and test the mdBook
run: make test-book run: make test-book
- name: Build book
run: mdbook build book
- name: Build book to tmp - name: Build book to tmp
run: mdbook build book -d docs-tmp run: mdbook build book -d docs-tmp
+4 -1
View File
@@ -82,7 +82,10 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
if: ${{ matrix.host == 'linux' }} if: ${{ matrix.host == 'linux' }}
run: | run: |
sudo apt-get update && sudo apt-get install -y cmake ninja-build curl git libssl-dev pkg-config clang lld musl cat /etc/apt/sources.list
sudo sed -i 's/jammy/noble/g' /etc/apt/sources.list
cat /etc/apt/sources.list
sudo apt-get update && sudo apt-get install -y cmake ninja-build curl git libssl-dev pkg-config clang lld musl xz-utils libc6-dev gcc-multilib g++ build-essential linux-libc-dev
- name: Install Dependencies - name: Install Dependencies
if: ${{ matrix.host == 'macos' }} if: ${{ matrix.host == 'macos' }}
+4 -4
View File
@@ -92,7 +92,7 @@ jobs:
if: ${{ matrix.type == 'native' }} if: ${{ matrix.type == 'native' }}
shell: bash shell: bash
run: | run: |
export LLVM_SYS_181_PREFIX=$PWD/llvm-${{ matrix.target }} export LLVM_SYS_211_PREFIX=$PWD/llvm-${{ matrix.target }}
make install-bin make install-bin
mv target/release/resolc resolc-${{ matrix.target }} || mv target/release/resolc.exe resolc-${{ matrix.target }}.exe mv target/release/resolc resolc-${{ matrix.target }} || mv target/release/resolc.exe resolc-${{ matrix.target }}.exe
@@ -103,7 +103,7 @@ jobs:
cd /opt/revive cd /opt/revive
chown -R root:root . chown -R root:root .
apt update && apt upgrade -y && apt install -y pkg-config apt update && apt upgrade -y && apt install -y pkg-config
export LLVM_SYS_181_PREFIX=/opt/revive/llvm-${{ matrix.target }} export LLVM_SYS_211_PREFIX=/opt/revive/llvm-${{ matrix.target }}
make install-bin make install-bin
mv target/${{ matrix.target }}/release/resolc resolc-${{ matrix.target }} mv target/${{ matrix.target }}/release/resolc resolc-${{ matrix.target }}
" "
@@ -163,7 +163,7 @@ jobs:
- name: Build - name: Build
run: | run: |
export LLVM_SYS_181_PREFIX=$PWD/llvm-x86_64-unknown-linux-gnu export LLVM_SYS_211_PREFIX=$PWD/llvm-x86_64-unknown-linux-gnu
export REVIVE_LLVM_TARGET_PREFIX=$PWD/llvm-wasm32-unknown-emscripten export REVIVE_LLVM_TARGET_PREFIX=$PWD/llvm-wasm32-unknown-emscripten
source emsdk/emsdk_env.sh source emsdk/emsdk_env.sh
make install-wasm make install-wasm
@@ -177,7 +177,7 @@ jobs:
- name: Basic Sanity Check - name: Basic Sanity Check
run: | run: |
mkdir -p solc mkdir -p solc
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.30/soljson.js curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.31/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');
+1 -1
View File
@@ -47,7 +47,7 @@ jobs:
- name: Set LLVM Environment Variables - name: Set LLVM Environment Variables
run: | run: |
echo "LLVM_SYS_181_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV echo "LLVM_SYS_211_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV
echo "REVIVE_LLVM_TARGET_PREFIX=$(pwd)/llvm-wasm32-unknown-emscripten" >> $GITHUB_ENV echo "REVIVE_LLVM_TARGET_PREFIX=$(pwd)/llvm-wasm32-unknown-emscripten" >> $GITHUB_ENV
- name: Build Revive - name: Build Revive
+1 -1
View File
@@ -38,7 +38,7 @@ jobs:
- name: Set LLVM Environment Variables - name: Set LLVM Environment Variables
run: | run: |
echo "LLVM_SYS_181_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV echo "LLVM_SYS_211_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV
- name: Install Geth - name: Install Geth
run: | run: |
+1 -1
View File
@@ -1,4 +1,4 @@
[submodule "llvm"] [submodule "llvm"]
path = llvm path = llvm
url = https://github.com/llvm/llvm-project.git url = https://github.com/llvm/llvm-project.git
branch = release/18.x branch = release/21.x
+6 -1
View File
@@ -4,17 +4,22 @@
This is a development pre-release. This is a development pre-release.
Supported `polkadot-sdk` rev: `2509.0.0` Supported `polkadot-sdk` rev: `unstable2507`
### Added ### Added
- The comprehensive revive compiler book documentation page: https://paritytech.github.io/revive/ - The comprehensive revive compiler book documentation page: https://paritytech.github.io/revive/
- Support for solc v0.8.31.
- Support for the `clz` Yul builtin.
### Changed ### Changed
- Instruct the LLVM backend and linker to `--relax` (may lead to smaller contract code size). - Instruct the LLVM backend and linker to `--relax` (may lead to smaller contract code size).
- Standard JSON mode: Don't forward EVM bytecode related output selections to solc. - Standard JSON mode: Don't forward EVM bytecode related output selections to solc.
- The supported `polkadot-sdk` release is `unstable2507`.
- The `INVALID` opcode and OOB memory accesses now consume all remaining gas.
### Fixed: ### Fixed:
- The missing `STOP` instruction at the end of `code` blocks. - The missing `STOP` instruction at the end of `code` blocks.
- The missing bounds check in the internal sbrk implementation.
## v0.5.0 ## v0.5.0
Generated
+1030 -1036
View File
File diff suppressed because it is too large Load Diff
+4 -3
View File
@@ -76,13 +76,14 @@ normpath = "1.5"
# polkadot-sdk and friends # polkadot-sdk and friends
codec = { version = "3.7.5", default-features = false, package = "parity-scale-codec" } codec = { version = "3.7.5", default-features = false, package = "parity-scale-codec" }
scale-info = { version = "2.11.6", default-features = false } scale-info = { version = "2.11.6", default-features = false }
polkadot-sdk = { version = "2509.0.0" } polkadot-sdk = { version = "=2507.4.0" }
# llvm # llvm
[workspace.dependencies.inkwell] [workspace.dependencies.inkwell]
version = "0.6.0" git = "https://github.com/TheDan64/inkwell.git"
branch = "master"
default-features = false default-features = false
features = ["serde", "llvm18-1", "no-libffi-linking", "target-riscv"] features = ["serde", "llvm21-1", "no-libffi-linking", "target-riscv"]
[profile.bench] [profile.bench]
inherits = "release" inherits = "release"
+1 -1
View File
@@ -21,7 +21,7 @@ RUN apt update && \
COPY . . COPY . .
COPY --from=llvm-builder /opt/revive/target-llvm /opt/revive/target-llvm COPY --from=llvm-builder /opt/revive/target-llvm /opt/revive/target-llvm
ENV LLVM_SYS_181_PREFIX=/opt/revive/target-llvm/musl/target-final ENV LLVM_SYS_211_PREFIX=/opt/revive/target-llvm/musl/target-final
RUN make install-bin RUN make install-bin
FROM alpine:latest FROM alpine:latest
-1
View File
@@ -92,7 +92,6 @@ test-llvm-builder:
test-book: test-book:
cargo install mdbook --version 0.5.1 --locked cargo install mdbook --version 0.5.1 --locked
mdbook test book mdbook test book
mdbook build book
bench: install-bin bench: install-bin
cargo criterion --all --all-features --message-format=json \ cargo criterion --all --all-features --message-format=json \
+5 -5
View File
@@ -69,9 +69,9 @@ Download the [latest LLVM build](https://github.com/paritytech/revive/releases?q
> xattr -rc </path/to/the/extracted/archive>/target-llvm/gnu/target-final/bin/* > xattr -rc </path/to/the/extracted/archive>/target-llvm/gnu/target-final/bin/*
> ``` > ```
After extracting the archive, point `$LLVM_SYS_181_PREFIX` to it: After extracting the archive, point `$LLVM_SYS_211_PREFIX` to it:
```sh ```sh
export LLVM_SYS_181_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/target-final export LLVM_SYS_211_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/target-final
``` ```
</details> </details>
@@ -79,18 +79,18 @@ export LLVM_SYS_181_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/targ
<details> <details>
<summary>Building from source</summary> <summary>Building from source</summary>
The `Makefile` provides a shortcut target to obtain a compatible LLVM build, using the provided [revive-llvm](crates/llvm-builder/README.md) utility. Once installed, point `$LLVM_SYS_181_PREFIX` to the installation afterwards: The `Makefile` provides a shortcut target to obtain a compatible LLVM build, using the provided [revive-llvm](crates/llvm-builder/README.md) utility. Once installed, point `$LLVM_SYS_211_PREFIX` to the installation afterwards:
```sh ```sh
make install-llvm make install-llvm
export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final export LLVM_SYS_211_PREFIX=${PWD}/target-llvm/gnu/target-final
``` ```
</details> </details>
### The `resolc` Solidity frontend ### The `resolc` Solidity frontend
To build the `resolc` Solidity frontend executable, make sure you have obtained a compatible LLVM build and did export the `LLVM_SYS_181_PREFIX` environment variable pointing to it (see [above](#LLVM)). To build the `resolc` Solidity frontend executable, make sure you have obtained a compatible LLVM build and did export the `LLVM_SYS_211_PREFIX` environment variable pointing to it (see [above](#LLVM)).
To install the `resolc` Solidity frontend executable: To install the `resolc` Solidity frontend executable:
+1 -1
View File
@@ -45,7 +45,7 @@ Unlike with the EVM, where heap memory usage is gas metered, our heap size is st
LLVM is a special non Rust dependency. We interface its builder interface via the [inkwell](https://crates.io/crates/inkwell) wrapper crate. LLVM is a special non Rust dependency. We interface its builder interface via the [inkwell](https://crates.io/crates/inkwell) wrapper crate.
We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM rv64e target and always leave assertions on. Furthermore, we need cross builds because `resolc` itself targets emscripten and musl. The [revive-llvm-builer](https://crates.io/crates/revive-llvm-builder) functions as a cross-platform build script and is used to build and release the LLVM dependency. We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM `rv64emacb` target and always leave assertions on. Furthermore, we need cross builds because `resolc` itself targets emscripten and musl. The [revive-llvm-builer](https://crates.io/crates/revive-llvm-builder) functions as a cross-platform build script and is used to build and release the LLVM dependency.
We also maintain the [lld-sys crate](https://crates.io/crates/lld-sys) for interfacing with `LLD`. The LLVM linker is used during the compilation process, but we don't want to distribute another binary. We also maintain the [lld-sys crate](https://crates.io/crates/lld-sys) for interfacing with `LLD`. The LLVM linker is used during the compilation process, but we don't want to distribute another binary.
+4 -4
View File
@@ -21,7 +21,7 @@ Valid levels are the following:
- `s`: Optimize for code size. - `s`: Optimize for code size.
- `z`: Aggressively optimize for code size. - `z`: Aggressively optimize for code size.
By default, `-O3` is applied. By default, `-Oz` is applied.
### Stack size ### Stack size
```bash ```bash
@@ -31,11 +31,11 @@ By default, `-O3` is applied.
PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use. PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use.
You are incentivized to keep this value as small as possible: You are incentivized to keep this value as small as possible:
1. Increasing the stack size will increase startup costs. 1. Increasing the stack size will increase gas costs due to increased startup costs.
2. The stack size contributes to the total memory size a contract can use, which includes the contract's code size. 2. The stack size contributes to the total memory size a contract can use, which includes the contract's code size.
Default value: 32768 Default value: 32768
> [!WARNING] > [!WARNING]
> >
> If the contract uses more stack memory than configured, it will compile fine but eventually revert execution at runtime! > If the contract uses more stack memory than configured, it will compile fine but eventually revert execution at runtime!
@@ -52,7 +52,7 @@ You are incentivized to keep this value as small as possible:
2.The heap size contributes to the total memory size a contract can use, which includes the contract's code size 2.The heap size contributes to the total memory size a contract can use, which includes the contract's code size
Default value: 65536 Default value: 65536
> [!WARNING] > [!WARNING]
> >
> If the contract uses more heap memory than configured, it will compile fine but eventually revert execution at runtime! > If the contract uses more heap memory than configured, it will compile fine but eventually revert execution at runtime!
+1 -1
View File
@@ -1,7 +1,7 @@
//! The compiler build utilities library. //! The compiler build utilities library.
/// The revive LLVM host dependency directory prefix environment variable. /// The revive LLVM host dependency directory prefix environment variable.
pub const REVIVE_LLVM_HOST_PREFIX: &str = "LLVM_SYS_181_PREFIX"; pub const REVIVE_LLVM_HOST_PREFIX: &str = "LLVM_SYS_211_PREFIX";
/// The revive LLVM target dependency directory prefix environment variable. /// The revive LLVM target dependency directory prefix environment variable.
pub const REVIVE_LLVM_TARGET_PREFIX: &str = "REVIVE_LLVM_TARGET_PREFIX"; pub const REVIVE_LLVM_TARGET_PREFIX: &str = "REVIVE_LLVM_TARGET_PREFIX";
+10
View File
@@ -43,6 +43,12 @@ pub enum EVMVersion {
/// The corresponding EVM version. /// The corresponding EVM version.
#[serde(rename = "cancun")] #[serde(rename = "cancun")]
Cancun, Cancun,
/// The corresponding EVM version.
#[serde(rename = "prague")]
Prague,
/// The corresponding EVM version.
#[serde(rename = "osaka")]
Osaka,
} }
impl TryFrom<&str> for EVMVersion { impl TryFrom<&str> for EVMVersion {
@@ -62,6 +68,8 @@ impl TryFrom<&str> for EVMVersion {
"paris" => Self::Paris, "paris" => Self::Paris,
"shanghai" => Self::Shanghai, "shanghai" => Self::Shanghai,
"cancun" => Self::Cancun, "cancun" => Self::Cancun,
"prague" => Self::Prague,
"osaka" => Self::Osaka,
_ => anyhow::bail!("Invalid EVM version: {}", value), _ => anyhow::bail!("Invalid EVM version: {}", value),
}) })
} }
@@ -82,6 +90,8 @@ impl std::fmt::Display for EVMVersion {
Self::Paris => write!(f, "paris"), Self::Paris => write!(f, "paris"),
Self::Shanghai => write!(f, "shanghai"), Self::Shanghai => write!(f, "shanghai"),
Self::Cancun => write!(f, "cancun"), Self::Cancun => write!(f, "cancun"),
Self::Prague => write!(f, "prague"),
Self::Osaka => write!(f, "osaka"),
} }
} }
} }
+13 -1
View File
@@ -15,6 +15,8 @@
"grayGlacierBlock": 0, "grayGlacierBlock": 0,
"shanghaiTime": 0, "shanghaiTime": 0,
"cancunTime": 0, "cancunTime": 0,
"pragueTime": 0,
"osakaTime": 0,
"terminalTotalDifficulty": 0, "terminalTotalDifficulty": 0,
"terminalTotalDifficultyPassed": true, "terminalTotalDifficultyPassed": true,
"blobSchedule": { "blobSchedule": {
@@ -22,6 +24,16 @@
"target": 3, "target": 3,
"max": 6, "max": 6,
"baseFeeUpdateFraction": 3338477 "baseFeeUpdateFraction": 3338477
},
"prague": {
"target": 6,
"max": 9,
"baseFeeUpdateFraction": 5007716
},
"osaka": {
"target": 6,
"max": 9,
"baseFeeUpdateFraction": 5007716
} }
} }
}, },
@@ -44,4 +56,4 @@
"balance": "1000000000" "balance": "1000000000"
} }
} }
} }
+8 -8
View File
@@ -1,10 +1,10 @@
{ {
"Baseline": 905, "Baseline": 911,
"Computation": 2286, "Computation": 2337,
"DivisionArithmetics": 14347, "DivisionArithmetics": 14488,
"ERC20": 16929, "ERC20": 17041,
"Events": 1665, "Events": 1672,
"FibonacciIterative": 1447, "FibonacciIterative": 1454,
"Flipper": 2077, "Flipper": 2106,
"SHA1": 7721 "SHA1": 7814
} }
+1 -1
View File
@@ -26,6 +26,6 @@ pragma solidity ^0.8;
contract BaseFee { contract BaseFee {
constructor() payable { constructor() payable {
assert(block.basefee == 0); assert(block.basefee > 0);
} }
} }
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.31;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "CountLeadingZeros"
}
}
}
}
]
}
*/
/// The EIP-7939 test vectors:
/// https://eips.ethereum.org/EIPS/eip-7939#test-cases
contract CountLeadingZeros {
function clz(uint256 x) internal pure returns (uint256 r) {
assembly {
r := clz(x)
}
}
constructor() payable {
assert(
clz(0x000000000000000000000000000000000000000000000000000000000000000)
== 0x0000000000000000000000000000000000000000000000000000000000000100
);
assert(
clz(0x8000000000000000000000000000000000000000000000000000000000000000)
== 0x0000000000000000000000000000000000000000000000000000000000000000
);
assert(
clz(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
== 0x0000000000000000000000000000000000000000000000000000000000000000
);
assert(
clz(0x4000000000000000000000000000000000000000000000000000000000000000)
== 0x0000000000000000000000000000000000000000000000000000000000000001
);
assert(
clz(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
== 0x0000000000000000000000000000000000000000000000000000000000000001
);
assert(
clz(0x0000000000000000000000000000000000000000000000000000000000000001)
== 0x00000000000000000000000000000000000000000000000000000000000000ff
);
}
}
-1
View File
@@ -26,7 +26,6 @@ pragma solidity ^0.8;
contract GasLeft { contract GasLeft {
constructor() payable { constructor() payable {
assert(gasleft() > gasleft());
assert(gasleft() > 0 && gasleft() < 0xffffffffffffffff); assert(gasleft() > 0 && gasleft() < 0xffffffffffffffff);
} }
} }
+1 -1
View File
@@ -26,6 +26,6 @@ pragma solidity ^0.8;
contract GasLimit { contract GasLimit {
constructor() payable { constructor() payable {
assert(block.gaslimit == 2000000000000); assert(block.gaslimit > 0);
} }
} }
+1 -1
View File
@@ -26,6 +26,6 @@ pragma solidity ^0.8;
contract GasPrice { contract GasPrice {
constructor() payable { constructor() payable {
assert(tx.gasprice == 1000); assert(tx.gasprice > 1000);
} }
} }
+95
View File
@@ -65,6 +65,7 @@ test_spec!(shift_arithmetic_right, "SAR", "SAR.sol");
test_spec!(add_mod_mul_mod, "AddModMulModTester", "AddModMulMod.sol"); test_spec!(add_mod_mul_mod, "AddModMulModTester", "AddModMulMod.sol");
test_spec!(memory_bounds, "MemoryBounds", "MemoryBounds.sol"); test_spec!(memory_bounds, "MemoryBounds", "MemoryBounds.sol");
test_spec!(selfdestruct, "Selfdestruct", "Selfdestruct.sol"); test_spec!(selfdestruct, "Selfdestruct", "Selfdestruct.sol");
test_spec!(clz, "CountLeadingZeros", "CountLeadingZeros.sol");
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> { fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
vec![Instantiate { vec![Instantiate {
@@ -619,3 +620,97 @@ fn code_block_with_nested_object_stops() {
} }
.run(); .run();
} }
#[test]
fn sbrk_bounds_checks() {
let code = &build_yul(&[(
"poc.yul",
r#"object "Test" {
code {
return(0x4, 0xffffffff)
stop()
}
object "Test_deployed" {
code {
stop()
}
}
}"#,
)])
.unwrap()["poc.yul:Test"];
let results = Specs {
actions: vec![
Instantiate {
origin: TestAddress::Alice,
value: 0,
gas_limit: Some(GAS_LIMIT),
storage_deposit_limit: None,
code: Code::Bytes(code.to_vec()),
data: Default::default(),
salt: OptionalHex::default(),
},
VerifyCall(VerifyCallExpectation {
success: false,
..Default::default()
}),
],
differential: false,
..Default::default()
}
.run();
let CallResult::Instantiate { result, .. } = results.last().unwrap() else {
unreachable!()
};
assert!(
format!("{result:?}").contains("ContractTrapped"),
"not seeing a trap means the contract did not catch the OOB"
);
}
#[test]
fn invalid_opcode_works() {
let code = &build_yul(&[(
"invalid.yul",
r#"object "Test" {
code {
invalid()
}
object "Test_deployed" {
code {
invalid()
}
}
}"#,
)])
.unwrap()["invalid.yul:Test"];
let results = Specs {
actions: vec![
Instantiate {
origin: TestAddress::Alice,
value: 0,
gas_limit: Some(GAS_LIMIT),
storage_deposit_limit: None,
code: Code::Bytes(code.to_vec()),
data: Default::default(),
salt: OptionalHex::default(),
},
VerifyCall(VerifyCallExpectation {
success: false,
..Default::default()
}),
],
differential: false,
..Default::default()
}
.run();
let CallResult::Instantiate { result, .. } = results.last().unwrap() else {
unreachable!()
};
assert_eq!(result.weight_consumed, GAS_LIMIT);
}
+28
View File
@@ -14,6 +14,7 @@ fn set_rustc_link_flags() {
"lldELF", "lldELF",
"lldCommon", "lldCommon",
"lldMachO", "lldMachO",
"lldWasm",
"LLVMSupport", "LLVMSupport",
"LLVMLinker", "LLVMLinker",
"LLVMCore", "LLVMCore",
@@ -68,6 +69,33 @@ fn set_rustc_link_flags() {
"LLVMBitReader", "LLVMBitReader",
"LLVMRemarks", "LLVMRemarks",
"LLVMBitstreamReader", "LLVMBitstreamReader",
"LLVMTextAPI",
"LLVMDebugInfoDWARFLowLevel",
"LLVMDebugInfoGSYM",
"LLVMDebugInfoMSF",
"LLVMDebugInfoPDB",
"LLVMDebugInfoBTF",
"LLVMInterfaceStub",
"LLVMCGData",
"LLVMMIRParser",
"LLVMDWARFLinker",
"LLVMDWARFLinkerParallel",
"LLVMDWARFLinkerClassic",
"LLVMLibDriver",
"LLVMDlltoolDriver",
"LLVMTextAPIBinaryReader",
"LLVMCoverage",
"LLVMLineEditor",
"LLVMRISCVTargetMCA",
"LLVMRuntimeDyld",
"LLVMDWP",
"LLVMDWARFCFIChecker",
"LLVMDebugInfoLogicalView",
"LLVMMCA",
"LLVMipo",
"LLVMVectorize",
"LLVMSandboxIR",
"LLVMExtensions",
] { ] {
println!("cargo:rustc-link-lib=static={lib}"); println!("cargo:rustc-link-lib=static={lib}");
} }
+2 -2
View File
@@ -82,10 +82,10 @@ Obtain a compatible build for your host platform from the release section of thi
Build artifacts end up in the `./target-llvm/gnu/target-final/` directory by default. Build artifacts end up in the `./target-llvm/gnu/target-final/` directory by default.
The `gnu` directory depends on the supported archticture and will either be `gnu`, `musl` or `emscripten`. The `gnu` directory depends on the supported archticture and will either be `gnu`, `musl` or `emscripten`.
You now need to export the final target directory `$LLVM_SYS_181_PREFIX`: You now need to export the final target directory `$LLVM_SYS_211_PREFIX`:
```shell ```shell
export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final export LLVM_SYS_211_PREFIX=${PWD}/target-llvm/gnu/target-final
``` ```
If built with the `--enable-tests` option, test tools will be in the `./target-llvm/gnu/build-final/` directory, along with copies of the build artifacts. For all supported build options, run `revive-llvm build --help`. If built with the `--enable-tests` option, test tools will be in the `./target-llvm/gnu/build-final/` directory, along with copies of the build artifacts. For all supported build options, run `revive-llvm build --help`.
@@ -221,7 +221,6 @@ fn build_host(
"-DCOMPILER_RT_BUILD_MEMPROF='Off'", "-DCOMPILER_RT_BUILD_MEMPROF='Off'",
"-DCOMPILER_RT_BUILD_ORC='Off'", "-DCOMPILER_RT_BUILD_ORC='Off'",
"-DCOMPILER_RT_DEFAULT_TARGET_ARCH='aarch64'", "-DCOMPILER_RT_DEFAULT_TARGET_ARCH='aarch64'",
"-DCOMPILER_RT_DEFAULT_TARGET_ONLY='On'",
]) ])
.args(crate::platforms::shared::SHARED_BUILD_OPTS) .args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::shared_build_opts_ccache( .args(crate::platforms::shared::shared_build_opts_ccache(
@@ -219,7 +219,6 @@ fn build_host(
"-DCOMPILER_RT_BUILD_MEMPROF='Off'", "-DCOMPILER_RT_BUILD_MEMPROF='Off'",
"-DCOMPILER_RT_BUILD_ORC='Off'", "-DCOMPILER_RT_BUILD_ORC='Off'",
"-DCOMPILER_RT_DEFAULT_TARGET_ARCH='x86_64'", "-DCOMPILER_RT_DEFAULT_TARGET_ARCH='x86_64'",
"-DCOMPILER_RT_DEFAULT_TARGET_ONLY='On'",
"-DLIBCLANG_BUILD_STATIC='On'", "-DLIBCLANG_BUILD_STATIC='On'",
"-DBUILD_SHARED_LIBS='Off'", "-DBUILD_SHARED_LIBS='Off'",
]) ])
+1 -1
View File
@@ -38,7 +38,7 @@ pub const MUSL_SNAPSHOTS_URL: &str = "https://git.musl-libc.org/cgit/musl/snapsh
pub const EMSDK_SOURCE_URL: &str = "https://github.com/emscripten-core/emsdk.git"; pub const EMSDK_SOURCE_URL: &str = "https://github.com/emscripten-core/emsdk.git";
/// The emscripten SDK version. /// The emscripten SDK version.
pub const EMSDK_VERSION: &str = "4.0.9"; pub const EMSDK_VERSION: &str = "4.0.20";
/// The subprocess runner. /// The subprocess runner.
/// ///
@@ -8,7 +8,7 @@ use serde::Serialize;
/// inside of the LLVM build directory. This order is actually generated during the building. /// inside of the LLVM build directory. This order is actually generated during the building.
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Attribute { pub enum Attribute {
Unused = 0, // FirstEnumAttr = 1,
AllocAlign = 1, AllocAlign = 1,
AllocatedPointer = 2, AllocatedPointer = 2,
AlwaysInline = 3, AlwaysInline = 3,
@@ -16,92 +16,107 @@ pub enum Attribute {
Cold = 5, Cold = 5,
Convergent = 6, Convergent = 6,
CoroDestroyOnlyWhenComplete = 7, CoroDestroyOnlyWhenComplete = 7,
DeadOnUnwind = 8, CoroElideSafe = 8,
DisableSanitizerInstrumentation = 9, DeadOnReturn = 9,
FnRetThunkExtern = 10, DeadOnUnwind = 10,
Hot = 11, DisableSanitizerInstrumentation = 11,
ImmArg = 12, FnRetThunkExtern = 12,
InReg = 13, Hot = 13,
InlineHint = 14, HybridPatchable = 14,
JumpTable = 15, ImmArg = 15,
MinSize = 16, InReg = 16,
MustProgress = 17, InlineHint = 17,
Naked = 18, JumpTable = 18,
Nest = 19, MinSize = 19,
NoAlias = 20, MustProgress = 20,
NoBuiltin = 21, Naked = 21,
NoCallback = 22, Nest = 22,
NoCapture = 23, NoAlias = 23,
NoCfCheck = 24, NoBuiltin = 24,
NoDuplicate = 25, NoCallback = 25,
NoFree = 26, NoCfCheck = 26,
NoImplicitFloat = 27, NoDivergenceSource = 27,
NoInline = 28, NoDuplicate = 28,
NoMerge = 29, NoExt = 29,
NoProfile = 30, NoFree = 30,
NoRecurse = 31, NoImplicitFloat = 31,
NoRedZone = 32, NoInline = 32,
NoReturn = 33, NoMerge = 33,
NoSanitizeBounds = 34, NoProfile = 34,
NoSanitizeCoverage = 35, NoRecurse = 35,
NoSync = 36, NoRedZone = 36,
NoUndef = 37, NoReturn = 37,
NoUnwind = 38, NoSanitizeBounds = 38,
NonLazyBind = 39, NoSanitizeCoverage = 39,
NonNull = 40, NoSync = 40,
NullPointerIsValid = 41, NoUndef = 41,
OptForFuzzing = 42, NoUnwind = 42,
OptimizeForDebugging = 43, NonLazyBind = 43,
OptimizeForSize = 44, NonNull = 44,
OptimizeNone = 45, NullPointerIsValid = 45,
PresplitCoroutine = 46, OptForFuzzing = 46,
ReadNone = 47, OptimizeForDebugging = 47,
ReadOnly = 48, OptimizeForSize = 48,
Returned = 49, OptimizeNone = 49,
ReturnsTwice = 50, PresplitCoroutine = 50,
SExt = 51, ReadNone = 51,
SafeStack = 52, ReadOnly = 52,
SanitizeAddress = 53, Returned = 53,
SanitizeHWAddress = 54, ReturnsTwice = 54,
SanitizeMemTag = 55, SExt = 55,
SanitizeMemory = 56, SafeStack = 56,
SanitizeThread = 57, SanitizeAddress = 57,
ShadowCallStack = 58, SanitizeHWAddress = 58,
SkipProfile = 59, SanitizeMemTag = 59,
Speculatable = 60, SanitizeMemory = 60,
SpeculativeLoadHardening = 61, SanitizeNumericalStability = 61,
StackProtect = 62, SanitizeRealtime = 62,
StackProtectReq = 63, SanitizeRealtimeBlocking = 63,
StackProtectStrong = 64, SanitizeThread = 64,
StrictFP = 65, SanitizeType = 65,
SwiftAsync = 66, ShadowCallStack = 66,
SwiftError = 67, SkipProfile = 67,
SwiftSelf = 68, Speculatable = 68,
WillReturn = 69, SpeculativeLoadHardening = 69,
Writable = 70, StackProtect = 70,
WriteOnly = 71, StackProtectReq = 71,
ZExt = 72, StackProtectStrong = 72,
// LastEnumAttr = 72, StrictFP = 73,
// FirstTypeAttr = 73, SwiftAsync = 74,
ByRef = 73, SwiftError = 75,
ByVal = 74, SwiftSelf = 76,
ElementType = 75, WillReturn = 77,
InAlloca = 76, Writable = 78,
Preallocated = 77, WriteOnly = 79,
StructRet = 78, ZExt = 80,
// LastTypeAttr = 78, //LastEnumAttr = 80,
// FirstIntAttr = 79, //FirstTypeAttr = 81,
Alignment = 79, ByRef = 81,
AllocKind = 80, ByVal = 82,
AllocSize = 81, ElementType = 83,
Dereferenceable = 82, InAlloca = 84,
DereferenceableOrNull = 83, Preallocated = 85,
Memory = 84, StructRet = 86,
NoFPClass = 85, //LastTypeAttr = 86,
StackAlignment = 86, //FirstIntAttr = 87,
UWTable = 87, Alignment = 87,
VScaleRange = 88, AllocKind = 88,
// LastIntAttr = 88, AllocSize = 89,
Captures = 90,
Dereferenceable = 91,
DereferenceableOrNull = 92,
Memory = 93,
NoFPClass = 94,
StackAlignment = 95,
UWTable = 96,
VScaleRange = 97,
//LastIntAttr = 97,
//FirstConstantRangeAttr = 98,
Range = 98,
//LastConstantRangeAttr = 98,
//FirstConstantRangeListAttr = 99,
Initializes = 99,
//LastConstantRangeListAttr = 99,
} }
impl TryFrom<&str> for Attribute { impl TryFrom<&str> for Attribute {
@@ -14,6 +14,8 @@ pub struct Intrinsics<'ctx> {
pub byte_swap_word: FunctionDeclaration<'ctx>, pub byte_swap_word: FunctionDeclaration<'ctx>,
/// Performs endianness swaps on i160 values /// Performs endianness swaps on i160 values
pub byte_swap_eth_address: FunctionDeclaration<'ctx>, pub byte_swap_eth_address: FunctionDeclaration<'ctx>,
/// Counts leading zeroes.
pub count_leading_zeros: FunctionDeclaration<'ctx>,
} }
impl<'ctx> Intrinsics<'ctx> { impl<'ctx> Intrinsics<'ctx> {
@@ -26,6 +28,9 @@ impl<'ctx> Intrinsics<'ctx> {
/// The corresponding intrinsic function name. /// The corresponding intrinsic function name.
pub const FUNCTION_BYTE_SWAP_ETH_ADDRESS: &'static str = "llvm.bswap.i160"; pub const FUNCTION_BYTE_SWAP_ETH_ADDRESS: &'static str = "llvm.bswap.i160";
/// The corresponding intrinsic function name.
pub const FUNCTION_COUNT_LEADING_ZEROS: &'static str = "llvm.ctlz.i256";
/// A shortcut constructor. /// A shortcut constructor.
pub fn new( pub fn new(
llvm: &'ctx inkwell::context::Context, llvm: &'ctx inkwell::context::Context,
@@ -53,11 +58,18 @@ impl<'ctx> Intrinsics<'ctx> {
Self::FUNCTION_BYTE_SWAP_ETH_ADDRESS, Self::FUNCTION_BYTE_SWAP_ETH_ADDRESS,
address_type.fn_type(&[address_type.as_basic_type_enum().into()], false), address_type.fn_type(&[address_type.as_basic_type_enum().into()], false),
); );
let count_leading_zeros = Self::declare(
llvm,
module,
Self::FUNCTION_COUNT_LEADING_ZEROS,
word_type.fn_type(&[word_type.into(), llvm.bool_type().into()], false),
);
Self { Self {
trap, trap,
byte_swap_word, byte_swap_word,
byte_swap_eth_address, byte_swap_eth_address,
count_leading_zeros,
} }
} }
@@ -85,12 +97,15 @@ impl<'ctx> Intrinsics<'ctx> {
let word_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32); let word_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32);
match name { match name {
name if name == Self::FUNCTION_BYTE_SWAP_WORD => vec![word_type.as_basic_type_enum()], _ if name == Self::FUNCTION_BYTE_SWAP_WORD => vec![word_type.as_basic_type_enum()],
name if name == Self::FUNCTION_BYTE_SWAP_ETH_ADDRESS => { _ if name == Self::FUNCTION_BYTE_SWAP_ETH_ADDRESS => {
vec![llvm vec![llvm
.custom_width_int_type(revive_common::BIT_LENGTH_ETH_ADDRESS as u32) .custom_width_int_type(revive_common::BIT_LENGTH_ETH_ADDRESS as u32)
.as_basic_type_enum()] .as_basic_type_enum()]
} }
_ if name == Self::FUNCTION_COUNT_LEADING_ZEROS => {
vec![word_type.as_basic_type_enum()]
}
_ => vec![], _ => vec![],
} }
} }
@@ -51,11 +51,11 @@ impl RuntimeFunction for WordToPointer {
)?; )?;
let block_continue = context.append_basic_block("offset_pointer_ok"); let block_continue = context.append_basic_block("offset_pointer_ok");
let block_trap = context.append_basic_block("offset_pointer_overflow"); let block_invalid = context.append_basic_block("offset_pointer_overflow");
context.build_conditional_branch(is_overflow, block_trap, block_continue)?; context.build_conditional_branch(is_overflow, block_invalid, block_continue)?;
context.set_basic_block(block_trap); context.set_basic_block(block_invalid);
context.build_call(context.intrinsics().trap, &[], "invalid_trap"); context.build_runtime_call(revive_runtime_api::polkavm_imports::INVALID, &[]);
context.build_unreachable(); context.build_unreachable();
context.set_basic_block(block_continue); context.set_basic_block(block_continue);
@@ -77,6 +77,20 @@ impl RuntimeFunction for Sbrk {
context.build_unreachable(); context.build_unreachable();
context.set_basic_block(offset_in_bounds_block); context.set_basic_block(offset_in_bounds_block);
let size_in_bounds_block = context.append_basic_block("size_in_bounds");
let is_size_out_of_bounds = context.builder().build_int_compare(
inkwell::IntPredicate::UGT,
size,
context.heap_size(),
"size_in_bounds",
)?;
context.build_conditional_branch(
is_size_out_of_bounds,
trap_block,
size_in_bounds_block,
)?;
context.set_basic_block(size_in_bounds_block);
let mask = context let mask = context
.xlen_type() .xlen_type()
.const_int(BYTE_LENGTH_WORD as u64 - 1, false); .const_int(BYTE_LENGTH_WORD as u64 - 1, false);
@@ -88,20 +102,20 @@ impl RuntimeFunction for Sbrk {
context.builder().build_not(mask, "mask_not")?, context.builder().build_not(mask, "mask_not")?,
"memory_size", "memory_size",
)?; )?;
let size_in_bounds_block = context.append_basic_block("size_in_bounds"); let total_size_in_bounds_block = context.append_basic_block("total_size_in_bounds");
let is_size_out_of_bounds = context.builder().build_int_compare( let is_total_size_out_of_bounds = context.builder().build_int_compare(
inkwell::IntPredicate::UGT, inkwell::IntPredicate::UGT,
memory_size, memory_size,
context.heap_size(), context.heap_size(),
"size_out_of_bounds", "size_out_of_bounds",
)?; )?;
context.build_conditional_branch( context.build_conditional_branch(
is_size_out_of_bounds, is_total_size_out_of_bounds,
trap_block, trap_block,
size_in_bounds_block, total_size_in_bounds_block,
)?; )?;
context.set_basic_block(size_in_bounds_block); context.set_basic_block(total_size_in_bounds_block);
let new_size_block = context.append_basic_block("new_size"); let new_size_block = context.append_basic_block("new_size");
let is_new_size = context.builder().build_int_compare( let is_new_size = context.builder().build_int_compare(
inkwell::IntPredicate::UGT, inkwell::IntPredicate::UGT,
+5 -12
View File
@@ -838,8 +838,7 @@ impl<'ctx> Context<'ctx> {
.builder() .builder()
.build_call(intrinsic, &[value.into()], "call_byte_swap")? .build_call(intrinsic, &[value.into()], "call_byte_swap")?
.try_as_basic_value() .try_as_basic_value()
.left() .unwrap_basic())
.unwrap())
} }
/// Builds a GEP instruction. /// Builds a GEP instruction.
@@ -912,7 +911,7 @@ impl<'ctx> Context<'ctx> {
) )
.unwrap() .unwrap()
.try_as_basic_value() .try_as_basic_value()
.left() .basic()
} }
/// Builds a call to the runtime API `import`, where `import` is a "getter" API. /// Builds a call to the runtime API `import`, where `import` is a "getter" API.
@@ -950,7 +949,7 @@ impl<'ctx> Context<'ctx> {
) )
.unwrap(); .unwrap();
self.modify_call_site_value(arguments, call_site_value, function); self.modify_call_site_value(arguments, call_site_value, function);
call_site_value.try_as_basic_value().left() call_site_value.try_as_basic_value().basic()
} }
/// Sets the alignment to `1`, since all non-stack memory pages have such alignment. /// Sets the alignment to `1`, since all non-stack memory pages have such alignment.
@@ -1082,13 +1081,7 @@ impl<'ctx> Context<'ctx> {
Ok(call_site_value Ok(call_site_value
.try_as_basic_value() .try_as_basic_value()
.left() .unwrap_basic()
.unwrap_or_else(|| {
panic!(
"revive runtime function {} should return a value",
<PolkaVMSbrkFunction as RuntimeFunction>::NAME,
)
})
.into_pointer_value()) .into_pointer_value())
} }
@@ -1277,7 +1270,7 @@ impl<'ctx> Context<'ctx> {
call_site_value.add_attribute( call_site_value.add_attribute(
inkwell::attributes::AttributeLoc::Param(index as u32), inkwell::attributes::AttributeLoc::Param(index as u32),
self.llvm self.llvm
.create_enum_attribute(Attribute::NoCapture as u32, 0), .create_enum_attribute(Attribute::Captures as u32, 0), // captures(none)
); );
call_site_value.add_attribute( call_site_value.add_attribute(
inkwell::attributes::AttributeLoc::Param(index as u32), inkwell::attributes::AttributeLoc::Param(index as u32),
@@ -261,3 +261,20 @@ pub fn byte<'ctx>(
Ok(byte.as_basic_value_enum()) Ok(byte.as_basic_value_enum())
} }
/// Translates the CLZ instruction.
pub fn count_leading_zeros<'ctx>(
context: &mut Context<'ctx>,
value: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> {
Ok(context
.builder()
.build_call(
context.intrinsics().count_leading_zeros.function_value(),
&[value.into(), context.bool_const(false).into()],
"clz",
)?
.try_as_basic_value()
.basic()
.expect("the llvm.ctlz should return a value"))
}
@@ -52,12 +52,14 @@ pub fn stop(context: &mut Context) -> anyhow::Result<()> {
/// Translates the `invalid` instruction. /// Translates the `invalid` instruction.
/// Burns all gas using an out-of-bounds memory store, causing a panic. /// Burns all gas using an out-of-bounds memory store, causing a panic.
pub fn invalid(context: &mut Context) -> anyhow::Result<()> { pub fn invalid(context: &mut Context) -> anyhow::Result<()> {
crate::polkavm::evm::memory::store( let invalid_block = context.append_basic_block("explicit_invalid");
context, context.build_unconditional_branch(invalid_block);
context.word_type().const_all_ones(), context.set_basic_block(invalid_block);
context.word_const(0), context.build_runtime_call(revive_runtime_api::polkavm_imports::INVALID, &[]);
)?; context.build_unreachable();
context.build_call(context.intrinsics().trap, &[], "invalid_trap");
context.set_basic_block(context.append_basic_block("dead_code"));
Ok(()) Ok(())
} }
+1 -1
View File
@@ -42,7 +42,7 @@ mimalloc = { version = "0.1.46", default-features = false }
[target.'cfg(target_os = "emscripten")'.dependencies] [target.'cfg(target_os = "emscripten")'.dependencies]
libc = { workspace = true } libc = { workspace = true }
inkwell = { workspace = true, features = ["target-riscv", "llvm18-1-no-llvm-linking"]} inkwell = { workspace = true, features = ["target-riscv", "llvm21-1-no-llvm-linking"]}
[build-dependencies] [build-dependencies]
git2 = { workspace = true, default-features = false } git2 = { workspace = true, default-features = false }
+1 -1
View File
@@ -23,7 +23,7 @@ pub mod version;
pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0); pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0);
/// The last supported version of `solc`. /// The last supported version of `solc`.
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 30); pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 31);
/// The Solidity compiler. /// The Solidity compiler.
pub trait Compiler { pub trait Compiler {
+10 -5
View File
@@ -59,7 +59,7 @@ pub const CHARLIE: H160 = H160([3u8; 20]);
/// Default gas limit /// Default gas limit
pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000_000, 3 * 1024 * 1024 * 1024); pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000_000, 3 * 1024 * 1024 * 1024);
/// Default deposit limit /// Default deposit limit
pub const DEPOSIT_LIMIT: Balance = 10_000_000; pub const DEPOSIT_LIMIT: Balance = 100_000_000_000;
/// The native to ETH balance factor. /// The native to ETH balance factor.
pub const ETH_RATIO: Balance = 1_000_000; pub const ETH_RATIO: Balance = 1_000_000;
@@ -97,14 +97,19 @@ impl ExtBuilder {
.unwrap(); .unwrap();
let mut ext = sp_io::TestExternalities::new(t); let mut ext = sp_io::TestExternalities::new(t);
let checking_account = Pallet::<Runtime>::account_id();
ext.register_extension(KeystoreExt::new(MemoryKeystore::new())); ext.register_extension(KeystoreExt::new(MemoryKeystore::new()));
ext.execute_with(|| { ext.execute_with(|| {
let _ = <Runtime as Config>::Currency::deposit_creating( let _ = <Runtime as Config>::Currency::deposit_creating(
&Pallet::<Runtime>::account_id(), &checking_account,
<Runtime as Config>::Currency::minimum_balance(), 1_000_000_000_000,
); );
System::set_block_number(1); System::set_block_number(1);
assert_ok!(Pallet::<Runtime>::map_account(RuntimeOrigin::signed(
checking_account
)));
}); });
ext ext
@@ -115,7 +120,7 @@ impl ExtBuilder {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VerifyCallExpectation { pub struct VerifyCallExpectation {
/// When provided, the expected gas consumed /// When provided, the expected gas consumed
pub gas_consumed: Option<Weight>, pub gas_consumed: Option<u128>,
/// When provided, the expected output /// When provided, the expected output
#[serde(default, with = "hex")] #[serde(default, with = "hex")]
pub output: OptionalHex<Vec<u8>>, pub output: OptionalHex<Vec<u8>>,
@@ -238,7 +243,7 @@ impl CallResult {
} }
/// Get the gas consumed by the call /// Get the gas consumed by the call
fn gas_consumed(&self) -> Weight { fn gas_consumed(&self) -> u128 {
match self { match self {
Self::Exec { result, .. } => result.gas_consumed, Self::Exec { result, .. } => result.gas_consumed,
Self::Instantiate { result, .. } => result.gas_consumed, Self::Instantiate { result, .. } => result.gas_consumed,
+2 -1
View File
@@ -2,7 +2,7 @@ use frame_support::{runtime, traits::FindAuthor, weights::constants::WEIGHT_REF_
use pallet_revive::AccountId32Mapper; use pallet_revive::AccountId32Mapper;
use polkadot_sdk::*; use polkadot_sdk::*;
use polkadot_sdk::{ use polkadot_sdk::{
polkadot_sdk_frame::{log, runtime::prelude::*}, polkadot_sdk_frame::runtime::prelude::*,
sp_runtime::{AccountId32, Perbill}, sp_runtime::{AccountId32, Perbill},
}; };
@@ -72,6 +72,7 @@ parameter_types! {
#[derive_impl(pallet_revive::config_preludes::TestDefaultConfig)] #[derive_impl(pallet_revive::config_preludes::TestDefaultConfig)]
impl pallet_revive::Config for Runtime { impl pallet_revive::Config for Runtime {
type Balance = Balance;
type Time = Timestamp; type Time = Timestamp;
type Currency = Balances; type Currency = Balances;
type DepositPerByte = DepositPerByte; type DepositPerByte = DepositPerByte;
+14 -9
View File
@@ -1,6 +1,6 @@
use std::{str::FromStr, time::Instant}; use std::{str::FromStr, time::Instant};
use polkadot_sdk::pallet_revive::Pallet; use polkadot_sdk::pallet_revive::{ExecConfig, Pallet, TransactionLimits};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::*; use crate::*;
@@ -210,9 +210,9 @@ impl Default for Specs {
Self { Self {
differential: false, differential: false,
balances: vec![ balances: vec![
(ALICE, 1_000_000_000), (ALICE, 1_000_000_000_000),
(BOB, 1_000_000_000), (BOB, 1_000_000_000_000),
(CHARLIE, 1_000_000_000), (CHARLIE, 1_000_000_000_000),
], ],
actions: Default::default(), actions: Default::default(),
} }
@@ -447,12 +447,14 @@ impl Specs {
let result = Contracts::bare_instantiate( let result = Contracts::bare_instantiate(
origin, origin,
value.into(), value.into(),
gas_limit.unwrap_or(GAS_LIMIT), TransactionLimits::WeightAndDeposit {
storage_deposit_limit.unwrap_or(DEPOSIT_LIMIT).into(), weight_limit: gas_limit.unwrap_or(GAS_LIMIT),
deposit_limit: storage_deposit_limit.unwrap_or(DEPOSIT_LIMIT),
},
code, code,
data, data,
salt.0, salt.0,
pallet_revive::BumpNonce::No, ExecConfig::new_substrate_tx(),
); );
results.push(CallResult::Instantiate { results.push(CallResult::Instantiate {
result, result,
@@ -486,9 +488,12 @@ impl Specs {
RuntimeOrigin::signed(origin.to_account_id(&results)), RuntimeOrigin::signed(origin.to_account_id(&results)),
dest.to_eth_addr(&results), dest.to_eth_addr(&results),
value.into(), value.into(),
gas_limit.unwrap_or(GAS_LIMIT), TransactionLimits::WeightAndDeposit {
storage_deposit_limit.unwrap_or(DEPOSIT_LIMIT).into(), weight_limit: gas_limit.unwrap_or(GAS_LIMIT),
deposit_limit: storage_deposit_limit.unwrap_or(DEPOSIT_LIMIT),
},
data, data,
ExecConfig::new_substrate_tx(),
); );
results.push(CallResult::Exec { results.push(CallResult::Exec {
result, result,
+1 -1
View File
@@ -9,7 +9,7 @@ description = "Implements the low level runtime API bindings with pallet contrac
[dependencies] [dependencies]
anyhow = { workspace = true } anyhow = { workspace = true }
inkwell = { workspace = true, features = ["target-riscv", "no-libffi-linking", "llvm18-1"] } inkwell = { workspace = true, features = ["target-riscv", "no-libffi-linking", "llvm21-1"] }
revive-common = { workspace = true } revive-common = { workspace = true }
+2
View File
@@ -69,6 +69,8 @@ POLKAVM_IMPORT(uint64_t, code_size, uint32_t)
POLKAVM_IMPORT(void, code_hash, uint32_t, uint32_t) POLKAVM_IMPORT(void, code_hash, uint32_t, uint32_t)
POLKAVM_IMPORT(void, consume_all_gas)
POLKAVM_IMPORT(uint32_t, delegate_call, uint64_t, uint64_t, uint64_t, uint32_t, uint64_t, uint64_t) POLKAVM_IMPORT(uint32_t, delegate_call, uint64_t, uint64_t, uint64_t, uint32_t, uint64_t, uint64_t)
POLKAVM_IMPORT(void, deposit_event, uint32_t, uint32_t, uint32_t, uint32_t) POLKAVM_IMPORT(void, deposit_event, uint32_t, uint32_t, uint32_t, uint32_t)
+4 -1
View File
@@ -48,6 +48,8 @@ pub static HASH_KECCAK_256: &str = "hash_keccak_256";
pub static INSTANTIATE: &str = "instantiate"; pub static INSTANTIATE: &str = "instantiate";
pub static INVALID: &str = "consume_all_gas";
pub static NOW: &str = "now"; pub static NOW: &str = "now";
pub static ORIGIN: &str = "origin"; pub static ORIGIN: &str = "origin";
@@ -70,7 +72,7 @@ pub static VALUE_TRANSFERRED: &str = "value_transferred";
/// All imported runtime API symbols. /// All imported runtime API symbols.
/// Useful for configuring common attributes and linkage. /// Useful for configuring common attributes and linkage.
pub static IMPORTS: [&str; 33] = [ pub static IMPORTS: [&str; 34] = [
ADDRESS, ADDRESS,
BALANCE, BALANCE,
BALANCE_OF, BALANCE_OF,
@@ -94,6 +96,7 @@ pub static IMPORTS: [&str; 33] = [
GET_STORAGE, GET_STORAGE,
HASH_KECCAK_256, HASH_KECCAK_256,
INSTANTIATE, INSTANTIATE,
INVALID,
NOW, NOW,
ORIGIN, ORIGIN,
REF_TIME_LEFT, REF_TIME_LEFT,
+1 -1
View File
@@ -7,7 +7,7 @@ repository.workspace = true
description = "revive compiler stdlib components" description = "revive compiler stdlib components"
[dependencies] [dependencies]
inkwell = { workspace = true, features = ["target-riscv", "no-libffi-linking", "llvm18-1"] } inkwell = { workspace = true, features = ["target-riscv", "no-libffi-linking", "llvm21-1"] }
[build-dependencies] [build-dependencies]
revive-build-utils = { workspace = true } revive-build-utils = { workspace = true }
@@ -348,6 +348,14 @@ impl FunctionCall {
) )
.map(Some) .map(Some)
} }
Name::Clz => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
revive_llvm_context::polkavm_evm_bitwise::count_leading_zeros(
context,
arguments[0].into_int_value(),
)
.map(Some)
}
Name::Byte => { Name::Byte => {
let arguments = self.pop_arguments_llvm::<2>(context)?; let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_bitwise::byte( revive_llvm_context::polkavm_evm_bitwise::byte(
@@ -54,6 +54,8 @@ pub enum Name {
Shr, Shr,
/// signed arithmetic shift right `y` by `x` bits /// signed arithmetic shift right `y` by `x` bits
Sar, Sar,
/// number of leading zero bits of x, 256 if x == 0
Clz,
/// `n`th byte of `x`, where the most significant byte is the `0`th byte /// `n`th byte of `x`, where the most significant byte is the `0`th byte
Byte, Byte,
/// discard value x /// discard value x
@@ -270,6 +272,7 @@ impl From<&str> for Name {
"shl" => Self::Shl, "shl" => Self::Shl,
"shr" => Self::Shr, "shr" => Self::Shr,
"sar" => Self::Sar, "sar" => Self::Sar,
"clz" => Self::Clz,
"byte" => Self::Byte, "byte" => Self::Byte,
"pop" => Self::Pop, "pop" => Self::Pop,
@@ -393,6 +396,7 @@ impl fmt::Display for Name {
Self::Shl => "shl", Self::Shl => "shl",
Self::Shr => "shr", Self::Shr => "shr",
Self::Sar => "sar", Self::Sar => "sar",
Self::Clz => "clz",
Self::Byte => "byte", Self::Byte => "byte",
Self::Pop => "pop", Self::Pop => "pop",
+1 -1
View File
@@ -36,7 +36,7 @@
const path_to_root = ""; const path_to_root = "";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-756a6899.js"; window.path_to_searchindex_js = "searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script> <script src="toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = ""; const path_to_root = "";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-756a6899.js"; window.path_to_searchindex_js = "searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script> <script src="toc-6f3f265e.js"></script>
+2 -2
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
@@ -205,7 +205,7 @@
<p>Unlike with the EVM, where heap memory usage is gas metered, our heap size is static (the size is user controllable via a setting flag). The compiler emits bound checks to prevent overflows.</p> <p>Unlike with the EVM, where heap memory usage is gas metered, our heap size is static (the size is user controllable via a setting flag). The compiler emits bound checks to prevent overflows.</p>
<h2 id="the-llvm-dependency"><a class="header" href="#the-llvm-dependency">The LLVM dependency</a></h2> <h2 id="the-llvm-dependency"><a class="header" href="#the-llvm-dependency">The LLVM dependency</a></h2>
<p>LLVM is a special non Rust dependency. We interface its builder interface via the <a href="https://crates.io/crates/inkwell">inkwell</a> wrapper crate.</p> <p>LLVM is a special non Rust dependency. We interface its builder interface via the <a href="https://crates.io/crates/inkwell">inkwell</a> wrapper crate.</p>
<p>We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM rv64e target and always leave assertions on. Furthermore, we need cross builds because <code>resolc</code> itself targets emscripten and musl. The <a href="https://crates.io/crates/revive-llvm-builder">revive-llvm-builer</a> functions as a cross-platform build script and is used to build and release the LLVM dependency.</p> <p>We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM <code>rv64emacb</code> target and always leave assertions on. Furthermore, we need cross builds because <code>resolc</code> itself targets emscripten and musl. The <a href="https://crates.io/crates/revive-llvm-builder">revive-llvm-builer</a> functions as a cross-platform build script and is used to build and release the LLVM dependency.</p>
<p>We also maintain the <a href="https://crates.io/crates/lld-sys">lld-sys crate</a> for interfacing with <code>LLD</code>. The LLVM linker is used during the compilation process, but we dont want to distribute another binary.</p> <p>We also maintain the <a href="https://crates.io/crates/lld-sys">lld-sys crate</a> for interfacing with <code>LLD</code>. The LLVM linker is used during the compilation process, but we dont want to distribute another binary.</p>
<h2 id="custom-optimizations"><a class="header" href="#custom-optimizations">Custom optimizations</a></h2> <h2 id="custom-optimizations"><a class="header" href="#custom-optimizations">Custom optimizations</a></h2>
<p>At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither <code>solc</code> nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, <code>solc</code> optimizes for EVM gas and a target machine orthogonal to our target (BE 256-bit stack machine EVM vs. 64-bit LE RISC architecture PVM). We have started working on an additional IR layer between Yul and LLVM to capture missed optimization opportunities, though.</p> <p>At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither <code>solc</code> nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, <code>solc</code> optimizes for EVM gas and a target machine orthogonal to our target (BE 256-bit stack machine EVM vs. 64-bit LE RISC architecture PVM). We have started working on an additional IR layer between Yul and LLVM to capture missed optimization opportunities, though.</p>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = ""; const path_to_root = "";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-756a6899.js"; window.path_to_searchindex_js = "searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script> <script src="toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = ""; const path_to_root = "";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-756a6899.js"; window.path_to_searchindex_js = "searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script> <script src="toc-6f3f265e.js"></script>
+4 -4
View File
@@ -36,7 +36,7 @@
const path_to_root = ""; const path_to_root = "";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-756a6899.js"; window.path_to_searchindex_js = "searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script> <script src="toc-6f3f265e.js"></script>
@@ -235,14 +235,14 @@ Please find our <a href="https://github.com/paritytech/revive/releases">binary r
<li><code>s</code>: Optimize for code size.</li> <li><code>s</code>: Optimize for code size.</li>
<li><code>z</code>: Aggressively optimize for code size.</li> <li><code>z</code>: Aggressively optimize for code size.</li>
</ul> </ul>
<p>By default, <code>-O3</code> is applied.</p> <p>By default, <code>-Oz</code> is applied.</p>
<h3 id="stack-size"><a class="header" href="#stack-size">Stack size</a></h3> <h3 id="stack-size"><a class="header" href="#stack-size">Stack size</a></h3>
<pre><code class="language-bash">--stack-size &lt;STACK_SIZE&gt; <pre><code class="language-bash">--stack-size &lt;STACK_SIZE&gt;
</code></pre> </code></pre>
<p>PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use.</p> <p>PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use.</p>
<p>You are incentivized to keep this value as small as possible:</p> <p>You are incentivized to keep this value as small as possible:</p>
<ol> <ol>
<li>Increasing the stack size will increase startup costs.</li> <li>Increasing the stack size will increase gas costs due to increased startup costs.</li>
<li>The stack size contributes to the total memory size a contract can use, which includes the contracts code size.</li> <li>The stack size contributes to the total memory size a contract can use, which includes the contracts code size.</li>
</ol> </ol>
<p>Default value: 32768</p> <p>Default value: 32768</p>
@@ -539,7 +539,7 @@ Thus, <code>revive</code> is able to supply the expected code hash and construct
<p>Unlike with the EVM, where heap memory usage is gas metered, our heap size is static (the size is user controllable via a setting flag). The compiler emits bound checks to prevent overflows.</p> <p>Unlike with the EVM, where heap memory usage is gas metered, our heap size is static (the size is user controllable via a setting flag). The compiler emits bound checks to prevent overflows.</p>
<h2 id="the-llvm-dependency"><a class="header" href="#the-llvm-dependency">The LLVM dependency</a></h2> <h2 id="the-llvm-dependency"><a class="header" href="#the-llvm-dependency">The LLVM dependency</a></h2>
<p>LLVM is a special non Rust dependency. We interface its builder interface via the <a href="https://crates.io/crates/inkwell">inkwell</a> wrapper crate.</p> <p>LLVM is a special non Rust dependency. We interface its builder interface via the <a href="https://crates.io/crates/inkwell">inkwell</a> wrapper crate.</p>
<p>We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM rv64e target and always leave assertions on. Furthermore, we need cross builds because <code>resolc</code> itself targets emscripten and musl. The <a href="https://crates.io/crates/revive-llvm-builder">revive-llvm-builer</a> functions as a cross-platform build script and is used to build and release the LLVM dependency.</p> <p>We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM <code>rv64emacb</code> target and always leave assertions on. Furthermore, we need cross builds because <code>resolc</code> itself targets emscripten and musl. The <a href="https://crates.io/crates/revive-llvm-builder">revive-llvm-builer</a> functions as a cross-platform build script and is used to build and release the LLVM dependency.</p>
<p>We also maintain the <a href="https://crates.io/crates/lld-sys">lld-sys crate</a> for interfacing with <code>LLD</code>. The LLVM linker is used during the compilation process, but we dont want to distribute another binary.</p> <p>We also maintain the <a href="https://crates.io/crates/lld-sys">lld-sys crate</a> for interfacing with <code>LLD</code>. The LLVM linker is used during the compilation process, but we dont want to distribute another binary.</p>
<h2 id="custom-optimizations"><a class="header" href="#custom-optimizations">Custom optimizations</a></h2> <h2 id="custom-optimizations"><a class="header" href="#custom-optimizations">Custom optimizations</a></h2>
<p>At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither <code>solc</code> nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, <code>solc</code> optimizes for EVM gas and a target machine orthogonal to our target (BE 256-bit stack machine EVM vs. 64-bit LE RISC architecture PVM). We have started working on an additional IR layer between Yul and LLVM to capture missed optimization opportunities, though.</p> <p>At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither <code>solc</code> nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, <code>solc</code> optimizes for EVM gas and a target machine orthogonal to our target (BE 256-bit stack machine EVM vs. 64-bit LE RISC architecture PVM). We have started working on an additional IR layer between Yul and LLVM to capture missed optimization opportunities, though.</p>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = ""; const path_to_root = "";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-756a6899.js"; window.path_to_searchindex_js = "searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script> <script src="toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = ""; const path_to_root = "";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-756a6899.js"; window.path_to_searchindex_js = "searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script> <script src="toc-6f3f265e.js"></script>
+1 -1
View File
@@ -437,7 +437,7 @@ window.search = window.search || {};
if (yes) { if (yes) {
loadSearchScript( loadSearchScript(
window.path_to_searchindex_js || window.path_to_searchindex_js ||
path_to_root + 'searchindex-756a6899.js', path_to_root + 'searchindex-82723808.js',
'mdbook-search-index'); 'mdbook-search-index');
search_wrap.classList.remove('hidden'); search_wrap.classList.remove('hidden');
searchicon.setAttribute('aria-expanded', 'true'); searchicon.setAttribute('aria-expanded', 'true');
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = ""; const path_to_root = "";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-756a6899.js"; window.path_to_searchindex_js = "searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script> <script src="toc-6f3f265e.js"></script>
+3 -3
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
@@ -193,14 +193,14 @@
<li><code>s</code>: Optimize for code size.</li> <li><code>s</code>: Optimize for code size.</li>
<li><code>z</code>: Aggressively optimize for code size.</li> <li><code>z</code>: Aggressively optimize for code size.</li>
</ul> </ul>
<p>By default, <code>-O3</code> is applied.</p> <p>By default, <code>-Oz</code> is applied.</p>
<h3 id="stack-size"><a class="header" href="#stack-size">Stack size</a></h3> <h3 id="stack-size"><a class="header" href="#stack-size">Stack size</a></h3>
<pre><code class="language-bash">--stack-size &lt;STACK_SIZE&gt; <pre><code class="language-bash">--stack-size &lt;STACK_SIZE&gt;
</code></pre> </code></pre>
<p>PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use.</p> <p>PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use.</p>
<p>You are incentivized to keep this value as small as possible:</p> <p>You are incentivized to keep this value as small as possible:</p>
<ol> <ol>
<li>Increasing the stack size will increase startup costs.</li> <li>Increasing the stack size will increase gas costs due to increased startup costs.</li>
<li>The stack size contributes to the total memory size a contract can use, which includes the contracts code size.</li> <li>The stack size contributes to the total memory size a contract can use, which includes the contracts code size.</li>
</ol> </ol>
<p>Default value: 32768</p> <p>Default value: 32768</p>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../"; const path_to_root = "../";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-756a6899.js"; window.path_to_searchindex_js = "../searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script> <script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = ""; const path_to_root = "";
const default_light_theme = "light"; const default_light_theme = "light";
const default_dark_theme = "navy"; const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-756a6899.js"; window.path_to_searchindex_js = "searchindex-82723808.js";
</script> </script>
<!-- Start loading toc.js asap --> <!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script> <script src="toc-6f3f265e.js"></script>
+1 -1
View File
@@ -3,7 +3,7 @@ const path = require("path");
const { minify } = require("terser"); const { minify } = require("terser");
const SOLJSON_URI = const SOLJSON_URI =
"https://binaries.soliditylang.org/wasm/soljson-v0.8.30+commit.73712a01.js"; "https://binaries.soliditylang.org/wasm/soljson-v0.8.31+commit.fd3a2265.js";
const RESOLC_WASM_URI = const RESOLC_WASM_URI =
process.env.RELEASE_RESOLC_WASM_URI || "http://127.0.0.1:8080/resolc.wasm"; process.env.RELEASE_RESOLC_WASM_URI || "http://127.0.0.1:8080/resolc.wasm";
const RESOLC_WASM_TARGET_DIR = path.join( const RESOLC_WASM_TARGET_DIR = path.join(
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "revive", "name": "revive",
"private": true, "private": true,
"dependencies": { "dependencies": {
"solc": ">=0.8.0 <=0.8.30" "solc": ">=0.8.0 <=0.8.31"
}, },
"scripts": { "scripts": {
"example:web": "http-server ./examples/web/", "example:web": "http-server ./examples/web/",
+1 -1
View File
@@ -34,6 +34,6 @@
"commander": "^13.1.0", "commander": "^13.1.0",
"package-json": "^10.0.1", "package-json": "^10.0.1",
"resolve-pkg": "^2.0.0", "resolve-pkg": "^2.0.0",
"solc": ">=0.8.0 <=0.8.30" "solc": ">=0.8.0 <=0.8.31"
} }
} }
+1 -1
Submodule llvm updated: 3b5b5c1ec4...f68f64eb81
+7 -2
View File
@@ -18,7 +18,7 @@
"js/emscripten": { "js/emscripten": {
"name": "revive", "name": "revive",
"dependencies": { "dependencies": {
"solc": ">=0.8.0 <=0.8.30" "solc": ">=0.8.0 <=0.8.31"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.49.1", "@playwright/test": "^1.49.1",
@@ -38,7 +38,7 @@
"commander": "^13.1.0", "commander": "^13.1.0",
"package-json": "^10.0.1", "package-json": "^10.0.1",
"resolve-pkg": "^2.0.0", "resolve-pkg": "^2.0.0",
"solc": ">=0.8.0 <=0.8.30" "solc": ">=0.8.0 <=0.8.31"
}, },
"bin": { "bin": {
"resolc": "dist/bin.js" "resolc": "dist/bin.js"
@@ -1585,6 +1585,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz",
"integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==", "integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.32.1", "@typescript-eslint/scope-manager": "8.32.1",
"@typescript-eslint/types": "8.32.1", "@typescript-eslint/types": "8.32.1",
@@ -1752,6 +1753,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -2361,6 +2363,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz",
"integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==", "integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
@@ -2519,6 +2522,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@ethersproject/abi": "5.8.0", "@ethersproject/abi": "5.8.0",
"@ethersproject/abstract-provider": "5.8.0", "@ethersproject/abstract-provider": "5.8.0",
@@ -4393,6 +4397,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"