1- use crate :: decoder_config;
2- use crate :: governance:: {
3- Environment , Governance , HeapGrowthPotential , RandomnessGenerator , RngError ,
1+ use crate :: {
2+ decoder_config,
3+ governance:: { Environment , Governance , HeapGrowthPotential , RandomnessGenerator , RngError } ,
4+ pb:: v1:: { GovernanceError , governance_error:: ErrorType } ,
5+ proposals:: execute_nns_function:: { ValidExecuteNnsFunction , ValidNnsFunction } ,
46} ;
7+
58use async_trait:: async_trait;
69use candid:: { Decode , Encode } ;
710use ic_base_types:: CanisterId ;
@@ -187,15 +190,8 @@ impl Environment for CanisterEnv {
187190 fn execute_nns_function (
188191 & self ,
189192 proposal_id : u64 ,
190- update : & crate :: pb :: v1 :: ExecuteNnsFunction ,
193+ execute_nns_function : & ValidExecuteNnsFunction ,
191194 ) -> Result < ( ) , crate :: pb:: v1:: GovernanceError > {
192- // use internal types, as this API is used in core
193- use crate :: pb:: v1:: { GovernanceError , NnsFunction , governance_error:: ErrorType } ;
194-
195- let mt = NnsFunction :: try_from ( update. nns_function ) . map_err ( |_|
196- // No update type specified.
197- GovernanceError :: new ( ErrorType :: PreconditionFailed ) ) ?;
198-
199195 let reply = move || {
200196 governance_mut ( ) . set_proposal_execution_status ( proposal_id, Ok ( ( ) ) ) ;
201197 } ;
@@ -227,22 +223,19 @@ impl Environment for CanisterEnv {
227223 ) ) ,
228224 ) ;
229225 } ;
230- let ( canister_id, method) = mt. canister_and_function ( ) ?;
231- let method = method. to_owned ( ) ;
226+ let ( canister_id, method) = execute_nns_function. nns_function . canister_and_function ( ) ;
232227 let proposal_timestamp_seconds = governance ( )
233228 . get_proposal_data ( ProposalId ( proposal_id) )
234229 . map ( |data| data. proposal_timestamp_seconds )
235230 . ok_or ( GovernanceError :: new ( ErrorType :: PreconditionFailed ) ) ?;
236231 let effective_payload = get_effective_payload (
237- mt,
238- update. payload . clone ( ) ,
232+ execute_nns_function,
239233 proposal_id,
240234 proposal_timestamp_seconds,
241235 ) ?;
242236
243237 ic_cdk:: futures:: spawn_017_compat ( async move {
244- match CdkRuntime :: call_bytes_with_cleanup ( canister_id, & method, & effective_payload)
245- . await
238+ match CdkRuntime :: call_bytes_with_cleanup ( canister_id, method, & effective_payload) . await
246239 {
247240 Ok ( _) => reply ( ) ,
248241 Err ( e) => reject ( e) ,
@@ -281,130 +274,127 @@ impl Environment for CanisterEnv {
281274}
282275// Processes the payload received and transforms it into a form the intended canister expects.
283276// The arguments `proposal_id` is used by AddSnsWasm proposals.
284- // `_proposal_timestamp_seconds` will be used in the future by subnet rental NNS proposals.
277+ // `proposal_timestamp_seconds` is used by subnet rental NNS proposals.
278+ // TODO(NNS1-4272): move this into `impl ValidExecuteNnsFunction`.
285279fn get_effective_payload (
286- mt : crate :: pb:: v1:: NnsFunction ,
287- payload : Vec < u8 > ,
280+ execute_nns_function : & ValidExecuteNnsFunction ,
288281 proposal_id : u64 ,
289282 proposal_timestamp_seconds : u64 ,
290283) -> Result < Vec < u8 > , crate :: pb:: v1:: GovernanceError > {
291- use crate :: pb:: v1:: { GovernanceError , NnsFunction , governance_error:: ErrorType } ;
284+ use crate :: pb:: v1:: { GovernanceError , governance_error:: ErrorType } ;
292285
293286 const BITCOIN_SET_CONFIG_METHOD_NAME : & str = "set_config" ;
294287 const BITCOIN_MAINNET_CANISTER_ID : & str = "ghsi2-tqaaa-aaaan-aaaca-cai" ;
295288 const BITCOIN_TESTNET_CANISTER_ID : & str = "g4xu7-jiaaa-aaaan-aaaaq-cai" ;
296289
297- match mt {
298- NnsFunction :: BitcoinSetConfig => {
290+ let ValidExecuteNnsFunction {
291+ nns_function,
292+ payload,
293+ } = execute_nns_function;
294+
295+ match nns_function {
296+ ValidNnsFunction :: BitcoinSetConfig => {
299297 // Decode the payload to get the network.
300- let payload = match Decode ! ( [ decoder_config( ) ] ; & payload, BitcoinSetConfigProposal ) {
301- Ok ( payload) => payload,
302- Err ( _) => {
303- return Err ( GovernanceError :: new_with_message ( ErrorType :: InvalidProposal , "Payload must be a valid BitcoinSetConfigProposal." ) ) ;
304- }
305- } ;
298+ let decoded_payload = Decode ! ( [ decoder_config( ) ] ; payload, BitcoinSetConfigProposal )
299+ . map_err ( |_| {
300+ GovernanceError :: new_with_message (
301+ ErrorType :: InvalidProposal ,
302+ "Unable to decode BitcoinSetConfigProposal proposal: {e}" ,
303+ )
304+ } ) ?;
306305
307306 // Convert it to a call canister payload.
308- let canister_id = CanisterId :: from_str ( match payload . network {
307+ let canister_id = CanisterId :: from_str ( match decoded_payload . network {
309308 BitcoinNetwork :: Mainnet => BITCOIN_MAINNET_CANISTER_ID ,
310309 BitcoinNetwork :: Testnet => BITCOIN_TESTNET_CANISTER_ID ,
311- } ) . expect ( "bitcoin canister id must be valid." ) ;
310+ } )
311+ . expect ( "bitcoin canister id must be valid." ) ;
312312
313313 let encoded_payload = Encode ! ( & CallCanisterRequest {
314314 canister_id,
315315 method_name: BITCOIN_SET_CONFIG_METHOD_NAME . to_string( ) ,
316- payload: payload . payload
316+ payload: decoded_payload . payload
317317 } )
318- . unwrap ( ) ;
318+ . unwrap ( ) ;
319319
320320 Ok ( encoded_payload)
321321 }
322- NnsFunction :: SubnetRentalRequest => {
322+ ValidNnsFunction :: SubnetRentalRequest => {
323323 // Decode the payload to `SubnetRentalRequest`.
324- let payload = match Decode ! ( [ decoder_config( ) ] ; & payload, SubnetRentalRequest ) {
325- Ok ( payload) => payload,
326- Err ( _) => {
327- return Err ( GovernanceError :: new_with_message ( ErrorType :: InvalidProposal , "Payload must be a valid SubnetRentalRequest." ) ) ;
328- }
329- } ;
324+ let decoded_payload = Decode ! ( [ decoder_config( ) ] ; payload, SubnetRentalRequest )
325+ . map_err ( |_| {
326+ GovernanceError :: new_with_message (
327+ ErrorType :: InvalidProposal ,
328+ "Unable to decode SubnetRentalRequest proposal: {e}" ,
329+ )
330+ } ) ?;
330331
331332 // Convert the payload to `SubnetRentalProposalPayload`.
332333 let SubnetRentalRequest {
333334 user,
334335 rental_condition_id,
335- } = payload ;
336+ } = decoded_payload ;
336337 let proposal_creation_time_seconds = proposal_timestamp_seconds;
337338 let encoded_payload = Encode ! ( & SubnetRentalProposalPayload {
338339 user,
339340 rental_condition_id,
340341 proposal_id,
341342 proposal_creation_time_seconds,
342- } ) . unwrap ( ) ;
343+ } )
344+ . unwrap ( ) ;
343345
344346 Ok ( encoded_payload)
345347 }
346348
347- | NnsFunction :: AddSnsWasm => {
348- let payload = add_proposal_id_to_add_wasm_request ( & payload, proposal_id) ?;
349+ ValidNnsFunction :: AddSnsWasm => {
350+ let transformed_payload = add_proposal_id_to_add_wasm_request ( payload, proposal_id) ?;
349351
350- Ok ( payload )
352+ Ok ( transformed_payload )
351353 }
352354
353355 // NOTE: Methods are listed explicitly as opposed to using the `_` wildcard so
354356 // that adding a new function causes a compile error here, ensuring that the developer
355357 // makes an explicit decision on how the payload is handled.
356- NnsFunction :: Unspecified
357- | NnsFunction :: UpdateElectedHostosVersions
358- | NnsFunction :: UpdateNodesHostosVersion
359- | NnsFunction :: ReviseElectedHostosVersions
360- | NnsFunction :: DeployHostosToSomeNodes
361- | NnsFunction :: AssignNoid
362- | NnsFunction :: CreateSubnet
363- | NnsFunction :: AddNodeToSubnet
364- | NnsFunction :: RemoveNodesFromSubnet
365- | NnsFunction :: ChangeSubnetMembership
366- | NnsFunction :: NnsCanisterInstall
367- | NnsFunction :: NnsCanisterUpgrade
368- | NnsFunction :: NnsRootUpgrade
369- | NnsFunction :: HardResetNnsRootToVersion
370- | NnsFunction :: RecoverSubnet
371- | NnsFunction :: BlessReplicaVersion
372- | NnsFunction :: RetireReplicaVersion
373- | NnsFunction :: ReviseElectedGuestosVersions
374- | NnsFunction :: UpdateNodeOperatorConfig
375- | NnsFunction :: DeployGuestosToAllSubnetNodes
376- | NnsFunction :: UpdateConfigOfSubnet
377- | NnsFunction :: IcpXdrConversionRate
378- | NnsFunction :: ClearProvisionalWhitelist
379- | NnsFunction :: SetAuthorizedSubnetworks
380- | NnsFunction :: SetFirewallConfig
381- | NnsFunction :: AddFirewallRules
382- | NnsFunction :: RemoveFirewallRules
383- | NnsFunction :: UpdateFirewallRules
384- | NnsFunction :: StopOrStartNnsCanister
385- | NnsFunction :: RemoveNodes
386- | NnsFunction :: UninstallCode
387- | NnsFunction :: UpdateNodeRewardsTable
388- | NnsFunction :: AddOrRemoveDataCenters
389- | NnsFunction :: UpdateUnassignedNodesConfig // obsolete
390- | NnsFunction :: RemoveNodeOperators
391- | NnsFunction :: RerouteCanisterRanges
392- | NnsFunction :: PrepareCanisterMigration
393- | NnsFunction :: CompleteCanisterMigration
394- | NnsFunction :: UpdateSubnetType
395- | NnsFunction :: ChangeSubnetTypeAssignment
396- | NnsFunction :: UpdateAllowedPrincipals
397- | NnsFunction :: UpdateSnsWasmSnsSubnetIds
398- | NnsFunction :: InsertSnsWasmUpgradePathEntries
399- | NnsFunction :: AddApiBoundaryNodes
400- | NnsFunction :: RemoveApiBoundaryNodes
401- | NnsFunction :: UpdateApiBoundaryNodesVersion // obsolete
402- | NnsFunction :: DeployGuestosToAllUnassignedNodes
403- | NnsFunction :: UpdateSshReadonlyAccessForAllUnassignedNodes
404- | NnsFunction :: DeployGuestosToSomeApiBoundaryNodes
405- | NnsFunction :: PauseCanisterMigrations
406- | NnsFunction :: UnpauseCanisterMigrations
407- | NnsFunction :: SetSubnetOperationalLevel => Ok ( payload) ,
358+ ValidNnsFunction :: CreateSubnet
359+ | ValidNnsFunction :: AddNodeToSubnet
360+ | ValidNnsFunction :: NnsCanisterInstall
361+ | ValidNnsFunction :: RecoverSubnet
362+ | ValidNnsFunction :: UpdateConfigOfSubnet
363+ | ValidNnsFunction :: AssignNoid
364+ | ValidNnsFunction :: DeployGuestosToAllSubnetNodes
365+ | ValidNnsFunction :: ClearProvisionalWhitelist
366+ | ValidNnsFunction :: RemoveNodesFromSubnet
367+ | ValidNnsFunction :: SetAuthorizedSubnetworks
368+ | ValidNnsFunction :: SetFirewallConfig
369+ | ValidNnsFunction :: UpdateNodeOperatorConfig
370+ | ValidNnsFunction :: RemoveNodes
371+ | ValidNnsFunction :: UninstallCode
372+ | ValidNnsFunction :: UpdateNodeRewardsTable
373+ | ValidNnsFunction :: AddOrRemoveDataCenters
374+ | ValidNnsFunction :: RemoveNodeOperators
375+ | ValidNnsFunction :: RerouteCanisterRanges
376+ | ValidNnsFunction :: AddFirewallRules
377+ | ValidNnsFunction :: RemoveFirewallRules
378+ | ValidNnsFunction :: UpdateFirewallRules
379+ | ValidNnsFunction :: PrepareCanisterMigration
380+ | ValidNnsFunction :: CompleteCanisterMigration
381+ | ValidNnsFunction :: ChangeSubnetMembership
382+ | ValidNnsFunction :: UpdateSubnetType
383+ | ValidNnsFunction :: ChangeSubnetTypeAssignment
384+ | ValidNnsFunction :: UpdateSnsWasmSnsSubnetIds
385+ | ValidNnsFunction :: InsertSnsWasmUpgradePathEntries
386+ | ValidNnsFunction :: ReviseElectedGuestosVersions
387+ | ValidNnsFunction :: HardResetNnsRootToVersion
388+ | ValidNnsFunction :: AddApiBoundaryNodes
389+ | ValidNnsFunction :: RemoveApiBoundaryNodes
390+ | ValidNnsFunction :: DeployGuestosToSomeApiBoundaryNodes
391+ | ValidNnsFunction :: DeployGuestosToAllUnassignedNodes
392+ | ValidNnsFunction :: UpdateSshReadonlyAccessForAllUnassignedNodes
393+ | ValidNnsFunction :: ReviseElectedHostosVersions
394+ | ValidNnsFunction :: DeployHostosToSomeNodes
395+ | ValidNnsFunction :: PauseCanisterMigrations
396+ | ValidNnsFunction :: UnpauseCanisterMigrations
397+ | ValidNnsFunction :: SetSubnetOperationalLevel => Ok ( payload. clone ( ) ) ,
408398 }
409399}
410400
@@ -446,7 +436,7 @@ fn add_proposal_id_to_add_wasm_request(
446436#[ cfg( test) ]
447437mod tests {
448438 use super :: * ;
449- use candid :: { Decode , Encode } ;
439+
450440 #[ test]
451441 fn test_set_time_warp ( ) {
452442 let environment = CanisterEnv :: new ( ) ;
@@ -461,7 +451,6 @@ mod tests {
461451
462452 #[ test]
463453 fn test_get_effective_payload_sets_proposal_id_for_add_wasm ( ) {
464- let mt = crate :: pb:: v1:: NnsFunction :: AddSnsWasm ;
465454 let proposal_id = 42 ;
466455 let wasm = vec ! [ 1 , 2 , 3 ] ;
467456 let canister_type = 3 ;
@@ -477,7 +466,13 @@ mod tests {
477466 } )
478467 . unwrap ( ) ;
479468
480- let effective_payload = get_effective_payload ( mt, payload, proposal_id, 0 ) . unwrap ( ) ;
469+ let execute_nns_function = ValidExecuteNnsFunction {
470+ nns_function : ValidNnsFunction :: AddSnsWasm ,
471+ payload,
472+ } ;
473+
474+ let effective_payload =
475+ get_effective_payload ( & execute_nns_function, proposal_id, 0 ) . unwrap ( ) ;
481476
482477 let decoded = Decode ! ( & effective_payload, AddWasmRequest ) . unwrap ( ) ;
483478 assert_eq ! (
@@ -496,7 +491,6 @@ mod tests {
496491
497492 #[ test]
498493 fn test_get_effective_payload_overrides_proposal_id_for_add_wasm ( ) {
499- let mt = crate :: pb:: v1:: NnsFunction :: AddSnsWasm ;
500494 let proposal_id = 42 ;
501495 let payload = Encode ! ( & AddWasmRequest {
502496 wasm: Some ( SnsWasm {
@@ -507,7 +501,13 @@ mod tests {
507501 } )
508502 . unwrap ( ) ;
509503
510- let effective_payload = get_effective_payload ( mt, payload, proposal_id, 0 ) . unwrap ( ) ;
504+ let execute_nns_function = ValidExecuteNnsFunction {
505+ nns_function : ValidNnsFunction :: AddSnsWasm ,
506+ payload,
507+ } ;
508+
509+ let effective_payload =
510+ get_effective_payload ( & execute_nns_function, proposal_id, 0 ) . unwrap ( ) ;
511511
512512 let decoded = Decode ! ( & effective_payload, AddWasmRequest ) . unwrap ( ) ;
513513 assert_eq ! ( decoded. wasm. unwrap( ) . proposal_id. unwrap( ) , proposal_id) ;
0 commit comments