ipld_traversal/
blockstore.rs

1use anyhow::Result;
2use libipld::{
3    cid::multihash::{self, MultihashDigest},
4    Cid,
5};
6use std::{
7    collections::HashMap,
8    rc::Rc,
9    sync::{Arc, Mutex},
10};
11
12// Same block/blockstore implementation as the fvm.
13// Will import from there once it gets published separately.
14
15#[derive(Copy, Clone, Debug, Eq, PartialEq)]
16pub struct Block<D>
17where
18    D: AsRef<[u8]> + ?Sized,
19{
20    pub codec: u64,
21    pub data: D,
22}
23
24impl<D> Block<D>
25where
26    D: AsRef<[u8]> + ?Sized,
27{
28    pub fn new(codec: u64, data: D) -> Self
29    where
30        Self: Sized,
31        D: Sized,
32    {
33        Self { codec, data }
34    }
35
36    pub fn cid(&self, mh_code: multihash::Code) -> Cid {
37        Cid::new_v1(self.codec, mh_code.digest(self.data.as_ref()))
38    }
39
40    pub fn len(&self) -> usize {
41        self.data.as_ref().len()
42    }
43}
44
45impl<D> AsRef<[u8]> for Block<D>
46where
47    D: AsRef<[u8]>,
48{
49    fn as_ref(&self) -> &[u8] {
50        self.data.as_ref()
51    }
52}
53
54impl<'a, D> From<&'a Block<D>> for Block<&'a [u8]>
55where
56    D: AsRef<[u8]>,
57{
58    fn from(b: &'a Block<D>) -> Self {
59        Block {
60            codec: b.codec,
61            data: b.data.as_ref(),
62        }
63    }
64}
65
66/// An IPLD blockstore suitable for injection into the FVM.
67///
68/// The cgo blockstore adapter implements this trait.
69pub trait Blockstore {
70    /// Gets the block from the blockstore.
71    fn get(&self, k: &Cid) -> Result<Option<Vec<u8>>>;
72
73    /// Put a block with a pre-computed cid.
74    ///
75    /// If you don't yet know the CID, use put. Some blockstores will re-compute the CID internally
76    /// even if you provide it.
77    ///
78    /// If you _do_ already know the CID, use this method as some blockstores _won't_ recompute it.
79    fn put_keyed(&self, k: &Cid, block: &[u8]) -> Result<()>;
80
81    /// Checks if the blockstore has the specified block.
82    fn has(&self, k: &Cid) -> Result<bool> {
83        Ok(self.get(k)?.is_some())
84    }
85
86    /// Puts the block into the blockstore, computing the hash with the specified multicodec.
87    ///
88    /// By default, this defers to put.
89    fn put<D>(&self, mh_code: multihash::Code, block: &Block<D>) -> Result<Cid>
90    where
91        Self: Sized,
92        D: AsRef<[u8]>,
93    {
94        let k = block.cid(mh_code);
95        self.put_keyed(&k, block.as_ref())?;
96        Ok(k)
97    }
98
99    /// Bulk put blocks into the blockstore.
100    fn put_many<D, I>(&self, blocks: I) -> Result<()>
101    where
102        Self: Sized,
103        D: AsRef<[u8]>,
104        I: IntoIterator<Item = (multihash::Code, Block<D>)>,
105    {
106        self.put_many_keyed(blocks.into_iter().map(|(mc, b)| (b.cid(mc), b)))?;
107        Ok(())
108    }
109
110    /// Bulk-put pre-keyed blocks into the blockstore.
111    ///
112    /// By default, this defers to put_keyed.
113    fn put_many_keyed<D, I>(&self, blocks: I) -> Result<()>
114    where
115        Self: Sized,
116        D: AsRef<[u8]>,
117        I: IntoIterator<Item = (Cid, D)>,
118    {
119        for (c, b) in blocks {
120            self.put_keyed(&c, b.as_ref())?
121        }
122        Ok(())
123    }
124
125    /// Deletes the block for the given Cid key.
126    fn delete_block(&self, k: &Cid) -> Result<()>;
127}
128
129impl<BS> Blockstore for &BS
130where
131    BS: Blockstore,
132{
133    fn get(&self, k: &Cid) -> Result<Option<Vec<u8>>> {
134        (*self).get(k)
135    }
136
137    fn put_keyed(&self, k: &Cid, block: &[u8]) -> Result<()> {
138        (*self).put_keyed(k, block)
139    }
140
141    fn has(&self, k: &Cid) -> Result<bool> {
142        (*self).has(k)
143    }
144
145    fn delete_block(&self, k: &Cid) -> Result<()> {
146        (*self).delete_block(k)
147    }
148
149    fn put<D>(&self, mh_code: multihash::Code, block: &Block<D>) -> Result<Cid>
150    where
151        Self: Sized,
152        D: AsRef<[u8]>,
153    {
154        (*self).put(mh_code, block)
155    }
156
157    fn put_many<D, I>(&self, blocks: I) -> Result<()>
158    where
159        Self: Sized,
160        D: AsRef<[u8]>,
161        I: IntoIterator<Item = (multihash::Code, Block<D>)>,
162    {
163        (*self).put_many(blocks)
164    }
165
166    fn put_many_keyed<D, I>(&self, blocks: I) -> Result<()>
167    where
168        Self: Sized,
169        D: AsRef<[u8]>,
170        I: IntoIterator<Item = (Cid, D)>,
171    {
172        (*self).put_many_keyed(blocks)
173    }
174}
175
176impl<BS> Blockstore for Rc<BS>
177where
178    BS: Blockstore,
179{
180    fn get(&self, k: &Cid) -> Result<Option<Vec<u8>>> {
181        (**self).get(k)
182    }
183
184    fn put_keyed(&self, k: &Cid, block: &[u8]) -> Result<()> {
185        (**self).put_keyed(k, block)
186    }
187
188    fn has(&self, k: &Cid) -> Result<bool> {
189        (**self).has(k)
190    }
191
192    fn delete_block(&self, k: &Cid) -> Result<()> {
193        (**self).delete_block(k)
194    }
195
196    fn put<D>(&self, mh_code: multihash::Code, block: &Block<D>) -> Result<Cid>
197    where
198        Self: Sized,
199        D: AsRef<[u8]>,
200    {
201        (**self).put(mh_code, block)
202    }
203
204    fn put_many<D, I>(&self, blocks: I) -> Result<()>
205    where
206        Self: Sized,
207        D: AsRef<[u8]>,
208        I: IntoIterator<Item = (multihash::Code, Block<D>)>,
209    {
210        (**self).put_many(blocks)
211    }
212
213    fn put_many_keyed<D, I>(&self, blocks: I) -> Result<()>
214    where
215        Self: Sized,
216        D: AsRef<[u8]>,
217        I: IntoIterator<Item = (Cid, D)>,
218    {
219        (**self).put_many_keyed(blocks)
220    }
221}
222
223#[derive(Debug, Default, Clone)]
224pub struct MemoryBlockstore {
225    blocks: Arc<Mutex<HashMap<Cid, Vec<u8>>>>,
226}
227
228impl MemoryBlockstore {
229    pub fn new() -> Self {
230        Self::default()
231    }
232}
233
234impl Blockstore for MemoryBlockstore {
235    fn has(&self, k: &Cid) -> Result<bool> {
236        Ok(self.blocks.lock().unwrap().contains_key(k))
237    }
238
239    fn get(&self, k: &Cid) -> Result<Option<Vec<u8>>> {
240        Ok(self.blocks.lock().unwrap().get(k).cloned())
241    }
242
243    fn put_keyed(&self, k: &Cid, block: &[u8]) -> Result<()> {
244        self.blocks.lock().unwrap().insert(*k, block.into());
245        Ok(())
246    }
247
248    fn delete_block(&self, k: &Cid) -> Result<()> {
249        self.blocks.lock().unwrap().remove(k);
250        Ok(())
251    }
252}