1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
use std::rc::Rc;
use std::sync::Arc;

use anyhow::Result;
use cid::{multihash, Cid};

pub mod tracking;

mod memory;
pub use memory::MemoryBlockstore;

mod block;
pub use block::*;

/// An IPLD blockstore suitable for injection into the FVM.
///
/// The cgo blockstore adapter implements this trait.
pub trait Blockstore {
    /// Gets the block from the blockstore.
    fn get(&self, k: &Cid) -> Result<Option<Vec<u8>>>;

    /// Put a block with a pre-computed cid.
    ///
    /// If you don't yet know the CID, use put. Some blockstores will re-compute the CID internally
    /// even if you provide it.
    ///
    /// If you _do_ already know the CID, use this method as some blockstores _won't_ recompute it.
    fn put_keyed(&self, k: &Cid, block: &[u8]) -> Result<()>;

    /// Checks if the blockstore has the specified block.
    fn has(&self, k: &Cid) -> Result<bool> {
        Ok(self.get(k)?.is_some())
    }

    /// Puts the block into the blockstore, computing the hash with the specified multicodec.
    ///
    /// By default, this defers to put.
    fn put<D>(&self, mh_code: multihash::Code, block: &Block<D>) -> Result<Cid>
    where
        Self: Sized,
        D: AsRef<[u8]>,
    {
        let k = block.cid(mh_code);
        self.put_keyed(&k, block.as_ref())?;
        Ok(k)
    }

    /// Bulk put blocks into the blockstore.
    ///
    ///
    /// ```rust
    /// use multihash::Code::Blake2b256;
    /// use fvm_ipld_blockstore::{Blockstore, MemoryBlockstore, Block};
    ///
    /// let bs = MemoryBlockstore::default();
    /// let blocks = vec![Block::new(0x55, vec![0, 1, 2])];
    /// bs.put_many(blocks.iter().map(|b| (Blake2b256, b.into()))).unwrap();
    /// ```
    fn put_many<D, I>(&self, blocks: I) -> Result<()>
    where
        Self: Sized,
        D: AsRef<[u8]>,
        I: IntoIterator<Item = (multihash::Code, Block<D>)>,
    {
        self.put_many_keyed(blocks.into_iter().map(|(mc, b)| (b.cid(mc), b)))?;
        Ok(())
    }

    /// Bulk-put pre-keyed blocks into the blockstore.
    ///
    /// By default, this defers to put_keyed.
    fn put_many_keyed<D, I>(&self, blocks: I) -> Result<()>
    where
        Self: Sized,
        D: AsRef<[u8]>,
        I: IntoIterator<Item = (Cid, D)>,
    {
        for (c, b) in blocks {
            self.put_keyed(&c, b.as_ref())?
        }
        Ok(())
    }
}

pub trait Buffered: Blockstore {
    fn flush(&self, root: &Cid) -> Result<()>;
}

macro_rules! impl_blockstore {
    ($($typ:ty),+) => {
        $(
            impl<BS> Blockstore for $typ where
            BS: Blockstore, {
                fn get(&self, k: &Cid) -> Result<Option<Vec<u8>>> {
                    (**self).get(k)
                }

                fn put_keyed(&self, k: &Cid, block: &[u8]) -> Result<()> {
                    (**self).put_keyed(k, block)
                }

                fn has(&self, k: &Cid) -> Result<bool> {
                    (**self).has(k)
                }

                fn put<D>(&self, mh_code: multihash::Code, block: &Block<D>) -> Result<Cid>
                where
                    Self: Sized,
                    D: AsRef<[u8]>,
                {
                    (**self).put(mh_code, block)
                }

                fn put_many<D, I>(&self, blocks: I) -> Result<()>
                where
                    Self: Sized,
                    D: AsRef<[u8]>,
                    I: IntoIterator<Item = (multihash::Code, Block<D>)>,
                {
                    (**self).put_many(blocks)
                }

                fn put_many_keyed<D, I>(&self, blocks: I) -> Result<()>
                where
                    Self: Sized,
                    D: AsRef<[u8]>,
                    I: IntoIterator<Item = (Cid, D)>,
                {
                    (**self).put_many_keyed(blocks)
                }
            }
        )+
    }
}

impl_blockstore!(Arc<BS>, Rc<BS>, &BS);