diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index 5a5bbdb9b0d..a66e4c025be 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -46,8 +46,7 @@ use gear_core::{ use gear_core_errors::{MessageError, ReplyCode, SignalCode}; use gear_sandbox::{default_executor::Caller, ReturnValue, Value}; use gear_sandbox_env::{HostError, WasmReturnValue}; -use gear_wasm_instrument::syscalls::UserBreakKind; -use gear_wasm_instrument::SystemBreakCode; +use gear_wasm_instrument::{syscalls::UserBreakKind, SystemBreakCode}; use gsys::{ BlockNumberWithHash, ErrorBytes, ErrorWithBlockNumberAndValue, ErrorWithGas, ErrorWithHandle, ErrorWithHash, ErrorWithReplyCode, ErrorWithSignalCode, ErrorWithTwoHashes, Gas, Hash, @@ -593,12 +592,13 @@ where }) } - pub fn exit(inheritor_id_ptr: u32) -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::Exit, move |ctx: &mut CallerWrap| { - let read_inheritor_id = ctx.manager.register_read_decoded(inheritor_id_ptr); - let inheritor_id = ctx.read_decoded(read_inheritor_id)?; - Err(ActorTerminationReason::Exit(inheritor_id).into()) - }) + pub fn exit( + ctx: &mut CallerWrap, + inheritor_id_ptr: u32, + ) -> Result<(), UndefinedTerminationReason> { + let read_inheritor_id = ctx.manager.register_read_decoded(inheritor_id_ptr); + let inheritor_id = ctx.read_decoded(read_inheritor_id)?; + Err(ActorTerminationReason::Exit(inheritor_id).into()) } pub fn reply_code() -> impl Syscall { @@ -1033,21 +1033,21 @@ where ) } - pub fn panic(data_ptr: u32, data_len: u16) -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::Null, move |ctx: &mut CallerWrap| { - let read_data = ctx.manager.register_read(data_ptr, data_len as u32); - let data = ctx.read(read_data).unwrap_or_default(); + pub fn panic( + ctx: &mut CallerWrap, + data_ptr: u32, + data_len: u16, + ) -> Result<(), UndefinedTerminationReason> { + let read_data = ctx.manager.register_read(data_ptr, data_len as u32); + let data = ctx.read(read_data).unwrap_or_default(); - let s = String::from_utf8_lossy(&data).to_string(); + let s = String::from_utf8_lossy(&data).to_string(); - Err(ActorTerminationReason::Trap(TrapExplanation::Panic(s.into())).into()) - }) + Err(ActorTerminationReason::Trap(TrapExplanation::Panic(s.into())).into()) } - pub fn oom_panic() -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::Null, |_ctx: &mut CallerWrap| { - Err(ActorTerminationReason::Trap(TrapExplanation::ProgramAllocOutOfBounds).into()) - }) + pub fn oom_panic() -> Result<(), UndefinedTerminationReason> { + Err(ActorTerminationReason::Trap(TrapExplanation::ProgramAllocOutOfBounds).into()) } pub fn reserve_gas(gas_value: u64, duration: u32) -> impl Syscall { @@ -1184,35 +1184,33 @@ where ) } - pub fn leave() -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::Leave, move |_ctx: &mut CallerWrap| { - Err(ActorTerminationReason::Leave.into()) - }) + pub fn leave() -> Result<(), UndefinedTerminationReason> { + Err(ActorTerminationReason::Leave.into()) } - pub fn wait() -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::Wait, move |ctx: &mut CallerWrap| { - ctx.ext_mut().wait()?; - Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into()) - }) + pub fn wait(ctx: &mut CallerWrap) -> Result<(), UndefinedTerminationReason> { + ctx.ext_mut().wait()?; + Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into()) } - pub fn wait_for(duration: u32) -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::WaitFor, move |ctx: &mut CallerWrap| { - ctx.ext_mut().wait_for(duration)?; - Err(ActorTerminationReason::Wait(Some(duration), MessageWaitedType::WaitFor).into()) - }) + pub fn wait_for( + ctx: &mut CallerWrap, + duration: u32, + ) -> Result<(), UndefinedTerminationReason> { + ctx.ext_mut().wait_for(duration)?; + Err(ActorTerminationReason::Wait(Some(duration), MessageWaitedType::WaitFor).into()) } - pub fn wait_up_to(duration: u32) -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::WaitUpTo, move |ctx: &mut CallerWrap| { - let waited_type = if ctx.ext_mut().wait_up_to(duration)? { - MessageWaitedType::WaitUpToFull - } else { - MessageWaitedType::WaitUpTo - }; - Err(ActorTerminationReason::Wait(Some(duration), waited_type).into()) - }) + pub fn wait_up_to( + ctx: &mut CallerWrap, + duration: u32, + ) -> Result<(), UndefinedTerminationReason> { + let waited_type = if ctx.ext_mut().wait_up_to(duration)? { + MessageWaitedType::WaitUpToFull + } else { + MessageWaitedType::WaitUpTo + }; + Err(ActorTerminationReason::Wait(Some(duration), waited_type).into()) } pub fn wake(message_id_ptr: u32, delay: u32) -> impl Syscall { @@ -1357,32 +1355,22 @@ where let break_kind = raw_data[0].try_into(); // We do this instead of 2..6 since this gives a fixed length array let data32 = u32::from_le_bytes([raw_data[2], raw_data[3], raw_data[4], raw_data[5]]); - match break_kind { - Ok(UserBreakKind::Exit) => { - FuncsHandler::exit(data32) - } - Ok(UserBreakKind::Leave) => { - FuncsHandler::leave() - } - Ok(UserBreakKind::Wait) => { - FuncsHandler::wait() - } - Ok(UserBreakKind::WaitFor) => { - FuncsHandler::wait_for(data32) - } - Ok(UserBreakKind::WaitUpTo) => { - FuncsHandler::wait_up_to(data32) - } + let cost = break_kind.map(Into::into).unwrap_or(RuntimeCosts::Null); + InfallibleSyscall::new(cost, move |ctx: &mut CallerWrap| match break_kind { + Ok(UserBreakKind::Exit) => FuncsHandler::exit(ctx, data32), + Ok(UserBreakKind::Leave) => FuncsHandler::::leave(), + Ok(UserBreakKind::Wait) => FuncsHandler::wait(ctx), + Ok(UserBreakKind::WaitFor) => FuncsHandler::wait_for(ctx, data32), + Ok(UserBreakKind::WaitUpTo) => FuncsHandler::wait_up_to(ctx, data32), Ok(UserBreakKind::Panic) => { let data16 = u16::from_le_bytes([raw_data[6], raw_data[7]]); - FuncsHandler::panic(data32, data16) + FuncsHandler::panic(ctx, data32, data16) } - Ok(UserBreakKind::OomPanic) => { - FuncsHandler::oom_panic() - } - _ => { - Err(ActorTerminationReason::Trap(TrapExplanation::Panic("Unknown user_break syscall codec".to_string().into())).into()) - } - } + Ok(UserBreakKind::OomPanic) => FuncsHandler::::oom_panic(), + _ => Err(ActorTerminationReason::Trap(TrapExplanation::Panic( + "Unknown user_break syscall codec".to_string().into(), + )) + .into()), + }) } } diff --git a/core/src/costs.rs b/core/src/costs.rs index 9cbe724bfb4..7a318186ff0 100644 --- a/core/src/costs.rs +++ b/core/src/costs.rs @@ -20,6 +20,7 @@ use crate::{gas::Token, pages::PageU32Size}; use core::{fmt::Debug, marker::PhantomData}; +use gear_wasm_instrument::syscalls::UserBreakKind; use paste::paste; use scale_info::scale::{Decode, Encode}; @@ -549,3 +550,16 @@ impl RuntimeCosts { RuntimeToken { weight } } } + +impl From for RuntimeCosts { + fn from(value: UserBreakKind) -> Self { + match value { + UserBreakKind::Exit => RuntimeCosts::Exit, + UserBreakKind::Leave => RuntimeCosts::Leave, + UserBreakKind::Wait => RuntimeCosts::Wait, + UserBreakKind::WaitFor => RuntimeCosts::WaitFor, + UserBreakKind::WaitUpTo => RuntimeCosts::WaitUpTo, + _ => RuntimeCosts::Null, + } + } +} diff --git a/gcore/src/exec.rs b/gcore/src/exec.rs index a5abe82ce29..090f9e4e4eb 100644 --- a/gcore/src/exec.rs +++ b/gcore/src/exec.rs @@ -146,7 +146,13 @@ pub fn reply_deposit(message_id: MessageId, amount: u64) -> Result<()> { /// } /// ``` pub fn exit(inheritor_id: ActorId) -> ! { - unsafe { gsys::gr_exit(inheritor_id.as_ptr()) } + let mut data = [0u8; 8]; + let ptr = (inheritor_id.as_ptr() as u32).to_le_bytes(); + data[2] = ptr[0]; + data[3] = ptr[1]; + data[4] = ptr[2]; + data[5] = ptr[3]; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Reserve the `amount` of gas for further usage. @@ -282,7 +288,9 @@ pub fn gas_available() -> u64 { /// } /// ``` pub fn leave() -> ! { - unsafe { gsys::gr_leave() } + let mut data = [0u8; 8]; + data[0] = 1; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Get the total available value amount. @@ -332,7 +340,9 @@ pub fn value_available() -> u128 { /// } /// ``` pub fn wait() -> ! { - unsafe { gsys::gr_wait() } + let mut data = [0u8; 8]; + data[0] = 2; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Same as [`wait`], but delays handling for a specific number of blocks. @@ -341,13 +351,27 @@ pub fn wait() -> ! { /// /// Panics if it is impossible to pay the given `duration`. pub fn wait_for(duration: u32) -> ! { - unsafe { gsys::gr_wait_for(duration) } + let mut data = [0u8; 8]; + data[0] = 3; + let raw_duration = duration.to_le_bytes(); + data[2] = raw_duration[0]; + data[3] = raw_duration[1]; + data[4] = raw_duration[2]; + data[5] = raw_duration[3]; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Same as [`wait`], but delays handling for the maximum number of blocks that /// can be paid for and doesn't exceed the given `duration`. pub fn wait_up_to(duration: u32) -> ! { - unsafe { gsys::gr_wait_up_to(duration) } + let mut data = [0u8; 8]; + data[0] = 4; + let raw_duration = duration.to_le_bytes(); + data[2] = raw_duration[0]; + data[3] = raw_duration[1]; + data[4] = raw_duration[2]; + data[5] = raw_duration[3]; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Resume previously paused message handling. diff --git a/gcore/src/utils.rs b/gcore/src/utils.rs index 14e9b05cfa6..1bfc16d00cf 100644 --- a/gcore/src/utils.rs +++ b/gcore/src/utils.rs @@ -57,7 +57,17 @@ pub mod ext { /// } /// ``` pub fn panic(data: &str) -> ! { - unsafe { gsys::gr_panic(data.as_ptr(), data.len() as u32) } + let mut data = [0u8; 8]; + data[0] = 5; + let ptr = (data.as_ptr() as u32).to_le_bytes(); + data[2] = ptr[0]; + data[3] = ptr[1]; + data[4] = ptr[2]; + data[5] = ptr[3]; + let len = (data.len() as u16).to_le_bytes(); + data[6] = len[0]; + data[7] = len[1]; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Out of memory panic @@ -90,6 +100,8 @@ pub mod ext { /// } /// ``` pub fn oom_panic() -> ! { - unsafe { gsys::gr_oom_panic() } + let mut data = [0u8; 8]; + data[0] = 6; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } } diff --git a/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs b/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs index 6a9009cda36..08431ddec8c 100644 --- a/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs +++ b/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs @@ -247,15 +247,9 @@ where SyscallName::BlockTimestamp => check_gr_block_timestamp::(), SyscallName::GasAvailable => check_gr_gas_available::(), SyscallName::ValueAvailable => check_gr_value_available::(), - SyscallName::Exit - | SyscallName::Leave - | SyscallName::Wait - | SyscallName::WaitFor - | SyscallName::WaitUpTo + SyscallName::UserBreak | SyscallName::Wake - | SyscallName::Debug - | SyscallName::Panic - | SyscallName::OomPanic => {/* tests here aren't required, read module docs for more info */}, + | SyscallName::Debug => {/* tests here aren't required, read module docs for more info */}, SyscallName::Alloc | SyscallName::Free | SyscallName::FreeRange => check_mem::(), diff --git a/utils/wasm-instrument/src/syscalls.rs b/utils/wasm-instrument/src/syscalls.rs index 8d5738ebe98..f0418384247 100644 --- a/utils/wasm-instrument/src/syscalls.rs +++ b/utils/wasm-instrument/src/syscalls.rs @@ -497,7 +497,7 @@ impl SyscallName { Ptr::Hash(HashType::SubjectId).into(), Ptr::MutBlockNumberWithHash(HashType::SubjectId).into(), ]), - Self::UserBreak => SyscallSignature::gr_infallible([ValueType::I64.into()]), + Self::UserBreak => SyscallSignature::gr_infallible([Data]), Self::SystemBreak => unimplemented!("Unsupported syscall signature for system_break"), } } @@ -564,7 +564,7 @@ impl TryFrom for UserBreakKind { 4 => Ok(UserBreakKind::WaitUpTo), 5 => Ok(UserBreakKind::Panic), 6 => Ok(UserBreakKind::OomPanic), - _ => Err(()) + _ => Err(()), } } } @@ -578,7 +578,7 @@ impl From for u8 { UserBreakKind::WaitFor => 3, UserBreakKind::WaitUpTo => 4, UserBreakKind::Panic => 5, - UserBreakKind::OomPanic => 6 + UserBreakKind::OomPanic => 6, } } } @@ -606,6 +606,7 @@ pub enum RegularParamType { Free, // i32 page number to free FreeUpperBound, // i32 free upper bound for use with free_range Version, // i32 version number of exec settings + Data, // i64 data for user_break } /// Hash type. @@ -629,7 +630,7 @@ impl From for ValueType { ParamType::Regular(regular_ptr) => match regular_ptr { Length | Pointer(_) | Offset | DurationBlockNumber | DelayBlockNumber | Handler | Alloc | Free | FreeUpperBound | Version => ValueType::I32, - Gas => ValueType::I64, + Gas | Data => ValueType::I64, }, ParamType::Error(_) => ValueType::I32, }