diff --git a/crates/sui-move/src/build.rs b/crates/sui-move/src/build.rs index 421ff6ca964fe9..77ef3f8430ac26 100644 --- a/crates/sui-move/src/build.rs +++ b/crates/sui-move/src/build.rs @@ -29,6 +29,11 @@ pub struct Build { /// and events. #[clap(long, global = true)] pub generate_struct_layouts: bool, + /// The chain ID, if resolved. Required when the dump_bytecode_as_base64 is true, + /// for automated address management, where package addresses are resolved for the0 + /// respective chain in the Move.lock file. + #[clap(skip)] + pub chain_id: Option, } impl Build { @@ -45,6 +50,7 @@ impl Build { self.with_unpublished_dependencies, self.dump_bytecode_as_base64, self.generate_struct_layouts, + self.chain_id.clone(), ) } @@ -54,12 +60,13 @@ impl Build { with_unpublished_deps: bool, dump_bytecode_as_base64: bool, generate_struct_layouts: bool, + chain_id: Option, ) -> anyhow::Result<()> { let pkg = BuildConfig { config, run_bytecode_verifier: true, print_diags_to_stderr: true, - chain_id: None, + chain_id, } .build(rerooted_path)?; if dump_bytecode_as_base64 { diff --git a/crates/sui/src/sui_commands.rs b/crates/sui/src/sui_commands.rs index b59ca8a50ad86d..3254dfa40fa31e 100644 --- a/crates/sui/src/sui_commands.rs +++ b/crates/sui/src/sui_commands.rs @@ -449,7 +449,25 @@ impl SuiCommand { package_path, build_config, cmd, - } => execute_move_command(package_path.as_deref(), build_config, cmd), + } => { + let cmd = match cmd { + sui_move::Command::Build(mut build) if build.dump_bytecode_as_base64 => { + // `sui move build` does not ordinarily require a network connection. + // The exception is when --dump-bytecode-as-base64 is specified: In this + // case, we should resolve the correct addresses for the respective chain + // (e.g., testnet, mainnet) from the Move.lock under automated address management. + let config = sui_config_dir()?.join(SUI_CLIENT_CONFIG); + prompt_if_no_config(&config, false).await?; + let context = WalletContext::new(&config, None, None)?; + let client = context.get_client().await?; + let chain_id = client.read_api().get_chain_identifier().await.ok(); + build.chain_id = chain_id; + sui_move::Command::Build(build) + } + _ => cmd, + }; + execute_move_command(package_path.as_deref(), build_config, cmd) + } SuiCommand::BridgeInitialize { network_config, client_config, diff --git a/crates/sui/tests/cli_tests.rs b/crates/sui/tests/cli_tests.rs index 59a13bc6e4c7e9..d8e6ff008206dd 100644 --- a/crates/sui/tests/cli_tests.rs +++ b/crates/sui/tests/cli_tests.rs @@ -7,6 +7,7 @@ use std::net::SocketAddr; use std::os::unix::prelude::FileExt; use std::{fmt::Write, fs::read_dir, path::PathBuf, str, thread, time::Duration}; +use std::env; #[cfg(not(msim))] use std::str::FromStr; @@ -3934,6 +3935,57 @@ async fn test_clever_errors() -> Result<(), anyhow::Error> { Ok(()) } +#[tokio::test] +async fn test_move_build_bytecode_with_address_resolution() -> Result<(), anyhow::Error> { + let test_cluster = TestClusterBuilder::new().build().await; + let config_path = test_cluster.swarm.dir().join(SUI_CLIENT_CONFIG); + + // Package setup: a simple package depends on another and copied to tmpdir + let mut simple_package_path = PathBuf::from(TEST_DATA_DIR); + simple_package_path.push("simple"); + + let mut depends_on_simple_package_path = PathBuf::from(TEST_DATA_DIR); + depends_on_simple_package_path.push("depends_on_simple"); + + let tmp_dir = tempfile::tempdir().unwrap(); + + fs_extra::dir::copy( + &simple_package_path, + &tmp_dir, + &fs_extra::dir::CopyOptions::default(), + )?; + + fs_extra::dir::copy( + &depends_on_simple_package_path, + &tmp_dir, + &fs_extra::dir::CopyOptions::default(), + )?; + + // Publish simple package. + let simple_tmp_dir = tmp_dir.path().join("simple"); + test_with_sui_binary(&[ + "client", + "--client.config", + config_path.to_str().unwrap(), + "publish", + simple_tmp_dir.to_str().unwrap(), + ]) + .await?; + + // Build the package that depends on 'simple' package. Addresses must resolve successfully + // from the `Move.lock` for this command to succeed at all. + let depends_on_simple_tmp_dir = tmp_dir.path().join("depends_on_simple"); + test_with_sui_binary(&[ + "move", + "build", + "--dump-bytecode-as-base64", + "--path", + depends_on_simple_tmp_dir.to_str().unwrap(), + ]) + .await?; + Ok(()) +} + #[tokio::test] async fn test_parse_host_port() { let input = "127.0.0.0"; diff --git a/crates/sui/tests/data/depends_on_simple/Move.toml b/crates/sui/tests/data/depends_on_simple/Move.toml new file mode 100644 index 00000000000000..0688373ff4de61 --- /dev/null +++ b/crates/sui/tests/data/depends_on_simple/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "depends_on_simple" +edition = "2024.beta" + +[dependencies] +simple = { local = "../simple" } + +[addresses] +depends_on_simple = "0x0" diff --git a/crates/sui/tests/data/depends_on_simple/sources/depends_on_simple.move b/crates/sui/tests/data/depends_on_simple/sources/depends_on_simple.move new file mode 100644 index 00000000000000..dee8c33579f698 --- /dev/null +++ b/crates/sui/tests/data/depends_on_simple/sources/depends_on_simple.move @@ -0,0 +1,4 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module depends_on_simple::depends_on_simple {} diff --git a/crates/sui/tests/data/simple/Move.toml b/crates/sui/tests/data/simple/Move.toml new file mode 100644 index 00000000000000..1775a6b3741ef1 --- /dev/null +++ b/crates/sui/tests/data/simple/Move.toml @@ -0,0 +1,8 @@ +[package] +name = "simple" +edition = "2024.beta" + +[dependencies] + +[addresses] +simple = "0x0" diff --git a/crates/sui/tests/data/simple/sources/simple.move b/crates/sui/tests/data/simple/sources/simple.move new file mode 100644 index 00000000000000..40d3377133359b --- /dev/null +++ b/crates/sui/tests/data/simple/sources/simple.move @@ -0,0 +1,4 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module simple::simple {}