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

[decompiler] Downgrade to bytecode v6 for Revela #15597

Merged
merged 1 commit into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 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
- Downgrade bytecode version to v6 before calling the Revela decompiler, if possible, i.e. no enum types are used. This allows to continue to use Revela until the new decompiler is ready.

## [5.0.0] - 2024/12/11
- [**Breaking Change**] `aptos init` and `aptos account fund-with-faucet` no longer work directly with testnet, you must now use the minting page at the [Aptos dev docs](https://aptos.dev/network/faucet).
Expand Down
58 changes: 56 additions & 2 deletions crates/aptos/src/move_tool/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ use async_trait::async_trait;
use clap::{Args, Parser};
use itertools::Itertools;
use move_binary_format::{
binary_views::BinaryIndexedView, file_format::CompiledScript, CompiledModule,
binary_views::BinaryIndexedView, file_format::CompiledScript, file_format_common,
CompiledModule,
};
use move_bytecode_source_map::{mapping::SourceMapping, utils::source_map_from_file};
use move_command_line_common::files::{
Expand All @@ -37,6 +38,7 @@ use std::{
process::Command,
str,
};
use tempfile::NamedTempFile;

const DISASSEMBLER_EXTENSION: &str = "mv.asm";
const DECOMPILER_EXTENSION: &str = "mv.move";
Expand Down Expand Up @@ -323,7 +325,14 @@ impl BytecodeCommand {
let exe = get_revela_path()?;
let to_cli_error = |e| CliError::IO(exe.display().to_string(), e);
let mut cmd = Command::new(exe.as_path());
cmd.arg(format!("--bytecode={}", bytecode_path.display()));
// WORKAROUND: if the bytecode is v7, try to downgrade to v6 since Revela
// does not support v7
let v6_temp_file = self.downgrade_to_v6(bytecode_path)?;
if let Some(file) = &v6_temp_file {
cmd.arg(format!("--bytecode={}", file.path().display()));
} else {
cmd.arg(format!("--bytecode={}", bytecode_path.display()));
}
if self.is_script {
cmd.arg("--script");
}
Expand All @@ -343,4 +352,49 @@ impl BytecodeCommand {
)))
}
}

fn downgrade_to_v6(&self, file_path: &Path) -> Result<Option<NamedTempFile>, CliError> {
let error_explanation = || {
format!(
"{} in `{}` contains Move 2 features (e.g. enum types) \
types which are not yet supported by the decompiler",
if self.is_script { "script " } else { "module" },
file_path.display()
)
};
let create_new_bytecode = |bytes: &[u8]| -> Result<NamedTempFile, CliError> {
let temp_file = NamedTempFile::new()
.map_err(|e| CliError::IO("creating v6 temp file".to_string(), e))?;
fs::write(temp_file.path(), bytes)
.map_err(|e| CliError::IO("writing v6 temp file".to_string(), e))?;
Ok(temp_file)
};
let bytes = read_from_file(file_path)?;
if self.is_script {
let script = CompiledScript::deserialize(&bytes).map_err(|e| {
CliError::UnableToParse("script", format!("cannot deserialize: {}", e))
})?;
if script.version < file_format_common::VERSION_7 {
return Ok(None);
}
let mut new_bytes = vec![];
script
.serialize_for_version(Some(file_format_common::VERSION_6), &mut new_bytes)
// The only reason why this can fail is because of Move 2 features
.map_err(|_| CliError::UnexpectedError(error_explanation()))?;
Ok(Some(create_new_bytecode(&new_bytes)?))
} else {
let module = CompiledModule::deserialize(&bytes).map_err(|e| {
CliError::UnableToParse("script", format!("cannot deserialize: {}", e))
})?;
if module.version < file_format_common::VERSION_7 {
return Ok(None);
}
let mut new_bytes = vec![];
module
.serialize_for_version(Some(file_format_common::VERSION_6), &mut new_bytes)
.map_err(|_| CliError::UnexpectedError(error_explanation()))?;
Ok(Some(create_new_bytecode(&new_bytes)?))
}
}
}
Loading