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

feat(sns): Automatically trigger upgrades when target_version is ahead of the current version #2034

Merged
merged 2 commits into from
Nov 14, 2024
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
10 changes: 10 additions & 0 deletions rs/nervous_system/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,16 @@ fn checked_div_mod(dividend: usize, divisor: usize) -> Option<(usize, usize)> {
Some((quotient, remainder))
}

/// Converts a sha256 hash into a hex string representation
pub fn hash_to_hex_string(hash: &[u8]) -> String {
use std::fmt::Write;
let mut result_hash = String::new();
for b in hash {
let _ = write!(result_hash, "{:02x}", b);
}
result_hash
}

#[cfg(test)]
mod serve_logs_tests;

Expand Down
20 changes: 19 additions & 1 deletion rs/nervous_system/common/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;

use crate::ledger::compute_neuron_staking_subaccount_bytes;
use crate::{hash_to_hex_string, ledger::compute_neuron_staking_subaccount_bytes};
use ic_base_types::PrincipalId;
use ic_crypto_sha2::Sha256;

Expand Down Expand Up @@ -46,3 +46,21 @@ fn test_compute_neuron_staking_subaccount_bytes() {
hash
);
}

#[test]
fn test_hash_to_hex_string_empty() {
let empty: [u8; 0] = [];
assert_eq!(hash_to_hex_string(&empty), "");
}

#[test]
fn test_hash_to_hex_string_single_byte() {
let single = [0xAB];
assert_eq!(hash_to_hex_string(&single), "ab");
}

#[test]
fn test_hash_to_hex_string_multiple_bytes() {
let bytes = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
assert_eq!(hash_to_hex_string(&bytes), "123456789abcdef0");
}
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,74 @@ async fn test_get_upgrade_journal() {
&expected_upgrade_journal_entries,
)
.await;

// Check that the target version is set to the new version.
{
let sns_pb::GetUpgradeJournalResponse { target_version, .. } =
sns::governance::get_upgrade_journal(&pocket_ic, sns.governance.canister_id).await;

assert_eq!(target_version, Some(new_sns_version_2.clone()));
}

await_with_timeout(
&pocket_ic,
UPGRADE_STEPS_INTERVAL_REFRESH_BACKOFF_SECONDS,
|pocket_ic| async {
sns::governance::get_upgrade_journal(pocket_ic, sns.governance.canister_id)
.await
.deployed_version
},
&Some(new_sns_version_2.clone()),
)
.await
.unwrap();

// Check that the deployed version is now set to the new version.
{
let sns_pb::GetUpgradeJournalResponse {
deployed_version, ..
} = sns::governance::get_upgrade_journal(&pocket_ic, sns.governance.canister_id).await;

assert_eq!(deployed_version, Some(new_sns_version_2.clone()));
}

// Check that the upgrade journal contains the correct entries.
{
expected_upgrade_journal_entries.push(
sns_pb::upgrade_journal_entry::Event::UpgradeStarted(
sns_pb::upgrade_journal_entry::UpgradeStarted::from_behind_target(
initial_sns_version.clone(),
new_sns_version_1.clone(),
),
),
);

expected_upgrade_journal_entries.push(
sns_pb::upgrade_journal_entry::Event::UpgradeOutcome(
sns_pb::upgrade_journal_entry::UpgradeOutcome::success(None),
),
);

expected_upgrade_journal_entries.push(
sns_pb::upgrade_journal_entry::Event::UpgradeStarted(
sns_pb::upgrade_journal_entry::UpgradeStarted::from_behind_target(
new_sns_version_1.clone(),
new_sns_version_2.clone(),
),
),
);

expected_upgrade_journal_entries.push(
anchpop marked this conversation as resolved.
Show resolved Hide resolved
sns_pb::upgrade_journal_entry::Event::UpgradeOutcome(
sns_pb::upgrade_journal_entry::UpgradeOutcome::success(None),
),
);

assert_upgrade_journal(
&pocket_ic,
sns.governance,
&expected_upgrade_journal_entries,
)
.await;
}
}
19 changes: 3 additions & 16 deletions rs/nns/sns-wasm/src/pb/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,13 @@ use crate::{
use ic_base_types::CanisterId;
use ic_cdk::api::stable::StableMemory;
use ic_crypto_sha2::Sha256;
use std::{
collections::HashMap,
convert::TryFrom,
fmt::{Display, Write},
str::FromStr,
};
use ic_nervous_system_common::hash_to_hex_string;
use std::{collections::HashMap, convert::TryFrom, str::FromStr};

#[allow(clippy::all)]
#[path = "../gen/ic_sns_wasm.pb.v1.rs"]
pub mod v1;

/// Converts a sha256 hash into a hex string representation
pub fn hash_to_hex_string(hash: &[u8; 32]) -> String {
let mut result_hash = String::new();
for b in hash {
let _ = write!(result_hash, "{:02X}", b);
}
result_hash
}

impl AddWasmResponse {
pub fn error(message: String) -> Self {
Self {
Expand Down Expand Up @@ -123,7 +110,7 @@ impl From<SnsVersion> for GetNextSnsVersionResponse {
}
}

impl Display for SnsVersion {
impl std::fmt::Display for SnsVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut versions_str = HashMap::<&str, String>::new();

Expand Down
32 changes: 14 additions & 18 deletions rs/nns/sns-wasm/src/sns_wasm.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
use crate::{
canister_api::CanisterApi,
pb::{
hash_to_hex_string,
v1::{
add_wasm_response, AddWasmRequest, AddWasmResponse, DappCanistersTransferResult,
DeployNewSnsRequest, DeployNewSnsResponse, DeployedSns,
GetDeployedSnsByProposalIdRequest, GetDeployedSnsByProposalIdResponse,
GetNextSnsVersionRequest, GetNextSnsVersionResponse, GetProposalIdThatAddedWasmRequest,
GetProposalIdThatAddedWasmResponse, GetSnsSubnetIdsResponse,
GetWasmMetadataRequest as GetWasmMetadataRequestPb,
GetWasmMetadataResponse as GetWasmMetadataResponsePb, GetWasmRequest, GetWasmResponse,
InsertUpgradePathEntriesRequest, InsertUpgradePathEntriesResponse,
ListDeployedSnsesRequest, ListDeployedSnsesResponse, ListUpgradeStep,
ListUpgradeStepsRequest, ListUpgradeStepsResponse,
MetadataSection as MetadataSectionPb, SnsCanisterIds, SnsCanisterType, SnsUpgrade,
SnsVersion, SnsWasm, SnsWasmError, SnsWasmStableIndex, StableCanisterState,
UpdateSnsSubnetListRequest, UpdateSnsSubnetListResponse,
},
pb::v1::{
add_wasm_response, AddWasmRequest, AddWasmResponse, DappCanistersTransferResult,
DeployNewSnsRequest, DeployNewSnsResponse, DeployedSns, GetDeployedSnsByProposalIdRequest,
GetDeployedSnsByProposalIdResponse, GetNextSnsVersionRequest, GetNextSnsVersionResponse,
GetProposalIdThatAddedWasmRequest, GetProposalIdThatAddedWasmResponse,
GetSnsSubnetIdsResponse, GetWasmMetadataRequest as GetWasmMetadataRequestPb,
GetWasmMetadataResponse as GetWasmMetadataResponsePb, GetWasmRequest, GetWasmResponse,
InsertUpgradePathEntriesRequest, InsertUpgradePathEntriesResponse,
ListDeployedSnsesRequest, ListDeployedSnsesResponse, ListUpgradeStep,
ListUpgradeStepsRequest, ListUpgradeStepsResponse, MetadataSection as MetadataSectionPb,
SnsCanisterIds, SnsCanisterType, SnsUpgrade, SnsVersion, SnsWasm, SnsWasmError,
SnsWasmStableIndex, StableCanisterState, UpdateSnsSubnetListRequest,
UpdateSnsSubnetListResponse,
},
stable_memory::SnsWasmStableMemory,
wasm_metadata::MetadataSection,
Expand All @@ -25,7 +21,7 @@ use candid::Encode;
use ic_base_types::{CanisterId, PrincipalId};
use ic_cdk::api::stable::StableMemory;
use ic_nervous_system_clients::canister_id_record::CanisterIdRecord;
use ic_nervous_system_common::{ONE_TRILLION, SNS_CREATION_FEE};
use ic_nervous_system_common::{hash_to_hex_string, ONE_TRILLION, SNS_CREATION_FEE};
use ic_nervous_system_proto::pb::v1::Canister;
use ic_nns_constants::{
DEFAULT_SNS_GOVERNANCE_CANISTER_WASM_MEMORY_LIMIT,
Expand Down
2 changes: 1 addition & 1 deletion rs/sns/governance/canister/canister.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ fn get_running_sns_version(_: GetRunningSnsVersionRequest) -> GetRunningSnsVersi
target_version: upgrade_in_progress.target_version.clone(),
mark_failed_at_seconds: upgrade_in_progress.mark_failed_at_seconds,
checking_upgrade_lock: upgrade_in_progress.checking_upgrade_lock,
proposal_id: upgrade_in_progress.proposal_id,
proposal_id: upgrade_in_progress.proposal_id.unwrap_or(0),
});
GetRunningSnsVersionResponse {
deployed_version: governance().proto.deployed_version.clone(),
Expand Down
13 changes: 10 additions & 3 deletions rs/sns/governance/canister/governance.did
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,12 @@ type GetProposalResponse = record {

type GetRunningSnsVersionResponse = record {
deployed_version : opt Version;
pending_version : opt UpgradeInProgress;
pending_version : opt record {
mark_failed_at_seconds : nat64;
checking_upgrade_lock : nat64;
proposal_id : nat64;
target_version : opt Version;
};
};

type GetSnsInitializationParametersResponse = record {
Expand Down Expand Up @@ -674,14 +679,14 @@ type TransferSnsTreasuryFunds = record {
type UpgradeInProgress = record {
mark_failed_at_seconds : nat64;
checking_upgrade_lock : nat64;
proposal_id : nat64;
proposal_id : opt nat64;
target_version : opt Version;
};

type PendingVersion = record {
mark_failed_at_seconds : nat64;
checking_upgrade_lock : nat64;
proposal_id : nat64;
proposal_id : opt nat64;
target_version : opt Version;
};

Expand Down Expand Up @@ -756,6 +761,7 @@ type TargetVersionSet = record {
type TargetVersionReset = record {
new_target_version : opt Version;
old_target_version : opt Version;
human_readable : opt text;
};

type UpgradeStarted = record {
Expand Down Expand Up @@ -787,6 +793,7 @@ type GetUpgradeJournalResponse = record {
upgrade_steps : opt Versions;
response_timestamp_seconds : opt nat64;
target_version : opt Version;
deployed_version : opt Version;
upgrade_journal : opt UpgradeJournal;
};

Expand Down
13 changes: 10 additions & 3 deletions rs/sns/governance/canister/governance_test.did
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,12 @@ type GetProposalResponse = record {

type GetRunningSnsVersionResponse = record {
deployed_version : opt Version;
pending_version : opt UpgradeInProgress;
pending_version : opt record {
anchpop marked this conversation as resolved.
Show resolved Hide resolved
mark_failed_at_seconds : nat64;
checking_upgrade_lock : nat64;
proposal_id : nat64;
target_version : opt Version;
};
};

type GetSnsInitializationParametersResponse = record {
Expand Down Expand Up @@ -688,14 +693,14 @@ type TransferSnsTreasuryFunds = record {
type UpgradeInProgress = record {
mark_failed_at_seconds : nat64;
checking_upgrade_lock : nat64;
proposal_id : nat64;
proposal_id : opt nat64;
target_version : opt Version;
};

type PendingVersion = record {
mark_failed_at_seconds : nat64;
checking_upgrade_lock : nat64;
proposal_id : nat64;
proposal_id : opt nat64;
target_version : opt Version;
};

Expand Down Expand Up @@ -770,6 +775,7 @@ type TargetVersionSet = record {
type TargetVersionReset = record {
new_target_version : opt Version;
old_target_version : opt Version;
human_readable : opt text;
};

type UpgradeStarted = record {
Expand Down Expand Up @@ -801,6 +807,7 @@ type GetUpgradeJournalResponse = record {
upgrade_steps : opt Versions;
response_timestamp_seconds : opt nat64;
target_version : opt Version;
deployed_version : opt Version;
upgrade_journal : opt UpgradeJournal;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1424,7 +1424,7 @@ message Governance {
// allowing us to fail in case we otherwise have gotten stuck.
uint64 checking_upgrade_lock = 3;
// The proposal that initiated this upgrade
uint64 proposal_id = 4;
optional uint64 proposal_id = 4;
}

// Version SNS is in process of upgrading to.
Expand Down Expand Up @@ -2185,6 +2185,7 @@ message UpgradeJournalEntry {
message TargetVersionReset {
optional Governance.Version old_target_version = 1;
optional Governance.Version new_target_version = 2;
optional string human_readable = 3;
}

message UpgradeStarted {
Expand Down Expand Up @@ -2230,6 +2231,7 @@ message GetUpgradeJournalResponse {
// Currently, this field is always None, but in the "effortless SNS upgrade"
// feature, it reflect the version of the SNS that the community has decided to upgrade to.
Governance.Version target_version = 3;
Governance.Version deployed_version = 5;

UpgradeJournal upgrade_journal = 4;
}
Expand Down
8 changes: 6 additions & 2 deletions rs/sns/governance/src/gen/ic_sns_governance.pb.v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1900,8 +1900,8 @@ pub mod governance {
#[prost(uint64, tag = "3")]
pub checking_upgrade_lock: u64,
/// The proposal that initiated this upgrade
#[prost(uint64, tag = "4")]
pub proposal_id: u64,
#[prost(uint64, optional, tag = "4")]
pub proposal_id: ::core::option::Option<u64>,
}
#[derive(
candid::CandidType,
Expand Down Expand Up @@ -3443,6 +3443,8 @@ pub mod upgrade_journal_entry {
pub old_target_version: ::core::option::Option<super::governance::Version>,
#[prost(message, optional, tag = "2")]
pub new_target_version: ::core::option::Option<super::governance::Version>,
#[prost(string, optional, tag = "3")]
pub human_readable: ::core::option::Option<::prost::alloc::string::String>,
}
#[derive(
candid::CandidType,
Expand Down Expand Up @@ -3600,6 +3602,8 @@ pub struct GetUpgradeJournalResponse {
/// feature, it reflect the version of the SNS that the community has decided to upgrade to.
#[prost(message, optional, tag = "3")]
pub target_version: ::core::option::Option<governance::Version>,
#[prost(message, optional, tag = "5")]
pub deployed_version: ::core::option::Option<governance::Version>,
#[prost(message, optional, tag = "4")]
pub upgrade_journal: ::core::option::Option<UpgradeJournal>,
}
Expand Down
Loading