Skip to main content

forest/libp2p_bitswap/
store.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use super::*;
5use multihash_derive::MultihashDigest;
6use std::marker::PhantomData;
7use std::ops::Deref;
8
9/// Trait implemented by a block store for reading.
10#[auto_impl::auto_impl(&, Arc)]
11pub trait BitswapStoreRead {
12    /// A have query needs to know if the block store contains the block.
13    fn contains(&self, cid: &Cid) -> anyhow::Result<bool>;
14
15    /// A block query needs to retrieve the block from the store.
16    fn get(&self, cid: &Cid) -> anyhow::Result<Option<Vec<u8>>>;
17}
18
19/// Trait implemented by a block store for reading and writing.
20#[auto_impl::auto_impl(&, Arc)]
21pub trait BitswapStoreReadWrite: BitswapStoreRead + Send + Sync + 'static {
22    /// The hashes parameters.
23    type Hashes: MultihashDigest<64>;
24
25    /// A block response needs to insert the block into the store.
26    fn insert(&self, block: &Block64<Self::Hashes>) -> anyhow::Result<()>;
27}
28
29pub type Block64<H> = Block<H, 64>;
30
31/// Block
32#[derive(Clone, Debug)]
33pub struct Block<H, const S: usize> {
34    /// Content identifier.
35    cid: Cid,
36    /// Binary data.
37    data: Vec<u8>,
38    _pd: PhantomData<H>,
39}
40
41impl<H, const S: usize> Deref for Block<H, S> {
42    type Target = Cid;
43
44    fn deref(&self) -> &Self::Target {
45        &self.cid
46    }
47}
48
49impl<H, const S: usize> PartialEq for Block<H, S> {
50    fn eq(&self, other: &Self) -> bool {
51        self.cid == other.cid
52    }
53}
54
55impl<H, const S: usize> Eq for Block<H, S> {}
56
57impl<H: MultihashDigest<S>, const S: usize> Block<H, S> {
58    /// Creates a new block. Returns an error if the hash doesn't match
59    /// the data.
60    pub fn new(cid: Cid, data: Vec<u8>) -> anyhow::Result<Self> {
61        Self::verify_cid(&cid, &data)?;
62        Ok(Self {
63            cid,
64            data,
65            _pd: Default::default(),
66        })
67    }
68
69    /// Returns the [`Cid`].
70    pub fn cid(&self) -> &Cid {
71        &self.cid
72    }
73
74    /// Returns the payload.
75    pub fn data(&self) -> &[u8] {
76        &self.data
77    }
78
79    fn verify_cid(cid: &Cid, payload: &[u8]) -> anyhow::Result<()> {
80        let code = cid.hash().code();
81        let mh = H::try_from(code)
82            .map_err(|_| anyhow::anyhow!("unsupported multihash code {code}"))?
83            .digest(payload);
84        if mh.digest() != cid.hash().digest() {
85            anyhow::bail!("invalid multihash digest");
86        }
87        Ok(())
88    }
89}