Skip to content

Commit ad6f4f6

Browse files
Stebalienshamb0
authored andcommitted
feat: basic f4 support (filecoin-project#684)
- Adds a create4 method to the init actor. - Adds embryo actor creation to the test vm.
1 parent e1bdaf3 commit ad6f4f6

File tree

12 files changed

+437
-65
lines changed

12 files changed

+437
-65
lines changed

Cargo.lock

Lines changed: 25 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

actors/embryo/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ crate-type = ["cdylib", "lib"]
1414

1515
[dependencies]
1616
fvm_sdk = { version = "3.0.0-alpha.2", optional = true }
17-
fvm_shared = { version = "3.0.0-alpha.1", optional = true }
17+
fvm_shared = { version = "3.0.0-alpha.2", optional = true }
1818

1919
[features]
2020
fil-actor = ["fvm_sdk", "fvm_shared"]

actors/evm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ crate-type = ["cdylib", "lib"]
1515

1616
[dependencies]
1717
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime" }
18-
fvm_shared = { version = "3.0.0-alpha.1", default-features = false }
18+
fvm_shared = { version = "3.0.0-alpha.2", default-features = false }
1919
fvm_ipld_hamt = "0.5.1"
2020
serde = { version = "1.0.136", features = ["derive"] }
2121
serde_tuple = "0.5"

actors/init/src/lib.rs

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright 2019-2022 ChainSafe Systems
22
// SPDX-License-Identifier: Apache-2.0, MIT
33

4+
use std::iter;
5+
46
use cid::Cid;
57
use fil_actors_runtime::runtime::{ActorCode, Runtime};
68
use fil_actors_runtime::{actor_error, cbor, ActorContext, ActorError, SYSTEM_ACTOR_ADDR};
@@ -27,8 +29,9 @@ fil_actors_runtime::wasm_trampoline!(Actor);
2729
pub enum Method {
2830
Constructor = METHOD_CONSTRUCTOR,
2931
Exec = 2,
32+
Exec4 = 3,
3033
#[cfg(feature = "m2-native")]
31-
InstallCode = 3,
34+
InstallCode = 4,
3235
}
3336

3437
/// Init actor
@@ -81,7 +84,7 @@ impl Actor {
8184
log::trace!("robust address: {:?}", &robust_address);
8285

8386
// Allocate an ID for this actor.
84-
// Store mapping of pubkey or actor address to actor ID
87+
// Store mapping of actor addresses to the actor ID.
8588
let id_address: ActorID = rt.transaction(|s: &mut State, rt| {
8689
s.map_address_to_new_id(rt.store(), &robust_address)
8790
.context("failed to allocate ID address")
@@ -102,6 +105,58 @@ impl Actor {
102105
Ok(ExecReturn { id_address: Address::new_id(id_address), robust_address })
103106
}
104107

108+
/// Exec init actor
109+
pub fn exec4<BS, RT>(rt: &mut RT, params: Exec4Params) -> Result<Exec4Return, ActorError>
110+
where
111+
BS: Blockstore,
112+
RT: Runtime<BS>,
113+
{
114+
if cfg!(feature = "m2-native") {
115+
rt.validate_immediate_caller_accept_any()?;
116+
} else {
117+
rt.validate_immediate_caller_is(iter::once(&EAM_ACTOR_ADDR))?;
118+
}
119+
120+
// Compute the f4 address.
121+
let caller_id = rt.message().caller().id().unwrap();
122+
let delegated_address =
123+
Address::new_delegated(caller_id, &params.subaddress).map_err(|e| {
124+
ActorError::illegal_argument(format!("invalid delegated address: {}", e))
125+
})?;
126+
127+
log::trace!("delegated address: {:?}", &delegated_address);
128+
129+
// Compute a re-org-stable address.
130+
// This address exists for use by messages coming from outside the system, in order to
131+
// stably address the newly created actor even if a chain re-org causes it to end up with
132+
// a different ID.
133+
let robust_address = rt.new_actor_address()?;
134+
135+
log::trace!("robust address: {:?}", &robust_address);
136+
137+
// Allocate an ID for this actor.
138+
// Store mapping of actor addresses to the actor ID.
139+
let id_address: ActorID = rt.transaction(|s: &mut State, rt| {
140+
s.map_address_to_f4(rt.store(), &robust_address, &delegated_address).map_err(|e| {
141+
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to allocate ID address")
142+
})
143+
})?;
144+
145+
// Create an empty actor
146+
rt.create_actor(params.code_cid, id_address)?;
147+
148+
// Invoke constructor
149+
rt.send(
150+
&Address::new_id(id_address),
151+
METHOD_CONSTRUCTOR,
152+
params.constructor_params,
153+
rt.message().value_received(),
154+
)
155+
.map_err(|err| err.wrap("constructor failed"))?;
156+
157+
Ok(Exec4Return { id_address: Address::new_id(id_address), robust_address })
158+
}
159+
105160
#[cfg(feature = "m2-native")]
106161
pub fn install<BS, RT>(rt: &mut RT, params: InstallParams) -> Result<InstallReturn, ActorError>
107162
where
@@ -171,6 +226,10 @@ impl ActorCode for Actor {
171226
let res = Self::exec(rt, cbor::deserialize_params(params)?)?;
172227
Ok(RawBytes::serialize(res)?)
173228
}
229+
Some(Method::Exec4) => {
230+
let res = Self::exec4(rt, cbor::deserialize_params(params)?)?;
231+
Ok(RawBytes::serialize(res)?)
232+
}
174233
#[cfg(feature = "m2-native")]
175234
Some(Method::InstallCode) => {
176235
let res = Self::install(rt, cbor::deserialize_params(params)?)?;

actors/init/src/state.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0, MIT
33

44
use cid::Cid;
5+
use fil_actors_runtime::actor_error;
56
use fil_actors_runtime::{
67
actor_error, make_empty_map, make_map_with_root_and_bitwidth, ActorError, AsActorError,
78
FIRST_NON_SINGLETON_ADDR,
@@ -34,7 +35,8 @@ impl State {
3435
/// Allocates a new ID address and stores a mapping of the argument address to it.
3536
/// Fails if the argument address is already present in the map to facilitate a tombstone
3637
/// for when the predictable robust address generation is implemented.
37-
/// Returns the newly-allocated address.
38+
///
39+
/// Returns the newly-allocated actor ID.
3840
pub fn map_address_to_new_id<BS: Blockstore>(
3941
&mut self,
4042
store: &BS,
@@ -63,6 +65,48 @@ impl State {
6365
Ok(id)
6466
}
6567

68+
/// Allocates a new ID address and stores a mapping of the argument addresses to it.
69+
/// Returns the newly-allocated actor ID.
70+
pub fn map_address_to_f4<BS: Blockstore>(
71+
&mut self,
72+
store: &BS,
73+
addr: &Address,
74+
f4addr: &Address,
75+
) -> anyhow::Result<ActorID>
76+
where
77+
BS: Blockstore,
78+
{
79+
let mut map = make_map_with_root_and_bitwidth(&self.address_map, store, HAMT_BIT_WIDTH)?;
80+
81+
// Assign a new ID address, or use the one currently mapped to the f4 address. We don't
82+
// bother checking if the target actor is an embryo here, the FVM will check that when we go to create the actor.
83+
let f4addr_key = f4addr.to_bytes().into();
84+
let id: u64 = match map.get(&f4addr_key)? {
85+
Some(id) => *id,
86+
None => {
87+
let id = self.next_id;
88+
self.next_id += 1;
89+
map.set(f4addr_key, id)?;
90+
id
91+
}
92+
};
93+
94+
// Then go ahead and assign the f2 address.
95+
let is_new = map.set_if_absent(addr.to_bytes().into(), id)?;
96+
if !is_new {
97+
// this is impossible today as the robust address is a hash of unique inputs
98+
// but in close future predictable address generation will make this possible
99+
return Err(anyhow!(actor_error!(
100+
forbidden,
101+
"robust address {} is already allocated in the address map",
102+
addr
103+
)));
104+
}
105+
self.address_map = map.flush()?;
106+
107+
Ok(id)
108+
}
109+
66110
/// ResolveAddress resolves an address to an ID-address, if possible.
67111
/// If the provided address is an ID address, it is returned as-is.
68112
/// This means that mapped ID-addresses (which should only appear as values, not keys) and

actors/init/src/testing.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ pub fn check_state_invariants<BS: Blockstore>(
2929

3030
let mut init_summary = StateSummary { ids_by_address: HashMap::new(), next_id: state.next_id };
3131

32-
let mut address_by_id = HashMap::<ActorID, Address>::new();
32+
let mut stable_address_by_id = HashMap::<ActorID, Address>::new();
33+
let mut delegated_address_by_id = HashMap::<ActorID, Address>::new();
3334
match Map::<_, ActorID>::load(&state.address_map, store) {
3435
Ok(address_map) => {
3536
let ret = address_map.for_each(|key, actor_id| {
@@ -44,11 +45,29 @@ pub fn check_state_invariants<BS: Blockstore>(
4445
format!("unexpected singleton ID value {actor_id}"),
4546
);
4647

47-
if let Some(duplicate) = address_by_id.insert(*actor_id, key_address) {
48-
acc.add(format!(
49-
"duplicate mapping to ID {actor_id}: {key_address} {duplicate}"
50-
));
48+
match key_address.protocol() {
49+
Protocol::ID => {
50+
acc.add(format!("key {key_address} is an ID address"));
51+
}
52+
Protocol::Delegated => {
53+
if let Some(duplicate) =
54+
delegated_address_by_id.insert(*actor_id, key_address)
55+
{
56+
acc.add(format!(
57+
"duplicate mapping to ID {actor_id}: {key_address} {duplicate}"
58+
));
59+
}
60+
}
61+
_ => {
62+
if let Some(duplicate) = stable_address_by_id.insert(*actor_id, key_address)
63+
{
64+
acc.add(format!(
65+
"duplicate mapping to ID {actor_id}: {key_address} {duplicate}"
66+
));
67+
}
68+
}
5169
}
70+
5271
init_summary.ids_by_address.insert(key_address, *actor_id);
5372

5473
Ok(())

0 commit comments

Comments
 (0)