Skip to content

Commit

Permalink
maintain one source of truth for chain identifier
Browse files Browse the repository at this point in the history
  • Loading branch information
jordanjennings-mysten committed Sep 27, 2024
1 parent 111b4e6 commit 594c093
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 58 deletions.
10 changes: 0 additions & 10 deletions crates/sui-protocol-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
56 changes: 53 additions & 3 deletions crates/sui-types/src/digests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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<ChainIdentifier> = OnceCell::new();
pub static TESTNET_CHAIN_IDENTIFIER: OnceCell<ChainIdentifier> = OnceCell::new();

Expand All @@ -179,6 +182,24 @@ static SUI_PROTOCOL_CONFIG_CHAIN_OVERRIDE: Lazy<Option<Chain>> = 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<Self> {
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();
Expand Down Expand Up @@ -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"),
Expand All @@ -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"),
Expand Down Expand Up @@ -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);
}
}
13 changes: 11 additions & 2 deletions crates/sui/src/client_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ use tabled::{
},
};

use sui_types::digests::ChainIdentifier;
use tracing::{debug, info};

#[path = "unit_tests/profiler_tests.rs"]
Expand Down Expand Up @@ -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
Expand Down
31 changes: 17 additions & 14 deletions crates/sui/src/unit_tests/upgrade_compatibility_tests.rs
Original file line number Diff line number Diff line change
@@ -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, ]
Expand Down Expand Up @@ -72,16 +73,16 @@ 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]
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");
}
Expand All @@ -90,32 +91,34 @@ 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<CompiledModule>, Vec<CompiledModule>) {
fn get_packages(name: &str) -> (Vec<CompiledModule>, Vec<CompiledModule>) {
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/");
path.push(format!("{}_v2", name));

let pkg_v2 = BuildConfig::new_for_testing()
.build(&path)
.unwrap().into_modules();
.unwrap()
.into_modules();

(pkg_v1, pkg_v2)
}
}
59 changes: 30 additions & 29 deletions crates/sui/src/upgrade_compatibility.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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,
};
Expand Down Expand Up @@ -67,7 +66,10 @@ pub async fn check_compatibility(
compare_packages(existing_modules, new_modules)
}

fn compare_packages(existing_modules: Vec<CompiledModule>, new_modules: Vec<CompiledModule>) -> Result<(), Error> {
fn compare_packages(
existing_modules: Vec<CompiledModule>,
new_modules: Vec<CompiledModule>,
) -> Result<(), Error> {
// create a map from the new modules
let new_modules_map: HashMap<Identifier, CompiledModule> = new_modules
.iter()
Expand All @@ -81,8 +83,7 @@ fn compare_packages(existing_modules: Vec<CompiledModule>, new_modules: Vec<Comp
// find the new module with the same name
match new_modules_map.get(&name) {
Some(new_module) => {
Compatibility::upgrade_check()
.check_with_mode::<CliCompatibilityMode>(
Compatibility::upgrade_check().check_with_mode::<CliCompatibilityMode>(
&Module::new(&existing_module),
&Module::new(new_module),
)?;
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -259,7 +260,6 @@ pub struct CliCompatibilityMode {
errors: Vec<UpgradeCompatibilityModeError>,
}


impl CompatibilityMode for CliCompatibilityMode {
type Error = anyhow::Error;
// ignored, address is not populated pre-tx
Expand Down Expand Up @@ -465,7 +465,8 @@ impl CompatibilityMode for CliCompatibilityMode {
}

fn finish(&self, compatability: &Compatibility) -> Result<(), Self::Error> {
let errors: Vec<String> = self.errors
let errors: Vec<String> = self
.errors
.iter()
.filter(|e| e.breaks_compatibility(compatability))
.map(|e| format!("- {}", e))
Expand All @@ -479,4 +480,4 @@ impl CompatibilityMode for CliCompatibilityMode {
}
Ok(())
}
}
}

0 comments on commit 594c093

Please sign in to comment.