From d6b1da9bdc1197e72ef24051293fd06d3842f318 Mon Sep 17 00:00:00 2001 From: Ivan Boldyrev Date: Thu, 11 Jan 2024 14:46:16 +0400 Subject: [PATCH] feat(air,air-cli): pretty-printing binary interpreter data (#794) Add new interpreter method `to_human_readable_data` and `air data` subcommand to convert binary data to JSON with indentation. --- Cargo.lock | 102 +++++++-------- air-interpreter/src/marine.rs | 9 ++ air/src/human_readable_data.rs | 41 ++++++ air/src/lib.rs | 2 + air/src/preparation_step/mod.rs | 1 + avm/server/src/errors.rs | 4 + avm/server/src/runner.rs | 15 +++ .../src/interpreter_outcome.rs | 2 +- tools/cli/air/Cargo.toml | 2 + tools/cli/air/src/data.rs | 119 ++++++++++++++++++ tools/cli/air/src/main.rs | 13 +- tools/cli/air/src/trace/run.rs | 37 +++--- tools/cli/air/src/trace/run/native.rs | 13 +- tools/cli/air/src/trace/run/runner.rs | 6 + tools/cli/air/src/trace/run/wasm.rs | 12 +- 15 files changed, 302 insertions(+), 76 deletions(-) create mode 100644 air/src/human_readable_data.rs create mode 100644 tools/cli/air/src/data.rs diff --git a/Cargo.lock b/Cargo.lock index 784be3be..3b3a23b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,7 +40,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -61,7 +61,7 @@ checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -192,7 +192,7 @@ dependencies = [ "polyplets", "rkyv", "rmp-serde", - "semver 1.0.20", + "semver 1.0.21", "serde", "serde_bytes", "serde_json", @@ -285,7 +285,7 @@ dependencies = [ "object-pool", "once_cell", "rand_chacha 0.3.1", - "semver 1.0.20", + "semver 1.0.21", "serde", "serde_json", "sha2 0.10.8", @@ -455,7 +455,7 @@ dependencies = [ "polyplets", "pretty_assertions 0.6.1", "rkyv", - "semver 1.0.20", + "semver 1.0.21", "serde", "serde_json", "strum", @@ -470,6 +470,7 @@ name = "aquavm-air-cli" version = "0.6.1" dependencies = [ "air-beautifier", + "air-interpreter-data", "air-interpreter-interface", "air-interpreter-sede", "air-test-utils", @@ -483,6 +484,7 @@ dependencies = [ "fluence-keypair", "itertools", "near-sdk", + "semver 1.0.21", "serde", "serde_json", "termcolor", @@ -701,7 +703,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -718,7 +720,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -1060,7 +1062,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", "syn_derive", ] @@ -1411,7 +1413,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -1452,7 +1454,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f76990911f2267d837d9d0ad060aa63aaad170af40904b29461734c339030d4d" dependencies = [ "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -1878,7 +1880,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -1902,7 +1904,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -1913,7 +1915,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -1981,7 +1983,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -2202,7 +2204,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -3405,7 +3407,7 @@ dependencies = [ "multimap 0.8.3", "once_cell", "paste", - "semver 1.0.20", + "semver 1.0.21", "serde", "thiserror", "wasmer-interface-types-fl", @@ -3450,7 +3452,7 @@ dependencies = [ "marine-module-interface", "marine-wasm-backend-traits", "nom", - "semver 1.0.20", + "semver 1.0.21", "serde", "thiserror", "walrus 0.20.3", @@ -3500,7 +3502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a84be3c30abaa13df50cdaceb6b62ca806ac8a10fd5bacfeb4371ec1bd0f5101" dependencies = [ "once_cell", - "semver 1.0.20", + "semver 1.0.21", ] [[package]] @@ -3514,7 +3516,7 @@ dependencies = [ "derivative", "marine-rs-sdk-main", "marine-wasm-backend-traits", - "semver 1.0.20", + "semver 1.0.21", "serde", "thiserror", "walrus 0.20.3", @@ -3530,7 +3532,7 @@ dependencies = [ "itertools", "marine-it-interfaces", "nom", - "semver 1.0.20", + "semver 1.0.21", "serde", "thiserror", "walrus 0.19.0", @@ -3863,7 +3865,7 @@ checksum = "e4ac4e2d843390b1a007ad206022b4252d0fe3756d8b6609bc025cce07949bc5" dependencies = [ "borsh 1.1.2", "schemars", - "semver 1.0.20", + "semver 1.0.21", "serde", ] @@ -4188,7 +4190,7 @@ checksum = "84c1eda300e2e78f4f945ae58117d49e806899f4a51ee2faa09eda5ebc2e6571" dependencies = [ "quote", "serde", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -4211,7 +4213,7 @@ dependencies = [ "fs2", "near-rpc-error-core 0.17.0", "serde", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -4269,7 +4271,7 @@ dependencies = [ "serde_json", "strum", "strum_macros", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -4524,7 +4526,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -4716,7 +4718,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -4944,9 +4946,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -5071,9 +5073,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -5467,7 +5469,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.20", + "semver 1.0.21", ] [[package]] @@ -5654,18 +5656,18 @@ checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] @@ -5691,13 +5693,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -5730,7 +5732,7 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -5787,7 +5789,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -5799,7 +5801,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -6079,9 +6081,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.41" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -6097,7 +6099,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -6231,7 +6233,7 @@ checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -6355,7 +6357,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -6562,7 +6564,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -7035,7 +7037,7 @@ dependencies = [ "log", "nom", "safe-transmute", - "semver 1.0.20", + "semver 1.0.21", "serde", "serde_json", "thiserror", @@ -7764,7 +7766,7 @@ checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] @@ -7784,7 +7786,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.48", ] [[package]] diff --git a/air-interpreter/src/marine.rs b/air-interpreter/src/marine.rs index 497ada60..f2e85bd4 100644 --- a/air-interpreter/src/marine.rs +++ b/air-interpreter/src/marine.rs @@ -88,3 +88,12 @@ pub fn invoke_tracing( pub fn ast(script: String) -> String { ast::ast(script) } + +/// Like ast, this function is intended to be run localy by tools. +#[marine] +pub fn to_human_readable_data(data: Vec) -> String { + match air::to_human_readable_data(data) { + Ok(text) => text, + Err(err) => err.to_string(), + } +} diff --git a/air/src/human_readable_data.rs b/air/src/human_readable_data.rs new file mode 100644 index 00000000..268b560d --- /dev/null +++ b/air/src/human_readable_data.rs @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::preparation_step::check_version_compatibility; + +use air_interpreter_data::InterpreterData; +use air_interpreter_data::InterpreterDataEnvelope; +use serde_json::json; + +use std::error::Error as StdError; + +pub fn to_human_readable_data(data: Vec) -> Result> { + let envelope = InterpreterDataEnvelope::try_from_slice(&data)?; + + check_version_compatibility(&envelope.versions)?; + + let data = InterpreterData::try_from_slice(&envelope.inner_data)?; + + // TODO convert value store strings to JSON + let envelope_json = json!({ + "versions": envelope.versions, + "data": data, + }); + + // it may produce quite a big string (whitespaces, escaping, etc), but this function + // is intended to be executed on user machine, not on chain or in a cloud. + Ok(serde_json::to_string_pretty(&envelope_json)?) +} diff --git a/air/src/lib.rs b/air/src/lib.rs index 9be4b883..34f60d56 100644 --- a/air/src/lib.rs +++ b/air/src/lib.rs @@ -28,6 +28,7 @@ mod execution_step; mod farewell_step; +mod human_readable_data; mod preparation_step; mod runner; mod signing_step; @@ -63,6 +64,7 @@ pub use preparation_step::min_supported_version; pub use preparation_step::PreparationError; pub use utils::ToErrorCode; +pub use crate::human_readable_data::to_human_readable_data; pub use crate::runner::execute_air; pub mod interpreter_data { diff --git a/air/src/preparation_step/mod.rs b/air/src/preparation_step/mod.rs index b5c61f16..3e4d1602 100644 --- a/air/src/preparation_step/mod.rs +++ b/air/src/preparation_step/mod.rs @@ -22,6 +22,7 @@ pub use errors::PreparationError; pub use interpreter_versions::interpreter_version; pub use interpreter_versions::min_supported_version; +pub(crate) use preparation::check_version_compatibility; pub(crate) use preparation::parse_data; pub(crate) use preparation::prepare; pub(crate) use preparation::ParsedDataPair; diff --git a/avm/server/src/errors.rs b/avm/server/src/errors.rs index 3ad080d0..8008f165 100644 --- a/avm/server/src/errors.rs +++ b/avm/server/src/errors.rs @@ -76,4 +76,8 @@ pub enum RunnerError { /// Invalid secret key. #[error(transparent)] KeyError(eyre::Error), + + /// Errors from auxiliary calls. + #[error("{0}")] + Aux(String), } diff --git a/avm/server/src/runner.rs b/avm/server/src/runner.rs index 1f1f28e3..15b3f6cd 100644 --- a/avm/server/src/runner.rs +++ b/avm/server/src/runner.rs @@ -17,6 +17,7 @@ use crate::RunnerError; use crate::RunnerResult; +use air_interpreter_interface::try_as_string; use air_interpreter_interface::CallResultsRepr; use air_interpreter_interface::InterpreterOutcome; use air_interpreter_sede::ToSerialized; @@ -171,6 +172,20 @@ impl AVMRunner { Ok(outcome) } + pub fn to_human_readable_data(&mut self, data: Vec) -> RunnerResult { + let args = vec![IValue::ByteArray(data)]; + + let result = self.marine.call_with_ivalues( + &self.wasm_filename, + "to_human_readable_data", + &args, + <_>::default(), + )?; + let result = try_as_one_value_vec(result)?; + let outcome = try_as_string(result, "result").map_err(RunnerError::Aux)?; + Ok(outcome) + } + pub fn memory_stats(&self) -> AVMMemoryStats { let stats = self.marine.module_memory_stats(); diff --git a/crates/air-lib/interpreter-interface/src/interpreter_outcome.rs b/crates/air-lib/interpreter-interface/src/interpreter_outcome.rs index a6b0aa5d..04d4cd5e 100644 --- a/crates/air-lib/interpreter-interface/src/interpreter_outcome.rs +++ b/crates/air-lib/interpreter-interface/src/interpreter_outcome.rs @@ -116,7 +116,7 @@ fn try_as_i64(ivalue: IValue, field_name: &str) -> Result { } #[cfg(feature = "marine")] -fn try_as_string(ivalue: IValue, field_name: &str) -> Result { +pub fn try_as_string(ivalue: IValue, field_name: &str) -> Result { match ivalue { IValue::String(value) => Ok(value), v => Err(format!("expected a string for {field_name}, got {v:?}")), diff --git a/tools/cli/air/Cargo.toml b/tools/cli/air/Cargo.toml index ceba62dd..9c068b40 100644 --- a/tools/cli/air/Cargo.toml +++ b/tools/cli/air/Cargo.toml @@ -15,12 +15,14 @@ air-beautifier = { version = "0.4.1", path = "../../../crates/beautifier" } avm-data-store = { version = "0.7.5", path = "../../../crates/data-store" } avm-interface = { version = "0.31.0", path = "../../../avm/interface" } air-interpreter-interface = { version = "0.17.0", path = "../../../crates/air-lib/interpreter-interface", default-features = false } +air-interpreter-data = { version = "0.16.0", path = "../../../crates/air-lib/interpreter-data" } air-interpreter-sede = { version = "0.1.0", path = "../../../crates/air-lib/interpreter-sede", default-features = false } air-test-utils = { version = "0.14.1",path = "../../../crates/air-lib/test-utils", optional = true } anyhow = "1.0.79" clap = { version = "4.4.7", features = ["derive", "env"] } itertools = "0.10.5" +semver = "1.0.21" serde = { version = "1.0.190", features = ["derive"] } serde_json = "1.0.108" tracing = "0.1.40" diff --git a/tools/cli/air/src/data.rs b/tools/cli/air/src/data.rs new file mode 100644 index 00000000..557b29b6 --- /dev/null +++ b/tools/cli/air/src/data.rs @@ -0,0 +1,119 @@ +/* + * Copyright 2024 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use anyhow::Context; +use clap::Parser; +use std::path::Path; +use std::path::PathBuf; + +use crate::trace::run::load_data; +use crate::trace::run::runner::DataToHumanReadable; + +#[derive(clap::Args, Debug, Copy, Clone)] +#[group(multiple = false)] +struct ModeArgs { + #[arg(long)] + native: bool, + + #[cfg(feature = "wasm")] + #[arg(long)] + wasm: bool, +} + +enum Mode { + Native, + + #[cfg(feature = "wasm")] + Wasm, +} + +impl From for Option { + fn from(value: ModeArgs) -> Self { + if value.native { + return Some(Mode::Native); + } + + #[cfg(feature = "wasm")] + if value.wasm { + return Some(Mode::Wasm); + } + + None + } +} + +#[derive(Parser)] +#[clap(about = "Print human-readable AquaVM data")] +pub(crate) struct Args { + #[clap( + long = "interpreter", + env = "AIR_INTERPRETER_WASM_PATH", + default_value = "target/wasm32-wasi/release/air_interpreter_server.wasm" + )] + air_interpreter_path: PathBuf, + + #[clap(flatten)] + mode: ModeArgs, + // TODO be able to read from stdin + #[arg(help = "Input path")] + input: PathBuf, +} + +pub(crate) fn to_human_readable_data(args: Args) -> Result<(), Box> { + init_tracing("warn"); + + let data: Vec = load_data(&args.input)?; + + if data.is_empty() { + Err(anyhow::anyhow!("empty input data: {:?}", args.input))?; + } + + let mut runner = create_runner(args.mode.into(), &args.air_interpreter_path)?; + let out = runner.to_human_readable(data)?; + println!("{out}"); + + Ok(()) +} + +fn init_tracing(tracing_params: &str) { + let builder = tracing_subscriber::fmt() + .with_env_filter(tracing_params) + .with_writer(std::io::stderr); + builder.init(); +} + +fn create_runner( + mode: Option, + _air_interpreter_wasm_path: &Path, +) -> anyhow::Result> { + #[cfg(not(feature = "wasm"))] + let default_mode = Mode::Native; + #[cfg(feature = "wasm")] + let default_mode = Mode::Wasm; + + let mode = mode.unwrap_or(default_mode); + let runner = match mode { + Mode::Native => crate::trace::run::native::create_native_avm_runner() + .context("Failed to instantiate a native AVM")? as _, + #[cfg(feature = "wasm")] + Mode::Wasm => { + crate::trace::run::wasm::create_wasm_avm_runner(_air_interpreter_wasm_path, None) + .context("Failed to instantiate WASM AVM")? as _ + } + }; + + Ok(runner) +} diff --git a/tools/cli/air/src/main.rs b/tools/cli/air/src/main.rs index ad3ebe96..be696fe0 100644 --- a/tools/cli/air/src/main.rs +++ b/tools/cli/air/src/main.rs @@ -27,6 +27,7 @@ )] mod beautify; +mod data; mod trace; use clap::Parser; @@ -42,17 +43,21 @@ struct Cli { enum Subcommand { #[clap(alias = "b")] Beautify(self::beautify::Args), + #[clap(alias = "d")] + Data(self::data::Args), #[clap(alias = "r")] Run(self::trace::run::Args), #[clap(alias = "s")] Stats(self::trace::stats::Args), } -fn main() -> anyhow::Result<()> { +fn main() -> Result<(), Box> { let args = Cli::parse(); match args.subcommand { - Subcommand::Run(args) => self::trace::run::run(args), - Subcommand::Stats(args) => self::trace::stats::stats(args), - Subcommand::Beautify(args) => self::beautify::beautify(args), + Subcommand::Beautify(args) => self::beautify::beautify(args)?, + Subcommand::Data(args) => self::data::to_human_readable_data(args)?, + Subcommand::Run(args) => self::trace::run::run(args)?, + Subcommand::Stats(args) => self::trace::stats::stats(args)?, } + Ok(()) } diff --git a/tools/cli/air/src/trace/run.rs b/tools/cli/air/src/trace/run.rs index 0a792b75..cd01002a 100644 --- a/tools/cli/air/src/trace/run.rs +++ b/tools/cli/air/src/trace/run.rs @@ -15,27 +15,28 @@ */ mod data; -mod native; +pub(crate) mod native; #[cfg(feature = "near")] mod near; #[cfg(feature = "risc0")] mod risc0; -mod runner; #[cfg(feature = "wasm")] -mod wasm; +pub(crate) mod wasm; + +pub(crate) mod runner; use self::runner::AirRunner; use avm_interface::CallResults; use anyhow::Context as _; -use clap::{Parser, Subcommand}; +use clap::Parser; +use clap::Subcommand; use fluence_keypair::KeyPair; use zeroize::Zeroize; -use std::{ - io::Read, - path::{Path, PathBuf}, -}; +use std::io::Read; +use std::path::Path; +use std::path::PathBuf; #[derive(Parser, Debug)] #[clap(about = "Run AIR script with AquaVM")] @@ -241,21 +242,21 @@ fn create_runner( let default_mode = Mode::Wasm; let mode = mode.unwrap_or(default_mode); - match mode { - Mode::Native => { - self::native::create_native_avm_runner().context("Failed to instantiate a native AVM") - } + let runner = match mode { + Mode::Native => self::native::create_native_avm_runner() + .context("Failed to instantiate a native AVM")? as _, #[cfg(feature = "wasm")] Mode::Wasm => { self::wasm::create_wasm_avm_runner(_air_interpreter_wasm_path, _max_heap_size) - .context("Failed to instantiate WASM AVM") + .context("Failed to instantiate WASM AVM")? as _ } #[cfg(feature = "near")] Mode::Near => self::near::create_near_runner(_air_contract_wasm_path) - .context("Failed to instantiate NEAR AVM"), + .context("Failed to instantiate NEAR AVM")?, #[cfg(feature = "risc0")] - Mode::Risc0 => Ok(Box::new(self::risc0::Risc0Runner::new())), - } + Mode::Risc0 => Box::new(self::risc0::Risc0Runner::new()), + }; + Ok(runner) } // TODO This is a copy of function from air_interpreter/marine.rs. It should be moved to the marine_rs_sdk. @@ -297,8 +298,8 @@ fn load_data_or_default( } } -fn load_data(data_path: &Path) -> anyhow::Result> { - Ok(std::fs::read(data_path)?) +pub(crate) fn load_data(data_path: &Path) -> anyhow::Result> { + std::fs::read(data_path).with_context(|| data_path.to_string_lossy().into_owned()) } fn load_keypair_ed25519(path: &PathBuf) -> Result { diff --git a/tools/cli/air/src/trace/run/native.rs b/tools/cli/air/src/trace/run/native.rs index d1a4cfd5..92c84e36 100644 --- a/tools/cli/air/src/trace/run/native.rs +++ b/tools/cli/air/src/trace/run/native.rs @@ -15,12 +15,15 @@ */ use super::runner::AirRunner; +use super::runner::DataToHumanReadable; use air_interpreter_interface::CallResultsRepr; use air_interpreter_interface::RunParameters; use avm_interface::raw_outcome::RawAVMOutcome; use fluence_keypair::KeyPair; -struct NativeAvmRunner {} +use std::error::Error as StdError; + +pub(crate) struct NativeAvmRunner {} impl AirRunner for NativeAvmRunner { fn call_tracing( @@ -70,6 +73,12 @@ impl AirRunner for NativeAvmRunner { } } -pub(crate) fn create_native_avm_runner() -> anyhow::Result> { +impl DataToHumanReadable for NativeAvmRunner { + fn to_human_readable(&mut self, data: Vec) -> Result> { + air::to_human_readable_data(data) + } +} + +pub(crate) fn create_native_avm_runner() -> anyhow::Result> { Ok(Box::new(NativeAvmRunner {})) } diff --git a/tools/cli/air/src/trace/run/runner.rs b/tools/cli/air/src/trace/run/runner.rs index 662574ed..575af424 100644 --- a/tools/cli/air/src/trace/run/runner.rs +++ b/tools/cli/air/src/trace/run/runner.rs @@ -18,6 +18,8 @@ use avm_interface::raw_outcome::RawAVMOutcome; use avm_interface::CallResults; use fluence_keypair::KeyPair; +use std::error::Error as StdError; + pub(crate) trait AirRunner { #[allow(clippy::too_many_arguments)] fn call_tracing( @@ -36,3 +38,7 @@ pub(crate) trait AirRunner { particle_id: String, ) -> anyhow::Result; } + +pub(crate) trait DataToHumanReadable { + fn to_human_readable(&mut self, data: Vec) -> Result>; +} diff --git a/tools/cli/air/src/trace/run/wasm.rs b/tools/cli/air/src/trace/run/wasm.rs index 15c1af96..fff62d14 100644 --- a/tools/cli/air/src/trace/run/wasm.rs +++ b/tools/cli/air/src/trace/run/wasm.rs @@ -13,9 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + use super::runner::AirRunner; +use super::runner::DataToHumanReadable; use air_test_utils::avm_runner::AVMRunner; use fluence_keypair::KeyPair; + +use std::error::Error as StdError; use std::path::Path; pub(crate) struct WasmAvmRunner(AVMRunner); @@ -58,10 +62,16 @@ impl AirRunner for WasmAvmRunner { } } +impl DataToHumanReadable for WasmAvmRunner { + fn to_human_readable(&mut self, data: Vec) -> Result> { + Ok(self.0.to_human_readable_data(data)?) + } +} + pub(crate) fn create_wasm_avm_runner( air_interpreter_wasm_path: &Path, max_heap_size: Option, -) -> anyhow::Result> { +) -> anyhow::Result> { Ok(Box::new(WasmAvmRunner(AVMRunner::new( air_interpreter_wasm_path.to_owned(), max_heap_size,