From 5d2eda6a5fff7ab57f3a4cada67f5e4398bb17cc Mon Sep 17 00:00:00 2001 From: suha jin <89185836+djm07073@users.noreply.github.com> Date: Fri, 23 May 2025 15:35:58 +0900 Subject: [PATCH 1/6] feat(initia-move-cli): decoder --- .github/workflows/move-cli.yml | 37 ++++++++++ Cargo.lock | 3 + Cargo.toml | 1 + libmovevm/src/lib.rs | 12 ++-- libmovevm/src/move_api/handler.rs | 45 ++++++------ tools/initia-move-cli/Cargo.toml | 5 +- tools/initia-move-cli/Dockerfile | 7 ++ tools/initia-move-cli/src/decode.rs | 103 +++++++++++++++++++++++++++ tools/initia-move-cli/src/execute.rs | 6 +- tools/initia-move-cli/src/main.rs | 31 +++++--- 10 files changed, 209 insertions(+), 41 deletions(-) create mode 100644 tools/initia-move-cli/Dockerfile create mode 100644 tools/initia-move-cli/src/decode.rs diff --git a/.github/workflows/move-cli.yml b/.github/workflows/move-cli.yml index 34957502..2709b860 100644 --- a/.github/workflows/move-cli.yml +++ b/.github/workflows/move-cli.yml @@ -103,3 +103,40 @@ jobs: tag_name: ${{ github.event.inputs.version || github.event.workflow_run.head_branch }} files: initia-move-cli-*.tar.gz + docker-build-push: + needs: [linux-build] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Download Linux AMD64 artifact + uses: actions/download-artifact@v4 + with: + name: x86_64-unknown-linux-gnu-build + path: tools/initia-move-cli + + - name: Extract binary + run: | + cd tools/initia-move-cli + tar -xzvf initia-move-cli-*.tar.gz + rm initia-move-cli-*.tar.gz + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: tools/initia-move-cli + file: tools/initia-move-cli/Dockerfile + push: true + tags: | + ghcr.io/${{ github.repository_owner }}/initia-move-cli:latest + ghcr.io/${{ github.repository_owner }}/initia-move-cli:${{ github.event.inputs.version || github.event.workflow_run.head_branch }} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 7d4816e8..fa82b9ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1421,6 +1421,9 @@ dependencies = [ "anyhow", "clap 4.5.15", "initia-move-compiler", + "movevm", + "serde", + "serde_json", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b96b8ff8..e767036f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,7 @@ initia-move-gas = { path = "crates/gas" } initia-move-compiler = { path = "crates/compiler" } initia-move-json = { path = "crates/json" } initia-move-resource-viewer = { path = "crates/resource-viewer" } +movevm = { path = "libmovevm" } # External crate dependencies. # Please do not add any test features here: they should be declared by the individual crate. diff --git a/libmovevm/src/lib.rs b/libmovevm/src/lib.rs index c6876c0f..ae5f95be 100644 --- a/libmovevm/src/lib.rs +++ b/libmovevm/src/lib.rs @@ -1,5 +1,6 @@ #![allow(clippy::not_unsafe_ptr_arg_deref, clippy::missing_safety_doc)] +pub mod move_api; mod api; mod args; mod db; @@ -7,7 +8,6 @@ mod error; mod interface; mod iterator; mod memory; -mod move_api; mod result; mod storage; mod table_storage; @@ -16,12 +16,16 @@ mod vm; // We only interact with this crate via `extern "C"` interfaces, not those public // exports. There are no guarantees those exports are stable. // We keep them here such that we can access them in the docs (`cargo doc`). -pub use api::{GoApi, GoApi_vtable}; -pub use db::{db_t, Db}; +pub use api::{ GoApi, GoApi_vtable }; +pub use db::{ db_t, Db }; pub use error::GoError; pub use iterator::Iterator_vtable; pub use memory::{ - destroy_unmanaged_vector, new_unmanaged_vector, ByteSliceView, U8SliceView, UnmanagedVector, + destroy_unmanaged_vector, + new_unmanaged_vector, + ByteSliceView, + U8SliceView, + UnmanagedVector, }; pub use storage::GoStorage; diff --git a/libmovevm/src/move_api/handler.rs b/libmovevm/src/move_api/handler.rs index 9b2f40eb..8034cad9 100644 --- a/libmovevm/src/move_api/handler.rs +++ b/libmovevm/src/move_api/handler.rs @@ -1,12 +1,12 @@ use crate::move_api::convert::MoveConverter; -use crate::move_api::move_types::{MoveModuleBytecode, MoveScriptBytecode}; +use crate::move_api::move_types::{ MoveModuleBytecode, MoveScriptBytecode }; use crate::result::to_vec; -use crate::{error::Error, Db, GoStorage}; +use crate::{ error::Error, Db, GoStorage }; use move_binary_format::access::ModuleAccess; use move_binary_format::deserializer::DeserializerConfig; use move_binary_format::CompiledModule; -use move_core_types::language_storage::{StructTag, TypeTag}; +use move_core_types::language_storage::{ StructTag, TypeTag }; use move_core_types::parser::parse_struct_tag; use serde::Serialize; @@ -17,9 +17,11 @@ struct ModuleInfoResponse { pub name: String, } -pub(crate) fn read_module_info(compiled: &[u8]) -> Result, Error> { - let m = CompiledModule::deserialize_with_config(compiled, &DeserializerConfig::default()) - .map_err(|e| Error::backend_failure(e.to_string()))?; +pub fn read_module_info(compiled: &[u8]) -> Result, Error> { + let m = CompiledModule::deserialize_with_config( + compiled, + &DeserializerConfig::default() + ).map_err(|e| Error::backend_failure(e.to_string()))?; let module_info = ModuleInfoResponse { address: m.address().to_vec(), @@ -29,23 +31,26 @@ pub(crate) fn read_module_info(compiled: &[u8]) -> Result, Error> { } pub(crate) fn struct_tag_to_string(struct_tag: &[u8]) -> Result, Error> { - let struct_tag: StructTag = - bcs::from_bytes(struct_tag).map_err(|e| Error::backend_failure(e.to_string()))?; + let struct_tag: StructTag = bcs + ::from_bytes(struct_tag) + .map_err(|e| Error::backend_failure(e.to_string()))?; Ok(struct_tag.to_string().as_bytes().to_vec()) } pub(crate) fn struct_tag_from_string(struct_tag_str: &[u8]) -> Result, Error> { - let struct_tag_str = - std::str::from_utf8(struct_tag_str).map_err(|e| Error::invalid_utf8(e.to_string()))?; - let struct_tag = - parse_struct_tag(struct_tag_str).map_err(|e| Error::backend_failure(e.to_string()))?; + let struct_tag_str = std::str + ::from_utf8(struct_tag_str) + .map_err(|e| Error::invalid_utf8(e.to_string()))?; + let struct_tag = parse_struct_tag(struct_tag_str).map_err(|e| + Error::backend_failure(e.to_string()) + )?; to_vec(&struct_tag) } pub(crate) fn decode_move_resource( db_handle: Db, struct_tag: &[u8], - blob: &[u8], + blob: &[u8] ) -> Result, Error> { let storage = GoStorage::new(&db_handle); let struct_tag: StructTag = bcs::from_bytes(struct_tag).unwrap(); @@ -62,7 +67,7 @@ pub(crate) fn decode_move_resource( pub(crate) fn decode_move_value( db_handle: Db, type_tag: &[u8], - blob: &[u8], + blob: &[u8] ) -> Result, Error> { let storage = GoStorage::new(&db_handle); let type_tag: TypeTag = bcs::from_bytes(type_tag).unwrap(); @@ -76,22 +81,18 @@ pub(crate) fn decode_move_value( serde_json::to_vec(&value).map_err(|e| Error::BackendFailure { msg: e.to_string() }) } -pub(crate) fn decode_script_bytes(script_bytes: Vec) -> Result, Error> { +pub fn decode_script_bytes(script_bytes: Vec) -> Result, Error> { let script: MoveScriptBytecode = MoveScriptBytecode::new(script_bytes); - let abi = script - .try_parse_abi() - .map_err(|e| Error::BackendFailure { msg: e.to_string() })?; + let abi = script.try_parse_abi().map_err(|e| Error::BackendFailure { msg: e.to_string() })?; // serialize response as json serde_json::to_vec(&abi).map_err(|e| Error::BackendFailure { msg: e.to_string() }) } -pub(crate) fn decode_module_bytes(module_bytes: Vec) -> Result, Error> { +pub fn decode_module_bytes(module_bytes: Vec) -> Result, Error> { // deserialized request from the json let module: MoveModuleBytecode = MoveModuleBytecode::new(module_bytes); - let abi = module - .try_parse_abi() - .map_err(|e| Error::BackendFailure { msg: e.to_string() })?; + let abi = module.try_parse_abi().map_err(|e| Error::BackendFailure { msg: e.to_string() })?; // serialize response as json serde_json::to_vec(&abi).map_err(|e| Error::BackendFailure { msg: e.to_string() }) } diff --git a/tools/initia-move-cli/Cargo.toml b/tools/initia-move-cli/Cargo.toml index 161120ca..9784cb3a 100644 --- a/tools/initia-move-cli/Cargo.toml +++ b/tools/initia-move-cli/Cargo.toml @@ -21,4 +21,7 @@ path = "src/main.rs" [dependencies] anyhow.workspace = true clap.workspace = true -initia-move-compiler.workspace = true \ No newline at end of file +initia-move-compiler.workspace = true +movevm.workspace = true +serde.workspace = true +serde_json.workspace = true diff --git a/tools/initia-move-cli/Dockerfile b/tools/initia-move-cli/Dockerfile new file mode 100644 index 00000000..1031f508 --- /dev/null +++ b/tools/initia-move-cli/Dockerfile @@ -0,0 +1,7 @@ +FROM debian:bullseye-slim + +WORKDIR /usr/local/bin +COPY initia-move-cli . +RUN chmod +x initia-move-cli + +ENTRYPOINT ["initia-move-cli"] \ No newline at end of file diff --git a/tools/initia-move-cli/src/decode.rs b/tools/initia-move-cli/src/decode.rs new file mode 100644 index 00000000..b2800ed1 --- /dev/null +++ b/tools/initia-move-cli/src/decode.rs @@ -0,0 +1,103 @@ +use crate::{ InitiaCLI, InitiaCommand }; +use std::{ fs, path::PathBuf }; +use anyhow::Context; +use clap::{ Parser, Subcommand }; +use movevm::move_api::handler::{ decode_module_bytes, decode_script_bytes, read_module_info }; + +#[derive(Parser)] +#[command( + name = "decode", + about = "Read or Decode Move modules and scripts", + long_about = "Read or Decode Move modules and prints the result in JSON format" +)] +pub struct Decode { + #[command(subcommand)] + pub command: DecodeCommands, +} + +#[derive(Subcommand)] +pub enum DecodeCommands { + #[command( + name = "read", + about = "Read Move module info from bytecode", + long_about = "Read and display basic information about a Move module from its bytecode file.\n\ + Example: initia-move decode read ./build/package/bytecode_modules/my_module.mv" + )] Read { + /// Path to the Move module bytecode file + #[arg(value_name = "FILE")] + path: String, + }, + + #[command( + name = "script", + about = "Decode Move script bytecode", + long_about = "Decode Move script bytecode and display its ABI (Application Binary Interface).\n\ + Example: initia-move decode script ./build/package/scripts/my_script.mv" + )] Script { + /// Path to the Move script bytecode file + #[arg(value_name = "FILE")] + path: String, + }, + + #[command( + name = "module", + about = "Decode Move module bytecode", + long_about = "Decode Move module bytecode and display its ABI (Application Binary Interface).\n\ + Example: initia-move decode module ./build/package/bytecode_modules/my_module.mv" + )] Module { + /// Path to the Move module bytecode file + #[arg(value_name = "FILE")] + path: String, + }, +} + +pub trait Decoder { + fn decode(self) -> anyhow::Result<()>; +} + +fn read_file(path: &str) -> anyhow::Result> { + let current_dir = std::env::current_dir()?; + let file_path = current_dir.join(PathBuf::from(path)); + fs::read(&file_path).with_context(|| format!("Failed to read file: {}", file_path.display())) +} + +impl Decoder for InitiaCLI { + fn decode(self) -> anyhow::Result<()> { + match &self.cmd { + InitiaCommand::Decode(cmd) => { + match &cmd.command { + DecodeCommands::Read { path } => { + let bytes = read_file(path)?; + let result = read_module_info(&bytes)?; + let mut json: serde_json::Value = serde_json::from_slice(&result)?; + + if let Some(address) = json.get_mut("address") { + if let serde_json::Value::Array(bytes) = address { + let hex = format!("0x{}", bytes.iter() + .filter_map(|b| b.as_u64()) + .map(|b| format!("{:02x}", b)) + .collect::()); + *address = serde_json::json!(hex); + } + } + println!("{}", serde_json::to_string_pretty(&json)?); + } + DecodeCommands::Script { path } => { + let bytes = read_file(path)?; + let result = decode_script_bytes(bytes)?; + let json: serde_json::Value = serde_json::from_slice(&result)?; + println!("{}", serde_json::to_string_pretty(&json)?); + } + DecodeCommands::Module { path } => { + let bytes = read_file(path)?; + let result = decode_module_bytes(bytes)?; + let json: serde_json::Value = serde_json::from_slice(&result)?; + println!("{}", serde_json::to_string_pretty(&json)?); + } + } + Ok(()) + } + _ => unreachable!(), + } + } +} diff --git a/tools/initia-move-cli/src/execute.rs b/tools/initia-move-cli/src/execute.rs index 269b7dd4..75e76d2b 100644 --- a/tools/initia-move-cli/src/execute.rs +++ b/tools/initia-move-cli/src/execute.rs @@ -1,5 +1,4 @@ -use anyhow::Error; -use initia_move_compiler::{execute, Command}; +use initia_move_compiler::{ execute, Command }; use crate::{InitiaCLI, InitiaCommand}; @@ -8,13 +7,14 @@ pub trait Execute { } impl Execute for InitiaCLI { - fn execute(self) -> anyhow::Result<(), Error> { + fn execute(self) -> anyhow::Result<()> { let move_args = self.move_args; let cmd = match self.cmd { InitiaCommand::Build(build) => Command::Build(build), InitiaCommand::Coverage(coverage) => Command::Coverage(coverage), InitiaCommand::New(new) => Command::New(new), InitiaCommand::Test(test) => Command::Test(test), + _ => unreachable!(), }; execute(move_args, cmd) } diff --git a/tools/initia-move-cli/src/main.rs b/tools/initia-move-cli/src/main.rs index af1cf61d..99992008 100644 --- a/tools/initia-move-cli/src/main.rs +++ b/tools/initia-move-cli/src/main.rs @@ -1,6 +1,8 @@ mod execute; +mod decode; use clap::Parser; +use decode::{ Decode, Decoder }; use execute::Execute; use initia_move_compiler::{ base::{build::Build, coverage::Coverage, test::Test}, @@ -12,37 +14,44 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); #[derive(Parser)] pub enum InitiaCommand { /// Build the package at `path`. If no path is provided defaults to current directory + #[command(flatten_help = true)] Build(Build), /// Inspect test coverage for this package + #[command(flatten_help = true)] Coverage(Coverage), /// Create a new Move package + #[command(flatten_help = true)] New(New), /// Run Move unit tests in this package + #[command(flatten_help = true)] Test(Test), + + /// Decode Move modules and scripts + #[command()] + Decode(Decode), } #[derive(Parser)] -#[command( - name = "initia-move", - about = "Initia Move CLI", - version = VERSION -)] +#[command(name = "initia-move", about = "Initia Move CLI", version = VERSION)] pub struct InitiaCLI { - #[clap(flatten)] - pub move_args: Move, - #[clap(subcommand)] pub cmd: InitiaCommand, + + #[command(flatten)] + pub move_args: Move, } fn main() -> anyhow::Result<()> { let cli = InitiaCLI::parse(); - if let Err(e) = cli.execute() { - eprintln!("Error: {}", e); - std::process::exit(1); + match cli.cmd { + InitiaCommand::Decode(_) => cli.decode()?, + | InitiaCommand::Build(_) + | InitiaCommand::Coverage(_) + | InitiaCommand::New(_) + | InitiaCommand::Test(_) => cli.execute()?, } Ok(()) } From 94322ec0b57490575c48736757d418437297d4f6 Mon Sep 17 00:00:00 2001 From: suha jin <89185836+djm07073@users.noreply.github.com> Date: Fri, 23 May 2025 16:49:17 +0900 Subject: [PATCH 2/6] fix: docker image push --- .github/workflows/move-cli.yml | 5 +-- tools/initia-move-cli/Dockerfile | 4 +++ tools/initia-move-cli/src/decode.rs | 56 +++++++++++++++++++---------- 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/.github/workflows/move-cli.yml b/.github/workflows/move-cli.yml index 2709b860..eeebc715 100644 --- a/.github/workflows/move-cli.yml +++ b/.github/workflows/move-cli.yml @@ -90,7 +90,6 @@ jobs: create-release: needs: [linux-build, macos-build] - if: ${{github.event.workflow_run.head_branch}} runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v4 @@ -129,7 +128,7 @@ jobs: with: registry: ghcr.io username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + password: ${{ secrets.CONTAINER_TOKEN }} - name: Build and push Docker image uses: docker/build-push-action@v5 @@ -137,6 +136,8 @@ jobs: context: tools/initia-move-cli file: tools/initia-move-cli/Dockerfile push: true + provenance: false + platforms: linux/amd64 tags: | ghcr.io/${{ github.repository_owner }}/initia-move-cli:latest ghcr.io/${{ github.repository_owner }}/initia-move-cli:${{ github.event.inputs.version || github.event.workflow_run.head_branch }} \ No newline at end of file diff --git a/tools/initia-move-cli/Dockerfile b/tools/initia-move-cli/Dockerfile index 1031f508..44cec072 100644 --- a/tools/initia-move-cli/Dockerfile +++ b/tools/initia-move-cli/Dockerfile @@ -1,5 +1,9 @@ FROM debian:bullseye-slim +RUN apt-get update && \ + apt-get install -y --no-install-recommends git ca-certificates && \ + rm -rf /var/lib/apt/lists/* + WORKDIR /usr/local/bin COPY initia-move-cli . RUN chmod +x initia-move-cli diff --git a/tools/initia-move-cli/src/decode.rs b/tools/initia-move-cli/src/decode.rs index b2800ed1..8048a937 100644 --- a/tools/initia-move-cli/src/decode.rs +++ b/tools/initia-move-cli/src/decode.rs @@ -23,9 +23,10 @@ pub enum DecodeCommands { long_about = "Read and display basic information about a Move module from its bytecode file.\n\ Example: initia-move decode read ./build/package/bytecode_modules/my_module.mv" )] Read { - /// Path to the Move module bytecode file - #[arg(value_name = "FILE")] - path: String, + #[arg(value_name = "PACKAGE_NAME")] + package_name: String, + #[arg(value_name = "MODULE_NAME")] + module_name: String, }, #[command( @@ -34,9 +35,10 @@ pub enum DecodeCommands { long_about = "Decode Move script bytecode and display its ABI (Application Binary Interface).\n\ Example: initia-move decode script ./build/package/scripts/my_script.mv" )] Script { - /// Path to the Move script bytecode file - #[arg(value_name = "FILE")] - path: String, + #[arg(value_name = "PACKAGE_NAME")] + package_name: String, + #[arg(value_name = "SCRIPT_NAME")] + script_name: String, }, #[command( @@ -45,9 +47,10 @@ pub enum DecodeCommands { long_about = "Decode Move module bytecode and display its ABI (Application Binary Interface).\n\ Example: initia-move decode module ./build/package/bytecode_modules/my_module.mv" )] Module { - /// Path to the Move module bytecode file - #[arg(value_name = "FILE")] - path: String, + #[arg(value_name = "PACKAGE_NAME")] + package_name: String, + #[arg(value_name = "MODULE_NAME")] + module_name: String, }, } @@ -66,30 +69,45 @@ impl Decoder for InitiaCLI { match &self.cmd { InitiaCommand::Decode(cmd) => { match &cmd.command { - DecodeCommands::Read { path } => { - let bytes = read_file(path)?; + DecodeCommands::Read { package_name, module_name } => { + let path = format!( + "build/{}/bytecode_modules/{}.mv", + package_name, + module_name + ); + let bytes = read_file(&path)?; let result = read_module_info(&bytes)?; let mut json: serde_json::Value = serde_json::from_slice(&result)?; if let Some(address) = json.get_mut("address") { if let serde_json::Value::Array(bytes) = address { - let hex = format!("0x{}", bytes.iter() - .filter_map(|b| b.as_u64()) - .map(|b| format!("{:02x}", b)) - .collect::()); + let hex = format!( + "0x{}", + bytes + .iter() + .filter_map(|b| b.as_u64()) + .map(|b| format!("{:02x}", b)) + .collect::() + ); *address = serde_json::json!(hex); } } println!("{}", serde_json::to_string_pretty(&json)?); } - DecodeCommands::Script { path } => { - let bytes = read_file(path)?; + DecodeCommands::Script { package_name, script_name } => { + let path = format!("build/{}/scripts/bytecode_scripts/{}.mv", package_name, script_name); + let bytes = read_file(&path)?; let result = decode_script_bytes(bytes)?; let json: serde_json::Value = serde_json::from_slice(&result)?; println!("{}", serde_json::to_string_pretty(&json)?); } - DecodeCommands::Module { path } => { - let bytes = read_file(path)?; + DecodeCommands::Module { package_name, module_name } => { + let path = format!( + "build/{}/bytecode_modules/{}.mv", + package_name, + module_name + ); + let bytes = read_file(&path)?; let result = decode_module_bytes(bytes)?; let json: serde_json::Value = serde_json::from_slice(&result)?; println!("{}", serde_json::to_string_pretty(&json)?); From 8def2824e868c827527912f0c9f1d5da13a56c2b Mon Sep 17 00:00:00 2001 From: suha jin <89185836+djm07073@users.noreply.github.com> Date: Mon, 26 May 2025 14:52:55 +0900 Subject: [PATCH 3/6] chore(fix): move-cli.yml --- .github/workflows/move-cli.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/move-cli.yml b/.github/workflows/move-cli.yml index eeebc715..974a38bb 100644 --- a/.github/workflows/move-cli.yml +++ b/.github/workflows/move-cli.yml @@ -90,6 +90,7 @@ jobs: create-release: needs: [linux-build, macos-build] + if: ${{github.event.workflow_run.head_branch}} runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v4 @@ -128,7 +129,7 @@ jobs: with: registry: ghcr.io username: ${{ github.actor }} - password: ${{ secrets.CONTAINER_TOKEN }} + password: ${{ secrets.REGISTRY_TOKEN }} - name: Build and push Docker image uses: docker/build-push-action@v5 From b86cedb4d65ce870530dfea0325ab1de535d0f91 Mon Sep 17 00:00:00 2001 From: suha jin <89185836+djm07073@users.noreply.github.com> Date: Mon, 26 May 2025 15:34:33 +0900 Subject: [PATCH 4/6] fmt --- libmovevm/src/lib.rs | 12 +++---- libmovevm/src/move_api/handler.rs | 39 +++++++++++---------- tools/initia-move-cli/src/decode.rs | 51 ++++++++++++++++------------ tools/initia-move-cli/src/execute.rs | 2 +- tools/initia-move-cli/src/main.rs | 6 ++-- 5 files changed, 57 insertions(+), 53 deletions(-) diff --git a/libmovevm/src/lib.rs b/libmovevm/src/lib.rs index ae5f95be..8e815a9e 100644 --- a/libmovevm/src/lib.rs +++ b/libmovevm/src/lib.rs @@ -1,6 +1,5 @@ #![allow(clippy::not_unsafe_ptr_arg_deref, clippy::missing_safety_doc)] -pub mod move_api; mod api; mod args; mod db; @@ -8,6 +7,7 @@ mod error; mod interface; mod iterator; mod memory; +pub mod move_api; mod result; mod storage; mod table_storage; @@ -16,16 +16,12 @@ mod vm; // We only interact with this crate via `extern "C"` interfaces, not those public // exports. There are no guarantees those exports are stable. // We keep them here such that we can access them in the docs (`cargo doc`). -pub use api::{ GoApi, GoApi_vtable }; -pub use db::{ db_t, Db }; +pub use api::{GoApi, GoApi_vtable}; +pub use db::{db_t, Db}; pub use error::GoError; pub use iterator::Iterator_vtable; pub use memory::{ - destroy_unmanaged_vector, - new_unmanaged_vector, - ByteSliceView, - U8SliceView, - UnmanagedVector, + destroy_unmanaged_vector, new_unmanaged_vector, ByteSliceView, U8SliceView, UnmanagedVector, }; pub use storage::GoStorage; diff --git a/libmovevm/src/move_api/handler.rs b/libmovevm/src/move_api/handler.rs index 8034cad9..c66ef2d9 100644 --- a/libmovevm/src/move_api/handler.rs +++ b/libmovevm/src/move_api/handler.rs @@ -1,12 +1,12 @@ use crate::move_api::convert::MoveConverter; -use crate::move_api::move_types::{ MoveModuleBytecode, MoveScriptBytecode }; +use crate::move_api::move_types::{MoveModuleBytecode, MoveScriptBytecode}; use crate::result::to_vec; -use crate::{ error::Error, Db, GoStorage }; +use crate::{error::Error, Db, GoStorage}; use move_binary_format::access::ModuleAccess; use move_binary_format::deserializer::DeserializerConfig; use move_binary_format::CompiledModule; -use move_core_types::language_storage::{ StructTag, TypeTag }; +use move_core_types::language_storage::{StructTag, TypeTag}; use move_core_types::parser::parse_struct_tag; use serde::Serialize; @@ -18,10 +18,8 @@ struct ModuleInfoResponse { } pub fn read_module_info(compiled: &[u8]) -> Result, Error> { - let m = CompiledModule::deserialize_with_config( - compiled, - &DeserializerConfig::default() - ).map_err(|e| Error::backend_failure(e.to_string()))?; + let m = CompiledModule::deserialize_with_config(compiled, &DeserializerConfig::default()) + .map_err(|e| Error::backend_failure(e.to_string()))?; let module_info = ModuleInfoResponse { address: m.address().to_vec(), @@ -31,26 +29,23 @@ pub fn read_module_info(compiled: &[u8]) -> Result, Error> { } pub(crate) fn struct_tag_to_string(struct_tag: &[u8]) -> Result, Error> { - let struct_tag: StructTag = bcs - ::from_bytes(struct_tag) - .map_err(|e| Error::backend_failure(e.to_string()))?; + let struct_tag: StructTag = + bcs::from_bytes(struct_tag).map_err(|e| Error::backend_failure(e.to_string()))?; Ok(struct_tag.to_string().as_bytes().to_vec()) } pub(crate) fn struct_tag_from_string(struct_tag_str: &[u8]) -> Result, Error> { - let struct_tag_str = std::str - ::from_utf8(struct_tag_str) - .map_err(|e| Error::invalid_utf8(e.to_string()))?; - let struct_tag = parse_struct_tag(struct_tag_str).map_err(|e| - Error::backend_failure(e.to_string()) - )?; + let struct_tag_str = + std::str::from_utf8(struct_tag_str).map_err(|e| Error::invalid_utf8(e.to_string()))?; + let struct_tag = + parse_struct_tag(struct_tag_str).map_err(|e| Error::backend_failure(e.to_string()))?; to_vec(&struct_tag) } pub(crate) fn decode_move_resource( db_handle: Db, struct_tag: &[u8], - blob: &[u8] + blob: &[u8], ) -> Result, Error> { let storage = GoStorage::new(&db_handle); let struct_tag: StructTag = bcs::from_bytes(struct_tag).unwrap(); @@ -67,7 +62,7 @@ pub(crate) fn decode_move_resource( pub(crate) fn decode_move_value( db_handle: Db, type_tag: &[u8], - blob: &[u8] + blob: &[u8], ) -> Result, Error> { let storage = GoStorage::new(&db_handle); let type_tag: TypeTag = bcs::from_bytes(type_tag).unwrap(); @@ -83,7 +78,9 @@ pub(crate) fn decode_move_value( pub fn decode_script_bytes(script_bytes: Vec) -> Result, Error> { let script: MoveScriptBytecode = MoveScriptBytecode::new(script_bytes); - let abi = script.try_parse_abi().map_err(|e| Error::BackendFailure { msg: e.to_string() })?; + let abi = script + .try_parse_abi() + .map_err(|e| Error::BackendFailure { msg: e.to_string() })?; // serialize response as json serde_json::to_vec(&abi).map_err(|e| Error::BackendFailure { msg: e.to_string() }) @@ -92,7 +89,9 @@ pub fn decode_script_bytes(script_bytes: Vec) -> Result, Error> { pub fn decode_module_bytes(module_bytes: Vec) -> Result, Error> { // deserialized request from the json let module: MoveModuleBytecode = MoveModuleBytecode::new(module_bytes); - let abi = module.try_parse_abi().map_err(|e| Error::BackendFailure { msg: e.to_string() })?; + let abi = module + .try_parse_abi() + .map_err(|e| Error::BackendFailure { msg: e.to_string() })?; // serialize response as json serde_json::to_vec(&abi).map_err(|e| Error::BackendFailure { msg: e.to_string() }) } diff --git a/tools/initia-move-cli/src/decode.rs b/tools/initia-move-cli/src/decode.rs index 8048a937..d726fe6c 100644 --- a/tools/initia-move-cli/src/decode.rs +++ b/tools/initia-move-cli/src/decode.rs @@ -1,8 +1,8 @@ -use crate::{ InitiaCLI, InitiaCommand }; -use std::{ fs, path::PathBuf }; +use crate::{InitiaCLI, InitiaCommand}; use anyhow::Context; -use clap::{ Parser, Subcommand }; -use movevm::move_api::handler::{ decode_module_bytes, decode_script_bytes, read_module_info }; +use clap::{Parser, Subcommand}; +use movevm::move_api::handler::{decode_module_bytes, decode_script_bytes, read_module_info}; +use std::{fs, path::PathBuf}; #[derive(Parser)] #[command( @@ -22,7 +22,8 @@ pub enum DecodeCommands { about = "Read Move module info from bytecode", long_about = "Read and display basic information about a Move module from its bytecode file.\n\ Example: initia-move decode read ./build/package/bytecode_modules/my_module.mv" - )] Read { + )] + Read { #[arg(value_name = "PACKAGE_NAME")] package_name: String, #[arg(value_name = "MODULE_NAME")] @@ -34,7 +35,8 @@ pub enum DecodeCommands { about = "Decode Move script bytecode", long_about = "Decode Move script bytecode and display its ABI (Application Binary Interface).\n\ Example: initia-move decode script ./build/package/scripts/my_script.mv" - )] Script { + )] + Script { #[arg(value_name = "PACKAGE_NAME")] package_name: String, #[arg(value_name = "SCRIPT_NAME")] @@ -46,7 +48,8 @@ pub enum DecodeCommands { about = "Decode Move module bytecode", long_about = "Decode Move module bytecode and display its ABI (Application Binary Interface).\n\ Example: initia-move decode module ./build/package/bytecode_modules/my_module.mv" - )] Module { + )] + Module { #[arg(value_name = "PACKAGE_NAME")] package_name: String, #[arg(value_name = "MODULE_NAME")] @@ -69,12 +72,12 @@ impl Decoder for InitiaCLI { match &self.cmd { InitiaCommand::Decode(cmd) => { match &cmd.command { - DecodeCommands::Read { package_name, module_name } => { - let path = format!( - "build/{}/bytecode_modules/{}.mv", - package_name, - module_name - ); + DecodeCommands::Read { + package_name, + module_name, + } => { + let path = + format!("build/{}/bytecode_modules/{}.mv", package_name, module_name); let bytes = read_file(&path)?; let result = read_module_info(&bytes)?; let mut json: serde_json::Value = serde_json::from_slice(&result)?; @@ -94,19 +97,25 @@ impl Decoder for InitiaCLI { } println!("{}", serde_json::to_string_pretty(&json)?); } - DecodeCommands::Script { package_name, script_name } => { - let path = format!("build/{}/scripts/bytecode_scripts/{}.mv", package_name, script_name); + DecodeCommands::Script { + package_name, + script_name, + } => { + let path = format!( + "build/{}/scripts/bytecode_scripts/{}.mv", + package_name, script_name + ); let bytes = read_file(&path)?; let result = decode_script_bytes(bytes)?; let json: serde_json::Value = serde_json::from_slice(&result)?; println!("{}", serde_json::to_string_pretty(&json)?); } - DecodeCommands::Module { package_name, module_name } => { - let path = format!( - "build/{}/bytecode_modules/{}.mv", - package_name, - module_name - ); + DecodeCommands::Module { + package_name, + module_name, + } => { + let path = + format!("build/{}/bytecode_modules/{}.mv", package_name, module_name); let bytes = read_file(&path)?; let result = decode_module_bytes(bytes)?; let json: serde_json::Value = serde_json::from_slice(&result)?; diff --git a/tools/initia-move-cli/src/execute.rs b/tools/initia-move-cli/src/execute.rs index 75e76d2b..b0cda18c 100644 --- a/tools/initia-move-cli/src/execute.rs +++ b/tools/initia-move-cli/src/execute.rs @@ -1,4 +1,4 @@ -use initia_move_compiler::{ execute, Command }; +use initia_move_compiler::{execute, Command}; use crate::{InitiaCLI, InitiaCommand}; diff --git a/tools/initia-move-cli/src/main.rs b/tools/initia-move-cli/src/main.rs index 99992008..ae16939c 100644 --- a/tools/initia-move-cli/src/main.rs +++ b/tools/initia-move-cli/src/main.rs @@ -1,8 +1,8 @@ -mod execute; mod decode; +mod execute; use clap::Parser; -use decode::{ Decode, Decoder }; +use decode::{Decode, Decoder}; use execute::Execute; use initia_move_compiler::{ base::{build::Build, coverage::Coverage, test::Test}, @@ -48,7 +48,7 @@ fn main() -> anyhow::Result<()> { let cli = InitiaCLI::parse(); match cli.cmd { InitiaCommand::Decode(_) => cli.decode()?, - | InitiaCommand::Build(_) + InitiaCommand::Build(_) | InitiaCommand::Coverage(_) | InitiaCommand::New(_) | InitiaCommand::Test(_) => cli.execute()?, From 8cb4952ed1530a14275800add97b29fd6fa6345f Mon Sep 17 00:00:00 2001 From: suha jin <89185836+djm07073@users.noreply.github.com> Date: Mon, 26 May 2025 16:44:18 +0900 Subject: [PATCH 5/6] chore: update readme --- tools/initia-move-cli/README.md | 63 +++++++++++++++++---------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/tools/initia-move-cli/README.md b/tools/initia-move-cli/README.md index 7b45bdde..0e79bfe8 100644 --- a/tools/initia-move-cli/README.md +++ b/tools/initia-move-cli/README.md @@ -72,38 +72,39 @@ sudo install -m 755 initia-move-cli /usr/local/bin/initia-move rm initia-move-cli-$VERSION-linux-arm64.tar.gz ``` -### How to use it +### Using Docker Container + +You can run the Move CLI tool using Docker without installing it locally. Here's how to use it: ```bash -Initia Move CLI - -Usage: initia-move [OPTIONS] - -Commands: - build Build the package at `path`. If no path is provided defaults to current directory - coverage Inspect test coverage for this package - new Create a new Move package - test Run Move unit tests in this package - help Print this message or the help of the given subcommand(s) - -Options: - -p, --path Path to a package which the command should be run with respect to - -v Print additional diagnostics if available - -d, --dev Compile in 'dev' mode. The 'dev-addresses' and 'dev-dependencies' fields will be used if this flag is set. This flag is - useful for development of packages that expose named addresses that are not set to a specific value - --test Compile in 'test' mode. The 'dev-addresses' and 'dev-dependencies' fields will be used along with any code in the 'tests' - directory - --override-std Whether to override the standard library with the given version [possible values: mainnet, testnet, devnet] - --doc Generate documentation for packages - --abi Generate ABIs for packages - --install-dir Installation directory for compiled artifacts. Defaults to current directory - --force Force recompilation of all packages - --fetch-deps-only Only fetch dependency repos to MOVE_HOME - --skip-fetch-latest-git-deps Skip fetching latest git dependencies - --bytecode-version Bytecode version to compile move code - --skip-attribute-checks Do not complain about an unknown attribute in Move code - --compiler-version Compiler version to use - --language-version Language version to support - --experiments Experiments for v2 compiler to set to true +docker run --rm \ + -v "$(pwd):/code:delegated" \ + -w /code \ + ghcr.io/initia-labs/initia-move-cli:latest \ + +``` +Example commands: +```bash +# Build Move modules +docker run --rm -v "$(pwd):/code" -w /code ghcr.io/initia-labs/initia-move-cli:latest build + +# Run tests +docker run --rm -v "$(pwd):/code" -w /code ghcr.io/initia-labs/initia-move-cli:latest test + +# Decode Move module +docker run --rm -v "$(pwd):/code" -w /code ghcr.io/initia-labs/initia-move-cli:latest decode read my_package my_module ``` + +For easier use, you can create an alias in your shell: +```bash +alias initia-move='docker run --rm -v "$(pwd):/code" -w /code ghcr.io/initia-labs/initia-move-cli:latest' +``` + +Then use it like the native command: +```bash +initia-move build +initia-move test + +### How to use it +initia-move From b461ee2678a619eeda602bd223100bf411500ab9 Mon Sep 17 00:00:00 2001 From: suha jin <89185836+djm07073@users.noreply.github.com> Date: Mon, 26 May 2025 19:15:11 +0900 Subject: [PATCH 6/6] fix: add package path option in decode --- tools/initia-move-cli/src/decode.rs | 36 +++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/tools/initia-move-cli/src/decode.rs b/tools/initia-move-cli/src/decode.rs index d726fe6c..288ec1b1 100644 --- a/tools/initia-move-cli/src/decode.rs +++ b/tools/initia-move-cli/src/decode.rs @@ -28,6 +28,13 @@ pub enum DecodeCommands { package_name: String, #[arg(value_name = "MODULE_NAME")] module_name: String, + #[clap( + long = "path", + short = 'p', + value_name = "PACKAGE_PATH", + help = "Path to the package directory" + )] + package_path: Option, }, #[command( @@ -41,6 +48,13 @@ pub enum DecodeCommands { package_name: String, #[arg(value_name = "SCRIPT_NAME")] script_name: String, + #[clap( + long = "path", + short = 'p', + value_name = "PACKAGE_PATH", + help = "Path to the package directory" + )] + package_path: Option, }, #[command( @@ -54,6 +68,13 @@ pub enum DecodeCommands { package_name: String, #[arg(value_name = "MODULE_NAME")] module_name: String, + #[clap( + long = "path", + short = 'p', + value_name = "PACKAGE_PATH", + help = "Path to the package directory" + )] + package_path: Option, }, } @@ -61,8 +82,10 @@ pub trait Decoder { fn decode(self) -> anyhow::Result<()>; } -fn read_file(path: &str) -> anyhow::Result> { - let current_dir = std::env::current_dir()?; +fn read_file(package_path: &Option, path: &str) -> anyhow::Result> { + let current_dir = package_path + .clone() + .unwrap_or_else(|| std::env::current_dir().expect("Failed to get current directory")); let file_path = current_dir.join(PathBuf::from(path)); fs::read(&file_path).with_context(|| format!("Failed to read file: {}", file_path.display())) } @@ -75,10 +98,11 @@ impl Decoder for InitiaCLI { DecodeCommands::Read { package_name, module_name, + package_path, } => { let path = format!("build/{}/bytecode_modules/{}.mv", package_name, module_name); - let bytes = read_file(&path)?; + let bytes = read_file(package_path, &path)?; let result = read_module_info(&bytes)?; let mut json: serde_json::Value = serde_json::from_slice(&result)?; @@ -100,12 +124,13 @@ impl Decoder for InitiaCLI { DecodeCommands::Script { package_name, script_name, + package_path, } => { let path = format!( "build/{}/scripts/bytecode_scripts/{}.mv", package_name, script_name ); - let bytes = read_file(&path)?; + let bytes = read_file(package_path, &path)?; let result = decode_script_bytes(bytes)?; let json: serde_json::Value = serde_json::from_slice(&result)?; println!("{}", serde_json::to_string_pretty(&json)?); @@ -113,10 +138,11 @@ impl Decoder for InitiaCLI { DecodeCommands::Module { package_name, module_name, + package_path, } => { let path = format!("build/{}/bytecode_modules/{}.mv", package_name, module_name); - let bytes = read_file(&path)?; + let bytes = read_file(package_path, &path)?; let result = decode_module_bytes(bytes)?; let json: serde_json::Value = serde_json::from_slice(&result)?; println!("{}", serde_json::to_string_pretty(&json)?);