Skip to content

Commit

Permalink
Merge pull request #7 from parallelchain-io/feature/dockerless
Browse files Browse the repository at this point in the history
Feature to support dockerless compilation
  • Loading branch information
manngayin612 authored Aug 16, 2023
2 parents 25b4e8c + a6ed87c commit 8ed4bdf
Show file tree
Hide file tree
Showing 12 changed files with 471 additions and 106 deletions.
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,21 @@ path = "src/lib.rs"

[[bin]]
name = "pchain_compile"
path = "src/bin/main.rs"

[dependencies]
bollard = "0.14.0"
clap = {version = "4.3.11", features = ["derive"]}
cargo = "0.72.2"
cargo_toml = "0.11.5"
dunce = "1.0.2"
faccess = "0.2.4"
rand = "0.6.0"
thiserror = "1.0.31"
tokio = {version = "1.19", features = ["full"]}
wasm-snip = "0.4.0"
wasm-snip = "=0.4.0"
futures-util = "0.3.28"
flate2 = "1.0.26"
tar = "0.4.38"
tar = "0.4.38"
wasm-opt = "=0.114.0"
walrus = "=0.12"
27 changes: 19 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@

`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/).

## Build the Source Code
## 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.

```sh
cargo install pchain_compile
```

## Build the Source Code

Suppose you have the source code of smart contract in the folder `contract` under your home directory.

Expand Down Expand Up @@ -42,11 +50,14 @@ Explanation about the command and its arguments can be displayed by appending "h

## Toolchain

`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. The docker image utilizes a toolchain whose components are shown below in the following table below:

|Toolchain Component | Utility
|:--- | :--- |
rustc | Compiler for Rust. |
wasm-snip (0.4.0) | WASM utility which removes functions that are never called at runtime. |
wasm-opt (109) | 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/). |
`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:
- 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:

|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 |
16 changes: 5 additions & 11 deletions docker_image/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
FROM rust:1.66.1 as cache

# Download binaryen sources
ADD https://github.com/WebAssembly/binaryen/archive/refs/tags/version_110.tar.gz /tmp/binaryen.tar.gz
FROM rust:1.71.0 as cache

# Extract and compile wasm-opt & install wasm-snip
RUN apt update && apt-get -y install wget && \
wget https://github.com/WebAssembly/binaryen/releases/download/version_109/binaryen-version_109-x86_64-linux.tar.gz && \
tar xzf binaryen-version_109-x86_64-linux.tar.gz && mv binaryen-version_109/bin/wasm-opt /usr/local/bin && \
rm -rf binaryen-version_109*
wget https://github.com/WebAssembly/binaryen/releases/download/version_114/binaryen-version_114-x86_64-linux.tar.gz && \
tar xzf binaryen-version_114-x86_64-linux.tar.gz && mv binaryen-version_114/bin/wasm-opt /usr/local/bin && \
rm -rf binaryen-version_114*

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

# Setup rust with wasm support
RUN cargo install wasm-snip && rustup target add wasm32-unknown-unknown && mkdir -p /root/bin

# Install cargo prefetch and cache some frequently used crates for faster builds
RUN cargo install cargo-prefetch && cargo prefetch --top-downloads=100

# Add wasm-opt
COPY --from=cache /usr/local/bin/wasm-opt /root/bin
RUN chmod +x /root/bin/wasm-opt
Expand Down
83 changes: 58 additions & 25 deletions src/main.rs → src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,8 @@
//! in a docker environment.

use clap::Parser;
use std::path::{PathBuf, Path};

mod build;

mod docker;

mod error;

mod manifests;
use pchain_compile::{config::Config, DockerConfig, DockerOption};
use std::path::{Path, PathBuf};

#[derive(Debug, Parser)]
#[clap(
Expand All @@ -31,11 +24,7 @@ enum PchainCompile {
/// Build the source code. Please make sure:
/// 1. Docker is installed and its execution permission under current user is granted.
/// 2. Internet is reachable. (for pulling the docker image from docker hub)
#[clap(
arg_required_else_help = true,
display_order = 1,
verbatim_doc_comment
)]
#[clap(arg_required_else_help = true, display_order = 1, verbatim_doc_comment)]
Build {
/// Absolute/Relative path to the source code directory. This field can be used multiple times to build multiple contracts at a time.
/// For example,
Expand All @@ -45,6 +34,35 @@ enum PchainCompile {
/// Absolute/Relative path for saving the compiled optimized wasm file.
#[clap(long = "destination", display_order = 2, verbatim_doc_comment)]
destination_path: Option<PathBuf>,

/// 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
/// process happens in your local changing environment.**
///
/// To install target "wasm32-unknown-unkown", run the following command:
///
/// $ rustup target add wasm32-unknown-unknown
#[clap(
long = "dockerless",
display_order = 3,
verbatim_doc_comment,
group = "docker-option"
)]
dockerless: bool,

/// Tag of the docker image being pulled from Dockerhub. Please find the tags information in
/// https://hub.docker.com/r/parallelchainlab/pchain_compile.
///
/// Available tags:
/// - mainnet01
/// - 0.4.2
#[clap(
long = "use-docker-tag",
display_order = 4,
verbatim_doc_comment,
group = "docker-option"
)]
docker_image_tag: Option<String>,
},
}

Expand All @@ -55,17 +73,33 @@ async fn main() {
PchainCompile::Build {
source_path,
destination_path,
dockerless,
docker_image_tag,
} => {
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 docker_option = if dockerless {
DockerOption::Dockerless
} else {
DockerOption::Docker(DockerConfig {
tag: docker_image_tag,
})
};

// Spawn threads to handle each contract code
let mut join_handles = vec![];
source_path.into_iter().for_each(|source_path|{
join_handles.push(tokio::spawn(crate::build::build_target(source_path, destination_path.clone())));
source_path.into_iter().for_each(|source_path| {
let config = Config {
source_path,
destination_path: destination_path.clone(),
docker_option: docker_option.clone(),
};

join_handles.push(tokio::spawn(config.run()));
});

// Join threads to obtain results
Expand All @@ -75,24 +109,23 @@ async fn main() {
}

// Display the results
let (
success,
fails
): (Vec<_>, Vec<_>) = results.into_iter().partition(Result::is_ok);
let (success, fails): (Vec<_>, Vec<_>) = results.into_iter().partition(Result::is_ok);

if !success.is_empty() {
let dst_path = destination_path.clone().unwrap_or(Path::new(".").to_path_buf());
let dst_path = destination_path
.clone()
.unwrap_or(Path::new(".").to_path_buf());
let contracts: Vec<String> = success.into_iter().map(|r| r.ok().unwrap()).collect();
println!("Finished compiling. ParallelChain Mainnet smart contract(s) {:?} are saved at ({})", contracts, crate::manifests::get_absolute_path(dst_path.as_os_str().to_str().unwrap()).unwrap());
println!("Finished compiling. ParallelChain Mainnet smart contract(s) {:?} are saved at ({})", contracts, dunce::canonicalize(dst_path).unwrap().to_str().unwrap());
}

if !fails.is_empty() {
println!("Compiling fails.");
fails.into_iter().for_each(|e|{
fails.into_iter().for_each(|e| {
let error = e.err().unwrap();
println!("{}\n{}\n", error, error.detail());
});
}
}
};
}
}
Loading

0 comments on commit 8ed4bdf

Please sign in to comment.