From fcbeb4bf7249d4d6ab8a26c7dbc6dd54fb59f39c Mon Sep 17 00:00:00 2001 From: Andre Popovitch Date: Fri, 24 May 2024 19:47:39 +0000 Subject: [PATCH] feat(nns/sns): NNS1-3061: Add `get_proposal_id_that_added_wasm` endpoint to SNS-W --- rs/nns/sns-wasm/canister/canister.rs | 17 +++++++ rs/nns/sns-wasm/canister/sns-wasm.did | 5 ++ .../proto/ic_sns_wasm/pb/v1/sns_wasm.proto | 10 ++++ rs/nns/sns-wasm/src/gen/ic_sns_wasm.pb.v1.rs | 16 ++++++ rs/nns/sns-wasm/src/sns_wasm.rs | 51 ++++++++++++++++++- 5 files changed, 97 insertions(+), 2 deletions(-) diff --git a/rs/nns/sns-wasm/canister/canister.rs b/rs/nns/sns-wasm/canister/canister.rs index 764e28b4268..a69e7c8335e 100644 --- a/rs/nns/sns-wasm/canister/canister.rs +++ b/rs/nns/sns-wasm/canister/canister.rs @@ -26,6 +26,7 @@ use ic_sns_wasm::{ AddWasmResponse, DeployNewSnsRequest, DeployNewSnsResponse, GetAllowedPrincipalsRequest, GetAllowedPrincipalsResponse, GetDeployedSnsByProposalIdRequest, GetDeployedSnsByProposalIdResponse, GetNextSnsVersionRequest, GetNextSnsVersionResponse, + GetProposalIdThatAddedWasmRequest, GetProposalIdThatAddedWasmResponse, GetSnsSubnetIdsRequest, GetSnsSubnetIdsResponse, GetWasmMetadataRequest, GetWasmMetadataResponse, GetWasmRequest, GetWasmResponse, InsertUpgradePathEntriesRequest, InsertUpgradePathEntriesResponse, ListDeployedSnsesRequest, ListDeployedSnsesResponse, @@ -399,6 +400,22 @@ fn get_wasm_metadata_( }) } +#[export_name = "canister_query get_proposal_id_that_added_wasm"] +fn get_proposal_id_that_added_wasm() { + over(candid_one, get_proposal_id_that_added_wasm_) +} + +#[candid_method(query, rename = "get_proposal_id_that_added_wasm")] +fn get_proposal_id_that_added_wasm_( + get_proposal_id_that_added_wasm_payload: GetProposalIdThatAddedWasmRequest, +) -> GetProposalIdThatAddedWasmResponse { + SNS_WASM.with(|sns_wasm| { + sns_wasm + .borrow() + .get_proposal_id_that_added_wasm(get_proposal_id_that_added_wasm_payload) + }) +} + #[export_name = "canister_query get_next_sns_version"] fn get_next_sns_version() { over(candid_one, get_next_sns_version_) diff --git a/rs/nns/sns-wasm/canister/sns-wasm.did b/rs/nns/sns-wasm/canister/sns-wasm.did index 611bcfdd082..88dfd79277c 100644 --- a/rs/nns/sns-wasm/canister/sns-wasm.did +++ b/rs/nns/sns-wasm/canister/sns-wasm.did @@ -57,6 +57,8 @@ type GetNextSnsVersionRequest = record { current_version : opt SnsVersion; }; type GetNextSnsVersionResponse = record { next_version : opt SnsVersion }; +type GetProposalIdThatAddedWasmRequest = record { hash : blob }; +type GetProposalIdThatAddedWasmResponse = record { proposal_id : opt nat64 }; type GetSnsSubnetIdsResponse = record { sns_subnet_ids : vec principal }; type GetWasmMetadataRequest = record { hash : opt blob }; type GetWasmMetadataResponse = record { result : opt Result_1 }; @@ -228,6 +230,9 @@ service : (SnsWasmCanisterInitPayload) -> { get_next_sns_version : (GetNextSnsVersionRequest) -> ( GetNextSnsVersionResponse, ) query; + get_proposal_id_that_added_wasm : (GetProposalIdThatAddedWasmRequest) -> ( + GetProposalIdThatAddedWasmResponse, + ) query; get_sns_subnet_ids : (record {}) -> (GetSnsSubnetIdsResponse) query; get_wasm : (GetWasmRequest) -> (GetWasmResponse) query; get_wasm_metadata : (GetWasmMetadataRequest) -> ( diff --git a/rs/nns/sns-wasm/proto/ic_sns_wasm/pb/v1/sns_wasm.proto b/rs/nns/sns-wasm/proto/ic_sns_wasm/pb/v1/sns_wasm.proto index 3a89bb94bdb..3aaacfdec67 100644 --- a/rs/nns/sns-wasm/proto/ic_sns_wasm/pb/v1/sns_wasm.proto +++ b/rs/nns/sns-wasm/proto/ic_sns_wasm/pb/v1/sns_wasm.proto @@ -150,6 +150,16 @@ message GetWasmResponse { SnsWasm wasm = 1; } +// Similar to GetWasmRequest, but only returns the NNS proposal ID that blessed the wasm. +message GetProposalIdThatAddedWasmRequest { + bytes hash = 1; +} + +// The NNS proposal ID that blessed the wasm, if it was recorded. +message GetProposalIdThatAddedWasmResponse { + optional uint64 proposal_id = 1; +} + // Payload to deploy a new SNS. message DeployNewSnsRequest { // The initial payload to initialize the SNS with. diff --git a/rs/nns/sns-wasm/src/gen/ic_sns_wasm.pb.v1.rs b/rs/nns/sns-wasm/src/gen/ic_sns_wasm.pb.v1.rs index 2f3375df813..1c8db6a8a54 100644 --- a/rs/nns/sns-wasm/src/gen/ic_sns_wasm.pb.v1.rs +++ b/rs/nns/sns-wasm/src/gen/ic_sns_wasm.pb.v1.rs @@ -204,6 +204,22 @@ pub struct GetWasmResponse { #[prost(message, optional, tag = "1")] pub wasm: ::core::option::Option, } +/// Similar to GetWasmRequest, but only returns the NNS proposal ID that blessed the wasm. +#[derive(candid::CandidType, candid::Deserialize, serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetProposalIdThatAddedWasmRequest { + #[prost(bytes = "vec", tag = "1")] + pub hash: ::prost::alloc::vec::Vec, +} +/// The NNS proposal ID that blessed the wasm, if it was recorded. +#[derive(candid::CandidType, candid::Deserialize, serde::Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetProposalIdThatAddedWasmResponse { + #[prost(uint64, optional, tag = "1")] + pub proposal_id: ::core::option::Option, +} /// Payload to deploy a new SNS. #[derive(candid::CandidType, candid::Deserialize, serde::Serialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/rs/nns/sns-wasm/src/sns_wasm.rs b/rs/nns/sns-wasm/src/sns_wasm.rs index a033c5a1999..15f2666c89e 100644 --- a/rs/nns/sns-wasm/src/sns_wasm.rs +++ b/rs/nns/sns-wasm/src/sns_wasm.rs @@ -6,7 +6,8 @@ use crate::{ add_wasm_response, AddWasmRequest, AddWasmResponse, DappCanistersTransferResult, DeployNewSnsRequest, DeployNewSnsResponse, DeployedSns, GetDeployedSnsByProposalIdRequest, GetDeployedSnsByProposalIdResponse, - GetNextSnsVersionRequest, GetNextSnsVersionResponse, GetSnsSubnetIdsResponse, + GetNextSnsVersionRequest, GetNextSnsVersionResponse, GetProposalIdThatAddedWasmRequest, + GetProposalIdThatAddedWasmResponse, GetSnsSubnetIdsResponse, GetWasmMetadataRequest as GetWasmMetadataRequestPb, GetWasmMetadataResponse as GetWasmMetadataResponsePb, GetWasmRequest, GetWasmResponse, InsertUpgradePathEntriesRequest, InsertUpgradePathEntriesResponse, @@ -298,6 +299,20 @@ where } } + /// Returns an Option(ProposalId) in the GetProposalIdThatAddedWasmResponse (a struct with the proposal ID + /// that blessed the given wasm hash) + pub fn get_proposal_id_that_added_wasm( + &self, + payload: GetProposalIdThatAddedWasmRequest, + ) -> GetProposalIdThatAddedWasmResponse { + let hash = vec_to_hash(payload.hash).unwrap(); + GetProposalIdThatAddedWasmResponse { + proposal_id: self + .read_wasm(&hash) + .and_then(|sns_wasm| sns_wasm.proposal_id), + } + } + /// Read a WASM with the given hash from stable memory, if such a WASM exists. fn read_wasm(&self, hash: &[u8; 32]) -> Option { self.wasm_indexes @@ -2104,7 +2119,7 @@ mod test { SnsWasm { wasm: vec![0, 0x61, 0x73, 0x6D, 1, 0, 0, 0], canister_type: i32::from(SnsCanisterType::Governance), - ..SnsWasm::default() + proposal_id: Some(2), } } @@ -2308,6 +2323,38 @@ mod test { assert_eq!(wasm_response.wasm.unwrap(), wasm); } + #[test] + fn test_api_get_proposal_id_that_added_wasm_returns_right_response() { + let mut canister = new_wasm_canister(); + + let wasm = smallest_valid_wasm(); + let expected_hash = Sha256::hash(&wasm.wasm); + let expected_proposal_id = wasm.proposal_id.unwrap(); + + canister.add_wasm(AddWasmRequest { + wasm: Some(wasm.clone()), + hash: expected_hash.to_vec(), + }); + + // When given non-existent hash, return None + let bad_hash = Sha256::hash("something_else".as_bytes()); + let proposal_id_response = + canister.get_proposal_id_that_added_wasm(GetProposalIdThatAddedWasmRequest { + hash: bad_hash.to_vec(), + }); + assert!(proposal_id_response.proposal_id.is_none()); + + // When given valid hash return correct proposal ID + let proposal_id_response = + canister.get_proposal_id_that_added_wasm(GetProposalIdThatAddedWasmRequest { + hash: expected_hash.to_vec(), + }); + assert_eq!( + proposal_id_response.proposal_id.unwrap(), + expected_proposal_id + ); + } + #[test] fn test_api_add_wasm_fails_on_unspecified_canister_type() { let mut canister = new_wasm_canister();