From 4c3bb97ceec4bd8cf36bdd1f15f90d46597a8a6f Mon Sep 17 00:00:00 2001 From: mertwole <33563701+mertwole@users.noreply.github.com> Date: Mon, 4 Sep 2023 17:30:14 +0300 Subject: [PATCH] feat(wasm-gen): Implement fallible syscalls error processing setup --- utils/wasm-gen/src/config/syscalls.rs | 44 +++++++++++++++---- utils/wasm-gen/src/generator/syscalls.rs | 4 +- .../src/generator/syscalls/invocator.rs | 22 ++++++++-- utils/wasm-gen/src/tests.rs | 8 +++- 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/utils/wasm-gen/src/config/syscalls.rs b/utils/wasm-gen/src/config/syscalls.rs index 3dbc167e8a6..b9a37a4ed17 100644 --- a/utils/wasm-gen/src/config/syscalls.rs +++ b/utils/wasm-gen/src/config/syscalls.rs @@ -25,11 +25,13 @@ mod param; use gear_utils::NonEmpty; use gear_wasm_instrument::syscalls::SysCallName; use gsys::{Hash, HashWithValue}; -use std::ops::RangeInclusive; +use std::{collections::HashSet, ops::RangeInclusive}; pub use amount::*; pub use param::*; +use crate::InvocableSysCall; + /// Builder for [`SysCallsConfig`]. pub struct SysCallsConfigBuilder(SysCallsConfig); @@ -40,7 +42,7 @@ impl SysCallsConfigBuilder { injection_amounts, params_config: SysCallsParamsConfig::default(), sending_message_destination: MessageDestination::default(), - ignore_fallible_syscall_errors: true, + error_processing_config: ErrorProcessingConfig::None, log_info: None, }) } @@ -84,9 +86,9 @@ impl SysCallsConfigBuilder { self } - /// Enable/disable processing of errors returned from fallible syscalls. - pub fn set_ignore_fallible_syscall_errors(mut self, ignore: bool) -> Self { - self.0.ignore_fallible_syscall_errors = ignore; + /// Setup fallible syscalls error processing options. + pub fn set_error_processing_config(mut self, config: ErrorProcessingConfig) -> Self { + self.0.error_processing_config = config; self } @@ -107,13 +109,37 @@ impl SysCallsConfigBuilder { } } +#[derive(Debug, Clone, Default)] +pub enum ErrorProcessingConfig { + /// Process errors on all the fallible syscalls. + All, + /// Process only errors on provided syscalls. + Whitelist(HashSet), + /// Process errors on all the syscalls excluding provided. + Blacklist(HashSet), + /// Don't process syscall errors at all. + #[default] + None, +} + +impl ErrorProcessingConfig { + pub fn error_should_be_processed(&self, syscall: &InvocableSysCall) -> bool { + match self { + Self::All => true, + Self::Whitelist(wl) => wl.contains(syscall), + Self::Blacklist(bl) => !bl.contains(syscall), + Self::None => false, + } + } +} + /// United config for all entities in sys-calls generator module. #[derive(Debug, Clone, Default)] pub struct SysCallsConfig { injection_amounts: SysCallsInjectionAmounts, params_config: SysCallsParamsConfig, sending_message_destination: MessageDestination, - ignore_fallible_syscall_errors: bool, + error_processing_config: ErrorProcessingConfig, log_info: Option, } @@ -142,9 +168,9 @@ impl SysCallsConfig { &self.params_config } - /// Should we ignore error processing of fallible syscalls? - pub fn ignore_fallible_syscall_errors(&self) -> bool { - self.ignore_fallible_syscall_errors + /// Error processing config for fallible syscalls. + pub fn error_processing_config(&self) -> &ErrorProcessingConfig { + &self.error_processing_config } } diff --git a/utils/wasm-gen/src/generator/syscalls.rs b/utils/wasm-gen/src/generator/syscalls.rs index f285968db21..6fc3ce9f3a8 100644 --- a/utils/wasm-gen/src/generator/syscalls.rs +++ b/utils/wasm-gen/src/generator/syscalls.rs @@ -54,8 +54,8 @@ use gear_wasm_instrument::syscalls::{ParamType, SysCallName, SysCallSignature}; /// which is pretty hard to predict beforehand with a generator. So this call context /// is created from scratch - first `gr_reserve_gas` is called and then it's result /// is used for the further `gr_reservation_send` call. Those are `Precise` sys-calls. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) enum InvocableSysCall { +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum InvocableSysCall { Loose(SysCallName), Precise(SysCallName), } diff --git a/utils/wasm-gen/src/generator/syscalls/invocator.rs b/utils/wasm-gen/src/generator/syscalls/invocator.rs index 0cdf9da6590..479913e10cf 100644 --- a/utils/wasm-gen/src/generator/syscalls/invocator.rs +++ b/utils/wasm-gen/src/generator/syscalls/invocator.rs @@ -208,6 +208,10 @@ impl<'a, 'b> SysCallsInvocator<'a, 'b> { self.unstructured.len() ); + let insert_error_processing = self + .config + .error_processing_config() + .error_should_be_processed(&invocable); let (fallible, mut signature) = (invocable.is_fallible(), invocable.into_signature()); if self.is_not_send_sys_call(invocable) { @@ -215,7 +219,12 @@ impl<'a, 'b> SysCallsInvocator<'a, 'b> { " -- Generating build call for non-send sys-call {}", invocable.to_str() ); - return self.build_call(signature, fallible, call_indexes_handle); + return self.build_call( + signature, + fallible, + insert_error_processing, + call_indexes_handle, + ); } log::trace!( @@ -226,8 +235,12 @@ impl<'a, 'b> SysCallsInvocator<'a, 'b> { // The value for the first param is chosen from config. // It's either the result of `gr_source`, some existing address (set in the data section) or a completely random value. signature.params.remove(0); - let mut call_without_destination_instrs = - self.build_call(signature, fallible, call_indexes_handle)?; + let mut call_without_destination_instrs = self.build_call( + signature, + fallible, + insert_error_processing, + call_indexes_handle, + )?; let res = if self.config.sending_message_destination().is_source() { log::trace!(" -- Message destination is result of `gr_source`"); @@ -306,6 +319,7 @@ impl<'a, 'b> SysCallsInvocator<'a, 'b> { &mut self, signature: SysCallSignature, fallible: bool, + insert_error_processing: bool, call_indexes_handle: CallIndexesHandle, ) -> Result> { let param_setters = self.build_param_setters(&signature.params)?; @@ -317,7 +331,7 @@ impl<'a, 'b> SysCallsInvocator<'a, 'b> { instructions.push(Instruction::Call(call_indexes_handle as u32)); - let mut result_processing = if self.config.ignore_fallible_syscall_errors() { + let mut result_processing = if !insert_error_processing { Self::build_result_processing_ignored(signature) } else if fallible { Self::build_result_processing_fallible(signature, ¶m_setters) diff --git a/utils/wasm-gen/src/tests.rs b/utils/wasm-gen/src/tests.rs index a52571ec4b2..588bdc7c989 100644 --- a/utils/wasm-gen/src/tests.rs +++ b/utils/wasm-gen/src/tests.rs @@ -247,6 +247,12 @@ fn execute_wasm_with_syscall_injected( let mut injection_amounts = SysCallsInjectionAmounts::all_never(); injection_amounts.set(syscall, INJECTED_SYSCALLS, INJECTED_SYSCALLS); + let error_processing_config = if ignore_fallible_errors { + ErrorProcessingConfig::None + } else { + ErrorProcessingConfig::All + }; + let gear_config = ( GearWasmGeneratorConfigBuilder::new() .with_memory_config(MemoryPagesConfig { @@ -256,7 +262,7 @@ fn execute_wasm_with_syscall_injected( .with_sys_calls_config( SysCallsConfigBuilder::new(injection_amounts) .with_params_config(params_config) - .set_ignore_fallible_syscall_errors(ignore_fallible_errors) + .set_error_processing_config(error_processing_config) .build(), ) .with_entry_points_config(EntryPointsSet::Init)