Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI: Automatic WASM discovery and optimization #164

Merged
merged 19 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions kairos-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ assert_cmd = "2"
predicates = "3"
kairos-test-utils = { path = "../kairos-test-utils" }
casper-client-hashing.workspace = true

[build-dependencies]
wasm-opt = "0.116"
84 changes: 84 additions & 0 deletions kairos-cli/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

fn main() {
// Path
let session_binaries_dir = get_wasm_directory();

// Get the output directory set by Cargo.
let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set");
let source_path = Path::new(&session_binaries_dir).join("deposit-session-optimized.wasm");
let dest_path = Path::new(&out_dir).join("deposit-session-optimized.wasm");

// Copy the file from the source to the destination
fs::copy(&source_path, dest_path).expect("Failed to copy WASM file");

// Print out a message to re-run this script if the source file changes.
println!("cargo:rerun-if-changed={}", source_path.display());
koxu1996 marked this conversation as resolved.
Show resolved Hide resolved
}

pub fn get_wasm_directory() -> PathBuf {
// Environment variable, or default path based on the project structure.
let base_path_session = if let Ok(custom_path) = env::var("PATH_TO_SESSION_BINARIES") {
PathBuf::from(custom_path)
} else {
let project_root = env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".to_string());
PathBuf::from(project_root)
.join("../kairos-session-code/target/wasm32-unknown-unknown/release/")
};

if !base_path_session.exists() {
panic!("WASM directory does not exist: {}. Please build session code at `./kairos-session-code` with `cargo build --release`; or set `PATH_TO_SESSION_BINARIES` env variable.", base_path_session.display());
}

// Ensure all WASM files are optimized.
optimize_files(&base_path_session).expect("Unable to optimize WASM files");

base_path_session
}

fn optimize_files(dir: &Path) -> Result<(), String> {
let entries = fs::read_dir(dir).map_err(|e| e.to_string())?;

let mut found_wasm = false;
for entry in entries {
let entry = entry.map_err(|e| e.to_string())?;
let path = entry.path();
if path.extension().and_then(|s| s.to_str()) == Some("wasm") {
found_wasm = true;

// Skip already optimized files.
let file_name = path.file_name().unwrap().to_str().unwrap();
if file_name.ends_with("-optimized.wasm") {
continue;
}

// Skip if optimized file already exists.
let optimized_file_name = format!(
"{}-optimized.wasm",
file_name.strip_suffix(".wasm").unwrap()
);
let optimized_file_path = dir.join(&optimized_file_name);
if optimized_file_path.exists() {
continue;
}

// Optimize and save as new file.
let infile = path.to_str().unwrap().to_string();
let outfile = optimized_file_path.to_str().unwrap().to_string();

let mut opts = wasm_opt::OptimizationOptions::new_optimize_for_size();
opts.add_pass(wasm_opt::Pass::StripDebug);
opts.add_pass(wasm_opt::Pass::SignextLowering);

opts.run(&infile, &outfile).map_err(|e| e.to_string())?;
}
}

if !found_wasm {
return Err("No WASM files found in the directory. You should change directory to `./kairos-session-code` and build with `cargo build --release`.".to_string());
}

Ok(())
}
11 changes: 1 addition & 10 deletions kairos-cli/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ use kairos_server::PublicKey;
use reqwest::Url;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::fs;
use std::path::Path;

#[cfg(feature = "database")]
use kairos_data::transaction::{TransactionFilter, Transactions};
Expand Down Expand Up @@ -55,20 +53,13 @@ impl From<reqwest::Error> for KairosClientError {

pub fn deposit(
base_url: &Url,
deposit_session_wasm_bytes: &[u8],
depositor_secret_key: &SecretKey,
chain_name: &str,
contract_hash: &ContractHash,
amount: impl Into<U512>,
recipient: casper_client_types::PublicKey,
) -> Result<DeployHash, KairosClientError> {
let deposit_session_wasm_path =
Path::new(env!("PATH_TO_SESSION_BINARIES")).join("deposit-session-optimized.wasm");
let deposit_session_wasm_bytes = fs::read(&deposit_session_wasm_path).unwrap_or_else(|err| {
panic!(
"Failed to read the deposit session wasm as bytes from file: {:?}.\n{}",
deposit_session_wasm_path, err
)
});
let deposit_session = ExecutableDeployItem::new_module_bytes(
deposit_session_wasm_bytes.into(),
runtime_args! {
Expand Down
35 changes: 34 additions & 1 deletion kairos-cli/src/commands/deposit.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
use std::fs;
use std::path::PathBuf;

use crate::client;
use crate::common::args::{
AmountArg, ChainNameArg, ContractHashArg, PrivateKeyPathArg, RecipientArg,
};
use crate::error::CliError;

use casper_client_types::{crypto::SecretKey, ContractHash};
use clap::Parser;
use clap::{Args as ClapArgs, Parser};
use hex::FromHex;
use reqwest::Url;

use kairos_crypto::error::CryptoError;

const DEFAULT_DEPOSIT_SESSION_WASM: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/deposit-session-optimized.wasm"));

#[derive(Parser, Debug)]
pub struct Args {
#[clap(flatten)]
Expand All @@ -22,6 +28,8 @@ pub struct Args {
#[clap(flatten)]
recipient: RecipientArg,
#[clap(flatten)]
session_path: SessionPathArg,
#[clap(flatten)]
chain_name: ChainNameArg,
}

Expand All @@ -46,8 +54,21 @@ pub fn run(args: Args, kairos_server_address: Url) -> Result<String, CliError> {
Some(name) => name,
};

let deposit_session_wasm: Vec<u8> = match args.session_path.field {
Some(deposit_session_wasm_path) => {
fs::read(&deposit_session_wasm_path).unwrap_or_else(|err| {
panic!(
"Failed to read the deposit session wasm as bytes from file: {:?}.\n{}",
deposit_session_wasm_path, err
)
})
}
None => DEFAULT_DEPOSIT_SESSION_WASM.to_vec(),
};

client::deposit(
&kairos_server_address,
&deposit_session_wasm,
&depositor_secret_key,
&chain_name,
&contract_hash,
Expand All @@ -68,3 +89,15 @@ pub fn run(args: Args, kairos_server_address: Url) -> Result<String, CliError> {
output
})
}

#[derive(ClapArgs, Debug)]
pub struct SessionPathArg {
#[arg(
id = "session-path",
long,
short = 's',
value_name = "PATH",
help = "Path to the custom WASM session code for deposit"
)]
pub field: Option<PathBuf>,
}
Loading