From d44a16068c2cb8a11e54ddf1130edfdba3996dcb Mon Sep 17 00:00:00 2001 From: Maxim Savenkov Date: Fri, 15 Sep 2023 16:49:54 +0200 Subject: [PATCH] refactor(pallet-gear): Allow `calculate_gas_info` on terminated program. --- pallets/gear/src/runtime_api.rs | 27 ++++++++++++++++++----- pallets/gear/src/tests.rs | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/pallets/gear/src/runtime_api.rs b/pallets/gear/src/runtime_api.rs index a37fea57381..5c486a8ab4b 100644 --- a/pallets/gear/src/runtime_api.rs +++ b/pallets/gear/src/runtime_api.rs @@ -17,9 +17,10 @@ // along with this program. If not, see . use super::*; -use crate::queue::QueueStep; +use crate::queue::{ActorResult, QueueStep}; use common::ActiveProgram; use core::convert::TryFrom; +use core_processor::common::PrechargedDispatch; use gear_core::{code::TryNewCodeConfig, pages::WasmPage}; use gear_wasm_instrument::syscalls::SysCallName; @@ -126,11 +127,25 @@ where break; }; + //let actor = ext_manager + // .get_actor(actor_id) + // .ok_or_else(|| b"Program not found in the storage".to_vec())?; + let actor_id = queued_dispatch.destination(); + let dispatch_id = queued_dispatch.id(); + let dispatch_reply = queued_dispatch.reply_details().is_some(); + + let balance = CurrencyOf::::free_balance(&::from_origin( + actor_id.into_origin(), + )); - let actor = ext_manager - .get_actor(actor_id) - .ok_or_else(|| b"Program not found in the storage".to_vec())?; + let get_actor_data = |precharged_dispatch: PrechargedDispatch| { + // At this point gas counters should be changed accordingly so fetch the program data. + match Self::get_active_actor_data(actor_id, dispatch_id, dispatch_reply) { + ActorResult::Data(data) => Ok((precharged_dispatch, data)), + ActorResult::Continue => Err(precharged_dispatch), + } + }; let dispatch_id = queued_dispatch.id(); let success_reply = queued_dispatch @@ -148,8 +163,8 @@ where ext_manager: &mut ext_manager, gas_limit, dispatch: queued_dispatch, - balance: actor.balance, - get_actor_data: |dispatch| Ok((dispatch, actor.executable_data)), + balance: balance.unique_saturated_into(), + get_actor_data, }; let journal = step.execute().unwrap_or_else(|e| unreachable!("{e:?}")); diff --git a/pallets/gear/src/tests.rs b/pallets/gear/src/tests.rs index ae861d0d365..c20269e10d2 100644 --- a/pallets/gear/src/tests.rs +++ b/pallets/gear/src/tests.rs @@ -15251,3 +15251,42 @@ mod utils { ::GasMultiplier::get().gas_to_value(gas) } } + +#[test] +fn test_gas_info_of_terminated_program() { + use demo_constructor::{Calls, Scheme}; + + init_logger(); + new_test_ext().execute_with(|| { + // Dies in init + let init_dead = Calls::builder().panic("Die in init"); + let handle_dead = Calls::builder().panic("Called after being terminated!"); + let (_, pid_dead) = utils::submit_constructor_with_args( + USER_1, + b"salt1".to_vec(), + Scheme::predefined(init_dead, handle_dead, Calls::default()), + 0, + ); + + // Sends in handle message do dead program + let handle_proxy = Calls::builder().send(pid_dead.into_bytes(), []); + let (_, proxy_pid) = utils::submit_constructor_with_args( + USER_1, + b"salt2".to_vec(), + Scheme::predefined(Calls::default(), handle_proxy, Calls::default()), + 0, + ); + + run_to_next_block(None); + + let _gas_info = Gear::calculate_gas_info( + USER_1.into_origin(), + HandleKind::Handle(proxy_pid), + EMPTY_PAYLOAD.to_vec(), + 0, + true, + true, + ) + .expect("failed getting gas info"); // panics here as `pid_dead` is terminated and rpc call wasn't able to get code. + }) +}