Skip to content

Commit

Permalink
[CLI] add option to aptos move decompile and `aptos move disassembl…
Browse files Browse the repository at this point in the history
…e` to print out metadata attached to the bytecode (#15273)

* add compiler option

* print metadata

* handle comments

* print json

* update changelog
  • Loading branch information
rahxephon89 authored Nov 19, 2024
1 parent 11490b5 commit fc9afa8
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 0 deletions.
1 change: 1 addition & 0 deletions crates/aptos/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
All notable changes to the Aptos CLI will be captured in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and the format set out by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## Unreleased
- Add option `--print-metadata-only` to `aptos move decompile` and `aptos move disassemble` to print out the metadata attached to the bytecode.

## [4.5.0] - 2024/11/15
- Determine network from URL to make explorer links better for legacy users
Expand Down
62 changes: 62 additions & 0 deletions crates/aptos/src/move_tool/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ use crate::{
update::get_revela_path,
};
use anyhow::Context;
use aptos_framework::{
get_compilation_metadata_from_compiled_module, get_compilation_metadata_from_compiled_script,
get_metadata_from_compiled_module, get_metadata_from_compiled_script, RuntimeModuleMetadataV1,
};
use async_trait::async_trait;
use clap::{Args, Parser};
use itertools::Itertools;
Expand All @@ -25,10 +29,13 @@ use move_command_line_common::files::{
use move_coverage::coverage_map::CoverageMap;
use move_disassembler::disassembler::{Disassembler, DisassemblerOptions};
use move_ir_types::location::Spanned;
use move_model::metadata::{CompilationMetadata, CompilerVersion, LanguageVersion};
use serde::{Deserialize, Serialize};
use std::{
fs,
path::{Path, PathBuf},
process::Command,
str,
};

const DISASSEMBLER_EXTENSION: &str = "mv.asm";
Expand Down Expand Up @@ -80,6 +87,11 @@ pub struct BytecodeCommand {

#[clap(flatten)]
pub(crate) prompt_options: PromptOptions,

/// When `--bytecode-path` is set with this option,
/// only print out the metadata and bytecode version of the target bytecode
#[clap(long)]
pub print_metadata_only: bool,
}

/// Allows to ensure that either one of both is selected (via the `group` attribute).
Expand Down Expand Up @@ -127,6 +139,13 @@ impl CliCommand<String> for Decompile {
}
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
struct BytecodeMetadata {
aptos_metadata: Option<RuntimeModuleMetadataV1>,
bytecode_version: u32,
compilation_metadata: CompilationMetadata,
}

impl BytecodeCommand {
async fn execute(self, command_type: BytecodeCommandType) -> CliTypedResult<String> {
let inputs = if let Some(path) = self.input.bytecode_path.clone() {
Expand All @@ -141,6 +160,10 @@ impl BytecodeCommand {
unreachable!("arguments required by clap")
};

if self.print_metadata_only && self.input.bytecode_path.is_some() {
return self.print_metadata(&inputs[0]);
}

let mut report = vec![];
let mut last_out_dir = String::new();
for bytecode_path in inputs {
Expand Down Expand Up @@ -201,6 +224,45 @@ impl BytecodeCommand {
})
}

fn print_metadata(&self, bytecode_path: &Path) -> Result<String, CliError> {
let bytecode_bytes = read_from_file(bytecode_path)?;

let v1_metadata = CompilationMetadata {
unstable: false,
compiler_version: CompilerVersion::V1.to_string(),
language_version: LanguageVersion::V1.to_string(),
};
let metadata = if self.is_script {
let script = CompiledScript::deserialize(&bytecode_bytes)
.context("Script blob can't be deserialized")?;
if let Some(data) = get_compilation_metadata_from_compiled_script(&script) {
serde_json::to_string_pretty(&data).expect("expect compilation metadata")
} else {
serde_json::to_string_pretty(&v1_metadata).expect("expect compilation metadata")
};
BytecodeMetadata {
aptos_metadata: get_metadata_from_compiled_script(&script),
bytecode_version: script.version,
compilation_metadata: get_compilation_metadata_from_compiled_script(&script)
.unwrap_or(v1_metadata),
}
} else {
let module = CompiledModule::deserialize(&bytecode_bytes)
.context("Module blob can't be deserialized")?;
BytecodeMetadata {
aptos_metadata: get_metadata_from_compiled_module(&module),
bytecode_version: module.version,
compilation_metadata: get_compilation_metadata_from_compiled_module(&module)
.unwrap_or(v1_metadata),
}
};
println!(
"Metadata: {}",
serde_json::to_string_pretty(&metadata).expect("expect metadata")
);
Ok("ok".to_string())
}

fn disassemble(&self, bytecode_path: &Path) -> Result<String, CliError> {
let bytecode_bytes = read_from_file(bytecode_path)?;
let move_path = bytecode_path.with_extension(MOVE_EXTENSION);
Expand Down

0 comments on commit fc9afa8

Please sign in to comment.