From 19533e68564813e407621fc6b4786284c7229d6e Mon Sep 17 00:00:00 2001 From: Ulan Degenbaev Date: Wed, 10 Jan 2024 13:30:34 +0000 Subject: [PATCH] RUN-882: Avoid traps in the `ic0.call_perform` System API --- rs/execution_environment/src/hypervisor/tests.rs | 6 ++---- rs/system_api/src/lib.rs | 13 ++++--------- rs/system_api/tests/system_api.rs | 13 ++++++------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/rs/execution_environment/src/hypervisor/tests.rs b/rs/execution_environment/src/hypervisor/tests.rs index bc7c46ca297..75fccdc0faa 100644 --- a/rs/execution_environment/src/hypervisor/tests.rs +++ b/rs/execution_environment/src/hypervisor/tests.rs @@ -5951,13 +5951,11 @@ fn call_perform_checks_freezing_threshold_in_update() { .build(); let err = test.ingress(canister_id, "update", body).unwrap_err(); assert!( - err.description().contains( - "Canister cannot grow message memory by 2097168 bytes due to insufficient cycles" - ), + err.description().contains("call_perform failed"), "Unexpected error: {}", err.description() ); - assert_eq!(err.code(), ErrorCode::InsufficientCyclesInMessageMemoryGrow); + assert_eq!(err.code(), ErrorCode::CanisterCalledTrap); } #[test] diff --git a/rs/system_api/src/lib.rs b/rs/system_api/src/lib.rs index 8c9bcc37651..90f75392b6b 100644 --- a/rs/system_api/src/lib.rs +++ b/rs/system_api/src/lib.rs @@ -1280,20 +1280,15 @@ impl SystemApiImpl { } else { (memory_required_to_push_request(&req) as u64).into() }; - if let Err(err) = self.memory_usage.allocate_message_memory( + if let Err(_err) = self.memory_usage.allocate_message_memory( reservation_bytes, &self.api_type, &self.sandbox_safe_system_state, ) { abort(req, &mut self.sandbox_safe_system_state); - match err { - err @ HypervisorError::InsufficientCyclesInMessageMemoryGrow { .. } => { - // Return an the out-of-cycles error in this case for a better - // error message to be relayed to the caller. - return Err(err); - } - _ => return Ok(RejectCode::SysTransient as i32), - } + // Return an error code instead of trapping here in order to allow + // the user code to handle the error gracefully. + return Ok(RejectCode::SysTransient as i32); } match self.sandbox_safe_system_state.push_output_request( diff --git a/rs/system_api/tests/system_api.rs b/rs/system_api/tests/system_api.rs index 28fca63bd49..596ed8106cd 100644 --- a/rs/system_api/tests/system_api.rs +++ b/rs/system_api/tests/system_api.rs @@ -1422,9 +1422,10 @@ fn msg_cycles_accept_all_cycles_in_call_context_when_more_asked() { } /// If call call_perform() fails because canister does not have enough -/// cycles to send the message, then the state is reset. +/// cycles to send the message, then it does not trap, but returns +/// a transient error reject code. #[test] -fn call_perform_not_enough_cycles_resets_state() { +fn call_perform_not_enough_cycles_does_not_trap() { let cycles_account_manager = CyclesAccountManagerBuilder::new() .with_subnet_type(SubnetType::Application) .build(); @@ -1453,11 +1454,9 @@ fn call_perform_not_enough_cycles_resets_state() { api.ic0_call_cycles_add128(Cycles::new(100)).unwrap(); let res = api.ic0_call_perform(); match res { - Err(HypervisorError::InsufficientCyclesInMessageMemoryGrow { - bytes: _, - available: _, - threshold: _, - }) => {} + Ok(code) => { + assert_eq!(code, RejectCode::SysTransient as i32); + } _ => panic!( "expected to get an InsufficientCyclesInMessageMemoryGrow error, got {:?}", res