diff --git a/fvm/src/blockstore/buffered.rs b/fvm/src/blockstore/buffered.rs index 17107b98b..606d35637 100644 --- a/fvm/src/blockstore/buffered.rs +++ b/fvm/src/blockstore/buffered.rs @@ -5,23 +5,25 @@ use std::cell::RefCell; use std::collections::HashMap; use std::io::{Cursor, Read, Seek}; +use std::marker::PhantomData; use anyhow::{anyhow, Result}; use byteorder::{BigEndian, ByteOrder, ReadBytesExt}; use cid::Cid; -use fvm_ipld_blockstore::{Blockstore, Buffered}; +use fvm_ipld_blockstore::{Block, Blockstore, Buffered}; use fvm_ipld_encoding::{CBOR, DAG_CBOR}; use fvm_shared::commcid::{FIL_COMMITMENT_SEALED, FIL_COMMITMENT_UNSEALED}; /// Wrapper around `Blockstore` to limit and have control over when values are written. /// This type is not threadsafe and can only be used in synchronous contexts. #[derive(Debug)] -pub struct BufferedBlockstore { +pub struct BufferedBlockstore { base: BS, write: RefCell>>, + _marker: PhantomData C>, } -impl BufferedBlockstore +impl BufferedBlockstore where BS: Blockstore, { @@ -29,6 +31,7 @@ where Self { base, write: Default::default(), + _marker: Default::default(), } } @@ -37,6 +40,20 @@ where } } +impl BufferedBlockstore +where + C: multihash::MultihashDigest<64>, + anyhow::Error: From, +{ + fn cid_of(&self, mh_code: u64, block: &dyn Block) -> Result { + let mh_code = C::try_from(mh_code)?; + let data = block.data(); + let codec = block.codec(); + let digest = mh_code.digest(data); + Ok(Cid::new_v1(codec, digest)) + } +} + impl Buffered for BufferedBlockstore where BS: Blockstore, @@ -229,9 +246,11 @@ fn copy_rec<'a>( Ok(()) } -impl Blockstore for BufferedBlockstore +impl Blockstore for BufferedBlockstore where BS: Blockstore, + C: multihash::MultihashDigest<64>, + anyhow::Error: From, { fn get(&self, cid: &Cid) -> Result>> { Ok(if let Some(data) = self.write.borrow().get(cid) { @@ -241,6 +260,12 @@ where }) } + fn put(&self, mh_code: u64, block: &dyn fvm_ipld_blockstore::Block) -> Result { + let k = self.cid_of(mh_code, block)?; + self.put_keyed(&k, block.data())?; + Ok(k) + } + fn put_keyed(&self, cid: &Cid, buf: &[u8]) -> Result<()> { self.write.borrow_mut().insert(*cid, Vec::from(buf)); Ok(()) diff --git a/fvm/src/blockstore/discard.rs b/fvm/src/blockstore/discard.rs index 9021c72d6..4e4e1a479 100644 --- a/fvm/src/blockstore/discard.rs +++ b/fvm/src/blockstore/discard.rs @@ -1,22 +1,67 @@ // Copyright 2021-2023 Protocol Labs // SPDX-License-Identifier: Apache-2.0, MIT +use std::marker::PhantomData; + use cid::Cid; use fvm_ipld_blockstore::Blockstore; // A blockstore that accepts but discards all insertions, and returns errors on reads. // Useful for when the FVM needs to stage ephemeral data structures without persisting them, // like the events AMT. -pub struct DiscardBlockstore; +#[derive(Copy, Clone)] +pub struct DiscardBlockstore(PhantomData C>); + +impl Default for DiscardBlockstore { + fn default() -> Self { + DiscardBlockstore(Default::default()) + } +} -impl Blockstore for DiscardBlockstore { +impl Blockstore for DiscardBlockstore +where + C: multihash::MultihashDigest<64>, + anyhow::Error: From, +{ fn get(&self, _: &Cid) -> anyhow::Result>> { Err(anyhow::anyhow!( - "Blockstore#get not supported with DiscardBlockstore" + "Blockstore::get not supported with DiscardBlockstore" )) } fn put_keyed(&self, _: &Cid, _: &[u8]) -> anyhow::Result<()> { Ok(()) } + + fn put(&self, mh_code: u64, block: &dyn fvm_ipld_blockstore::Block) -> anyhow::Result { + let mh_code = C::try_from(mh_code)?; + let data = block.data(); + let codec = block.codec(); + let digest = mh_code.digest(data); + Ok(Cid::new_v1(codec, digest)) + } + + fn has(&self, _: &Cid) -> anyhow::Result { + Err(anyhow::anyhow!( + "Blockstore::has not supported with DiscardBlockstore" + )) + } + + fn put_many(&self, _: I) -> anyhow::Result<()> + where + Self: Sized, + B: fvm_ipld_blockstore::Block, + I: IntoIterator, + { + Ok(()) + } + + fn put_many_keyed(&self, _: I) -> anyhow::Result<()> + where + Self: Sized, + D: AsRef<[u8]>, + I: IntoIterator, + { + Ok(()) + } } diff --git a/fvm/src/call_manager/default.rs b/fvm/src/call_manager/default.rs index dfb35d237..453f3b5ee 100644 --- a/fvm/src/call_manager/default.rs +++ b/fvm/src/call_manager/default.rs @@ -928,7 +928,7 @@ impl EventsAccumulator { let root = if !self.events.is_empty() { const EVENTS_AMT_BITWIDTH: u32 = 5; let root = Amt::new_from_iter_with_bit_width( - DiscardBlockstore, + DiscardBlockstore::default(), EVENTS_AMT_BITWIDTH, self.events.iter().cloned(), ) diff --git a/fvm/src/machine/default.rs b/fvm/src/machine/default.rs index 023ec84b6..33efd6025 100644 --- a/fvm/src/machine/default.rs +++ b/fvm/src/machine/default.rs @@ -4,7 +4,8 @@ use std::ops::RangeInclusive; use anyhow::{anyhow, Context as _}; use cid::Cid; -use fvm_ipld_blockstore::{Block, Blockstore, Buffered}; +use fvm_ipld_blockstore::{Blockstore, Buffered}; +use fvm_ipld_encoding::ipld_block::IpldBlock; use fvm_ipld_encoding::{to_vec, CborStore, DAG_CBOR}; use fvm_shared::version::NetworkVersion; use log::debug; @@ -24,8 +25,9 @@ use crate::EMPTY_ARR_CID; lazy_static::lazy_static! { /// Pre-serialized block containing the empty array - pub static ref EMPTY_ARRAY_BLOCK: Block> = { - Block::new(DAG_CBOR, to_vec::<[(); 0]>(&[]).unwrap()) + pub static ref EMPTY_ARRAY_BLOCK: IpldBlock = IpldBlock { + codec: DAG_CBOR, + data: to_vec::<[(); 0]>(&[]).unwrap(), }; } @@ -194,7 +196,7 @@ where // Helper method that puts certain "empty" types in the blockstore. // These types are privileged by some parts of the system (eg. as the default actor state). fn put_empty_blocks(blockstore: B) -> anyhow::Result<()> { - let empty_arr_cid = blockstore.put(Blake2b256, &EMPTY_ARRAY_BLOCK)?; + let empty_arr_cid = blockstore.put(Blake2b256.into(), &*EMPTY_ARRAY_BLOCK)?; debug_assert!( empty_arr_cid == *EMPTY_ARR_CID, diff --git a/fvm/tests/default_kernel/mod.rs b/fvm/tests/default_kernel/mod.rs index 3827e9f45..5e167c2ce 100644 --- a/fvm/tests/default_kernel/mod.rs +++ b/fvm/tests/default_kernel/mod.rs @@ -5,7 +5,7 @@ use std::rc::Rc; // test target use fvm::kernel::default::DefaultKernel; -use fvm::kernel::{Block, BlockRegistry}; +use fvm::kernel::BlockRegistry; use fvm::Kernel; use multihash::Code; use num_traits::Zero; diff --git a/fvm/tests/default_kernel/ops.rs b/fvm/tests/default_kernel/ops.rs index 381a00757..cb044febe 100644 --- a/fvm/tests/default_kernel/ops.rs +++ b/fvm/tests/default_kernel/ops.rs @@ -177,7 +177,6 @@ mod ipld { "charge_gas should only be called exactly once per block_link" ); - let expected_block = Block::new(cid.codec(), block); let expected_create_price = call_manager .machine .context() @@ -190,7 +189,7 @@ mod ipld { .price_list .on_block_link( SupportedHashes::try_from(cid.hash().code()).unwrap(), - expected_block.size() as usize, + block.len(), ) .total(); diff --git a/testing/integration/src/tester.rs b/testing/integration/src/tester.rs index 23fedf922..2b68dcc3d 100644 --- a/testing/integration/src/tester.rs +++ b/testing/integration/src/tester.rs @@ -9,7 +9,7 @@ use fvm::externs::Externs; use fvm::machine::{DefaultMachine, Machine, MachineContext, NetworkConfig}; use fvm::state_tree::{ActorState, StateTree}; use fvm::{init_actor, system_actor, DefaultKernel}; -use fvm_ipld_blockstore::{Block, Blockstore, MemoryBlockstore}; +use fvm_ipld_blockstore::{Blockstore, MemoryBlockstore}; use fvm_ipld_encoding::{ser, CborStore}; use fvm_shared::address::{Address, Protocol}; use fvm_shared::econ::TokenAmount; @@ -421,12 +421,6 @@ impl BasicTester { /// Inserts the WASM code for the actor into the blockstore. fn put_wasm_code(blockstore: &impl Blockstore, wasm_binary: &[u8]) -> Result { - let cid = blockstore.put( - Code::Blake2b256, - &Block { - codec: IPLD_RAW, - data: wasm_binary, - }, - )?; + let cid = blockstore.put(Code::Blake2b256.into(), &(IPLD_RAW, wasm_binary))?; Ok(cid) } diff --git a/testing/integration/tests/fil-integer-overflow-actor/src/actor/blockstore.rs b/testing/integration/tests/fil-integer-overflow-actor/src/actor/blockstore.rs index d74565ef3..5d2b0264e 100644 --- a/testing/integration/tests/fil-integer-overflow-actor/src/actor/blockstore.rs +++ b/testing/integration/tests/fil-integer-overflow-actor/src/actor/blockstore.rs @@ -1,9 +1,6 @@ // Copyright 2021-2023 Protocol Labs // SPDX-License-Identifier: Apache-2.0, MIT -use std::convert::TryFrom; - use anyhow::{anyhow, Result}; -use cid::multihash::Code; use cid::Cid; use fvm_ipld_blockstore::Block; use fvm_sdk as sdk; @@ -20,22 +17,18 @@ impl fvm_ipld_blockstore::Blockstore for Blockstore { } fn put_keyed(&self, k: &Cid, block: &[u8]) -> Result<()> { - let code = Code::try_from(k.hash().code()).map_err(|e| anyhow!(e.to_string()))?; - let k2 = self.put(code, &Block::new(k.codec(), block))?; + let k2 = self.put(k.hash().code(), &(k.codec(), block))?; if k != &k2 { return Err(anyhow!("put block with cid {} but has cid {}", k, k2)); } Ok(()) } - fn put(&self, code: Code, block: &Block) -> Result - where - D: AsRef<[u8]>, - { + fn put(&self, mh_code: u64, block: &dyn Block) -> Result { // TODO: Don't hard-code the size. Unfortunately, there's no good way to get it from the // codec at the moment. const SIZE: u32 = 32; - let k = sdk::ipld::put(code.into(), SIZE, block.codec, block.data.as_ref()) + let k = sdk::ipld::put(mh_code, SIZE, block.codec(), block.data()) .map_err(|e| anyhow!("put failed with {:?}", e))?; Ok(k) } diff --git a/testing/integration/tests/main.rs b/testing/integration/tests/main.rs index 290bf532e..2efa02614 100644 --- a/testing/integration/tests/main.rs +++ b/testing/integration/tests/main.rs @@ -961,4 +961,8 @@ impl Blockstore for FailingBlockstore { fn put_keyed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { self.target.put_keyed(k, block) } + + fn put(&self, mh_code: u64, block: &dyn fvm_ipld_blockstore::Block) -> anyhow::Result { + self.target.put(mh_code, block) + } }