Skip to content

Commit

Permalink
feat: implement file blockstore (#660)
Browse files Browse the repository at this point in the history
  • Loading branch information
cernicc authored Jan 9, 2025
1 parent 866115c commit 31533cd
Show file tree
Hide file tree
Showing 12 changed files with 662 additions and 42 deletions.
29 changes: 28 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ axum = "0.7.5"
base64 = "0.22.1"
bitflags = "2.5.0"
blake2b_simd = { version = "1.0.2", default-features = false }
blockstore = "0.7.1"
bls12_381 = "0.8"
bs58 = "0.5.1"
byteorder = "1.5.0"
Expand Down
6 changes: 6 additions & 0 deletions mater/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ name = "mater" # name WIP
repository.workspace = true
version = "0.1.0"

[features]
blockstore = ["dep:blockstore"]

[dependencies]
async-stream.workspace = true
bitflags.workspace = true
Expand All @@ -27,6 +30,9 @@ tokio = { workspace = true, features = ["fs", "macros", "rt-multi-thread"] }
tokio-stream.workspace = true
tokio-util = { workspace = true, features = ["io"] }

# Optional dependencies
blockstore = { workspace = true, optional = true }

[dev-dependencies]
criterion = { workspace = true, features = ["async_tokio", "html_reports"] }
rand = { workspace = true, default_features = true }
Expand Down
6 changes: 5 additions & 1 deletion mater/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ mod v2;

// We need to re-expose this because `read_block` returns `(Cid, Vec<u8>)`.
pub use ipld_core::cid::Cid;
pub use stores::{create_filestore, Blockstore, Config};
pub use stores::{create_filestore, Blockstore, Config, FileBlockstore};
pub use v1::{Header as CarV1Header, Reader as CarV1Reader, Writer as CarV1Writer};
pub use v2::{
verify_cid, Characteristics, Header as CarV2Header, Index, IndexEntry, IndexSorted,
Expand Down Expand Up @@ -47,6 +47,10 @@ pub enum Error {
#[error("CAR file must have roots")]
EmptyRootsError,

/// Returned when the number of roots is wrong.
#[error("Wrong number of roots")]
WrongNumberOfRoots,

/// Unknown type of index. Supported indexes are
/// [`IndexSorted`] and [`MultihashIndexSorted`].
#[error("unknown index type {0}")]
Expand Down
10 changes: 9 additions & 1 deletion mater/lib/src/multicodec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
//! as per the [code table](https://github.com/multiformats/multicodec/blob/c954a787dc6a17d099653e5f90d26fbd177d2074/table.csv).
use digest::Digest;
use ipld_core::cid::multihash::Multihash;
use ipld_core::cid::{multihash::Multihash, CidGeneric};

pub const SHA_256_CODE: u64 = 0x12;
pub const SHA_512_CODE: u64 = 0x13;
pub const RAW_CODE: u64 = 0x55;
pub const DAG_PB_CODE: u64 = 0x70;

/// The IDENTITY multicodec code
pub const IDENTITY_CODE: u64 = 0x00;

/// Trait to ease implementing generic multihash generation.
pub(crate) trait MultihashCode {
/// Multihash code as defined in the [specification](https://github.com/multiformats/multicodec/blob/c954a787dc6a17d099653e5f90d26fbd177d2074/table.csv).
Expand All @@ -35,3 +38,8 @@ where
Multihash::wrap(H::CODE, &hashed_bytes)
.expect("the digest should be valid (enforced by the type system)")
}

// Returns Some(data) if the CID is an identity. If not, None is returned.
pub fn get_identity_data<const S: usize>(cid: &CidGeneric<S>) -> Option<&[u8]> {
(cid.hash().code() == IDENTITY_CODE).then(|| cid.hash().digest())
}
17 changes: 7 additions & 10 deletions mater/lib/src/stores/blockstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ impl Blockstore {

/// Get the [`CarV2Header`] that will be written out.
fn header_v2(&self) -> CarV2Header {
let data_offset = CarV2Header::SIZE as u64;
let data_offset = CarV2Header::SIZE;
let data_size: u64 = self
.blocks
.iter()
Expand Down Expand Up @@ -298,16 +298,13 @@ mod tests {
car_reader.read_pragma().await.unwrap();

let car_v2_header = car_reader.read_header().await.unwrap();
assert_eq!(car_v2_header.data_offset, CarV2Header::SIZE as u64);
assert_eq!(car_v2_header.data_offset, CarV2Header::SIZE);
// Extracted with go-car and validated with an hex viewer
// to extract the values, run the following commands:
// $ car inspect <output of this process>
// The dump is necessary because go-car does not support parametrization
assert_eq!(car_v2_header.data_size, 1358);
assert_eq!(
car_v2_header.index_offset,
(CarV2Header::SIZE as u64) + 1358
);
assert_eq!(car_v2_header.index_offset, CarV2Header::SIZE + 1358);

let car_v1_header = car_reader.read_v1_header().await.unwrap();
assert_eq!(car_v1_header.roots.len(), 1);
Expand Down Expand Up @@ -343,13 +340,13 @@ mod tests {
match index {
Index::MultihashIndexSorted(index) => {
// There's only Sha256
assert_eq!(index.0.len(), 1);
assert_eq!(index.len(), 1);

let index_sorted = &index.0[&SHA_256_CODE];
let index_sorted = &index[&SHA_256_CODE];
// There's only a single length
assert_eq!(index_sorted.0.len(), 1);
assert_eq!(index_sorted.len(), 1);

let single_width_index = &index_sorted.0[0];
let single_width_index = &index_sorted[0];
assert_eq!(single_width_index.count, 2);
// Sha256 output size (32) + the offset size (8)
assert_eq!(single_width_index.width, Sha256::output_size() as u32 + 8);
Expand Down
Loading

0 comments on commit 31533cd

Please sign in to comment.