Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ env:
RELEASE_DIR: artifacts
GITHUB_REF: '${{ github.ref }}'
WINDOWS_TARGET: x86_64-pc-windows-msvc
MACOS_TARGET: x86_64-apple-darwin
MACOS_TARGET: aarch64-apple-darwin
LINUX_TARGET: x86_64-unknown-linux-gnu

jobs:
Expand All @@ -21,10 +21,10 @@ jobs:
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-20.04
os: ubuntu-22.04
rust: stable
- target: x86_64-apple-darwin
os: macos-12
- target: aarch64-apple-darwin
os: macos-14
rust: stable
- target: x86_64-pc-windows-msvc
os: windows-2022
Expand All @@ -44,7 +44,7 @@ jobs:
echo ::set-output name=version::"${GITHUB_REF:10}"

- name: Install p7zip (MacOS)
if: matrix.os == 'macos-12'
if: matrix.os == 'macos-14'
run: brew install p7zip

- name: Add rustup target
Expand All @@ -63,7 +63,7 @@ jobs:
mkdir -p ${{ env.RELEASE_DIR }}/${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-${{ matrix.target }}

- name: Move binaries (Linux/MacOS)
if: matrix.os == 'ubuntu-20.04' || matrix.os == 'macos-12'
if: matrix.os == 'ubuntu-22.04' || matrix.os == 'macos-14'
run: |
mv ./target/${{ matrix.target }}/release/${{ env.RELEASE_BIN }} ${{ env.RELEASE_DIR }}/${{ env.RELEASE_BIN }}-${{ steps.get_version.outputs.VERSION }}-${{ matrix.target }}/${{ env.RELEASE_BIN }}

Expand Down
17 changes: 12 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pchain_compile"
version = "0.4.2"
version = "0.4.4"
authors = ["ParallelChain Lab <[email protected]>"]
edition = "2021"
description = "ParallelChain Smart Contract Compile CLI - A command line tool for compiling ParallelChain Smart Contract."
Expand All @@ -17,17 +17,24 @@ path = "src/bin/main.rs"

[dependencies]
bollard = "0.14.0"
clap = {version = "4.3.11", features = ["derive"]}
clap = { version = "4.3.11", features = ["derive"] }
cargo = "0.72.2"
cargo_toml = "0.11.5"
cargo_toml = "0.20.4"
dunce = "1.0.2"
faccess = "0.2.4"
rand = "0.6.0"
thiserror = "1.0.31"
tokio = {version = "1.19", features = ["full"]}
tokio = { version = "1.19", features = ["full"] }
wasm-snip = "=0.4.0"
futures-util = "0.3.28"
flate2 = "1.0.26"
tar = "0.4.38"
wasm-opt = "=0.114.0"
walrus = "=0.12"
walrus = "=0.12"
bstr = "=1.6.0"
log = "0.4"
fern = { version = "0.6", features = ["date-based"] }
chrono = { version = "0.4.22", default-features = false }

[dev-dependencies]
assert_cmd = "2.0.16"
62 changes: 44 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
# ParallelChain Mainnet Contract Compiler (pchain_compile)

`pchain_compile` is a command line tool for reproducibly building Rust code into compact, gas-efficient WebAssembly [ParallelChain Mainnet Smart Contracts](https://github.com/parallelchain-io/parallelchain-protocol/blob/master/Contracts.md).
`pchain_compile` is a command line tool for reproducibly building [Rust](https://www.rust-lang.org/) code into compact, gas-efficient WebAssembly [ParallelChain Mainnet Smart Contracts](https://github.com/parallelchain-io/parallelchain-protocol/blob/master/Contracts.md).

## Pre-Requisites

`pchain_compile` builds the source code in a docker environment. To know more about Docker and install it, refer to the [official instructions](https://docs.docker.com/get-docker/).
`pchain_compile` compiles the ParallelChain smart contract code from Rust into a WebAssembly binary. To know more about developing ParallelChain smart contracts, visit [ParallelChain Mainnet Contract SDK](https://crates.io/crates/pchain-sdk).

By default, the compiler requires **docker** to be installed in your local machine. In detail, it pulls the [Docker Image](#using-the-pchain_compile-docker-image) from DockerHub, and starts a docker container which provides a complete environment for building WebAssembly binary. To install docker, follow the instructions in [Docker Docs](https://docs.docker.com/get-docker/).

## Installation

Prebuilt binaries can be downloaded from assets in Github [releases page](https://github.com/parallelchain-io/pchain-compile/releases). Alternatively, you can install by `cargo install` if Rust has been installed already.

Download prebuilt executables from the Github [Releases page](https://github.com/parallelchain-io/pchain-compile/releases).

Alternatively, you can install the binary crate [pchain_compile](https://crates.io/crates/pchain_compile) by [cargo install](https://doc.rust-lang.org/cargo/commands/cargo-install.html) if Rust has been installed already.

```sh
cargo install pchain_compile
```

## Build the Source Code
## Build Smart Contract

Suppose you have the source code of smart contract in the folder `contract` under your home directory.
Let's say your smart contract source code is in the folder `contract` under your home directory.

```text
/home/
Expand All @@ -27,37 +32,58 @@ Suppose you have the source code of smart contract in the folder `contract` unde
|- Cargo.toml
```

To build smart contract into WebAssembly bytecode (file extension `.wasm`), you can simply run the program by specifying the arguments **source** and **destination**.
Run `pchain_compile` with the arguments **source** and **destination** to specify the folder of the source code and the folder for saving the result.

On a Linux Bash Shell:

```sh
$ ./pchain_compile build --source /home/user/contract --destination /home/user/result
pchain_compile build --source /home/user/contract --destination /home/user/result
```

Once complete, the console displays message:

```text
Build process started. This could take several minutes for large contracts.

Finished compiling. ParallelChain Mainnet smart contract(s) ["contract.wasm"] are saved at (/home/user/result).
```

On a Windows Shell:
Your WebAssembly smart contract is now saved with file extension `.wasm` at the destination folder.

If you are running on Windows, here is the example output:
```powershell
$ .\pchain_compile.exe build --source 'C:\Users\user\contract' --destination 'C:\Users\user\result'
Build process started. This could take several minutes for large contracts.

Finished compiling. ParallelChain Mainnet smart contract(s) ["contract.wasm"] are saved at (C:\Users\user\result).
```

Explanation about the command and its arguments can be displayed by appending "help" or "--help" to `pchain_compile`.
To understand more about the commands and arguments, run `pchain_compile build --help`.

## Toolchain
## Compile with Docker (default)

`pchain_compile` utilizes a docker_image hosted on a public DockerHub repository of ParallelChain see [here](https://hub.docker.com/r/parallelchainlab/pchain_compile) for the build process. Required components include:
`pchain_compile` pulls a docker image from ParallelChain Lab's official DockerHub [repository](https://hub.docker.com/r/parallelchainlab/pchain_compile) for the build process. The docker image provides an environment with installed components:
- rustc: compiler for Rust.
- wasm-snip: WASM utility which removes functions that are never called at runtime.
- wasm-opt: WASM utility to load WebAssembly in text format and run Binaryen IR passes to optimize its size. For more information on Binaryen IR see [here](http://webassembly.github.io/binaryen/).

The docker images utilize a toolchain whose versions of each component are shown in the following table:
There are different tags of the docker image. They vary on the versions of the components. The table below describes the tags and their differences.

| Image Tag | rustc | wasm-snip | wasm-opt |
| :-------- | :----- | :-------- | :------- |
| latest | 1.80.1 | 0.4.0 | 114 |
| 0.4.3 | 1.77.1 | 0.4.0 | 114 |
| 0.4.2 | 1.71.0 | 0.4.0 | 114 |
| mainnet01 | 1.66.1 | 0.4.0 | 109 |

To build a smart contract in a specific docker environment, run with argument **use-docker-tag**. For example,

```sh
pchain_compile build --source /home/user/contract --destination /home/user/result --use-docker-tag 0.4.3
```

If **use-docker-tag** is not used, will pull the docker image with tag `latest`.

|Image Tag |rustc |wasm-snip |wasm-opt |
|:---|:---|:---|:---|
|0.4.2 |1.71.0 |0.4.0 |114 |
|mainnet01 |1.66.1 |0.4.0 |109 |
## Compile without Docker
Run `pchain_compile` with the argument **dockerless** will compile smart contract without docker. User needs to make sure **wasm32-unknown-unknown** has already been installed to the active rust tool chain.
For linux user:
1. Run `rustup target install wasm32-unknown-unknown` to install **wasm32-unknown-unknown**
2. Run `rustup show` to check if **wasm32-unknown-unknown** been installed to acitve toolchain succesfully or not
4 changes: 2 additions & 2 deletions docker_image/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM rust:1.71.0 as cache
FROM rust:1.80.1 as cache

# Extract and compile wasm-opt & install wasm-snip
RUN apt update && apt-get -y install wget && \
Expand All @@ -7,7 +7,7 @@ RUN apt update && apt-get -y install wget && \
rm -rf binaryen-version_114*

# pchain-compile base image
FROM rust:1.71.0 as base-image
FROM rust:1.80.1 as base-image

# Setup rust with wasm support
RUN cargo install wasm-snip && rustup target add wasm32-unknown-unknown && mkdir -p /root/bin
Expand Down
49 changes: 39 additions & 10 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
//! in a docker environment.

use clap::Parser;
use pchain_compile::{config::Config, DockerConfig, DockerOption, BuildOptions};
use std::path::{Path, PathBuf};
use pchain_compile::{config::Config, BuildOptions, DockerConfig, DockerOption};
use std::{
path::{Path, PathBuf},
str::FromStr,
};

#[derive(Debug, Parser)]
#[clap(
Expand Down Expand Up @@ -39,16 +42,16 @@ enum PchainCompile {
/// the contract will be built with the dependencies specified in the file. It is equivalent to
/// running "cargo build" with the flag "--locked". If the file does not exist, the building process continues
/// without using the version-locked dependencies.
///
///
/// With or without the file "Cargo.lock", the compilation output includes the file "Cargo.lock" which was used or
/// generated in the building process.
#[clap(long = "locked", display_order = 3, verbatim_doc_comment)]
locked: bool,

/// Compile contract without using docker. This option requires installation of Rust and target "wasm32-unknown-unknown".
/// **Please note the compiled contracts are not always consistent with the previous compiled ones, because the building
/// **Please note the compiled contracts are not always consistent with the previous compiled ones, because the building
/// process happens in your local changing environment.**
///
///
/// To install target "wasm32-unknown-unknown", run the following command:
///
/// $ rustup target add wasm32-unknown-unknown
Expand All @@ -66,13 +69,23 @@ enum PchainCompile {
/// Available tags:
/// - mainnet01
/// - 0.4.2
/// - 0.4.3
#[clap(
long = "use-docker-tag",
display_order = 5,
verbatim_doc_comment,
group = "docker-option"
)]
docker_image_tag: Option<String>,

/// Set log level, default is Error
///
/// Available log levels:
/// - Error
/// - Info
/// - Debug (provide compile progress information )
#[clap(long = "log-level", display_order = 6, verbatim_doc_comment)]
log_level: Option<String>,
},
}

Expand All @@ -86,25 +99,41 @@ async fn main() {
locked,
dockerless,
docker_image_tag,
log_level,
} => {
if source_path.is_empty() {
println!("Please provide at least one source!");
std::process::exit(-1);
}
println!("Build process started. This could take several minutes for large contracts.");

let build_options = BuildOptions {
locked
};

let build_options = BuildOptions { locked };

let docker_option = if dockerless {
DockerOption::Dockerless
} else {
DockerOption::Docker(DockerConfig {
tag: docker_image_tag,
})
};

let log_level_filter = log_level.map_or(log::LevelFilter::Error, |level_str| {
log::LevelFilter::from_str(&level_str).unwrap()
});
fern::Dispatch::new()
.format(|out, message, record| {
out.finish(format_args!(
"{}[{}][{}] {}",
chrono::Local::now().format("[%H:%M:%S]"),
record.target(),
record.level(),
message
))
})
.level(log::LevelFilter::Error)
.level_for("pchain_compile", log_level_filter)
.chain(std::io::stdout())
.apply()
.unwrap();
// Spawn threads to handle each contract code
let mut join_handles = vec![];
source_path.into_iter().for_each(|source_path| {
Expand Down
Loading