Skip to content

Commit

Permalink
Traits and impls for adding context and exit codes to results. (#589)
Browse files Browse the repository at this point in the history
Co-authored-by: dignifiedquire <[email protected]>
  • Loading branch information
2 people authored and Stebalien committed Sep 20, 2022
1 parent 023dd20 commit 6ecf99d
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 311 deletions.
66 changes: 26 additions & 40 deletions actors/init/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use std::iter;

use cid::Cid;
use fil_actors_runtime::runtime::{ActorCode, Runtime};
use fil_actors_runtime::EAM_ACTOR_ADDR;
use fil_actors_runtime::{actor_error, cbor, ActorDowncast, ActorError, SYSTEM_ACTOR_ADDR};
use fil_actors_runtime::{
actor_error, cbor, ActorContext, ActorError, EAM_ACTOR_ADDR, SYSTEM_ACTOR_ADDR,
};
use fvm_ipld_blockstore::Blockstore;
use fvm_ipld_encoding::RawBytes;
use fvm_shared::address::Address;
use fvm_shared::error::ExitCode;
use fvm_shared::{ActorID, MethodNum, METHOD_CONSTRUCTOR};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
Expand Down Expand Up @@ -47,10 +47,7 @@ impl Actor {
{
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).map_err(|e| {
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to construct init actor state")
})?;

let state = State::new(rt.store(), params.network_name)?;
rt.create(&state)?;

Ok(())
Expand Down Expand Up @@ -91,9 +88,8 @@ impl Actor {
// Allocate an ID for this actor.
// Store mapping of actor addresses to the actor ID.
let id_address: ActorID = rt.transaction(|s: &mut State, rt| {
s.map_address_to_new_id(rt.store(), &robust_address).map_err(|e| {
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to allocate ID address")
})
s.map_address_to_new_id(rt.store(), &robust_address)
.context("failed to allocate ID address")
})?;

// Create an empty actor
Expand All @@ -106,7 +102,7 @@ impl Actor {
params.constructor_params,
rt.message().value_received(),
)
.map_err(|err| err.wrap("constructor failed"))?;
.context("constructor failed")?;

Ok(ExecReturn { id_address: Address::new_id(id_address), robust_address })
}
Expand Down Expand Up @@ -143,9 +139,8 @@ impl Actor {
// Allocate an ID for this actor.
// Store mapping of actor addresses to the actor ID.
let id_address: ActorID = rt.transaction(|s: &mut State, rt| {
s.map_address_to_f4(rt.store(), &robust_address, &delegated_address).map_err(|e| {
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to allocate ID address")
})
s.map_address_to_f4(rt.store(), &robust_address, &delegated_address)
.context("constructor failed")
})?;

// Create an empty actor
Expand Down Expand Up @@ -176,36 +171,27 @@ impl Actor {

let (code_cid, installed) = rt.transaction(|st: &mut State, rt| {
let code = params.code.bytes();
let code_cid =
rt.store().put(Code::Blake2b256, &Block::new(0x55, code)).map_err(|e| {
e.downcast_default(
ExitCode::USR_SERIALIZATION,
"failed to put code into the bockstore",
)
})?;

if st.is_installed_actor(rt.store(), &code_cid).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
"failed to check state for installed actor",
)
})? {
let code_cid = rt.store().put(Code::Blake2b256, &Block::new(0x55, code)).context_code(
ExitCode::USR_SERIALIZATION,
"failed to put code into the bockstore",
)?;

if st.is_installed_actor(rt.store(), &code_cid).context_code(
ExitCode::USR_ILLEGAL_STATE,
"failed to check state for installed actor",
)? {
return Ok((code_cid, false));
}

rt.install_actor(&code_cid).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_ARGUMENT,
"failed to check state for installed actor",
)
})?;
rt.install_actor(&code_cid).context_code(
ExitCode::USR_ILLEGAL_ARGUMENT,
"failed to check state for installed actor",
)?;

st.add_installed_actor(rt.store(), code_cid).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
"failed to add installed actor to state",
)
})?;
st.add_installed_actor(rt.store(), code_cid).context_code(
ExitCode::USR_ILLEGAL_STATE,
"failed to add installed actor to state",
)?;
Ok((code_cid, true))
})?;

Expand Down
64 changes: 40 additions & 24 deletions actors/init/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
// Copyright 2019-2022 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

use anyhow::anyhow;
#[cfg(feature = "m2-native")]
use cid::multihash::Code;
use cid::Cid;
use fil_actors_runtime::actor_error;
use fil_actors_runtime::{
make_empty_map, make_map_with_root_and_bitwidth, FIRST_NON_SINGLETON_ADDR,
actor_error, make_empty_map, make_map_with_root_and_bitwidth, ActorError, AsActorError,
FIRST_NON_SINGLETON_ADDR,
};
use fvm_ipld_blockstore::Blockstore;
use fvm_ipld_encoding::tuple::*;
use fvm_ipld_encoding::Cbor;
#[cfg(feature = "m2-native")]
use fvm_ipld_encoding::CborStore;
use fvm_shared::address::{Address, Protocol};
use fvm_shared::error::ExitCode;
use fvm_shared::{ActorID, HAMT_BIT_WIDTH};

/// State is reponsible for creating
Expand All @@ -28,10 +28,10 @@ pub struct State {
}

impl State {
pub fn new<BS: Blockstore>(store: &BS, network_name: String) -> anyhow::Result<Self> {
pub fn new<BS: Blockstore>(store: &BS, network_name: String) -> Result<Self, ActorError> {
let empty_map = make_empty_map::<_, ()>(store, HAMT_BIT_WIDTH)
.flush()
.map_err(|e| anyhow!("failed to create empty map: {}", e))?;
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to create empty map")?;
#[cfg(feature = "m2-native")]
let installed_actors = store.put_cbor(&Vec::<Cid>::new(), Code::Blake2b256)?;
Ok(Self {
Expand All @@ -52,22 +52,26 @@ impl State {
&mut self,
store: &BS,
addr: &Address,
) -> anyhow::Result<ActorID> {
) -> Result<ActorID, ActorError> {
let id = self.next_id;
self.next_id += 1;

let mut map = make_map_with_root_and_bitwidth(&self.address_map, store, HAMT_BIT_WIDTH)?;
let is_new = map.set_if_absent(addr.to_bytes().into(), id)?;
let mut map = make_map_with_root_and_bitwidth(&self.address_map, store, HAMT_BIT_WIDTH)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load address map")?;
let is_new = map
.set_if_absent(addr.to_bytes().into(), id)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to set map key")?;
if !is_new {
// this is impossible today as the robust address is a hash of unique inputs
// but in close future predictable address generation will make this possible
return Err(anyhow!(actor_error!(
return Err(actor_error!(
forbidden,
"robust address {} is already allocated in the address map",
addr
)));
));
}
self.address_map = map.flush()?;
self.address_map =
map.flush().context_code(ExitCode::USR_ILLEGAL_STATE, "failed to store address map")?;

Ok(id)
}
Expand All @@ -79,37 +83,45 @@ impl State {
store: &BS,
addr: &Address,
f4addr: &Address,
) -> anyhow::Result<ActorID>
) -> Result<ActorID, ActorError>
where
BS: Blockstore,
{
let mut map = make_map_with_root_and_bitwidth(&self.address_map, store, HAMT_BIT_WIDTH)?;
let mut map = make_map_with_root_and_bitwidth(&self.address_map, store, HAMT_BIT_WIDTH)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load address map")?;

// Assign a new ID address, or use the one currently mapped to the f4 address. We don't
// bother checking if the target actor is an embryo here, the FVM will check that when we go to create the actor.
let f4addr_key = f4addr.to_bytes().into();
let id: u64 = match map.get(&f4addr_key)? {
let id: u64 = match map
.get(&f4addr_key)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to lookup f4 address in map")?
{
Some(id) => *id,
None => {
let id = self.next_id;
self.next_id += 1;
map.set(f4addr_key, id)?;
map.set(f4addr_key, id)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to set f4 address in map")?;
id
}
};

// Then go ahead and assign the f2 address.
let is_new = map.set_if_absent(addr.to_bytes().into(), id)?;
let is_new = map
.set_if_absent(addr.to_bytes().into(), id)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to set map key")?;
if !is_new {
// this is impossible today as the robust address is a hash of unique inputs
// but in close future predictable address generation will make this possible
return Err(anyhow!(actor_error!(
return Err(actor_error!(
forbidden,
"robust address {} is already allocated in the address map",
addr
)));
));
}
self.address_map = map.flush()?;
self.address_map =
map.flush().context_code(ExitCode::USR_ILLEGAL_STATE, "failed to store address map")?;

Ok(id)
}
Expand All @@ -128,14 +140,18 @@ impl State {
&self,
store: &BS,
addr: &Address,
) -> anyhow::Result<Option<Address>> {
) -> Result<Option<Address>, ActorError> {
if addr.protocol() == Protocol::ID {
return Ok(Some(*addr));
}

let map = make_map_with_root_and_bitwidth(&self.address_map, store, HAMT_BIT_WIDTH)?;
let map = make_map_with_root_and_bitwidth(&self.address_map, store, HAMT_BIT_WIDTH)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load address map")?;

Ok(map.get(&addr.to_bytes())?.copied().map(Address::new_id))
let found = map
.get(&addr.to_bytes())
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to get address entry")?;
Ok(found.copied().map(Address::new_id))
}

/// Check to see if an actor is already installed
Expand All @@ -144,7 +160,7 @@ impl State {
&self,
store: &BS,
cid: &Cid,
) -> anyhow::Result<bool> {
) -> Result<bool, ActorError> {
let installed: Vec<Cid> = match store.get_cbor(&self.installed_actors)? {
Some(v) => v,
None => Vec::new(),
Expand All @@ -158,7 +174,7 @@ impl State {
&mut self,
store: &BS,
cid: Cid,
) -> anyhow::Result<()> {
) -> Result<(), ActorError> {
let mut installed: Vec<Cid> = match store.get_cbor(&self.installed_actors)? {
Some(v) => v,
None => Vec::new(),
Expand Down
Loading

0 comments on commit 6ecf99d

Please sign in to comment.