From 5bed4e01da690f24f1751e99ca98f3dbb4325a06 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 3 Mar 2023 15:37:32 -0800 Subject: [PATCH] Adapt fvm to blockstore changes --- fvm/src/blockstore/buffered.rs | 33 ++++++++++-- fvm/src/blockstore/discard.rs | 51 +++++++++++++++++-- fvm/src/call_manager/default.rs | 2 +- fvm/src/machine/default.rs | 10 ++-- fvm/tests/default_kernel/mod.rs | 2 +- fvm/tests/default_kernel/ops.rs | 3 +- .../src/actor/blockstore.rs | 5 +- 7 files changed, 87 insertions(+), 19 deletions(-) diff --git a/fvm/src/blockstore/buffered.rs b/fvm/src/blockstore/buffered.rs index 17107b98bf..606d356371 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 9021c72d66..4e4e1a4792 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 dfb35d2375..453f3b5ee9 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 023ec84b6c..33efd60250 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 3827e9f458..5e167c2ce6 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 381a00757f..cb044febe1 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/tests/fil-integer-overflow-actor/src/actor/blockstore.rs b/testing/integration/tests/fil-integer-overflow-actor/src/actor/blockstore.rs index d74565ef38..a55a8a2f6e 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 @@ -28,10 +28,7 @@ impl fvm_ipld_blockstore::Blockstore for Blockstore { 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;