use cid::Cid;
use fvm_ipld_blockstore::Blockstore;
use fvm_ipld_encoding::CborStore;
use fvm_shared4::address::Address;
use fvm_shared4::clock::ChainEpoch;
use fvm_shared4::econ::TokenAmount;
use fvm_shared4::randomness::RANDOMNESS_LENGTH;
use fvm_shared4::version::NetworkVersion;
use fvm_shared4::{ActorID, MethodNum, Response};
use serde::de::DeserializeOwned;
use serde::Serialize;
pub use self::policy::*;
pub use self::randomness::DomainSeparationTag;
use crate::actor_error_v13;
use crate::v13::runtime::builtins::Type;
use crate::v13::{ActorError, SendError};
pub mod builtins;
pub mod policy;
mod randomness;
pub(crate) mod empty;
pub use crate::v13::vm_api::Primitives;
use cid::multihash::Code;
pub use empty::EMPTY_ARR_CID;
use fvm_ipld_encoding::ipld_block::IpldBlock;
use fvm_shared4::chainid::ChainID;
use fvm_shared4::event::ActorEvent;
use fvm_shared4::sys::SendFlags;
pub trait Runtime: Primitives + RuntimePolicy {
type Blockstore: Blockstore;
fn network_version(&self) -> NetworkVersion;
fn message(&self) -> &dyn MessageInfo;
fn curr_epoch(&self) -> ChainEpoch;
fn chain_id(&self) -> ChainID;
fn validate_immediate_caller_accept_any(&self) -> Result<(), ActorError>;
fn validate_immediate_caller_is<'a, I>(&self, addresses: I) -> Result<(), ActorError>
where
I: IntoIterator<Item = &'a Address>;
fn validate_immediate_caller_namespace<I>(
&self,
namespace_manager_addresses: I,
) -> Result<(), ActorError>
where
I: IntoIterator<Item = u64>;
fn validate_immediate_caller_type<'a, I>(&self, types: I) -> Result<(), ActorError>
where
I: IntoIterator<Item = &'a Type>;
fn current_balance(&self) -> TokenAmount;
fn actor_balance(&self, id: ActorID) -> Option<TokenAmount>;
fn resolve_address(&self, address: &Address) -> Option<ActorID>;
fn lookup_delegated_address(&self, id: ActorID) -> Option<Address>;
fn get_actor_code_cid(&self, id: &ActorID) -> Option<Cid>;
fn get_randomness_from_tickets(
&self,
personalization: DomainSeparationTag,
rand_epoch: ChainEpoch,
entropy: &[u8],
) -> Result<[u8; RANDOMNESS_LENGTH], ActorError>;
fn get_randomness_from_beacon(
&self,
personalization: DomainSeparationTag,
rand_epoch: ChainEpoch,
entropy: &[u8],
) -> Result<[u8; RANDOMNESS_LENGTH], ActorError>;
fn create<T: Serialize>(&self, obj: &T) -> Result<(), ActorError> {
let root = self.get_state_root()?;
if root != EMPTY_ARR_CID {
return Err(
actor_error_v13!(illegal_state; "failed to create state; expected empty array CID, got: {}", root),
);
}
let new_root = self.store().put_cbor(obj, Code::Blake2b256)
.map_err(|e| actor_error_v13!(illegal_argument; "failed to write actor state during creation: {}", e.to_string()))?;
self.set_state_root(&new_root)?;
Ok(())
}
fn state<T: DeserializeOwned>(&self) -> Result<T, ActorError> {
Ok(self
.store()
.get_cbor(&self.get_state_root()?)
.map_err(
|_| actor_error_v13!(illegal_argument; "failed to get actor for Readonly state"),
)?
.expect("State does not exist for actor state root"))
}
fn get_state_root(&self) -> Result<Cid, ActorError>;
fn set_state_root(&self, root: &Cid) -> Result<(), ActorError>;
fn transaction<S, RT, F>(&self, f: F) -> Result<RT, ActorError>
where
S: Serialize + DeserializeOwned,
F: FnOnce(&mut S, &Self) -> Result<RT, ActorError>;
fn store(&self) -> &Self::Blockstore;
fn send(
&self,
to: &Address,
method: MethodNum,
params: Option<IpldBlock>,
value: TokenAmount,
gas_limit: Option<u64>,
flags: SendFlags,
) -> Result<Response, SendError>;
fn send_simple(
&self,
to: &Address,
method: MethodNum,
params: Option<IpldBlock>,
value: TokenAmount,
) -> Result<Response, SendError> {
self.send(to, method, params, value, None, SendFlags::empty())
}
fn new_actor_address(&self) -> Result<Address, ActorError>;
fn create_actor(
&self,
code_id: Cid,
actor_id: ActorID,
predictable_address: Option<Address>,
) -> Result<(), ActorError>;
fn delete_actor(&self) -> Result<(), ActorError>;
fn resolve_builtin_actor_type(&self, code_id: &Cid) -> Option<Type>;
fn get_code_cid_for_type(&self, typ: Type) -> Cid;
fn total_fil_circ_supply(&self) -> TokenAmount;
fn charge_gas(&self, name: &'static str, compute: i64);
fn base_fee(&self) -> TokenAmount;
fn gas_available(&self) -> u64;
fn tipset_timestamp(&self) -> u64;
fn tipset_cid(&self, epoch: i64) -> Result<Cid, ActorError>;
fn emit_event(&self, event: &ActorEvent) -> Result<(), ActorError>;
fn read_only(&self) -> bool;
}
pub trait MessageInfo {
fn nonce(&self) -> u64;
fn caller(&self) -> Address;
fn origin(&self) -> Address;
fn receiver(&self) -> Address;
fn value_received(&self) -> TokenAmount;
fn gas_premium(&self) -> TokenAmount;
}