Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cli] Implement upgrade compatibility checks client side #19562

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "upgrades"
edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move

[addresses]
upgrades = "0x0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// Module: UpgradeErrors

#[allow(unused_field)]
module upgrades::upgrades {
// struct missing
public struct StructToBeRemoved {
b: u64
}

// struct ability mismatch (add)
public struct StructAbilityMismatchAdd {}

// struct ability mismatch (remove)
public struct StructAbilityMismatchRemove has copy {}

// struct ability mismatch (change)
public struct StructAbilityMismatchChange has copy {}

// struct type param mismatch
public struct StructTypeParamMismatch<S, T> { a: S }

// struct field mismatch (add)
public struct StructFieldMismatchAdd {
a: u64,
b: u64
}

// struct field mismatch (remove)
public struct StructFieldMismatchRemove {
a: u64,
b: u64
}

// struct field mismatch (change)
public struct StructFieldMismatchChange {
a: u64,
b: u64
}

// enum missing
public enum EnumToBeRemoved {
A,
B
}

// enum ability mismatch (add)
public enum EnumAbilityMismatchAdd {
A,
}

// enum ability mismatch (remove)
public enum EnumAbilityMismatchRemove has copy {
A,
}

// enum ability mismatch (change)
public enum EnumAbilityMismatchChange has copy {
A,
}

// enum new variant
public enum EnumNewVariant {
A,
B,
C
}

// enum variant missing
public enum EnumVariantMissing {
A,
B,
}

// function missing public
public fun function_to_have_public_removed() {}

// function missing friend
public(package) fun function_to_have_friend_removed() {}

// function missing entry


// function signature mismatch (add)
public fun function_add_arg() {}

// function signature mismatch (remove)
public fun function_remove_arg(a: u64) {}

// function signature mismatch (change)
public fun function_change_arg(a: u64) {}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "upgrades"
edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move

[addresses]
upgrades = "0x0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
/// Module: UpgradeErrors

#[allow(unused_field)]
module upgrades::upgrades {
// struct missing
// public struct StructToBeRemoved {}

// struct ability mismatch (add)
public struct StructAbilityMismatchAdd has copy {} // added the copy ability where none existed

// struct field mismatch (remove)
public struct StructAbilityMismatchRemove {} // removed the copy ability

// struct field mismatch (change)
public struct StructAbilityMismatchChange has drop {} // changed from drop to copy

// struct type param mismatch
public struct StructTypeParamMismatch<T> { a: T } // changed S to T

// struct field mismatch (add)
public struct StructFieldMismatchAdd {
a: u64,
b: u64,
c: u64, // added
}

// struct field mismatch (remove)
public struct StructFieldMismatchRemove {
a: u64,
// removed b: u64
}

// struct field mismatch (change)
public struct StructFieldMismatchChange {
a: u64,
b: u8 // changed b from u64 to u8
}

// enum missing
// public enum EnumToBeRemoved {}

// enum ability mismatch (add)
public enum EnumAbilityMismatchAdd has copy {
A,
}

// enum ability mismatch (remove)
public enum EnumAbilityMismatchRemove {
A,
}

// enum ability mismatch (change)
public enum EnumAbilityMismatchChange has drop {
A,
}

// enum new variant
public enum EnumNewVariant {
A,
B,
C,
D // new variant
}

// enum variant missing
public enum EnumVariantMissing {
A,
// remove B,
}

// function missing public
fun function_to_have_public_removed() {}

// function missing friend
fun function_to_have_friend_removed() {}

// function missing entry

// function signature mismatch (add)
public fun function_add_arg(a: u64) {}

// function signature mismatch (remove)
public fun function_remove_arg() {}

// function signature mismatch (change)
public fun function_change_arg(a: u8) {} // now has u8 instead of u64
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "upgrades"
edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move

[addresses]
upgrades = "0x0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// Module: UpgradeErrors

#[allow(unused_field)]
module upgrades::upgrades {
entry fun entry_to_be_removed() {}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "upgrades"
edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move

[addresses]
upgrades = "0x0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// Module: UpgradeErrors

#[allow(unused_field)]
module upgrades::upgrades {
fun entry_to_be_removed() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "upgrades"
edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move

[addresses]
upgrades = "0x0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// Module: UpgradeErrors

#[allow(unused_field)]
module upgrades::upgrades {
fun call_friend() {
upgrades::upgrades_friend::friend_to_be_dropped();
}
}

module upgrades::upgrades_friend {
public(package) fun friend_to_be_dropped() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "upgrades"
edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move

[addresses]
upgrades = "0x0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// Module: UpgradeErrors

#[allow(unused_field)]
module upgrades::upgrades {
fun call_friend() {}
}


module upgrades::upgrades_friend {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "upgrades"
edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move

[addresses]
upgrades = "0x0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// Module: UpgradeErrors

#[allow(unused_field)]
module upgrades::upgrades {
// struct missing
public struct StructToBeRemoved {
b: u64
}
}

Loading
Loading