diff --git a/Cargo.lock b/Cargo.lock index 8e1c02fa4..c267f189a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2696,9 +2696,11 @@ dependencies = [ name = "fendermint_actor_chainmetadata" version = "0.1.0" dependencies = [ + "anyhow", "cid", "fil_actors_runtime", "frc42_dispatch", + "fvm_ipld_blockstore", "fvm_ipld_encoding", "fvm_shared", "num-derive 0.3.3", diff --git a/fendermint/Makefile b/fendermint/Makefile index aba30e535..6cc04c476 100644 --- a/fendermint/Makefile +++ b/fendermint/Makefile @@ -98,7 +98,7 @@ docker-build: docker-deps $(FENDERMINT_CODE) # Build a bundle CAR; this is so we don't have to have a project reference, # which means we are not tied to the release cycle of both FVM _and_ actors; # so long as they work together. -actor-bundle: $(BUILTIN_ACTORS_BUNDLE) +actor-bundle: $(BUILTIN_ACTORS_BUNDLE) $(ACTORS_BUNDLE) compile-abi: $(IPC_ACTORS_GEN) diff --git a/fendermint/actors/build.rs b/fendermint/actors/build.rs index 97f78e063..cc60fcae4 100644 --- a/fendermint/actors/build.rs +++ b/fendermint/actors/build.rs @@ -42,7 +42,7 @@ fn main() -> Result<(), Box> { .arg("--target=wasm32-unknown-unknown") .arg("--profile=wasm") .arg("--features=fil-actor") - .arg("--manifest-path=".to_owned() + manifest_path.to_str().unwrap()) + .arg(format!("--manifest-path={}", manifest_path.display())) .stdout(Stdio::piped()) .stderr(Stdio::piped()) // We are supposed to only generate artifacts under OUT_DIR, diff --git a/fendermint/actors/chainmetadata/Cargo.toml b/fendermint/actors/chainmetadata/Cargo.toml index a0b2f5d6d..ba06a2550 100644 --- a/fendermint/actors/chainmetadata/Cargo.toml +++ b/fendermint/actors/chainmetadata/Cargo.toml @@ -14,11 +14,13 @@ cid = { workspace = true, default-features = false } fil_actors_runtime = { workspace = true, features = ["fil-actor"] } fvm_shared = { workspace = true } fvm_ipld_encoding = { workspace = true } +fvm_ipld_blockstore = { workspace = true } num-derive = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_tuple = { workspace = true } num-traits = { workspace = true } frc42_dispatch = { workspace = true } +anyhow = { workspace = true } [features] fil-actor = [] diff --git a/fendermint/actors/chainmetadata/src/actor.rs b/fendermint/actors/chainmetadata/src/actor.rs index ecbf999bd..59e4b6ca2 100644 --- a/fendermint/actors/chainmetadata/src/actor.rs +++ b/fendermint/actors/chainmetadata/src/actor.rs @@ -14,7 +14,6 @@ use fil_actors_runtime::Array; use fvm_shared::clock::ChainEpoch; use fvm_shared::error::ExitCode; -use crate::shared::BLOCKHASHES_AMT_BITWIDTH; use crate::{ConstructorParams, Method, PushBlockParams, State}; #[cfg(feature = "fil-actor")] @@ -26,17 +25,9 @@ impl Actor { fn constructor(rt: &impl Runtime, params: ConstructorParams) -> Result<(), ActorError> { rt.validate_immediate_caller_is(std::iter::once(&SYSTEM_ACTOR_ADDR))?; - let empty_arr_cid = - Array::<(), _>::new_with_bit_width(rt.store(), BLOCKHASHES_AMT_BITWIDTH) - .flush() - .map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to create empty AMT") - })?; - - let state = State { - blockhashes: empty_arr_cid, - lookback_len: params.lookback_len, - }; + let state = State::new(rt.store(), params.lookback_len).map_err(|e| { + e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to create empty AMT") + })?; rt.create(&state)?; @@ -60,7 +51,8 @@ impl Actor { .set(params.epoch as u64, params.block.to_string()) .unwrap(); - // remove the oldest block if the AMT is full + // remove the oldest block if the AMT is full (note that this assume the + // for_each_while iterates in order, which it seems to do) if blockhashes.count() > st.lookback_len { let mut first_idx = 0; blockhashes diff --git a/fendermint/actors/chainmetadata/src/shared.rs b/fendermint/actors/chainmetadata/src/shared.rs index 4daf88f49..3da87b435 100644 --- a/fendermint/actors/chainmetadata/src/shared.rs +++ b/fendermint/actors/chainmetadata/src/shared.rs @@ -2,12 +2,13 @@ // SPDX-License-Identifier: Apache-2.0, MIT use cid::Cid; +use fil_actors_runtime::Array; +use fvm_ipld_blockstore::Blockstore; use fvm_ipld_encoding::tuple::{Deserialize_tuple, Serialize_tuple}; use fvm_shared::{clock::ChainEpoch, METHOD_CONSTRUCTOR}; use num_derive::FromPrimitive; -// The state is a stores `blockhashes` in an AMT containing the blockhashes of the -// last `lookback_len` epochs +// The state stores the blockhashes of the last `lookback_len` epochs #[derive(Serialize_tuple, Deserialize_tuple)] pub struct State { // the AMT root cid of blockhashes @@ -17,6 +18,26 @@ pub struct State { pub lookback_len: u64, } +impl State { + pub fn new(store: &BS, lookback_len: u64) -> anyhow::Result { + let empty_blockhashes_cid = + match Array::<(), _>::new_with_bit_width(store, BLOCKHASHES_AMT_BITWIDTH).flush() { + Ok(cid) => cid, + Err(e) => { + return Err(anyhow::anyhow!( + "chainmetadata actor failed to create empty Amt: {}", + e + )) + } + }; + + Ok(Self { + blockhashes: empty_blockhashes_cid, + lookback_len, + }) + } +} + // the default lookback length is 256 epochs pub const DEFAULT_LOOKBACK_LEN: u64 = 256; @@ -38,7 +59,7 @@ pub struct PushBlockParams { #[repr(u64)] pub enum Method { Constructor = METHOD_CONSTRUCTOR, - PushBlock = 2, + PushBlock = frc42_dispatch::method_hash!("PushBlock"), LookbackLen = frc42_dispatch::method_hash!("LookbackLen"), BlockCID = frc42_dispatch::method_hash!("BlockCID"), } diff --git a/fendermint/app/src/app.rs b/fendermint/app/src/app.rs index 72f5f1f3b..4cdb5284c 100644 --- a/fendermint/app/src/app.rs +++ b/fendermint/app/src/app.rs @@ -116,7 +116,7 @@ pub struct AppConfig { #[derive(Clone)] pub struct App where - SS: Blockstore + 'static, + SS: Blockstore + Clone + 'static, S: KVStore, { /// Database backing all key-value operations. diff --git a/fendermint/app/src/ipc.rs b/fendermint/app/src/ipc.rs index e3e76443f..bb0d983b9 100644 --- a/fendermint/app/src/ipc.rs +++ b/fendermint/app/src/ipc.rs @@ -16,7 +16,7 @@ use std::sync::Arc; /// Queries the LATEST COMMITTED parent finality from the storage pub struct AppParentFinalityQuery where - SS: Blockstore + 'static, + SS: Blockstore + Clone + 'static, S: KVStore, { /// The app to get state diff --git a/fendermint/testing/contract-test/src/ipc/registry.rs b/fendermint/testing/contract-test/src/ipc/registry.rs index 7ce373604..ffa54b000 100644 --- a/fendermint/testing/contract-test/src/ipc/registry.rs +++ b/fendermint/testing/contract-test/src/ipc/registry.rs @@ -41,7 +41,7 @@ impl RegistryCaller { } } -impl RegistryCaller { +impl RegistryCaller { /// Create a new instance of the built-in subnet implemetation. /// /// Returns the address of the deployed contract. diff --git a/fendermint/testing/contract-test/src/ipc/subnet.rs b/fendermint/testing/contract-test/src/ipc/subnet.rs index 41619dd22..0392fb601 100644 --- a/fendermint/testing/contract-test/src/ipc/subnet.rs +++ b/fendermint/testing/contract-test/src/ipc/subnet.rs @@ -49,7 +49,7 @@ impl SubnetCaller { type TryCallResult = anyhow::Result>; -impl SubnetCaller { +impl SubnetCaller { /// Join a subnet as a validator. pub fn join( &self, diff --git a/fendermint/testing/contract-test/tests/staking/machine.rs b/fendermint/testing/contract-test/tests/staking/machine.rs index 9c7bee886..1f03011d2 100644 --- a/fendermint/testing/contract-test/tests/staking/machine.rs +++ b/fendermint/testing/contract-test/tests/staking/machine.rs @@ -620,7 +620,7 @@ fn choose_account<'a>( Ok(a) } -fn get_actor_balance( +fn get_actor_balance( exec_state: &mut FvmExecState, addr: EthAddress, ) -> TokenAmount { diff --git a/fendermint/vm/interpreter/src/chain.rs b/fendermint/vm/interpreter/src/chain.rs index 0e4111ca9..ff2243020 100644 --- a/fendermint/vm/interpreter/src/chain.rs +++ b/fendermint/vm/interpreter/src/chain.rs @@ -170,7 +170,7 @@ where #[async_trait] impl ExecInterpreter for ChainMessageInterpreter where - DB: Blockstore + Clone + 'static + Send + Sync, + DB: Blockstore + Clone + 'static + Send + Sync + Clone, I: ExecInterpreter< Message = VerifiableMessage, DeliverOutput = SignedMessageApplyRes, diff --git a/fendermint/vm/interpreter/src/fvm/check.rs b/fendermint/vm/interpreter/src/fvm/check.rs index 36c796c19..52d8a174c 100644 --- a/fendermint/vm/interpreter/src/fvm/check.rs +++ b/fendermint/vm/interpreter/src/fvm/check.rs @@ -22,7 +22,7 @@ pub struct FvmCheckRet { #[async_trait] impl CheckInterpreter for FvmMessageInterpreter where - DB: Blockstore + 'static + Send + Sync, + DB: Blockstore + 'static + Send + Sync + Clone, TC: Send + Sync + 'static, { // We simulate the full pending state so that client can call methods on diff --git a/fendermint/vm/interpreter/src/fvm/checkpoint.rs b/fendermint/vm/interpreter/src/fvm/checkpoint.rs index 61f14b903..c107b16f3 100644 --- a/fendermint/vm/interpreter/src/fvm/checkpoint.rs +++ b/fendermint/vm/interpreter/src/fvm/checkpoint.rs @@ -50,7 +50,7 @@ pub fn maybe_create_checkpoint( state: &mut FvmExecState, ) -> anyhow::Result> where - DB: Blockstore + Sync + Send + 'static, + DB: Blockstore + Sync + Send + Clone + 'static, { // Epoch transitions for checkpointing. let height: tendermint::block::Height = state @@ -164,7 +164,7 @@ pub fn unsigned_checkpoints( validator_key: PublicKey, ) -> anyhow::Result> where - DB: Blockstore + Send + Sync + 'static, + DB: Blockstore + Send + Sync + Clone + 'static, { let mut unsigned_checkpoints = Vec::new(); let validator_addr = EthAddress::from(validator_key); @@ -196,7 +196,7 @@ pub async fn broadcast_incomplete_signatures( ) -> anyhow::Result<()> where C: Client + Clone + Send + Sync + 'static, - DB: Blockstore + Send + Sync + 'static, + DB: Blockstore + Send + Sync + Clone + 'static, { // Make sure that these had time to be added to the ledger. if let Some(highest) = incomplete_checkpoints @@ -268,7 +268,7 @@ pub async fn broadcast_signature( ) -> anyhow::Result<()> where C: Client + Clone + Send + Sync + 'static, - DB: Blockstore + Send + Sync + 'static, + DB: Blockstore + Send + Sync + Clone + 'static, { let calldata = gateway .add_checkpoint_signature_calldata(checkpoint, &power_table.0, validator, secret_key) @@ -291,7 +291,7 @@ fn should_create_checkpoint( height: Height, ) -> anyhow::Result> where - DB: Blockstore, + DB: Blockstore + Clone, { if gateway.enabled(state)? { let id = gateway.subnet_id(state)?; @@ -336,7 +336,7 @@ fn ipc_power_table( state: &mut FvmExecState, ) -> anyhow::Result<(ConfigurationNumber, PowerTable)> where - DB: Blockstore + Sync + Send + 'static, + DB: Blockstore + Sync + Send + Clone + 'static, { let membership = gateway .current_validator_set(state) diff --git a/fendermint/vm/interpreter/src/fvm/externs.rs b/fendermint/vm/interpreter/src/fvm/externs.rs index 5402a0a6b..ab865cb05 100644 --- a/fendermint/vm/interpreter/src/fvm/externs.rs +++ b/fendermint/vm/interpreter/src/fvm/externs.rs @@ -1,14 +1,44 @@ // Copyright 2022-2024 Protocol Labs // SPDX-License-Identifier: Apache-2.0, MIT +use anyhow::anyhow; use cid::Cid; -use fvm::externs::{Chain, Consensus, Externs, Rand}; +use fendermint_actors::CHAINMETADATA_ACTOR_ID; +use fil_actors_runtime::Array; +use fvm::{ + externs::{Chain, Consensus, Externs, Rand}, + state_tree::StateTree, +}; +use fvm_ipld_blockstore::Blockstore; +use fvm_ipld_encoding::CborStore; use fvm_shared::clock::ChainEpoch; +use std::str::FromStr; -/// Dummy externs - these are related to Expected Consensus, -/// which I believe we have nothing to do with. -pub struct FendermintExterns; +use super::store::ReadOnlyBlockstore; -impl Rand for FendermintExterns { +pub struct FendermintExterns +where + DB: Blockstore + 'static, +{ + blockstore: DB, + state_root: Cid, +} + +impl FendermintExterns +where + DB: Blockstore + 'static, +{ + pub fn new(blockstore: DB, state_root: Cid) -> Self { + Self { + blockstore, + state_root, + } + } +} + +impl Rand for FendermintExterns +where + DB: Blockstore + 'static, +{ fn get_chain_randomness(&self, _round: ChainEpoch) -> anyhow::Result<[u8; 32]> { todo!("might need randomness") } @@ -18,7 +48,10 @@ impl Rand for FendermintExterns { } } -impl Consensus for FendermintExterns { +impl Consensus for FendermintExterns +where + DB: Blockstore + 'static, +{ fn verify_consensus_fault( &self, _h1: &[u8], @@ -29,10 +62,75 @@ impl Consensus for FendermintExterns { } } -impl Chain for FendermintExterns { - fn get_tipset_cid(&self, _epoch: ChainEpoch) -> anyhow::Result { - unimplemented!("not expecting to use tipsets") +impl Chain for FendermintExterns +where + DB: Blockstore + Clone + 'static, +{ + // for retreiving the tipset_cid, we load the chain metadata actor state + // at the given state_root and retrieve the blockhash for the given epoch + fn get_tipset_cid(&self, epoch: ChainEpoch) -> anyhow::Result { + // create a read only state tree from the state root + let bstore = ReadOnlyBlockstore::new(&self.blockstore); + let state_tree = StateTree::new_from_root(&bstore, &self.state_root)?; + + // get the chain metadata actor state cid + let actor_state_cid = match state_tree.get_actor(CHAINMETADATA_ACTOR_ID) { + Ok(Some(actor_state)) => actor_state.state, + Ok(None) => { + return Err(anyhow!( + "chain metadata actor id ({}) not found in state", + CHAINMETADATA_ACTOR_ID + )); + } + Err(err) => { + return Err(anyhow!( + "failed to get chain metadata actor ({}) state, error: {}", + CHAINMETADATA_ACTOR_ID, + err + )); + } + }; + + // get the chain metadata actor state from the blockstore + let actor_state: fendermint_actor_chainmetadata::State = + match state_tree.store().get_cbor(&actor_state_cid) { + Ok(Some(v)) => v, + Ok(None) => { + return Err(anyhow!( + "chain metadata actor ({}) state not found", + CHAINMETADATA_ACTOR_ID + )); + } + Err(err) => { + return Err(anyhow!( + "failed to get chain metadata actor ({}) state, error: {}", + CHAINMETADATA_ACTOR_ID, + err + )); + } + }; + + // load the blockhashe Array from the AMT root cid + let blockhashes = Array::load(&actor_state.blockhashes, &bstore)?; + + // get the block hash at the given epoch + let blockhash: &String = match blockhashes.get(epoch as u64).unwrap() { + Some(v) => v, + None => { + return Ok(Cid::default()); + } + }; + + // return the blockhash as a cid, or an error if the cid is invalid + match Cid::from_str(blockhash.as_str()) { + Ok(cid) => Ok(cid), + Err(_) => Err(anyhow!( + "failed to parse cid, blockhash: {}, epoch: {}", + blockhash, + epoch + )), + } } } -impl Externs for FendermintExterns {} +impl Externs for FendermintExterns where DB: Blockstore + Clone + 'static {} diff --git a/fendermint/vm/interpreter/src/fvm/genesis.rs b/fendermint/vm/interpreter/src/fvm/genesis.rs index c1516a056..7db305319 100644 --- a/fendermint/vm/interpreter/src/fvm/genesis.rs +++ b/fendermint/vm/interpreter/src/fvm/genesis.rs @@ -9,7 +9,6 @@ use anyhow::{anyhow, Context}; use async_trait::async_trait; use ethers::abi::Tokenize; use ethers::core::types as et; -use fendermint_actor_chainmetadata::BLOCKHASHES_AMT_BITWIDTH; use fendermint_eth_hardhat::{Hardhat, FQN}; use fendermint_vm_actor_interface::diamond::{EthContract, EthContractMap}; use fendermint_vm_actor_interface::eam::EthAddress; @@ -19,7 +18,6 @@ use fendermint_vm_actor_interface::{ }; use fendermint_vm_core::{chainid, Timestamp}; use fendermint_vm_genesis::{ActorMeta, Genesis, Power, PowerScale, Validator}; -use fil_actors_runtime::Array; use fvm_ipld_blockstore::Blockstore; use fvm_shared::chainid::ChainID; use fvm_shared::econ::TokenAmount; @@ -235,16 +233,14 @@ where // Initialize the chain metadata actor which handles saving metadata about the chain // (e.g. block hashes) which we can query. - let empty_blockhashes_cid = - Array::<(), _>::new_with_bit_width(state.store(), BLOCKHASHES_AMT_BITWIDTH).flush()?; + const LOOKBACK_LEN: u64 = 256; + let chainmetadata_state = + fendermint_actor_chainmetadata::State::new(&state.store(), LOOKBACK_LEN)?; state .create_actor( fendermint_actors::CHAINMETADATA_ACTOR_CODE_ID, fendermint_actors::CHAINMETADATA_ACTOR_ID, - &fendermint_actor_chainmetadata::State { - blockhashes: empty_blockhashes_cid, - lookback_len: fendermint_actor_chainmetadata::DEFAULT_LOOKBACK_LEN, - }, + &chainmetadata_state, TokenAmount::zero(), None, ) diff --git a/fendermint/vm/interpreter/src/fvm/state/check.rs b/fendermint/vm/interpreter/src/fvm/state/check.rs index de0b61043..10ecfa639 100644 --- a/fendermint/vm/interpreter/src/fvm/state/check.rs +++ b/fendermint/vm/interpreter/src/fvm/state/check.rs @@ -14,7 +14,7 @@ use crate::fvm::store::ReadOnlyBlockstore; /// A state we create for the execution of all the messages in a block. pub struct FvmCheckState where - DB: Blockstore + 'static, + DB: Blockstore + Clone + 'static, { state_tree: StateTree>, chain_id: ChainID, @@ -22,7 +22,7 @@ where impl FvmCheckState where - DB: Blockstore + 'static, + DB: Blockstore + Clone + 'static, { pub fn new(blockstore: DB, state_root: Cid, chain_id: ChainID) -> anyhow::Result { // Sanity check that the blockstore contains the supplied state root. @@ -57,7 +57,7 @@ where impl HasChainID for FvmCheckState where - DB: Blockstore + 'static, + DB: Blockstore + Clone + 'static, { fn chain_id(&self) -> ChainID { self.chain_id diff --git a/fendermint/vm/interpreter/src/fvm/state/exec.rs b/fendermint/vm/interpreter/src/fvm/state/exec.rs index b7520e12c..4bc7e1f8c 100644 --- a/fendermint/vm/interpreter/src/fvm/state/exec.rs +++ b/fendermint/vm/interpreter/src/fvm/state/exec.rs @@ -3,6 +3,7 @@ use std::collections::{HashMap, HashSet}; +use anyhow::Ok; use cid::Cid; use fendermint_vm_genesis::PowerScale; use fvm::{ @@ -76,15 +77,17 @@ pub struct FvmUpdatableParams { pub power_scale: PowerScale, } -pub type MachineBlockstore = as Machine>::Blockstore; +pub type MachineBlockstore = > as Machine>::Blockstore; /// A state we create for the execution of all the messages in a block. pub struct FvmExecState where - DB: Blockstore + 'static, + DB: Blockstore + Clone + 'static, { - executor: - DefaultExecutor>>>, + #[allow(clippy::type_complexity)] + executor: DefaultExecutor< + DefaultKernel>>>, + >, /// Hash of the block currently being executed. For queries and checks this is empty. /// @@ -101,7 +104,7 @@ where impl FvmExecState where - DB: Blockstore + 'static, + DB: Blockstore + Clone + 'static, { /// Create a new FVM execution environment. /// @@ -128,7 +131,8 @@ where // let engine = EnginePool::new_default(ec)?; let engine = multi_engine.get(&nc)?; - let machine = DefaultMachine::new(&mc, blockstore, FendermintExterns)?; + let externs = FendermintExterns::new(blockstore.clone(), params.state_root); + let machine = DefaultMachine::new(&mc, blockstore, externs)?; let executor = DefaultExecutor::new(engine, machine)?; Ok(Self { @@ -258,7 +262,7 @@ where impl HasChainID for FvmExecState where - DB: Blockstore, + DB: Blockstore + Clone, { fn chain_id(&self) -> ChainID { self.executor.context().network.chain_id diff --git a/fendermint/vm/interpreter/src/fvm/state/fevm.rs b/fendermint/vm/interpreter/src/fvm/state/fevm.rs index d475a4d14..51f265dcc 100644 --- a/fendermint/vm/interpreter/src/fvm/state/fevm.rs +++ b/fendermint/vm/interpreter/src/fvm/state/fevm.rs @@ -164,7 +164,7 @@ impl ContractCaller { impl ContractCaller where - DB: Blockstore, + DB: Blockstore + Clone, E: ContractRevert + Debug, { /// Call an EVM method implicitly to read its return value. diff --git a/fendermint/vm/interpreter/src/fvm/state/genesis.rs b/fendermint/vm/interpreter/src/fvm/state/genesis.rs index c4cc3e273..e493f866d 100644 --- a/fendermint/vm/interpreter/src/fvm/state/genesis.rs +++ b/fendermint/vm/interpreter/src/fvm/state/genesis.rs @@ -49,7 +49,7 @@ pub fn empty_state_tree(store: DB) -> anyhow::Result { +enum Stage { Tree(StateTree), Exec(FvmExecState), } @@ -57,7 +57,7 @@ enum Stage { /// A state we create for the execution of genesis initialisation. pub struct FvmGenesisState where - DB: Blockstore + 'static, + DB: Blockstore + Clone + 'static, { pub manifest_data_cid: Cid, pub manifest: Manifest, diff --git a/fendermint/vm/interpreter/src/fvm/state/ipc.rs b/fendermint/vm/interpreter/src/fvm/state/ipc.rs index c9a95dd9b..85aa9b404 100644 --- a/fendermint/vm/interpreter/src/fvm/state/ipc.rs +++ b/fendermint/vm/interpreter/src/fvm/state/ipc.rs @@ -81,7 +81,7 @@ impl GatewayCaller { } } -impl GatewayCaller { +impl GatewayCaller { /// Check that IPC is configured in this deployment. pub fn enabled(&self, state: &mut FvmExecState) -> anyhow::Result { match state.state_tree_mut().get_actor(GATEWAY_ACTOR_ID)? { diff --git a/fendermint/vm/interpreter/src/fvm/state/query.rs b/fendermint/vm/interpreter/src/fvm/state/query.rs index fa814d121..f8d411aa0 100644 --- a/fendermint/vm/interpreter/src/fvm/state/query.rs +++ b/fendermint/vm/interpreter/src/fvm/state/query.rs @@ -24,7 +24,7 @@ use super::{CheckStateRef, FvmExecState, FvmStateParams}; /// The state over which we run queries. These can interrogate the IPLD block store or the state tree. pub struct FvmQueryState where - DB: Blockstore + 'static, + DB: Blockstore + Clone + 'static, { /// A read-only wrapper around the blockstore, to make sure we aren't /// accidentally committing any state. Any writes by the FVM will be @@ -215,7 +215,7 @@ where impl HasChainID for FvmQueryState where - DB: Blockstore + 'static, + DB: Blockstore + Clone + 'static, { fn chain_id(&self) -> ChainID { ChainID::from(self.state_params.chain_id) diff --git a/fendermint/vm/interpreter/src/fvm/state/snapshot.rs b/fendermint/vm/interpreter/src/fvm/state/snapshot.rs index ddd56ce20..c1aedfbb2 100644 --- a/fendermint/vm/interpreter/src/fvm/state/snapshot.rs +++ b/fendermint/vm/interpreter/src/fvm/state/snapshot.rs @@ -40,7 +40,7 @@ type SnapshotStreamer = Box)>>; impl Snapshot where - BS: Blockstore + 'static + Send, + BS: Blockstore + 'static + Send + Clone, { pub fn new( store: BS, @@ -151,7 +151,7 @@ pub type BlockStateParams = (FvmStateParams, BlockHeight); impl V1Snapshot where - BS: Blockstore + 'static + Send, + BS: Blockstore + 'static + Send + Clone, { /// Creates a new V2Snapshot struct. Caller ensure store pub fn new( diff --git a/fendermint/vm/interpreter/src/fvm/store/mod.rs b/fendermint/vm/interpreter/src/fvm/store/mod.rs index 9e369992f..f3b10a43e 100644 --- a/fendermint/vm/interpreter/src/fvm/store/mod.rs +++ b/fendermint/vm/interpreter/src/fvm/store/mod.rs @@ -17,7 +17,7 @@ impl ReadOnlyBlockstore { impl Blockstore for ReadOnlyBlockstore where - DB: Blockstore, + DB: Blockstore + Clone, { fn get(&self, k: &Cid) -> anyhow::Result>> { self.0.get(k) diff --git a/fendermint/vm/interpreter/src/fvm/topdown.rs b/fendermint/vm/interpreter/src/fvm/topdown.rs index 4448620cc..c376a94b4 100644 --- a/fendermint/vm/interpreter/src/fvm/topdown.rs +++ b/fendermint/vm/interpreter/src/fvm/topdown.rs @@ -22,7 +22,7 @@ pub async fn commit_finality( provider: &TopDownFinalityProvider, ) -> anyhow::Result<(BlockHeight, Option)> where - DB: Blockstore + Sync + Send + 'static, + DB: Blockstore + Sync + Send + Clone + 'static, { let (prev_height, prev_finality) = if let Some(prev_finality) = gateway_caller.commit_parent_finality(state, finality)? { @@ -46,7 +46,7 @@ pub async fn execute_topdown_msgs( messages: Vec, ) -> anyhow::Result where - DB: Blockstore + Sync + Send + 'static, + DB: Blockstore + Sync + Send + Clone + 'static, { let minted_tokens = tokens_to_mint(&messages); tracing::debug!(token = minted_tokens.to_string(), "tokens to mint in child"); diff --git a/fendermint/vm/snapshot/src/state.rs b/fendermint/vm/snapshot/src/state.rs index 4a37a9df3..1d6e3a025 100644 --- a/fendermint/vm/snapshot/src/state.rs +++ b/fendermint/vm/snapshot/src/state.rs @@ -83,7 +83,7 @@ impl SnapshotItem { /// Import a snapshot into the blockstore. pub async fn import(&self, store: BS, validate: bool) -> anyhow::Result> where - BS: Blockstore + Send + 'static, + BS: Blockstore + Send + Clone + 'static, { let parts = manifest::list_parts(self.parts_dir()).context("failed to list snapshot parts")?;