From feb86548770c4b5a7804ac785e45953e3d30a010 Mon Sep 17 00:00:00 2001 From: Rijnard van Tonder Date: Thu, 9 Mar 2023 12:13:53 -0800 Subject: [PATCH] move: validate dependencies' published addresses (#8919) ## Description Validate `published-at` properties in `Move.toml` for all transitive package dependencies on `publish`. ## Test Plan Covered by existing `simtest` and publish tests. Added additional test to exercise the case where `published-at` is not set. --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [x] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes Copied from `doc/in-progress/move_published_at_property.md`: > Package dependencies are now required to specify a `published-at` field in `Move.toml` that specifies the address that the dependency is published at. For example, The SUI framework is published at address `0x2`. So, the `Move.toml` file for the SUI framework has a corresponding line that says: > ```toml published-at = "0x2" ``` > > If your package depends on another package, like the SUI framework, your package will be linked against the `published-at` address specified by the SUI framework on-chain once you publish your package. When publishing, we resolve all of your package dependencies (i.e., transitive dependencies) to link against. This means we recommend publishing packages where all dependencies have a `published-at` address in their manifest. The publish command will fail by default if this is not the case. If needed, you may use the `--with-unpublished-dependencies` flag with the publish command to bypass the requirement that all dependencies require a `published-at` address. When using `--with-unpublished-dependencies`, all unpublished dependencies are treated as if they are part of your package. --- Cargo.lock | 5 + crates/sui-benchmark/Cargo.toml | 1 + crates/sui-core/src/test_utils.rs | 3 +- .../Move.toml | 8 + .../sources/main.move | 6 + .../Move.toml | 8 + .../sources/main.move | 6 + .../Move.toml | 10 ++ .../sources/main.move | 6 + .../src/unit_tests/move_integration_tests.rs | 44 ++++- .../src/compiled_package.rs | 151 ++++++++++++++---- crates/sui-framework/Move.toml | 1 + crates/sui-framework/build.rs | 3 +- .../sui-framework/deps/move-stdlib/Move.toml | 1 + crates/sui-json-rpc/Cargo.toml | 1 + crates/sui-proc-macros/src/lib.rs | 4 +- crates/sui-simulator/Cargo.toml | 1 + crates/sui-simulator/src/lib.rs | 1 + crates/sui/Cargo.toml | 1 + crates/sui/src/client_commands.rs | 26 ++- crates/test-utils/Cargo.toml | 1 + doc/in-progress/move_published_at_property.md | 9 ++ 22 files changed, 249 insertions(+), 48 deletions(-) create mode 100644 crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/Move.toml create mode 100644 crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/sources/main.move create mode 100644 crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/Move.toml create mode 100644 crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/sources/main.move create mode 100644 crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/Move.toml create mode 100644 crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/sources/main.move create mode 100644 doc/in-progress/move_published_at_property.md diff --git a/Cargo.lock b/Cargo.lock index bb0ebcc76600b..2e5835cd5f3bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8423,6 +8423,7 @@ dependencies = [ "move-prover", "move-prover-boogie-backend", "move-stackless-bytecode", + "move-symbol-pool", "move-unit-test", "multiaddr", "mysten-metrics", @@ -8520,6 +8521,7 @@ dependencies = [ "indicatif", "itertools", "move-core-types", + "move-package", "multiaddr", "narwhal-node", "num_cpus", @@ -8931,6 +8933,7 @@ dependencies = [ "move-binary-format", "move-bytecode-utils", "move-core-types", + "move-package", "mysten-metrics", "prometheus", "rand 0.8.5", @@ -9295,6 +9298,7 @@ dependencies = [ "anemo", "anemo-tower", "fastcrypto", + "move-package", "msim", "narwhal-network", "sui-framework", @@ -9864,6 +9868,7 @@ dependencies = [ "jsonrpsee", "move-binary-format", "move-core-types", + "move-package", "multiaddr", "mysten-metrics", "mysten-network", diff --git a/crates/sui-benchmark/Cargo.toml b/crates/sui-benchmark/Cargo.toml index 81584acbaf74d..57fd7f41cf7cf 100644 --- a/crates/sui-benchmark/Cargo.toml +++ b/crates/sui-benchmark/Cargo.toml @@ -49,6 +49,7 @@ telemetry-subscribers.workspace = true roaring = "0.10.1" move-core-types.workspace = true +move-package.workspace = true narwhal-node = { path = "../../narwhal/node" } workspace-hack = { version = "0.1", path = "../workspace-hack" } test-utils = { path = "../test-utils" } diff --git a/crates/sui-core/src/test_utils.rs b/crates/sui-core/src/test_utils.rs index eb8e825e5380a..422989b693784 100644 --- a/crates/sui-core/src/test_utils.rs +++ b/crates/sui-core/src/test_utils.rs @@ -13,7 +13,7 @@ use std::sync::Arc; use std::time::Duration; use sui_config::genesis::Genesis; use sui_config::ValidatorInfo; -use sui_framework_build::compiled_package::{BuildConfig, CompiledPackage}; +use sui_framework_build::compiled_package::{BuildConfig, CompiledPackage, SuiPackageHooks}; use sui_protocol_config::ProtocolConfig; use sui_types::base_types::ObjectID; use sui_types::crypto::{ @@ -128,6 +128,7 @@ pub fn dummy_transaction_effects(tx: &Transaction) -> TransactionEffects { } pub fn compile_basics_package() -> CompiledPackage { + move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks {})); let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.push("../../sui_programmability/examples/basics"); diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/Move.toml b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/Move.toml new file mode 100644 index 0000000000000..9605bcde70248 --- /dev/null +++ b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/Move.toml @@ -0,0 +1,8 @@ +[package] +name = "CustomPropertiesInManifestDependencyInvalidPublishedAt" +version = "0.0.0" +# oops we put a non-ID value for published-at... +published-at = "mystery" + +[addresses] +main = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/sources/main.move b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/sources/main.move new file mode 100644 index 0000000000000..923954f53ff28 --- /dev/null +++ b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_invalid_published_at/sources/main.move @@ -0,0 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module main::main { + public entry fun main() {} +} diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/Move.toml b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/Move.toml new file mode 100644 index 0000000000000..8a5a7fdd44292 --- /dev/null +++ b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/Move.toml @@ -0,0 +1,8 @@ +[package] +name = "CustomPropertiesInManifestDependencyMissingPublishedAt" +version = "0.0.0" +# oops we there's no published-at field, so a package that depends on us should fail when published... +# published-at = "0x777" + +[addresses] +main = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/sources/main.move b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/sources/main.move new file mode 100644 index 0000000000000..923954f53ff28 --- /dev/null +++ b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_dependency_missing_published_at/sources/main.move @@ -0,0 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module main::main { + public entry fun main() {} +} diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/Move.toml b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/Move.toml new file mode 100644 index 0000000000000..fccf5ec2769e5 --- /dev/null +++ b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "CustomPropertiesInManifestEnsurePublishedAt" +version = "0.0.0" + +[dependencies] +CustomPropertiesInManifestDependencyMissingPublishedAt = { local = "../custom_properties_in_manifest_dependency_missing_published_at" } +CustomPropertiesInManifestDependencyInvalidPublishedAt = { local = "../custom_properties_in_manifest_dependency_invalid_published_at" } + +[addresses] +main = "0x0" diff --git a/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/sources/main.move b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/sources/main.move new file mode 100644 index 0000000000000..923954f53ff28 --- /dev/null +++ b/crates/sui-core/src/unit_tests/data/custom_properties_in_manifest_ensure_published_at/sources/main.move @@ -0,0 +1,6 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module main::main { + public entry fun main() {} +} diff --git a/crates/sui-core/src/unit_tests/move_integration_tests.rs b/crates/sui-core/src/unit_tests/move_integration_tests.rs index 2987b9c0da2cd..c173e618bd907 100644 --- a/crates/sui-core/src/unit_tests/move_integration_tests.rs +++ b/crates/sui-core/src/unit_tests/move_integration_tests.rs @@ -18,7 +18,7 @@ use move_core_types::{ value::{MoveStruct, MoveValue}, }; use move_package::source_package::manifest_parser; -use sui_framework_build::compiled_package::{BuildConfig, SuiPackageHooks}; +use sui_framework_build::compiled_package::{ensure_published_dependencies, BuildConfig}; use sui_types::{ crypto::{get_key_pair, AccountKeyPair}, error::SuiError, @@ -2097,16 +2097,14 @@ async fn test_generate_lock_file() { #[tokio::test] #[cfg_attr(msim, ignore)] -async fn test_custom_property_published_at() { +async fn test_custom_property_parse_published_at() { let build_config = BuildConfig::new_for_testing(); let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.extend(["src", "unit_tests", "data", "custom_properties_in_manifest"]); - move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks {})); sui_framework::build_move_package(&path, build_config).expect("Move package did not build"); - let manifest = - manifest_parser::parse_move_manifest_from_file(&path.as_path().join("Move.toml")) - .expect("Could not parse Move.toml"); + let manifest = manifest_parser::parse_move_manifest_from_file(path.as_path()) + .expect("Could not parse Move.toml"); let properties = manifest .package .custom_properties @@ -2125,6 +2123,40 @@ async fn test_custom_property_published_at() { expected.assert_debug_eq(&properties) } +#[tokio::test] +#[cfg_attr(msim, ignore)] +async fn test_custom_property_ensure_published_at() { + let build_config = BuildConfig::new_for_testing(); + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.extend([ + "src", + "unit_tests", + "data", + "custom_properties_in_manifest_ensure_published_at", + ]); + + let resolution_graph = build_config + .config + .resolution_graph_for_package(&path, &mut Vec::new()) + .expect("Could not build resolution graph."); + + let error_message = if let SuiError::ModulePublishFailure { error } = + ensure_published_dependencies(&resolution_graph) + .err() + .unwrap() + { + error + } else { + "Expected ModulePublishFailure".into() + }; + + let expected = expect![[r#" + Package dependency "CustomPropertiesInManifestDependencyInvalidPublishedAt" does not specify a valid published address: could not parse value "mystery" for published-at field. + Package dependency "CustomPropertiesInManifestDependencyMissingPublishedAt" does not specify a published address (the Move.toml manifest for "CustomPropertiesInManifestDependencyMissingPublishedAt" does not contain a published-at field). + If this is intentional, you may use the --with-unpublished-dependencies flag to continue publishing these dependencies as part of your package (they won't be linked against existing packages on-chain)."#]]; + expected.assert_eq(&error_message) +} + pub async fn build_and_try_publish_test_package( authority: &AuthorityState, sender: &SuiAddress, diff --git a/crates/sui-framework-build/src/compiled_package.rs b/crates/sui-framework-build/src/compiled_package.rs index d86c7caec5ead..c2de4a883cc2e 100644 --- a/crates/sui-framework-build/src/compiled_package.rs +++ b/crates/sui-framework-build/src/compiled_package.rs @@ -1,10 +1,12 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +use core::fmt; use std::{ collections::{BTreeMap, BTreeSet, HashSet}, io::Write, path::PathBuf, + str::FromStr, }; use fastcrypto::encoding::Base64; @@ -35,8 +37,10 @@ use move_package::{ resolution::resolution_graph::ResolvedGraph, BuildConfig as MoveBuildConfig, }; +use move_symbol_pool::Symbol; use serde_reflection::Registry; use sui_types::{ + base_types::ObjectID, error::{SuiError, SuiResult}, move_package::{FnInfo, FnInfoKey, FnInfoMap}, MOVE_STDLIB_ADDRESS, SUI_FRAMEWORK_ADDRESS, @@ -126,48 +130,62 @@ impl BuildConfig { /// Given a `path` and a `build_config`, build the package in that path, including its dependencies. /// If we are building the Sui framework, we skip the check that the addresses should be 0 pub fn build(self, path: PathBuf) -> SuiResult { - let res = if self.print_diags_to_stderr { - let resolution_graph = self - .config + let resolution_graph = if self.print_diags_to_stderr { + self.config .resolution_graph_for_package(&path, &mut std::io::stderr()) .map_err(|err| SuiError::ModuleBuildFailure { error: format!("{:?}", err), - })?; - Self::compile_package(resolution_graph, &mut std::io::stderr()) + })? } else { - let resolution_graph = self - .config + self.config .resolution_graph_for_package(&path, &mut Vec::new()) .map_err(|err| SuiError::ModuleBuildFailure { error: format!("{:?}", err), - })?; - Self::compile_package(resolution_graph, &mut Vec::new()) + })? }; + build_from_resolution_graph( + path, + resolution_graph, + self.run_bytecode_verifier, + self.print_diags_to_stderr, + ) + } +} - // write build failure diagnostics to stderr, convert `error` to `String` using `Debug` - // format to include anyhow's error context chain. - let (package, fn_info) = match res { - Err(error) => { - return Err(SuiError::ModuleBuildFailure { - error: format!("{:?}", error), - }) - } - Ok((package, fn_info)) => (package, fn_info), - }; - let compiled_modules = package.root_modules_map(); - if self.run_bytecode_verifier { - for m in compiled_modules.iter_modules() { - move_bytecode_verifier::verify_module(m).map_err(|err| { - SuiError::ModuleVerificationFailure { - error: err.to_string(), - } - })?; - sui_bytecode_verifier::verify_module(m, &fn_info)?; - } - // TODO(https://github.com/MystenLabs/sui/issues/69): Run Move linker +pub fn build_from_resolution_graph( + path: PathBuf, + resolution_graph: ResolvedGraph, + run_bytecode_verifier: bool, + print_diags_to_stderr: bool, +) -> SuiResult { + let result = if print_diags_to_stderr { + BuildConfig::compile_package(resolution_graph, &mut std::io::stderr()) + } else { + BuildConfig::compile_package(resolution_graph, &mut Vec::new()) + }; + // write build failure diagnostics to stderr, convert `error` to `String` using `Debug` + // format to include anyhow's error context chain. + let (package, fn_info) = match result { + Err(error) => { + return Err(SuiError::ModuleBuildFailure { + error: format!("{:?}", error), + }) } - Ok(CompiledPackage { package, path }) + Ok((package, fn_info)) => (package, fn_info), + }; + let compiled_modules = package.root_modules_map(); + if run_bytecode_verifier { + for m in compiled_modules.iter_modules() { + move_bytecode_verifier::verify_module(m).map_err(|err| { + SuiError::ModuleVerificationFailure { + error: err.to_string(), + } + })?; + sui_bytecode_verifier::verify_module(m, &fn_info)?; + } + // TODO(https://github.com/MystenLabs/sui/issues/69): Run Move linker } + Ok(CompiledPackage { package, path }) } impl CompiledPackage { @@ -474,3 +492,74 @@ impl PackageHooks for SuiPackageHooks { Ok(()) } } + +enum AddressError { + NoPublishedAddress(Symbol), + InvalidPublishedAddress(Symbol, String), +} + +impl fmt::Display for AddressError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + AddressError::NoPublishedAddress(name) => write!( + f, + "Package dependency \"{name}\" does not \ + specify a published address \ + (the Move.toml manifest for \"{name}\" does \ + not contain a published-at field)." + ), + AddressError::InvalidPublishedAddress(name, value) => write!( + f, + "Package dependency \"{name}\" does not \ + specify a valid published address: \ + could not parse value \"{value}\" for published-at field.", + ), + } + } +} + +/// Ensure dependencies are published (contain `published-at` address in manifest). +pub fn ensure_published_dependencies(resolution_graph: &ResolvedGraph) -> Result<(), SuiError> { + let mut address_errors = vec![]; + for name in resolution_graph.graph.package_table.keys() { + if let Some(package) = &resolution_graph.package_table.get(name) { + let value = package + .source_package + .package + .custom_properties + .get(&Symbol::from(PUBLISHED_AT_MANIFEST_FIELD)); + + if value.is_none() { + address_errors.push(AddressError::NoPublishedAddress(*name)); + continue; + } + + if value + .and_then(|v| ObjectID::from_str(v.as_str()).ok()) + .is_none() + { + address_errors.push(AddressError::InvalidPublishedAddress( + *name, + value.unwrap().to_string(), + )); + continue; + } + } + } + if !address_errors.is_empty() { + let mut error_messages = address_errors + .iter() + .map(|v| format!("{}", v)) + .collect::>(); + error_messages.push( + "If this is intentional, you may use the --with-unpublished-dependencies flag to \ + continue publishing these dependencies as part of your package (they won't be \ + linked against existing packages on-chain)." + .into(), + ); + return Err(SuiError::ModulePublishFailure { + error: error_messages.join("\n"), + }); + } + Ok(()) +} diff --git a/crates/sui-framework/Move.toml b/crates/sui-framework/Move.toml index 7047ffa7216c4..db9f16a0f2687 100644 --- a/crates/sui-framework/Move.toml +++ b/crates/sui-framework/Move.toml @@ -1,6 +1,7 @@ [package] name = "Sui" version = "0.0.1" +published-at = "0x2" [dependencies] # Using a local dep for the Move stdlib instead of a git dep to avoid the overhead of fetching the git dep in diff --git a/crates/sui-framework/build.rs b/crates/sui-framework/build.rs index 00198ea175941..1fb1d774199a3 100644 --- a/crates/sui-framework/build.rs +++ b/crates/sui-framework/build.rs @@ -10,12 +10,13 @@ use std::{ path::{Path, PathBuf}, }; -use sui_framework_build::compiled_package::BuildConfig; +use sui_framework_build::compiled_package::{BuildConfig, SuiPackageHooks}; const FRAMEWORK_DOCS_DIR: &str = "docs"; /// Save revision info to environment variable fn main() { + move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks {})); let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let sui_framework_path = Path::new(env!("CARGO_MANIFEST_DIR")); diff --git a/crates/sui-framework/deps/move-stdlib/Move.toml b/crates/sui-framework/deps/move-stdlib/Move.toml index 15b23a4e45bff..78251e4057170 100644 --- a/crates/sui-framework/deps/move-stdlib/Move.toml +++ b/crates/sui-framework/deps/move-stdlib/Move.toml @@ -1,6 +1,7 @@ [package] name = "MoveStdlib" version = "1.5.0" +published-at = "0x1" [addresses] std = "0x1" diff --git a/crates/sui-json-rpc/Cargo.toml b/crates/sui-json-rpc/Cargo.toml index 64246b294572a..46162b4d62222 100644 --- a/crates/sui-json-rpc/Cargo.toml +++ b/crates/sui-json-rpc/Cargo.toml @@ -19,6 +19,7 @@ tower-http = { version = "0.3.4", features = ["full"] } move-binary-format.workspace = true move-bytecode-utils.workspace = true move-core-types.workspace = true +move-package.workspace = true prometheus = "0.13.3" anyhow = "1.0.64" tracing = "0.1.36" diff --git a/crates/sui-proc-macros/src/lib.rs b/crates/sui-proc-macros/src/lib.rs index 48e179a8ce1f5..0f066e6f549da 100644 --- a/crates/sui-proc-macros/src/lib.rs +++ b/crates/sui-proc-macros/src/lib.rs @@ -36,10 +36,12 @@ pub fn init_static_initializers(_args: TokenStream, item: TokenStream) -> TokenS // Initialize the static initializers here: // https://github.com/move-language/move/blob/652badf6fd67e1d4cc2aa6dc69d63ad14083b673/language/tools/move-package/src/package_lock.rs#L12 use std::path::PathBuf; - use sui_simulator::sui_framework_build::compiled_package::BuildConfig; + use sui_simulator::sui_framework_build::compiled_package::{BuildConfig, SuiPackageHooks}; use sui_simulator::sui_framework::build_move_package; use sui_simulator::tempfile::TempDir; + use sui_simulator::move_package::package_hooks::register_package_hooks; + move_package::package_hooks::register_package_hooks(Box::new(SuiPackageHooks {})); let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.push("../../sui_programmability/examples/basics"); let mut build_config = BuildConfig::default(); diff --git a/crates/sui-simulator/Cargo.toml b/crates/sui-simulator/Cargo.toml index 89c5fa5227dbd..4c426dc22f7f8 100644 --- a/crates/sui-simulator/Cargo.toml +++ b/crates/sui-simulator/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] workspace-hack = { version = "0.1", path = "../workspace-hack" } +move-package.workspace = true sui-framework = { path = "../sui-framework" } sui-framework-build = { path = "../sui-framework-build" } sui-types = { path = "../sui-types" } diff --git a/crates/sui-simulator/src/lib.rs b/crates/sui-simulator/src/lib.rs index 56efd0ce275e7..5acd873688d85 100644 --- a/crates/sui-simulator/src/lib.rs +++ b/crates/sui-simulator/src/lib.rs @@ -8,6 +8,7 @@ pub use msim::*; pub use anemo; pub use anemo_tower; pub use fastcrypto; +pub use move_package; pub use narwhal_network; pub use sui_framework; pub use sui_framework_build; diff --git a/crates/sui/Cargo.toml b/crates/sui/Cargo.toml index 215feca44cfac..38e576a6d9adb 100644 --- a/crates/sui/Cargo.toml +++ b/crates/sui/Cargo.toml @@ -61,6 +61,7 @@ move-stackless-bytecode.workspace = true move-unit-test.workspace = true move-cli.workspace = true move-package.workspace = true +move-symbol-pool.workspace = true workspace-hack = { version = "0.1", path = "../workspace-hack" } multiaddr = "0.17.0" diff --git a/crates/sui/src/client_commands.rs b/crates/sui/src/client_commands.rs index 971bff8ae33a2..3aff2431de46e 100644 --- a/crates/sui/src/client_commands.rs +++ b/crates/sui/src/client_commands.rs @@ -30,7 +30,9 @@ use sui_move::build::resolve_lock_file_path; use sui_source_validation::{BytecodeSourceVerifier, SourceMode}; use sui_types::error::SuiError; -use sui_framework_build::compiled_package::BuildConfig; +use sui_framework_build::compiled_package::{ + build_from_resolution_graph, ensure_published_dependencies, BuildConfig, +}; use sui_json::SuiJsonValue; use sui_json_rpc_types::{ DynamicFieldPage, SuiObjectData, SuiObjectInfo, SuiObjectResponse, SuiRawData, @@ -469,13 +471,21 @@ impl SuiClientCommands { let build_config = resolve_lock_file_path(build_config, Some(package_path.clone()))?; - let compiled_package = build_move_package( - &package_path, - BuildConfig { - config: build_config, - run_bytecode_verifier: true, - print_diags_to_stderr: true, - }, + let resolution_graph = build_config + .resolution_graph_for_package(&package_path, &mut std::io::stderr()) + .map_err(|err| SuiError::ModuleBuildFailure { + error: format!("{:?}", err), + })?; + + if !with_unpublished_dependencies { + ensure_published_dependencies(&resolution_graph)?; + }; + + let compiled_package = build_from_resolution_graph( + package_path, + resolution_graph, + /* run_bytecode_verifier */ true, + /* print_diags_to_stderr */ true, )?; if !compiled_package.is_framework() { diff --git a/crates/test-utils/Cargo.toml b/crates/test-utils/Cargo.toml index e649b86e6134c..b47be53a69053 100644 --- a/crates/test-utils/Cargo.toml +++ b/crates/test-utils/Cargo.toml @@ -40,6 +40,7 @@ mysten-network.workspace = true move-binary-format.workspace = true move-core-types.workspace = true +move-package.workspace = true workspace-hack = { version = "0.1", path = "../workspace-hack" } [target.'cfg(msim)'.dependencies] diff --git a/doc/in-progress/move_published_at_property.md b/doc/in-progress/move_published_at_property.md new file mode 100644 index 0000000000000..655daf1333ab6 --- /dev/null +++ b/doc/in-progress/move_published_at_property.md @@ -0,0 +1,9 @@ +# The `published-at` property in `Move.toml` + +Package dependencies are now required to specify a `published-at` field in `Move.toml` that specifies the address that the dependency is published at. For example, The SUI framework is published at address `0x2`. So, the `Move.toml` file for the SUI framework has a corresponding line that says: + +```toml +published-at = "0x2" +``` + +If your package depends on another package, like the SUI framework, your package will be linked against the `published-at` address specified by the SUI framework on-chain once you publish your package. When publishing, we resolve all of your package dependencies (i.e., transitive dependencies) to link against. This means we recommend publishing packages where all dependencies have a `published-at` address in their manifest. The publish command will fail by default if this is not the case. If needed, you may use the `--with-unpublished-dependencies` flag with the publish command to bypass the requirement that all dependencies require a `published-at` address. When using `--with-unpublished-dependencies`, all unpublished dependencies are treated as if they are part of your package.