Skip to content

Commit dc4e730

Browse files
committed
Support entrypoints with different number of params
1 parent 2d0b51e commit dc4e730

File tree

6 files changed

+103
-45
lines changed

6 files changed

+103
-45
lines changed

fvm/src/call_manager/default.rs

+80-40
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use fvm_shared::econ::TokenAmount;
1212
use fvm_shared::error::{ErrorNumber, ExitCode};
1313
use fvm_shared::event::StampedEvent;
1414
use fvm_shared::sys::BlockId;
15+
use fvm_shared::upgrade::UpgradeInfo;
1516
use fvm_shared::{ActorID, MethodNum, METHOD_SEND};
1617
use num_traits::Zero;
1718

@@ -417,8 +418,8 @@ where
417418
.get_actor(actor_id)?
418419
.ok_or_else(|| syscall_error!(NotFound; "actor not found: {}", actor_id))?;
419420

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

@@ -434,11 +435,11 @@ where
434435
),
435436
);
436437

437-
// run the upgrade endpoint
438+
// run the upgrade entrypoint
438439
let result = self.send::<K>(
439440
actor_id,
440441
Address::new_id(actor_id),
441-
Entrypoint::Upgrade,
442+
Entrypoint::Upgrade(UpgradeInfo { old_code_cid: code }),
442443
params,
443444
&TokenAmount::zero(),
444445
None,
@@ -735,6 +736,11 @@ where
735736
NO_DATA_BLOCK_ID
736737
};
737738

739+
// additional_params takes care of adding entrypoint specific params to the block
740+
// registry and passing them to wasmtime
741+
let mut additional_params = EntrypointParams::new(entrypoint);
742+
additional_params.maybe_put_registry(&mut block_registry)?;
743+
738744
// Increment invocation count
739745
self.invocation_count += 1;
740746

@@ -782,20 +788,21 @@ where
782788

783789
store.data_mut().memory = memory;
784790

785-
// Lookup the invoke method.
786-
let invoke: wasmtime::TypedFunc<(u32,), u32> = instance
787-
.get_typed_func(&mut store, entrypoint.func_name())
788-
// All actors will have an invoke method.
789-
.map_err(Abort::Fatal)?;
791+
let func = match instance.get_func(&mut store, entrypoint.func_name()) {
792+
Some(func) => func,
793+
None => {
794+
return Err(Abort::EntrypointNotFound);
795+
}
796+
};
797+
798+
let mut params = vec![wasmtime::Val::I32(params_id as i32)];
799+
params.extend_from_slice(additional_params.params().as_slice());
790800

791801
// Set the available gas.
792802
update_gas_available(&mut store)?;
793803

794-
// Invoke it.
795-
let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
796-
invoke.call(&mut store, (params_id,))
797-
}))
798-
.map_err(|panic| Abort::Fatal(anyhow!("panic within actor: {:?}", panic)))?;
804+
let mut out = [wasmtime::Val::I32(0)];
805+
func.call(&mut store, params.as_slice(), &mut out)?;
799806

800807
// Charge for any remaining uncharged execution gas, returning an error if we run
801808
// out.
@@ -805,35 +812,26 @@ where
805812
// detected it and returned OutOfGas above. Any other invocation failure is returned
806813
// here as an Abort
807814

808-
Ok(res?)
815+
Ok(out[0].unwrap_i32() as u32)
809816
})();
810817

811818
let invocation_data = store.into_data();
812819
let last_error = invocation_data.last_error;
813820
let (mut cm, block_registry) = invocation_data.kernel.into_inner();
814821

815-
// Resolve the return block's ID into an actual block, converting to an abort if it
816-
// doesn't exist.
817-
let result = result.and_then(|ret_id| {
818-
Ok(if ret_id == NO_DATA_BLOCK_ID {
819-
None
820-
} else {
821-
Some(block_registry.get(ret_id).map_err(|_| {
822-
Abort::Exit(
823-
ExitCode::SYS_MISSING_RETURN,
824-
String::from("returned block does not exist"),
825-
NO_DATA_BLOCK_ID,
826-
)
827-
})?)
828-
})
829-
});
830-
831822
// Process the result, updating the backtrace if necessary.
832823
let mut ret = match result {
833-
Ok(ret) => Ok(InvocationResult {
824+
Ok(NO_DATA_BLOCK_ID) => Ok(InvocationResult {
834825
exit_code: ExitCode::OK,
835-
value: ret.cloned(),
826+
value: None,
836827
}),
828+
Ok(block_id) => match block_registry.get(block_id) {
829+
Ok(blk) => Ok(InvocationResult {
830+
exit_code: ExitCode::OK,
831+
value: Some(blk.clone()),
832+
}),
833+
Err(e) => Err(ExecutionError::Fatal(anyhow!(e))),
834+
},
837835
Err(abort) => {
838836
let (code, message, res) = match abort {
839837
Abort::Exit(code, message, NO_DATA_BLOCK_ID) => (
@@ -845,11 +843,6 @@ where
845843
}),
846844
),
847845
Abort::Exit(code, message, blk_id) => match block_registry.get(blk_id) {
848-
Err(e) => (
849-
ExitCode::SYS_MISSING_RETURN,
850-
"error getting exit data block".to_owned(),
851-
Err(ExecutionError::Fatal(anyhow!(e))),
852-
),
853846
Ok(blk) => (
854847
code,
855848
message,
@@ -858,7 +851,20 @@ where
858851
value: Some(blk.clone()),
859852
}),
860853
),
854+
Err(e) => (
855+
ExitCode::SYS_MISSING_RETURN,
856+
"error getting exit data block".to_owned(),
857+
Err(ExecutionError::Fatal(anyhow!(e))),
858+
),
861859
},
860+
Abort::EntrypointNotFound => (
861+
ExitCode::USR_FORBIDDEN,
862+
"entrypoint not found".to_owned(),
863+
Err(ExecutionError::Syscall(SyscallError::new(
864+
ErrorNumber::Forbidden,
865+
"entrypoint not found",
866+
))),
867+
),
862868
Abort::OutOfGas => (
863869
ExitCode::SYS_OUT_OF_GAS,
864870
"out of gas".to_owned(),
@@ -1033,14 +1039,48 @@ impl Entrypoint {
10331039
fn method_num(&self) -> MethodNum {
10341040
match self {
10351041
Entrypoint::Invoke(num) => *num,
1036-
Entrypoint::Upgrade => 191919,
1042+
Entrypoint::Upgrade(_) => fvm_shared::METHOD_UPGRADE,
10371043
}
10381044
}
10391045

10401046
fn func_name(&self) -> &'static str {
10411047
match self {
10421048
Entrypoint::Invoke(_) => "invoke",
1043-
Entrypoint::Upgrade => "upgrade",
1049+
Entrypoint::Upgrade(_) => "upgrade",
1050+
}
1051+
}
1052+
}
1053+
1054+
// EntrypointParams is a helper struct to init the registry with the entrypoint specific
1055+
// parameters and then forward them to wasmtime
1056+
struct EntrypointParams {
1057+
entrypoint: Entrypoint,
1058+
params: Vec<wasmtime::Val>,
1059+
}
1060+
1061+
impl EntrypointParams {
1062+
fn new(entrypoint: Entrypoint) -> Self {
1063+
Self {
1064+
entrypoint,
1065+
params: Vec::new(),
10441066
}
10451067
}
1068+
1069+
fn maybe_put_registry(&mut self, br: &mut BlockRegistry) -> Result<()> {
1070+
match self.entrypoint {
1071+
Entrypoint::Invoke(_) => Ok(()),
1072+
Entrypoint::Upgrade(ui) => {
1073+
let ui_params = to_vec(&ui).map_err(
1074+
|e| syscall_error!(IllegalArgument; "failed to serialize upgrade params: {}", e),
1075+
)?;
1076+
let block_id = br.put(Block::new(CBOR, ui_params))?;
1077+
self.params.push(wasmtime::Val::I32(block_id as i32));
1078+
Ok(())
1079+
}
1080+
}
1081+
}
1082+
1083+
fn params(&self) -> &Vec<wasmtime::Val> {
1084+
&self.params
1085+
}
10461086
}

fvm/src/call_manager/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use cid::Cid;
44
use fvm_shared::address::Address;
55
use fvm_shared::econ::TokenAmount;
66
use fvm_shared::error::ExitCode;
7+
use fvm_shared::upgrade::UpgradeInfo;
78
use fvm_shared::{ActorID, MethodNum};
89

910
use crate::engine::Engine;
@@ -210,14 +211,14 @@ pub struct FinishRet {
210211
#[derive(Clone, Debug, Copy)]
211212
pub enum Entrypoint {
212213
Invoke(MethodNum),
213-
Upgrade,
214+
Upgrade(UpgradeInfo),
214215
}
215216

216217
impl std::fmt::Display for Entrypoint {
217218
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218219
match self {
219220
Entrypoint::Invoke(method) => write!(f, "invoke({})", method),
220-
Entrypoint::Upgrade => write!(f, "upgrade"),
221+
Entrypoint::Upgrade(_) => write!(f, "upgrade"),
221222
}
222223
}
223224
}

fvm/src/syscalls/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ pub enum Abort {
1717
/// The actor ran out of gas.
1818
#[error("out of gas")]
1919
OutOfGas,
20+
/// The actor did not export the endpoint that was called.
21+
#[error("entrypoint not found")]
22+
EntrypointNotFound,
2023
/// The system failed with a fatal error.
2124
#[error("fatal error: {0}")]
2225
Fatal(anyhow::Error),

shared/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ pub type MethodNum = u64;
109109
pub const METHOD_SEND: MethodNum = 0;
110110
/// Base actor constructor method.
111111
pub const METHOD_CONSTRUCTOR: MethodNum = 1;
112+
/// Upgrade actor method.
113+
pub const METHOD_UPGRADE: MethodNum = 932083;
112114

113115
/// The outcome of a `Send`, covering its ExitCode and optional return data
114116
#[derive(Debug, PartialEq, Eq, Clone)]

shared/src/upgrade/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use cid::Cid;
44
use fvm_ipld_encoding::tuple::*;
55

6-
#[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
6+
#[derive(Clone, Debug, Copy, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)]
77
pub struct UpgradeInfo {
88
// the old code cid we are upgrading from
99
pub old_code_cid: Cid,

testing/test_actors/actors/fil-upgrade-actor/src/actor.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use fvm_ipld_encoding::ipld_block::IpldBlock;
44
use fvm_ipld_encoding::{to_vec, CBOR};
55
use fvm_sdk as sdk;
66
use fvm_shared::address::Address;
7+
use fvm_shared::upgrade::UpgradeInfo;
78
use serde_tuple::*;
89
#[derive(Serialize_tuple, Deserialize_tuple, PartialEq, Eq, Clone, Debug)]
910
struct SomeStruct {
@@ -13,13 +14,24 @@ struct SomeStruct {
1314
const UPGRADE_FAILED_EXIT_CODE: u32 = 19;
1415

1516
#[no_mangle]
16-
pub fn upgrade(params_id: u32) -> u32 {
17+
pub fn upgrade(params_id: u32, upgrade_info_id: u32) -> u32 {
1718
sdk::initialize();
1819

1920
let params = sdk::message::params_raw(params_id).unwrap().unwrap();
21+
let ui_params = sdk::message::params_raw(upgrade_info_id).unwrap().unwrap();
22+
2023
assert_eq!(params.codec, fvm_ipld_encoding::CBOR);
24+
assert_eq!(ui_params.codec, fvm_ipld_encoding::CBOR);
25+
26+
let p = params.deserialize::<SomeStruct>().unwrap();
27+
let ui = ui_params.deserialize::<UpgradeInfo>().unwrap();
28+
29+
sdk::debug::log(format!(
30+
"[upgrade] value: {}, old_code_cid: {}",
31+
p.value, ui.old_code_cid
32+
));
2133

22-
match params.deserialize::<SomeStruct>().unwrap().value {
34+
match p.value {
2335
1 => {
2436
let block_id = sdk::ipld::put_block(CBOR, &to_vec(&666).unwrap()).unwrap();
2537
sdk::debug::log(format!(

0 commit comments

Comments
 (0)