-
Notifications
You must be signed in to change notification settings - Fork 84
/
Copy pathlib.rs
189 lines (155 loc) · 6.49 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright 2019-2022 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT
use cid::Cid;
use fil_actors_runtime::runtime::builtins::Type;
use fil_actors_runtime::runtime::{ActorCode, Runtime};
use fil_actors_runtime::{
actor_dispatch, actor_error, extract_send_result, ActorResult, ActorError, AsActorError,
EAM_ACTOR_ADDR, SYSTEM_ACTOR_ADDR,
};
use fvm_shared::address::Address;
use fvm_shared::error::ExitCode;
use fvm_shared::{ActorID, METHOD_CONSTRUCTOR};
use num_derive::FromPrimitive;
pub use self::state::State;
pub use self::types::*;
mod state;
pub mod testing;
mod types;
#[cfg(feature = "fil-actor")]
fil_actors_runtime::wasm_trampoline!(Actor);
/// Init actor methods available
#[derive(FromPrimitive)]
#[repr(u64)]
pub enum Method {
Constructor = METHOD_CONSTRUCTOR,
Exec = 2,
Exec4 = 3,
}
/// Init actor
pub struct Actor;
impl Actor {
/// Init actor constructor
pub fn constructor(rt: &impl Runtime, params: ConstructorParams) -> Result<(), ActorError> {
let sys_ref: &Address = &SYSTEM_ACTOR_ADDR;
rt.validate_immediate_caller_is(std::iter::once(sys_ref))?;
let state = State::new(rt.store(), params.network_name)?;
rt.create(&state)?;
Ok(())
}
/// Exec init actor
pub fn exec(rt: &impl Runtime, params: ExecParams) -> Result<ExecReturn, ActorError> {
rt.validate_immediate_caller_accept_any()?;
log::trace!("called exec; params.code_cid: {:?}", ¶ms.code_cid);
let caller_code =
rt.get_actor_code_cid(&rt.message().caller().id().unwrap()).ok_or_else(|| {
actor_error!(illegal_state, "no code for caller as {}", rt.message().caller())
})?;
log::trace!("caller code CID: {:?}", &caller_code);
if !can_exec(rt, &caller_code, ¶ms.code_cid) {
return Err(actor_error!(forbidden;
"called type {} cannot exec actor type {}",
&caller_code, ¶ms.code_cid
));
}
// Compute a re-org-stable address.
// This address exists for use by messages coming from outside the system, in order to
// stably address the newly created actor even if a chain re-org causes it to end up with
// a different ID.
let robust_address = rt.new_actor_address()?;
log::trace!("robust address: {:?}", &robust_address);
// Allocate an ID for this actor.
// Store mapping of actor addresses to the actor ID.
let (id_address, existing): (ActorID, bool) = rt.transaction(|s: &mut State, rt| {
s.map_addresses_to_id(rt.store(), &robust_address, None)
.context("failed to allocate ID address")
})?;
if existing {
// NOTE: this case should be impossible, but we check it anyways just in case something
// changes.
return Err(actor_error!(
forbidden,
"cannot exec over an existing actor {}",
id_address
));
}
// Create an empty actor
rt.create_actor(params.code_cid, id_address, None)?;
// Invoke constructor
extract_send_result(rt.send_simple(
&Address::new_id(id_address),
METHOD_CONSTRUCTOR,
params.constructor_params.into(),
rt.message().value_received(),
))
.context("constructor failed")?;
Ok(ExecReturn { id_address: Address::new_id(id_address), robust_address })
}
/// Exec4 init actor
pub fn exec4(rt: &impl Runtime, params: Exec4Params) -> Result<Exec4Return, ActorError> {
rt.validate_immediate_caller_is(std::iter::once(&EAM_ACTOR_ADDR))?;
// Compute the f4 address.
let caller_id = rt.message().caller().id().unwrap();
let delegated_address =
Address::new_delegated(caller_id, ¶ms.subaddress).map_err(|e| {
ActorError::illegal_argument(format!("invalid delegated address: {}", e))
})?;
log::trace!("delegated address: {:?}", &delegated_address);
// Compute a re-org-stable address.
// This address exists for use by messages coming from outside the system, in order to
// stably address the newly created actor even if a chain re-org causes it to end up with
// a different ID.
let robust_address = rt.new_actor_address()?;
log::trace!("robust address: {:?}", &robust_address);
// Allocate an ID for this actor.
// Store mapping of actor addresses to the actor ID.
let (id_address, existing): (ActorID, bool) = rt.transaction(|s: &mut State, rt| {
s.map_addresses_to_id(rt.store(), &robust_address, Some(&delegated_address))
.context("failed to map addresses to ID")
})?;
// If the f4 address was already assigned, make sure we're deploying over a placeholder and not
// some other existing actor (and make sure the target actor wasn't deleted either).
if existing {
let code_cid = rt
.get_actor_code_cid(&id_address)
.context_code(ExitCode::USR_FORBIDDEN, "cannot redeploy a deleted actor")?;
let placeholder_cid = rt.get_code_cid_for_type(Type::Placeholder);
if code_cid != placeholder_cid {
return Err(ActorError::forbidden(format!(
"cannot replace an existing non-placeholder actor with code: {code_cid}"
)));
}
}
// Create an empty actor
rt.create_actor(params.code_cid, id_address, Some(delegated_address))?;
// Invoke constructor
extract_send_result(rt.send_simple(
&Address::new_id(id_address),
METHOD_CONSTRUCTOR,
params.constructor_params.into(),
rt.message().value_received(),
))
.context("constructor failed")?;
Ok(Exec4Return { id_address: Address::new_id(id_address), robust_address })
}
}
impl ActorCode for Actor {
type Methods = Method;
fn name() -> &'static str {
"Init"
}
actor_dispatch! {
Constructor => constructor,
Exec => exec,
Exec4 => exec4,
}
}
fn can_exec(rt: &impl Runtime, caller: &Cid, exec: &Cid) -> bool {
rt.resolve_builtin_actor_type(exec)
.map(|typ| match typ {
Type::Multisig | Type::PaymentChannel => true,
Type::Miner if rt.resolve_builtin_actor_type(caller) == Some(Type::Power) => true,
_ => false,
})
.unwrap_or(false)
}