diff --git a/wnfs-common/src/blockstore.rs b/wnfs-common/src/blockstore.rs index c683ad8c..64adfbf9 100644 --- a/wnfs-common/src/blockstore.rs +++ b/wnfs-common/src/blockstore.rs @@ -66,11 +66,35 @@ pub trait BlockStore: CondSync { /// /// This funciton allows the blockstore to choose the hashing function itself. /// The hashing function that was chosen will be readable from the `Cid` metadata. + /// + /// If you need control over the concrete hashing function that's used, see `put_block_keyed`. fn put_block( &self, bytes: impl Into + CondSend, codec: u64, - ) -> impl Future> + CondSend; + ) -> impl Future> + CondSend { + let bytes = bytes.into(); + async move { + let cid = self.create_cid(&bytes, codec)?; + self.put_block_keyed(cid, bytes).await?; + Ok(cid) + } + } + + /// Put a block of data into this blockstore. The block's CID needs to match the CID given. + /// + /// It's up to the blockstore whether to check this fact or assume it when this function is called. + /// + /// The default implementation of `put_block` will use this function under the hood and use + /// the correct CID provided by the `create_cid` function. + /// + /// This is useful to be able to add blocks that were generated from other + /// clients with differently configured hashing functions to this blockstore. + fn put_block_keyed( + &self, + cid: Cid, + bytes: impl Into + CondSend, + ) -> impl Future> + CondSend; /// Find out whether a call to `get_block` would return with a result or not. /// @@ -108,6 +132,10 @@ impl BlockStore for &B { (**self).put_block(bytes, codec).await } + async fn put_block_keyed(&self, cid: Cid, bytes: impl Into + CondSend) -> Result<()> { + (**self).put_block_keyed(cid, bytes).await + } + async fn has_block(&self, cid: &Cid) -> Result { (**self).has_block(cid).await } @@ -126,6 +154,10 @@ impl BlockStore for Box { (**self).put_block(bytes, codec).await } + async fn put_block_keyed(&self, cid: Cid, bytes: impl Into + CondSend) -> Result<()> { + (**self).put_block_keyed(cid, bytes).await + } + async fn has_block(&self, cid: &Cid) -> Result { (**self).has_block(cid).await } @@ -165,17 +197,10 @@ impl BlockStore for MemoryBlockStore { Ok(bytes) } - async fn put_block(&self, bytes: impl Into + CondSend, codec: u64) -> Result { - // Convert the bytes into a Bytes object - let bytes: Bytes = bytes.into(); + async fn put_block_keyed(&self, cid: Cid, bytes: impl Into + CondSend) -> Result<()> { + self.0.lock().insert(cid, bytes.into()); - // Try to build the CID from the bytes and codec - let cid = self.create_cid(&bytes, codec)?; - - // Insert the bytes into the HashMap using the CID as the key - self.0.lock().insert(cid, bytes); - - Ok(cid) + Ok(()) } async fn has_block(&self, cid: &Cid) -> Result { diff --git a/wnfs-common/src/utils/test.rs b/wnfs-common/src/utils/test.rs index 78994cc3..c173da73 100644 --- a/wnfs-common/src/utils/test.rs +++ b/wnfs-common/src/utils/test.rs @@ -122,6 +122,11 @@ impl BlockStore for SnapshotBlockStore { self.inner.put_block(bytes, codec).await } + #[inline] + async fn put_block_keyed(&self, cid: Cid, bytes: impl Into + CondSend) -> Result<()> { + self.inner.put_block_keyed(cid, bytes).await + } + #[inline] async fn has_block(&self, cid: &Cid) -> Result { self.inner.has_block(cid).await diff --git a/wnfs-wasm/src/fs/blockstore.rs b/wnfs-wasm/src/fs/blockstore.rs index d19987a5..681dc7e5 100644 --- a/wnfs-wasm/src/fs/blockstore.rs +++ b/wnfs-wasm/src/fs/blockstore.rs @@ -18,14 +18,14 @@ extern "C" { #[wasm_bindgen(typescript_type = "BlockStore")] pub type BlockStore; - #[wasm_bindgen(method, js_name = "putBlock")] - pub(crate) fn put_block(store: &BlockStore, bytes: Vec, codec: u32) -> Promise; - - #[wasm_bindgen(method, js_name = "hasBlock")] - pub(crate) fn has_block(store: &BlockStore, cid: Vec) -> Promise; + #[wasm_bindgen(method, js_name = "putBlockKeyed")] + pub(crate) fn put_block_keyed(store: &BlockStore, cid: Vec, bytes: Vec) -> Promise; #[wasm_bindgen(method, js_name = "getBlock")] pub(crate) fn get_block(store: &BlockStore, cid: Vec) -> Promise; + + #[wasm_bindgen(method, js_name = "hasBlock")] + pub(crate) fn has_block(store: &BlockStore, cid: Vec) -> Promise; } //-------------------------------------------------------------------------------------------------- @@ -41,18 +41,14 @@ pub struct ForeignBlockStore(pub(crate) BlockStore); //-------------------------------------------------------------------------------------------------- impl WnfsBlockStore for ForeignBlockStore { - async fn put_block(&self, bytes: impl Into, codec: u64) -> Result { + async fn put_block_keyed(&self, cid: Cid, bytes: impl Into) -> Result<()> { let bytes: Bytes = bytes.into(); - let value = JsFuture::from(self.0.put_block(bytes.into(), codec.try_into()?)) + JsFuture::from(self.0.put_block_keyed(cid.to_bytes(), bytes.into())) .await .map_err(anyhow_error("Cannot put block: {:?}"))?; - // Convert the value to a vector of bytes. - let bytes = Uint8Array::new(&value).to_vec(); - - // Construct CID from the bytes. - Ok(Cid::try_from(&bytes[..])?) + Ok(()) } async fn get_block(&self, cid: &Cid) -> Result { diff --git a/wnfs-wasm/src/fs/types.rs b/wnfs-wasm/src/fs/types.rs index 3b52cbd1..002d4344 100644 --- a/wnfs-wasm/src/fs/types.rs +++ b/wnfs-wasm/src/fs/types.rs @@ -3,7 +3,8 @@ use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen(typescript_custom_section)] const TS_BLOCKSTORE: &'static str = r#" export interface BlockStore { - putBlock(bytes: Uint8Array, code: number): Promise; + putBlockKeyed(cid: Uint8Array, bytes: Uint8Array): Promise; getBlock(cid: Uint8Array): Promise; + hasBlock(cid: Uint8Array): Promise; } "#; diff --git a/wnfs-wasm/tests/mock.ts b/wnfs-wasm/tests/mock.ts index 4a7423c5..695a79fd 100644 --- a/wnfs-wasm/tests/mock.ts +++ b/wnfs-wasm/tests/mock.ts @@ -35,11 +35,9 @@ class MemoryBlockStore { } /** Retrieves an array of bytes from the block store with given CID. */ - async putBlock(bytes: Uint8Array, codec: number): Promise { - const hash = await sha256.digest(bytes); - const cid = CID.create(1, codec, hash); - this.store.set(cid.toString(), bytes); - return cid.bytes; + async putBlockKeyed(cid: Uint8Array, bytes: Uint8Array): Promise { + const decodedCid = CID.decode(cid); + this.store.set(decodedCid.toString(), bytes); } /** Finds out whether a block is retrievable from this blockstore */ diff --git a/wnfs-wasm/tests/public.spec.ts b/wnfs-wasm/tests/public.spec.ts index 3cc34a18..02e4df67 100644 --- a/wnfs-wasm/tests/public.spec.ts +++ b/wnfs-wasm/tests/public.spec.ts @@ -368,6 +368,6 @@ test.describe("PublicDirectory", () => { }); expect(result).not.toBeUndefined(); - expect(result).toEqual("bafkreibm6jg3ux5qumhcn2b3flc3tyu6dmlb4xa7u5bf44yegnrjhc4yeq"); + expect(result).toEqual("bafkr4ihkr4ld3m4gqkjf4reryxsy2s5tkbxprqkow6fin2iiyvreuzzab4"); }); }); diff --git a/wnfs/examples/tiered_blockstores.rs b/wnfs/examples/tiered_blockstores.rs index 75d067db..078f42a3 100644 --- a/wnfs/examples/tiered_blockstores.rs +++ b/wnfs/examples/tiered_blockstores.rs @@ -97,16 +97,19 @@ struct TieredBlockStore { impl BlockStore for TieredBlockStore { async fn get_block(&self, cid: &Cid) -> Result { - match self.hot.get_block(cid).await { - Ok(block) => Ok(block), - // We could technically get better about this - // and only match "NotFound" errors. - Err(_) => self.cold.get_block(cid).await, + if self.hot.has_block(cid).await? { + self.hot.get_block(cid).await + } else { + self.cold.get_block(cid).await } } async fn put_block(&self, bytes: impl Into + CondSend, codec: u64) -> Result { - self.hot.put_block(bytes.into(), codec).await + self.hot.put_block(bytes, codec).await + } + + async fn put_block_keyed(&self, cid: Cid, bytes: impl Into + CondSend) -> Result<()> { + self.hot.put_block_keyed(cid, bytes).await } async fn has_block(&self, cid: &Cid) -> Result {