Skip to content

Commit bd71e35

Browse files
authored
[decompiler] Downgrade to bytecode v6 for Revela (aptos-labs#15597)
Since the bytecode version default is v7, Revela cannot be used at all anymore. This PR attempts to downgrade to v6 before calling Revela, if possible. This allows to continue to work with Revela until the new decompiler is available.
1 parent c9b71bc commit bd71e35

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

crates/aptos/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
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/).
44

55
# Unreleased
6+
- 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.
67

78
## [5.0.0] - 2024/12/11
89
- [**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).

crates/aptos/src/move_tool/bytecode.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use async_trait::async_trait;
2020
use clap::{Args, Parser};
2121
use itertools::Itertools;
2222
use move_binary_format::{
23-
binary_views::BinaryIndexedView, file_format::CompiledScript, CompiledModule,
23+
binary_views::BinaryIndexedView, file_format::CompiledScript, file_format_common,
24+
CompiledModule,
2425
};
2526
use move_bytecode_source_map::{mapping::SourceMapping, utils::source_map_from_file};
2627
use move_command_line_common::files::{
@@ -37,6 +38,7 @@ use std::{
3738
process::Command,
3839
str,
3940
};
41+
use tempfile::NamedTempFile;
4042

4143
const DISASSEMBLER_EXTENSION: &str = "mv.asm";
4244
const DECOMPILER_EXTENSION: &str = "mv.move";
@@ -323,7 +325,14 @@ impl BytecodeCommand {
323325
let exe = get_revela_path()?;
324326
let to_cli_error = |e| CliError::IO(exe.display().to_string(), e);
325327
let mut cmd = Command::new(exe.as_path());
326-
cmd.arg(format!("--bytecode={}", bytecode_path.display()));
328+
// WORKAROUND: if the bytecode is v7, try to downgrade to v6 since Revela
329+
// does not support v7
330+
let v6_temp_file = self.downgrade_to_v6(bytecode_path)?;
331+
if let Some(file) = &v6_temp_file {
332+
cmd.arg(format!("--bytecode={}", file.path().display()));
333+
} else {
334+
cmd.arg(format!("--bytecode={}", bytecode_path.display()));
335+
}
327336
if self.is_script {
328337
cmd.arg("--script");
329338
}
@@ -343,4 +352,49 @@ impl BytecodeCommand {
343352
)))
344353
}
345354
}
355+
356+
fn downgrade_to_v6(&self, file_path: &Path) -> Result<Option<NamedTempFile>, CliError> {
357+
let error_explanation = || {
358+
format!(
359+
"{} in `{}` contains Move 2 features (e.g. enum types) \
360+
types which are not yet supported by the decompiler",
361+
if self.is_script { "script " } else { "module" },
362+
file_path.display()
363+
)
364+
};
365+
let create_new_bytecode = |bytes: &[u8]| -> Result<NamedTempFile, CliError> {
366+
let temp_file = NamedTempFile::new()
367+
.map_err(|e| CliError::IO("creating v6 temp file".to_string(), e))?;
368+
fs::write(temp_file.path(), bytes)
369+
.map_err(|e| CliError::IO("writing v6 temp file".to_string(), e))?;
370+
Ok(temp_file)
371+
};
372+
let bytes = read_from_file(file_path)?;
373+
if self.is_script {
374+
let script = CompiledScript::deserialize(&bytes).map_err(|e| {
375+
CliError::UnableToParse("script", format!("cannot deserialize: {}", e))
376+
})?;
377+
if script.version < file_format_common::VERSION_7 {
378+
return Ok(None);
379+
}
380+
let mut new_bytes = vec![];
381+
script
382+
.serialize_for_version(Some(file_format_common::VERSION_6), &mut new_bytes)
383+
// The only reason why this can fail is because of Move 2 features
384+
.map_err(|_| CliError::UnexpectedError(error_explanation()))?;
385+
Ok(Some(create_new_bytecode(&new_bytes)?))
386+
} else {
387+
let module = CompiledModule::deserialize(&bytes).map_err(|e| {
388+
CliError::UnableToParse("script", format!("cannot deserialize: {}", e))
389+
})?;
390+
if module.version < file_format_common::VERSION_7 {
391+
return Ok(None);
392+
}
393+
let mut new_bytes = vec![];
394+
module
395+
.serialize_for_version(Some(file_format_common::VERSION_6), &mut new_bytes)
396+
.map_err(|_| CliError::UnexpectedError(error_explanation()))?;
397+
Ok(Some(create_new_bytecode(&new_bytes)?))
398+
}
399+
}
346400
}

0 commit comments

Comments
 (0)