diff --git a/crates/sui-protocol-config/src/lib.rs b/crates/sui-protocol-config/src/lib.rs index 54ee7bee79f5a..8e0447344b093 100644 --- a/crates/sui-protocol-config/src/lib.rs +++ b/crates/sui-protocol-config/src/lib.rs @@ -257,16 +257,6 @@ impl Chain { Chain::Unknown => "unknown", } } - - /// Convert a four byte chain ID digest string to a Chain enum. - /// necessary for use with sui_getChainIdentifier JSON RPC - pub fn from_chain_id(chain_id: String) -> Self { - match chain_id.as_str() { - "35834a8a" => Chain::Mainnet, - "4c78adac" => Chain::Testnet, - _ => Chain::Unknown, - } - } } pub struct Error(pub String); diff --git a/crates/sui-types/src/digests.rs b/crates/sui-types/src/digests.rs index 52444720d158d..0b19e5772253d 100644 --- a/crates/sui-types/src/digests.rs +++ b/crates/sui-types/src/digests.rs @@ -4,7 +4,7 @@ use std::{env, fmt}; use crate::{error::SuiError, sui_serde::Readable}; -use fastcrypto::encoding::{Base58, Encoding}; +use fastcrypto::encoding::{Base58, Encoding, Hex}; use once_cell::sync::{Lazy, OnceCell}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -157,6 +157,9 @@ impl fmt::UpperHex for Digest { )] pub struct ChainIdentifier(CheckpointDigest); +pub const MAINNET_CHAIN_IDENTIFIER_BASE58: &str = "4btiuiMPvEENsttpZC7CZ53DruC3MAgfznDbASZ7DR6S"; +pub const TESTNET_CHAIN_IDENTIFIER_BASE58: &str = "69WiPg3DAQiwdxfncX6wYQ2siKwAe6L9BZthQea3JNMD"; + pub static MAINNET_CHAIN_IDENTIFIER: OnceCell = OnceCell::new(); pub static TESTNET_CHAIN_IDENTIFIER: OnceCell = OnceCell::new(); @@ -179,6 +182,24 @@ static SUI_PROTOCOL_CONFIG_CHAIN_OVERRIDE: Lazy> = Lazy::new(|| { }); impl ChainIdentifier { + /// take a short 4 byte identifier and convert it into a ChainIdentifier + /// short ids come from the JSON RPC getChainIdentifier and are encoded in hex + pub fn from_chain_short_id(short_id: &String) -> Option { + if Hex::from_bytes(&Base58::decode(MAINNET_CHAIN_IDENTIFIER_BASE58).ok()?) + .encoded_with_format() + .starts_with(&format!("0x{}", short_id)) + { + Some(get_mainnet_chain_identifier()) + } else if Hex::from_bytes(&Base58::decode(TESTNET_CHAIN_IDENTIFIER_BASE58).ok()?) + .encoded_with_format() + .starts_with(&format!("0x{}", short_id)) + { + Some(get_testnet_chain_identifier()) + } else { + None + } + } + pub fn chain(&self) -> Chain { let mainnet_id = get_mainnet_chain_identifier(); let testnet_id = get_testnet_chain_identifier(); @@ -206,7 +227,7 @@ impl ChainIdentifier { pub fn get_mainnet_chain_identifier() -> ChainIdentifier { let digest = MAINNET_CHAIN_IDENTIFIER.get_or_init(|| { let digest = CheckpointDigest::new( - Base58::decode("4btiuiMPvEENsttpZC7CZ53DruC3MAgfznDbASZ7DR6S") + Base58::decode(MAINNET_CHAIN_IDENTIFIER_BASE58) .expect("mainnet genesis checkpoint digest literal is invalid") .try_into() .expect("Mainnet genesis checkpoint digest literal has incorrect length"), @@ -219,7 +240,7 @@ pub fn get_mainnet_chain_identifier() -> ChainIdentifier { pub fn get_testnet_chain_identifier() -> ChainIdentifier { let digest = TESTNET_CHAIN_IDENTIFIER.get_or_init(|| { let digest = CheckpointDigest::new( - Base58::decode("69WiPg3DAQiwdxfncX6wYQ2siKwAe6L9BZthQea3JNMD") + Base58::decode(TESTNET_CHAIN_IDENTIFIER_BASE58) .expect("testnet genesis checkpoint digest literal is invalid") .try_into() .expect("Testnet genesis checkpoint digest literal has incorrect length"), @@ -1043,3 +1064,32 @@ impl fmt::Debug for ConsensusCommitDigest { .finish() } } + +mod test { + #[allow(unused_imports)] + use crate::digests::ChainIdentifier; + // check that the chain id returns mainnet + #[test] + fn test_chain_id_mainnet() { + let chain_id = ChainIdentifier::from_chain_short_id(&String::from("35834a8a")); + assert_eq!( + chain_id.unwrap().chain(), + sui_protocol_config::Chain::Mainnet + ); + } + + #[test] + fn test_chain_id_testnet() { + let chain_id = ChainIdentifier::from_chain_short_id(&String::from("4c78adac")); + assert_eq!( + chain_id.unwrap().chain(), + sui_protocol_config::Chain::Testnet + ); + } + + #[test] + fn test_chain_id_unknown() { + let chain_id = ChainIdentifier::from_chain_short_id(&String::from("unknown")); + assert_eq!(chain_id, None); + } +} diff --git a/crates/sui/src/client_commands.rs b/crates/sui/src/client_commands.rs index 2d191b4c3d2a8..f62335ff2c53f 100644 --- a/crates/sui/src/client_commands.rs +++ b/crates/sui/src/client_commands.rs @@ -94,6 +94,7 @@ use tabled::{ }, }; +use sui_types::digests::ChainIdentifier; use tracing::{debug, info}; #[path = "unit_tests/profiler_tests.rs"] @@ -867,8 +868,16 @@ impl SuiClientCommands { let sender = sender.unwrap_or(context.active_address()?); let client = context.get_client().await?; let chain_id = client.read_api().get_chain_identifier().await.ok(); - let protocol_config = - ProtocolConfig::get_for_version(ProtocolVersion::MAX, Chain::Unknown); + let protocol_config = ProtocolConfig::get_for_version( + ProtocolVersion::MAX, + match chain_id + .as_ref() + .and_then(ChainIdentifier::from_chain_short_id) + { + Some(chain_id) => chain_id.chain(), + None => Chain::Unknown, + }, + ); let package_path = package_path diff --git a/crates/sui/src/unit_tests/upgrade_compatibility_tests.rs b/crates/sui/src/unit_tests/upgrade_compatibility_tests.rs index 336f54c9add10..87a050a1bf7a9 100644 --- a/crates/sui/src/unit_tests/upgrade_compatibility_tests.rs +++ b/crates/sui/src/unit_tests/upgrade_compatibility_tests.rs @@ -1,18 +1,19 @@ -use std::path::PathBuf; +use crate::upgrade_compatibility::compare_packages; use move_binary_format::CompiledModule; +use std::path::PathBuf; use sui_move_build::BuildConfig; -use crate::upgrade_compatibility::compare_packages; #[test] fn test_all_fail() { let (pkg_v1, pkg_v2) = get_packages("all"); let result = compare_packages(pkg_v1, pkg_v2); - assert_eq!(result.is_err(), true); + assert!(result.is_err()); let err = result.unwrap_err(); - assert_eq!(err.to_string(), -r#"Upgrade compatibility check failed with the following errors: + assert_eq!( + err.to_string(), + r#"Upgrade compatibility check failed with the following errors: - Struct ability mismatch: StructAbilityMismatchAdd Old: [] New: [Copy, ] @@ -72,8 +73,8 @@ r#"Upgrade compatibility check failed with the following errors: New: Params: [] Return: [] -- Function lost public visibility: function_to_have_public_removed"#) - +- Function lost public visibility: function_to_have_public_removed"# + ) } #[test] @@ -81,7 +82,7 @@ fn test_struct_missing() { let (pkg_v1, pkg_v2) = get_packages("struct_missing"); let result = compare_packages(pkg_v1, pkg_v2); - assert_eq!(result.is_err(), true); + assert!(result.is_err()); let err = result.unwrap_err(); assert_eq!(err.to_string(), "Upgrade compatibility check failed with the following errors:\n- Struct missing: StructToBeRemoved"); } @@ -90,24 +91,25 @@ fn test_struct_missing() { fn test_friend_link_ok() { let (pkg_v1, pkg_v2) = get_packages("friend_linking"); // upgrade compatibility ignores friend linking - assert_eq!(compare_packages(pkg_v1, pkg_v2).is_ok(), true); + assert!(compare_packages(pkg_v1, pkg_v2).is_ok()); } #[test] fn test_entry_linking_ok() { let (pkg_v1, pkg_v2) = get_packages("entry_linking"); // upgrade compatibility ignores entry linking - assert_eq!(compare_packages(pkg_v1, pkg_v2).is_ok(), true); + assert!(compare_packages(pkg_v1, pkg_v2).is_ok()); } -fn get_packages(name: &str) -> (Vec, Vec) { +fn get_packages(name: &str) -> (Vec, Vec) { let mut path: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.push("src/unit_tests/fixtures/upgrade_errors/"); path.push(format!("{}_v1", name)); let pkg_v1 = BuildConfig::new_for_testing() .build(&path) - .unwrap().into_modules(); + .unwrap() + .into_modules(); let mut path: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.push("src/unit_tests/fixtures/upgrade_errors/"); @@ -115,7 +117,8 @@ fn get_packages(name: &str) -> (Vec, Vec) { let pkg_v2 = BuildConfig::new_for_testing() .build(&path) - .unwrap().into_modules(); + .unwrap() + .into_modules(); (pkg_v1, pkg_v2) -} \ No newline at end of file +} diff --git a/crates/sui/src/upgrade_compatibility.rs b/crates/sui/src/upgrade_compatibility.rs index d7dec62b80ede..8ab0d9b0c9260 100644 --- a/crates/sui/src/upgrade_compatibility.rs +++ b/crates/sui/src/upgrade_compatibility.rs @@ -1,7 +1,6 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 - #[path = "unit_tests/upgrade_compatibility_tests.rs"] #[cfg(test)] mod upgrade_compatibility_tests; @@ -13,7 +12,7 @@ use thiserror::Error; use move_binary_format::{ compatibility::Compatibility, compatibility_mode::CompatibilityMode, - file_format::{Visibility}, + file_format::Visibility, normalized::{Enum, Function, Module, Struct}, CompiledModule, }; @@ -67,7 +66,10 @@ pub async fn check_compatibility( compare_packages(existing_modules, new_modules) } -fn compare_packages(existing_modules: Vec, new_modules: Vec) -> Result<(), Error> { +fn compare_packages( + existing_modules: Vec, + new_modules: Vec, +) -> Result<(), Error> { // create a map from the new modules let new_modules_map: HashMap = new_modules .iter() @@ -81,8 +83,7 @@ fn compare_packages(existing_modules: Vec, new_modules: Vec { - Compatibility::upgrade_check() - .check_with_mode::( + Compatibility::upgrade_check().check_with_mode::( &Module::new(&existing_module), &Module::new(new_module), )?; @@ -202,31 +203,32 @@ enum UpgradeCompatibilityModeError { impl UpgradeCompatibilityModeError { fn breaks_compatibility(&self, compatability: &Compatibility) -> bool { match self { - UpgradeCompatibilityModeError::StructAbilityMismatch { .. } | - UpgradeCompatibilityModeError::StructTypeParamMismatch { .. } | - UpgradeCompatibilityModeError::EnumAbilityMismatch { .. } | - UpgradeCompatibilityModeError::EnumTypeParamMismatch { .. } | - UpgradeCompatibilityModeError::FunctionMissingPublic { .. } | - UpgradeCompatibilityModeError::FunctionLostPublicVisibility { .. } => { + UpgradeCompatibilityModeError::StructAbilityMismatch { .. } + | UpgradeCompatibilityModeError::StructTypeParamMismatch { .. } + | UpgradeCompatibilityModeError::EnumAbilityMismatch { .. } + | UpgradeCompatibilityModeError::EnumTypeParamMismatch { .. } + | UpgradeCompatibilityModeError::FunctionMissingPublic { .. } + | UpgradeCompatibilityModeError::FunctionLostPublicVisibility { .. } => { compatability.check_datatype_and_pub_function_linking } - UpgradeCompatibilityModeError::StructFieldMismatch { .. } | - UpgradeCompatibilityModeError::EnumVariantMissing { .. } | - UpgradeCompatibilityModeError::EnumVariantMismatch { .. } => { + UpgradeCompatibilityModeError::StructFieldMismatch { .. } + | UpgradeCompatibilityModeError::EnumVariantMissing { .. } + | UpgradeCompatibilityModeError::EnumVariantMismatch { .. } => { compatability.check_datatype_layout } - UpgradeCompatibilityModeError::StructMissing { .. } | - UpgradeCompatibilityModeError::EnumMissing { .. } => { - compatability.check_datatype_and_pub_function_linking || compatability.check_datatype_layout + UpgradeCompatibilityModeError::StructMissing { .. } + | UpgradeCompatibilityModeError::EnumMissing { .. } => { + compatability.check_datatype_and_pub_function_linking + || compatability.check_datatype_layout } - UpgradeCompatibilityModeError::FunctionSignatureMismatch { old_function, .. } => { + UpgradeCompatibilityModeError::FunctionSignatureMismatch { old_function, .. } => { if old_function.visibility == Visibility::Public { - return compatability.check_datatype_and_pub_function_linking + return compatability.check_datatype_and_pub_function_linking; } else if old_function.visibility == Visibility::Friend { - return compatability.check_friend_linking + return compatability.check_friend_linking; } if old_function.is_entry { compatability.check_private_entry_linking @@ -235,16 +237,15 @@ impl UpgradeCompatibilityModeError { } } - UpgradeCompatibilityModeError::FunctionMissingFriend { .. } | - UpgradeCompatibilityModeError::FunctionLostFriendVisibility { .. } | - UpgradeCompatibilityModeError::FriendModuleMissing(_, _) => { + UpgradeCompatibilityModeError::FunctionMissingFriend { .. } + | UpgradeCompatibilityModeError::FunctionLostFriendVisibility { .. } + | UpgradeCompatibilityModeError::FriendModuleMissing(_, _) => { compatability.check_friend_linking } - UpgradeCompatibilityModeError::FunctionMissingEntry {..} | - UpgradeCompatibilityModeError::FunctionEntryCompatibility { .. } => { + UpgradeCompatibilityModeError::FunctionMissingEntry { .. } + | UpgradeCompatibilityModeError::FunctionEntryCompatibility { .. } => { compatability.check_private_entry_linking - } UpgradeCompatibilityModeError::EnumNewVariant { .. } => { compatability.disallow_new_variants @@ -259,7 +260,6 @@ pub struct CliCompatibilityMode { errors: Vec, } - impl CompatibilityMode for CliCompatibilityMode { type Error = anyhow::Error; // ignored, address is not populated pre-tx @@ -465,7 +465,8 @@ impl CompatibilityMode for CliCompatibilityMode { } fn finish(&self, compatability: &Compatibility) -> Result<(), Self::Error> { - let errors: Vec = self.errors + let errors: Vec = self + .errors .iter() .filter(|e| e.breaks_compatibility(compatability)) .map(|e| format!("- {}", e)) @@ -479,4 +480,4 @@ impl CompatibilityMode for CliCompatibilityMode { } Ok(()) } -} \ No newline at end of file +}