Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(core): Add gr_user_break syscall to replace all non returning syscalls. #3662

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions core-backend/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,16 +190,12 @@ where
builder.add_func(CreateProgram, wrap_syscall!(create_program));
builder.add_func(CreateProgramWGas, wrap_syscall!(create_program_wgas));
builder.add_func(Debug, wrap_syscall!(debug));
builder.add_func(Panic, wrap_syscall!(panic));
builder.add_func(OomPanic, wrap_syscall!(oom_panic));
builder.add_func(Exit, wrap_syscall!(exit));
builder.add_func(ReplyCode, wrap_syscall!(reply_code));
builder.add_func(SignalCode, wrap_syscall!(signal_code));
builder.add_func(ReserveGas, wrap_syscall!(reserve_gas));
builder.add_func(ReplyDeposit, wrap_syscall!(reply_deposit));
builder.add_func(UnreserveGas, wrap_syscall!(unreserve_gas));
builder.add_func(GasAvailable, wrap_syscall!(gas_available));
builder.add_func(Leave, wrap_syscall!(leave));
builder.add_func(MessageId, wrap_syscall!(message_id));
builder.add_func(PayProgramRent, wrap_syscall!(pay_program_rent));
builder.add_func(ProgramId, wrap_syscall!(program_id));
Expand Down Expand Up @@ -228,16 +224,14 @@ where
builder.add_func(Source, wrap_syscall!(source));
builder.add_func(Value, wrap_syscall!(value));
builder.add_func(ValueAvailable, wrap_syscall!(value_available));
builder.add_func(Wait, wrap_syscall!(wait));
builder.add_func(WaitFor, wrap_syscall!(wait_for));
builder.add_func(WaitUpTo, wrap_syscall!(wait_up_to));
builder.add_func(Wake, wrap_syscall!(wake));
builder.add_func(SystemReserveGas, wrap_syscall!(system_reserve_gas));
builder.add_func(ReservationReply, wrap_syscall!(reservation_reply));
builder.add_func(ReservationReplyCommit, wrap_syscall!(reservation_reply_commit));
builder.add_func(ReservationSend, wrap_syscall!(reservation_send));
builder.add_func(ReservationSendCommit, wrap_syscall!(reservation_send_commit));
builder.add_func(SystemBreak, wrap_syscall!(system_break));
builder.add_func(UserBreak, wrap_syscall!(user_break));

builder.add_func(Alloc, wrap_syscall!(alloc));
builder.add_func(Free, wrap_syscall!(free));
Expand Down
105 changes: 64 additions & 41 deletions core-backend/src/funcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +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::SystemBreakCode;
use gear_wasm_instrument::{syscalls::UserBreakKind, SystemBreakCode};
use gsys::{
BlockNumberWithHash, ErrorBytes, ErrorWithBlockNumberAndValue, ErrorWithGas, ErrorWithHandle,
ErrorWithHash, ErrorWithReplyCode, ErrorWithSignalCode, ErrorWithTwoHashes, Gas, Hash,
Expand Down Expand Up @@ -592,12 +592,13 @@ where
})
}

pub fn exit(inheritor_id_ptr: u32) -> impl Syscall<Ext> {
InfallibleSyscall::new(RuntimeCosts::Exit, move |ctx: &mut CallerWrap<Ext>| {
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<Ext>,
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<Ext> {
Expand Down Expand Up @@ -1032,21 +1033,21 @@ where
)
}

pub fn panic(data_ptr: u32, data_len: u32) -> impl Syscall<Ext> {
InfallibleSyscall::new(RuntimeCosts::Null, move |ctx: &mut CallerWrap<Ext>| {
let read_data = ctx.manager.register_read(data_ptr, data_len);
let data = ctx.read(read_data).unwrap_or_default();
pub fn panic(
ctx: &mut CallerWrap<Ext>,
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<Ext> {
InfallibleSyscall::new(RuntimeCosts::Null, |_ctx: &mut CallerWrap<Ext>| {
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<Ext> {
Expand Down Expand Up @@ -1183,35 +1184,33 @@ where
)
}

pub fn leave() -> impl Syscall<Ext> {
InfallibleSyscall::new(RuntimeCosts::Leave, move |_ctx: &mut CallerWrap<Ext>| {
Err(ActorTerminationReason::Leave.into())
})
pub fn leave() -> Result<(), UndefinedTerminationReason> {
Err(ActorTerminationReason::Leave.into())
}

pub fn wait() -> impl Syscall<Ext> {
InfallibleSyscall::new(RuntimeCosts::Wait, move |ctx: &mut CallerWrap<Ext>| {
ctx.ext_mut().wait()?;
Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into())
})
pub fn wait(ctx: &mut CallerWrap<Ext>) -> Result<(), UndefinedTerminationReason> {
ctx.ext_mut().wait()?;
Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into())
}

pub fn wait_for(duration: u32) -> impl Syscall<Ext> {
InfallibleSyscall::new(RuntimeCosts::WaitFor, move |ctx: &mut CallerWrap<Ext>| {
ctx.ext_mut().wait_for(duration)?;
Err(ActorTerminationReason::Wait(Some(duration), MessageWaitedType::WaitFor).into())
})
pub fn wait_for(
ctx: &mut CallerWrap<Ext>,
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<Ext> {
InfallibleSyscall::new(RuntimeCosts::WaitUpTo, move |ctx: &mut CallerWrap<Ext>| {
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<Ext>,
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<Ext> {
Expand Down Expand Up @@ -1350,4 +1349,28 @@ where
Err(HostError)
})
}

pub fn user_break(data: u64) -> impl Syscall<Ext> {
let raw_data = data.to_le_bytes();
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]]);
let cost = break_kind.map(Into::into).unwrap_or(RuntimeCosts::Null);
InfallibleSyscall::new(cost, move |ctx: &mut CallerWrap<Ext>| match break_kind {
Ok(UserBreakKind::Exit) => FuncsHandler::exit(ctx, data32),
Ok(UserBreakKind::Leave) => FuncsHandler::<Ext>::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(ctx, data32, data16)
}
Ok(UserBreakKind::OomPanic) => FuncsHandler::<Ext>::oom_panic(),
_ => Err(ActorTerminationReason::Trap(TrapExplanation::Panic(
"Unknown user_break syscall codec".to_string().into(),
))
.into()),
})
}
}
14 changes: 14 additions & 0 deletions core/src/costs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -549,3 +550,16 @@ impl RuntimeCosts {
RuntimeToken { weight }
}
}

impl From<UserBreakKind> 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,
}
}
}
34 changes: 29 additions & 5 deletions gcore/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down
16 changes: 14 additions & 2 deletions gcore/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)) }
}
}
45 changes: 9 additions & 36 deletions gsys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ pub type SignalCode = u32;
/// Represents value type.
pub type Value = u128;

/// Represents data for `gr_user_break`
pub type Data = u64;

/// Represents type defining concatenated block number with hash. 36 bytes.
#[repr(C, packed)]
#[derive(Default, Debug)]
Expand Down Expand Up @@ -489,18 +492,6 @@ extern "C" {
/// - `len`: `u32` length of the payload buffer.
pub fn gr_debug(payload: *const SizedBufferStart, len: Length);

/// Infallible `gr_panic` control syscall.
///
/// Stops the execution.
///
/// Arguments type:
/// - `payload`: `const ptr` for the begging of the payload buffer.
/// - `len`: `u32` length of the payload buffer.
pub fn gr_panic(payload: *const SizedBufferStart, len: Length) -> !;

/// Infallible `gr_oom_panic` control syscall.
pub fn gr_oom_panic() -> !;

/// Fallible `gr_reply_code` get syscall.
///
/// Arguments type:
Expand All @@ -513,21 +504,12 @@ extern "C" {
/// - `err_code`: `mut ptr` for concatenated error code and signal code.
pub fn gr_signal_code(err_code: *mut ErrorWithSignalCode);

/// Infallible `gr_exit` control syscall.
///
/// Arguments type:
/// - `inheritor_id`: `const ptr` for program id.
pub fn gr_exit(inheritor_id: *const Hash) -> !;

/// Infallible `gr_gas_available` get syscall.
///
/// Arguments type:
/// - `gas`: `mut ptr` for `u64`.
pub fn gr_gas_available(gas: *mut Gas);

/// Infallible `gr_leave` control syscall.
pub fn gr_leave() -> !;

/// Infallible `gr_message_id` get syscall.
///
/// Arguments type:
Expand Down Expand Up @@ -907,26 +889,17 @@ extern "C" {
/// - `value`: `mut ptr` for incoming value of the message.
pub fn gr_value(value: *mut Value);

/// Infallible `gr_wait_for` control syscall.
///
/// Arguments type:
/// - `duration`: `u32` defining amount of blocks to wait.
pub fn gr_wait_for(duration: BlockNumber) -> !;

/// Infallible `gr_wait_up_to` control syscall.
///
/// Arguments type:
/// - `duration`: `u32` defining amount of blocks to wait.
pub fn gr_wait_up_to(duration: BlockNumber) -> !;

/// Infallible `gr_wait` control syscall.
pub fn gr_wait() -> !;

/// Fallible `gr_wake` control syscall.
///
/// Arguments type:
/// - `message_id`: `const ptr` for message id.
/// - `delay`: `u32` amount of blocks to delay.
/// - `err_mid`: `mut ptr` for error code.
pub fn gr_wake(message_id: *const Hash, delay: BlockNumber, err: *mut ErrorCode);

/// Infallible `gr_user_break` control syscall.
///
/// Arguments type:
/// - `data`: `u64` which contains syscall data as le bytes.
pub fn gr_user_break(data: Data) -> !;
}
Loading
Loading