The revive compiler documentation (#424)

This PR adds comprehensive project documentation in the form of an
mdBook.

---------

Signed-off-by: xermicus <cyrill@parity.io>
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Co-authored-by: LJ <81748770+elle-j@users.noreply.github.com>
Co-authored-by: PG Herveou <pgherveou@gmail.com>
This commit is contained in:
authored and GitHub committed 2025-12-01 14:58:02 +01:00
1 parent 94b14b079b
commit e7e40a0ded
87 files changed
+14012 -43

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
# Compiler architecture and internals
`revive` relies on `solc`, the [Ethereum Solidity compiler](https://github.com/argotorg/solidity), as the Solidity frontend to process smart contracts written in Solidity. [LLVM](https://github.com/llvm/llvm-project), a popular and powerful compiler framework, is used as the compiler backend and does the heavy lifting in terms of optimizitations and RISC-V code generation.
`revive` mainly takes care of lowering the Yul intermediate representation (IR) produced by `solc` to LLVM IR. This approach provides a good balance between maintaining a high level of Ethereum compatibility, good contract performance and feasible engineering efforts.
## `resolc`
`resolc` is the overarching compiler driver library and binary.
When compiling a Solidity source file with `resolc`, the following steps happen under the hood:
1. `solc` is used to lower the Solidity source code into [YUL intermediate representation](https://docs.soliditylang.org/en/latest/yul.html).
2. `revive` lowers the YUL IR into LLVM IR.
3. LLVM optimizes the code and emits a RISC-V ELF shared object (through LLD).
4. The [PolkaVM](https://github.com/paritytech/polkavm) linker finally links the ELF shared object into a PolkaVM blob.
This compilation process can be visualized as follows:
![Architecture Overview](images/resolc.svg)
## Reproducible contract builds
Because on-chain contract code is identified via its code blob hash, it is crucial to maintain reproducible contract builds. A given compiler version must reproduce the contract build _exactly_ on every target platform `resolc` supports via the official binary releases.
To ensure this, we employ the following measures:
- The code generation must be fully deterministic. For example iterating over standard `HashMap` invalidates this due to its internal state, making it an invalid operation in `revive`. To circumvent that, a `BTreeMap` can be used instead.
- We release fully statically linked `resolc` binaries. This prevents dynamic linking of potentially differentiating libraries.
- The only non-bundled dependency is the `solc` compiler. This is considered fine because the same properties apply to `solc`.
## The `revive` compiler libraries
The main compiler logic is implemented in the `revive-yul` and `revive-llvm-context` crates.
The Yul library implements a lexer and parser and lowers the resulting tree into LLVM IR. It does so by emitting LL using the LLVM builder and our own `revive-llvm-context` compiler context crate. The revive LLVM context crate encapsulates code generation logic (decoupled from the parser).
The Yul library also implements a simple [visitor](https://en.wikipedia.org/wiki/Visitor_pattern) interface (see [visitor.rs](https://github.com/paritytech/revive/blob/main/crates/yul/src/visitor.rs)). If you want to work with the AST, it is strongly recommended to implement visitors. The LLVM code generation is implemented using a dedicated trait for historical reasons only.
## EVM heap memory
PVM doesn't offer a similar API. Hence the emitted contract code emulates the linear EVM heap memory using a static byte buffer. Data inside this byte buffer is kept big endian for EVM compatibility reasons (unaligned access is allowed and makes optimizing this non-trivial).
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.
## The LLVM dependency
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 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.
## Custom optimizations
At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither `solc` nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, `solc` 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.
+65
View File
@@ -0,0 +1,65 @@
# Contributor guide
The `revive` compiler is an open source software project and we gladly accept quality contributions from anyone!
## Getting started
A quick reference on how to build the Solidity compiler is maintained in the project's [README.md](https://github.com/paritytech/revive?tab=readme-ov-file#building-from-source).
### Using the `Makefile`
The [Makefile](https://github.com/paritytech/revive/blob/main/Makefile) comprehensively encapsulates all development aspects of this codebase. It is kept concise and readable. Please read and use it! You'll learn for example:
- How to build and install a `resolc` development version.
- How to run tests and benchmarks.
- How to cross-compile `resolc`.
As a general rule-of-thumb: If `make test` runs fine locally, chances for green CI pipelines are good.
### Codebase organization
For the most parts, `revive` is a rather standard Rust workspace codebase. There are some non-Rust dependencies, which sometimes complicates things a little bit.
#### The `crates/` dir
All Rust crates live under the `crates/` directory. The workspace automatically considers any crate found therein. If you need to add a new create, please implement it there.
Compiler library crates should be named with the `revive-` prefix. The crate location doesn't need the prefix.
#### Dependencies
Dependencies should be added as workspace dependencies. Try to avoid pinning dependencies whenever possible. If possible, add dev dependencies as `dev-dependencies` only.
Please do always include the `Cargo.lock` dependency lock file with your PR. Please don't run `cargo update` together with other changes (it is preferred to update the lock file in a dedicated dependency update PR).
## Contribution rules
1. Changes must be submitted via a pull request (PR) to the github upstream repository.
2. Ensure that your branch passes `make test` locally when submitting a pull request.
3. A PR must not be merged until CI fully passes. Exceptions can be made (for example to fix CI issues itself).
4. No force pushes to the `main` branch and open PR branches.
5. Maintainers can request changes or deny contributions at their own discretion.
## Style guide
We require the official Rust formatter and clippy linter. In addition to that, please also consider the following best-effort aspects:
- Avoid [magic numbers](https://en.wikipedia.org/wiki/Magic_number_(programming)) and strings. Instead, add them as module constants.
- Avoid abbreviated variable and function names. Always provide meaningful and readable symbols.
- Don't write macros and don't use third party macros for things that can easily be expressed in few lines of code or outlined into functions.
- Avoid import aliasing. Please use the parent or fully qualified path for conflicting symbols.
- Any inline comments must provide additional semantic meaning, explain counter-intuitive behavior or highlight non-obvious design decisions. In other words, try to make the code expressive enough to a degree it doesn't need comments expressing the same thing again in the English language. Delete such comments if your AI assistant generated them.
- Public items must have a meaningful doc comment.
- Provide meaningful panic messages to `.expect()` or just use `.unwrap()`.
## AI policy
Contributors may use whatever AI assistance tools they wish to whatever degree they wish in the process of creating their contribution, __given they acknowledge the following__:
_Project maintainers may reject any contribution (or portions of it) if the contribution shows signs of problematic involvement of generative AI_.
Judgement of "problematic involvement" lies at the sole discretion of project maintainers. No proof (whether a contribution was in fact AI generated or not) is required. Rationale:
- No one enjoys reading soulless and uncanny LLM slop. Please review and fix any AI slop yourself prior to submitting a PR.
- A Solidity compiler is security sensitive software. Even miniscule mistakes can ultimately lead to loss of funds. AI models are inherently stochastic. They regurarly fail to capture important nuances or produce straight hallucinations. Code that was "blindly" generated has no home here.
- `revive` is a large codebase. Generative AI assistants may not have enough "context window" to sufficiently capture correctness, consistency and style aspects of the codebase. We'd like to keep this codebase maintainable _by humans_ for the forseeable future.
@@ -0,0 +1,30 @@
# Cross compilation
We cross-compile the `resolc.js` frontend executable to Wasm for running it in a Node.js or browser environment.
The [musl](https://www.musl-libc.org/) target is used to obtain statically linked ELF binaries for Linux.
## Wasm via emscripten
The `REVIVE_LLVM_TARGET_PREFIX` environment variable is used to control the target environment LLVM dependency. This requires a compatible LLVM build, obtainable via the `revive-llvm` build script. Example:
```sh
# Build the host LLVM dependency with PolkaVM target support
make install-llvm
export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final
# Build the target LLVM dependency with PolkaVM target support
revive-llvm emsdk
source emsdk/emsdk_env.sh
revive-llvm --target-env emscripten build --llvm-projects lld
export REVIVE_LLVM_TARGET_PREFIX=${PWD}/target-llvm/emscripten/target-final
# Build the resolc frontend executable
make install-wasm
make test-wasm
```
## musl libc
[rust-musl-cross](https://github.com/rust-cross/rust-musl-cross) is a straightforward way to cross compile Rust to musl. The [Dockerfile](https://github.com/paritytech/revive/blob/main/Dockerfile) is an executable example of how to do that.
@@ -0,0 +1,2 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1693.333333333334 1164.4444444444443" width="3386.666666666668" height="2328.8888888888887"><!-- svg-source:excalidraw --><metadata></metadata><defs><symbol id="image-4b75a93eb5e7f97b53388fe7a347179cca2ed45c"><image href="data:image/png;base64,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 truncated
@font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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 truncated

After

Width:  |  Height:  |  Size: 290 KiB

+29
View File
@@ -0,0 +1,29 @@
# PVM and the pallet-revive runtime target
The `revive` compiler targets [PolkaVM (PVM)](https://github.com/paritytech/polkavm) via [pallet-revive](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/revive) on Polkadot.
## Target CPU configuration
The exact target CPU configuration can be found [here](https://github.com/paritytech/revive/blob/8cd10a613625428956eb33c39c9022a91bfbf103/crates/llvm-context/src/target_machine/mod.rs#L22-L32).
> [!NOTE]
>
> The PVM linker requires fully relocatable ELF objects.
## Why PVM
PVM is a RISC-V based VM designed to overcome the flaws of [WebAssebmly (Wasm)](https://webassembly.org/). Wasm was believed to be a more efficient successor to the rather slow EVM. However, Wasm is far from an ideal target for smart contracts as some of its design decisions are unfavorable for short-lived workloads. The main problem is on-chain Wasm bytecode compilation or interpretation overhead. Prior benchmarks consistently ignoring this overhead seeded the blockchain industry with flawed assumptions: _Only when ignoring the startup overhead_ Wasm is much faster than the slow computing EVM. In practice however, gains are nullified entirely and Wasm loses completely even against very slow VMs like the EVM. Executing Wasm contracts is in fact so inefficient that typical contract workloads are _orders of magnitude_ more expensive than the equivalent EVM variant.
On the other hand, since RISC-V is similar to CPUs found in validator hardware (x86 and ARM), bytecode translation mostly boils down to a linear mapping from one instruction to another. The _embedded_ ISA specification reduces the number of general purpose registers, in turn removing the need for expensive register allocation. This guarantees single-pass `O(n)` JIT compilation of contract bytecode. The close proximity of PVM bytecode with actual validator CPU bytecode effectively allows to move all expensive compilation workload off-chain. Benchmarks ([1](https://hackmd.io/@XXX9CM1uSSCWVNFRYaSB5g/HJarTUhJA#Results-execute), [2](https://github.com/paritytech/polkavm/blob/master/BENCHMARKS.md)) show that with the PVM JIT, sandboxed PVM code executes at around half the speed of native code, which falls into the same ballpark of the state-of-the-art `wasmtime` Wasm implementation (while EVM sits somewhere around 1/10 to less than 1/100 of native speed). However, the PVM JIT compiler only uses a fraction of the time `wasmtime` requires to compile the code.
> [!NOTE]
>
> The PVM JIT isn't available yet in `pallet-revive`. At the time of writing, the contract code is interpreted, which is orders of magnitude slower than the JIT.
## Host environment: `pallet-revive`
The `revive` compiler targets the [`pallet-revive` runtime environment](https://docs.rs/pallet-revive/).
`pallet-revive` exposes a [syscall like interface](https://docs.rs/pallet-revive/latest/pallet_revive/trait.SyscallDoc.html) for contract interactions with the host environment. This is provided by the [revive-runtime-api](https://crates.io/crates/revive-runtime-api) library.
After the initial launch on the Polkadot Asset Hub blockchain, the runtime API is considered stable and backwards compatible indefinitively.
+67
View File
@@ -0,0 +1,67 @@
# Testing strategy
Contributors are encouraged to implement some appropriate unit and integration tests together with any bug fixes or new feature implementations. However, when it comes to testing the code generation logic, our testing strategy goes way beyond simple unit and integration tests. This chapter explains how the `revive` compiler implementation is tested for correctness and how we define correctness.
> [!TIP]
>
> Running the integration tests require the `evm` tool from `go-ethereum` in your `$PATH`.
>
> Either install it using your package manager or to build it from source:
> ```bash
> git clone https://github.com/ethereum/go-ethereum/
> cd go-ethereum
> make all
> export PATH=/path/to/go-ethereum/build/bin/:$PATH
> ```
## Bug compatibility with Ethereum Solidity
As a Solidity compiler, we aim to preserve contract code semantics as close as possible to Solidity compiled to EVM with the `solc` reference implementation. As highlighted in the user guide, due to the underlying target difference, this isn't always possible. However, wherever it is possible, we follow the philosophy of [**bug compatibility**](https://en.wikipedia.org/wiki/Bug_compatibility) with the Ethereum contracts stack.
## Differential integration tests
A high level of bug compatibility with Ethereum is ensured through [**differential testing**](https://en.wikipedia.org/wiki/Differential_testing) with the Ethereum `solc` and EVM contracts stack. The [revive-integration](https://crates.io/crates/revive-integration) library is the central integration test utility, providing a set of Solidity integration test cases. Further, it implements differential tests against the reference implementation by combining the [revive-runner](https://crates.io/crates/revive-runner) sandbox, the [go-ethereum EVM tool](https://github.com/ethereum/go-ethereum/tree/master/cmd/evm) and the [revive-differential](https://crates.io/crates/revive-differential).
The `revive-runner` library provides a [**declarative**](https://en.wikipedia.org/wiki/Declarative_programming) test [specification format](https://github.com/paritytech/revive/blob/main/crates/runner/src/specs.rs). This vastly simplifies writing differential test cases and removes a lot of room for errors in test logic. Example:
```json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "Bitwise"
}
}
}
},
{
"Call": {
"dest": {
"Instantiated": 0
},
"data": "3fa4f245"
}
}
]
}
```
Above example instantiates the `Bitwise` contract and calls it with some defined calldata. The `revive-runner` library implements a helper wrapper to execute test specs on the go-ethereum standalone `evm` tool. This allows the `revive-runner` to execute specs against the EVM and the `pallet-revive` runtime. Key to differential testing is setting `"differential": true`, resulting in the following:
1. The `Bitwise` contract is compiled to EVM and PVM code.
2. The runner executes the defined `actions` on the EVM and collects all state changes (storage, balance) and execution results.
3. The runner executes each action on the PVM. Observed state changes _after each step_ as well as the final execution result is asserted to match the EVM counterparts __exactly__.
__Note how we never defined any expected outcome manually.__ Instead, we simply observe and collect the data defining the "correct" outcome.
Differential testing in combination with declarative test specifications proved to be simple, yet very effective, in ensuring expected Ethereum Solidity semantics on `pallet-revive`.
## The differential testing utility
A lot of nuanced bugs caused by tiny implementation details inside the `revive` compiler _and_ the `pallet-revive` runtime could be identified and eliminated early on thanks to the differential testing strategy. Thus, we decided to take this approach further and created a comprehensive test runner and a large suite of more complex test cases.
The [Revive Differential Tests](https://github.com/paritytech/revive-differential-tests/) follow the exact same strategy but implement a much more powerful test spec format, spec runner and reports. This allows differentially testing much more complex test cases (for example testing Uniswap pair creations and swaps), executed via transactions sent to actual blockchain nodes.