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

Add type parameter to Kernel::send specifying type for receiving kernel #1780

Merged
merged 1 commit into from
Jun 21, 2023
Merged
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
133 changes: 64 additions & 69 deletions fvm/src/kernel/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,70 @@ where
fn machine(&self) -> &<Self::CallManager as CallManager>::Machine {
self.call_manager.machine()
}

fn send<K: Kernel<CallManager = C>>(
&mut self,
recipient: &Address,
method: MethodNum,
params_id: BlockId,
value: &TokenAmount,
gas_limit: Option<Gas>,
flags: SendFlags,
) -> Result<SendResult> {
let from = self.actor_id;
let read_only = self.read_only || flags.read_only();

if read_only && !value.is_zero() {
return Err(syscall_error!(ReadOnly; "cannot transfer value when read-only").into());
}

// Load parameters.
let params = if params_id == NO_DATA_BLOCK_ID {
None
} else {
Some(self.blocks.get(params_id)?.clone())
};

// Make sure we can actually store the return block.
if self.blocks.is_full() {
return Err(syscall_error!(LimitExceeded; "cannot store return block").into());
}

// Send.
let result = self.call_manager.with_transaction(|cm| {
cm.send::<K>(
from, *recipient, method, params, value, gas_limit, read_only,
)
})?;

// Store result and return.
Ok(match result {
InvocationResult {
exit_code,
value: Some(blk),
} => {
let block_stat = blk.stat();
let block_id = self
.blocks
.put(blk)
.or_fatal()
.context("failed to store a valid return value")?;
SendResult {
block_id,
block_stat,
exit_code,
}
}
InvocationResult {
exit_code,
value: None,
} => SendResult {
block_id: NO_DATA_BLOCK_ID,
block_stat: BlockStat { codec: 0, size: 0 },
exit_code,
},
})
}
}

impl<C> DefaultKernel<C>
Expand Down Expand Up @@ -358,75 +422,6 @@ where
}
}

impl<C> SendOps for DefaultKernel<C>
where
C: CallManager,
{
fn send(
&mut self,
recipient: &Address,
method: MethodNum,
params_id: BlockId,
value: &TokenAmount,
gas_limit: Option<Gas>,
flags: SendFlags,
) -> Result<SendResult> {
let from = self.actor_id;
let read_only = self.read_only || flags.read_only();

if read_only && !value.is_zero() {
return Err(syscall_error!(ReadOnly; "cannot transfer value when read-only").into());
}

// Load parameters.
let params = if params_id == NO_DATA_BLOCK_ID {
None
} else {
Some(self.blocks.get(params_id)?.clone())
};

// Make sure we can actually store the return block.
if self.blocks.is_full() {
return Err(syscall_error!(LimitExceeded; "cannot store return block").into());
}

// Send.
let result = self.call_manager.with_transaction(|cm| {
cm.send::<Self>(
from, *recipient, method, params, value, gas_limit, read_only,
)
})?;

// Store result and return.
Ok(match result {
InvocationResult {
exit_code,
value: Some(blk),
} => {
let block_stat = blk.stat();
let block_id = self
.blocks
.put(blk)
.or_fatal()
.context("failed to store a valid return value")?;
SendResult {
block_id,
block_stat,
exit_code,
}
}
InvocationResult {
exit_code,
value: None,
} => SendResult {
block_id: NO_DATA_BLOCK_ID,
block_stat: BlockStat { codec: 0, size: 0 },
exit_code,
},
})
}
}

impl<C> CircSupplyOps for DefaultKernel<C>
where
C: CallManager,
Expand Down
31 changes: 17 additions & 14 deletions fvm/src/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ pub trait Kernel:
+ NetworkOps
+ RandomnessOps
+ SelfOps
+ SendOps
+ LimiterOps
+ 'static
{
Expand Down Expand Up @@ -97,6 +96,23 @@ pub trait Kernel:

/// The kernel's underlying "machine".
fn machine(&self) -> &<Self::CallManager as CallManager>::Machine;

/// Sends a message to another actor.
/// The method type parameter K is the type of the kernel to instantiate for
/// the receiving actor. This is necessary to support wrapping a kernel, so the outer
/// kernel can specify its Self as the receiver's kernel type, rather than the wrapped
/// kernel specifying its Self.
/// This method is part of the Kernel trait so it can refer to the Self::CallManager
/// associated type necessary to constrain K.
fn send<K: Kernel<CallManager = Self::CallManager>>(
&mut self,
recipient: &Address,
method: u64,
params: BlockId,
value: &TokenAmount,
gas_limit: Option<Gas>,
flags: SendFlags,
) -> Result<SendResult>;
}

/// Network-related operations.
Expand Down Expand Up @@ -209,19 +225,6 @@ pub trait ActorOps {
fn balance_of(&self, actor_id: ActorID) -> Result<TokenAmount>;
}

/// Operations to send messages to other actors.
pub trait SendOps {
fn send(
&mut self,
recipient: &Address,
method: u64,
params: BlockId,
value: &TokenAmount,
gas_limit: Option<Gas>,
flags: SendFlags,
) -> Result<SendResult>;
}

/// Operations to query the circulating supply.
pub trait CircSupplyOps {
/// Returns the total token supply in circulation at the beginning of the current epoch.
Expand Down
6 changes: 3 additions & 3 deletions fvm/src/syscalls/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use crate::Kernel;
/// Send a message to another actor. The result is placed as a CBOR-encoded
/// receipt in the block registry, and can be retrieved by the returned BlockId.
#[allow(clippy::too_many_arguments)]
pub fn send(
context: Context<'_, impl Kernel>,
pub fn send<K: Kernel>(
context: Context<'_, K>,
recipient_off: u32,
recipient_len: u32,
method: u64,
Expand Down Expand Up @@ -43,7 +43,7 @@ pub fn send(
exit_code,
} = context
.kernel
.send(&recipient, method, params_id, &value, gas_limit, flags)?;
.send::<K>(&recipient, method, params_id, &value, gas_limit, flags)?;

Ok(sys::out::send::Send {
exit_code: exit_code.value(),
Expand Down
Loading