Skip to content

Commit

Permalink
Move upgrade logic to kernel
Browse files Browse the repository at this point in the history
  • Loading branch information
fridrik01 committed Oct 3, 2023
1 parent b341d4c commit 0c5ed7b
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 93 deletions.
60 changes: 1 addition & 59 deletions fvm/src/call_manager/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use fvm_shared::econ::TokenAmount;
use fvm_shared::error::{ErrorNumber, ExitCode};
use fvm_shared::event::StampedEvent;
use fvm_shared::sys::BlockId;
use fvm_shared::upgrade::UpgradeInfo;
use fvm_shared::{ActorID, MethodNum, METHOD_SEND};
use num_traits::Zero;

Expand Down Expand Up @@ -167,7 +166,7 @@ where
&mut self.limits
}

fn send<K>(
fn call_actor<K>(
&mut self,
from: ActorID,
to: Address,
Expand Down Expand Up @@ -405,63 +404,6 @@ where
Ok(())
}

fn upgrade_actor<K: Kernel<CallManager = Self>>(
&mut self,
caller: ActorID,
actor_id: ActorID,
new_code_cid: Cid,
params: Option<Block>,
) -> Result<InvocationResult> {
let origin = self.origin;

let state = self
.state_tree_mut()
.get_actor(actor_id)?
.ok_or_else(|| syscall_error!(NotFound; "actor not found: {}", actor_id))?;

// store the code cid of the calling actor before running the upgrade entrypoint
// in case it was changed (which could happen if the target upgrade entrypoint
// sent a message to this actor which in turn called upgrade)
let code = state.code;

// update the code cid of the actor to new_code_cid
self.state_tree_mut().set_actor(
origin,
ActorState::new(
new_code_cid,
state.state,
state.balance,
state.sequence,
None,
),
);

// run the upgrade entrypoint
let result = self.send::<K>(
caller,
Address::new_id(actor_id),
Entrypoint::Upgrade(UpgradeInfo { old_code_cid: code }),
params,
&TokenAmount::zero(),
None,
false,
)?;

if result.exit_code == ExitCode::OK {
// after running the upgrade, our code cid must not have changed
let code_after_upgrade = self
.state_tree_mut()
.get_actor(actor_id)?
.ok_or_else(|| syscall_error!(NotFound; "actor not found: {}", actor_id))?
.code;
if code != code_after_upgrade {
return Err(syscall_error!(Forbidden; "re-entrant upgrade detected").into());
}
}

Ok(result)
}

fn append_event(&mut self, evt: StampedEvent) {
self.events.append_event(evt)
}
Expand Down
12 changes: 1 addition & 11 deletions fvm/src/call_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub trait CallManager: 'static {
/// Send a message. The type parameter `K` specifies the the _kernel_ on top of which the target
/// actor should execute.
#[allow(clippy::too_many_arguments)]
fn send<K: Kernel<CallManager = Self>>(
fn call_actor<K: Kernel<CallManager = Self>>(
&mut self,
from: ActorID,
to: Address,
Expand Down Expand Up @@ -118,16 +118,6 @@ pub trait CallManager: 'static {
delegated_address: Option<Address>,
) -> Result<()>;

fn upgrade_actor<K>(
&mut self,
caller: ActorID,
actor_id: ActorID,
new_code_cid: Cid,
params: Option<kernel::Block>,
) -> Result<InvocationResult>
where
K: Kernel<CallManager = Self>;

/// Resolve an address into an actor ID, charging gas as appropriate.
fn resolve_address(&self, address: &Address) -> Result<Option<ActorID>>;

Expand Down
2 changes: 1 addition & 1 deletion fvm/src/executor/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ where
let result = cm.with_transaction(|cm| {
// Invoke the message. We charge for the return value internally if the call-stack depth
// is 1.
cm.send::<K>(
cm.call_actor::<K>(
sender_id,
msg.to,
Entrypoint::Invoke(msg.method_num),
Expand Down
52 changes: 49 additions & 3 deletions fvm/src/kernel/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use fvm_shared::event::{ActorEvent, Entry, Flags};
use fvm_shared::piece::{zero_piece_commitment, PaddedPieceSize};
use fvm_shared::sector::{RegisteredPoStProof, SectorInfo};
use fvm_shared::sys::out::vm::ContextFlags;
use fvm_shared::upgrade::UpgradeInfo;
use fvm_shared::{commcid, ActorID};
use lazy_static::lazy_static;
use multihash::MultihashDigest;
Expand Down Expand Up @@ -139,7 +140,7 @@ where

// Send.
let result = self.call_manager.with_transaction(|cm| {
cm.send::<K>(
cm.call_actor::<K>(
from,
*recipient,
Entrypoint::Invoke(method),
Expand Down Expand Up @@ -873,7 +874,7 @@ where
.create_actor(code_id, actor_id, delegated_address)
}

fn upgrade_actor(&mut self, new_code_cid: Cid, params_id: BlockId) -> Result<u32> {
fn upgrade_actor<K: Kernel>(&mut self, new_code_cid: Cid, params_id: BlockId) -> Result<u32> {
if self.read_only {
return Err(
syscall_error!(ReadOnly, "upgrade_actor cannot be called while read-only").into(),
Expand All @@ -888,7 +889,52 @@ where
};

let result = self.call_manager.with_transaction(|cm| {
cm.upgrade_actor::<Self>(self.caller, self.actor_id, new_code_cid, params)
let origin = cm.origin();

let state = cm
.get_actor(self.actor_id)?
.ok_or_else(|| syscall_error!(NotFound; "actor not found"))?;

// store the code cid of the calling actor before running the upgrade entrypoint
// in case it was changed (which could happen if the target upgrade entrypoint
// sent a message to this actor which in turn called upgrade)
let code = state.code;

// update the code cid of the actor to new_code_cid
cm.set_actor(
origin,
ActorState::new(
new_code_cid,
state.state,
state.balance,
state.sequence,
None,
),
)?;

// run the upgrade entrypoint
let result = cm.call_actor::<Self>(
self.caller,
Address::new_id(self.actor_id),
Entrypoint::Upgrade(UpgradeInfo { old_code_cid: code }),
params,
&TokenAmount::from_whole(0),
None,
false,
)?;

if result.exit_code == ExitCode::OK {
// after running the upgrade, our code cid must not have changed
let code_after_upgrade = cm
.get_actor(self.actor_id)?
.ok_or_else(|| syscall_error!(NotFound; "actor not found"))?
.code;
if code != code_after_upgrade {
return Err(syscall_error!(Forbidden; "re-entrant upgrade detected").into());
}
}

Ok(result)
});

match result {
Expand Down
2 changes: 1 addition & 1 deletion fvm/src/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ pub trait ActorOps {
delegated_address: Option<Address>,
) -> Result<()>;

fn upgrade_actor(&mut self, new_code_cid: Cid, params_id: BlockId) -> Result<u32>;
fn upgrade_actor<K: Kernel>(&mut self, new_code_cid: Cid, params_id: BlockId) -> Result<u32>;

/// Installs actor code pointed by cid
#[cfg(feature = "m2-native")]
Expand Down
7 changes: 3 additions & 4 deletions fvm/src/syscalls/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,14 @@ pub fn create_actor(
context.kernel.create_actor(typ, actor_id, addr)
}

#[allow(dead_code)]
pub fn upgrade_actor(
context: Context<'_, impl Kernel>,
pub fn upgrade_actor<K: Kernel>(
context: Context<'_, K>,
new_code_cid_off: u32,
params_id: u32,
) -> Result<u32> {
let cid = context.memory.read_cid(new_code_cid_off)?;

context.kernel.upgrade_actor(cid, params_id)
context.kernel.upgrade_actor::<K>(cid, params_id)
}

pub fn get_builtin_actor_type(
Expand Down
15 changes: 1 addition & 14 deletions fvm/tests/dummy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ impl CallManager for DummyCallManager {
}
}

fn send<K: Kernel<CallManager = Self>>(
fn call_actor<K: Kernel<CallManager = Self>>(
&mut self,
_from: fvm_shared::ActorID,
_to: Address,
Expand Down Expand Up @@ -400,17 +400,4 @@ impl CallManager for DummyCallManager {
) -> fvm::kernel::Result<()> {
todo!()
}

fn upgrade_actor<K>(
&mut self,
_caller: ActorID,
_actor_id: ActorID,
_new_code_cid: Cid,
_params: Option<kernel::Block>,
) -> kernel::Result<InvocationResult>
where
K: Kernel<CallManager = Self>,
{
todo!()
}
}

0 comments on commit 0c5ed7b

Please sign in to comment.