summaryrefslogtreecommitdiffstats
path: root/src/swarm/blob.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-24 18:18:29 +0200
committertv <tv@krebsco.de>2026-10-24 18:18:29 +0200
commit09f2dfd083c4fcdce4c5ca7376353906eb025c42 (patch)
treee13141f10e3854408bd70d18d1bf31581abe5458 /src/swarm/blob.rs
parent371e52cb48bae99232547f6fae6a0487a85c2d04 (diff)
put remake content into blobs
Diffstat (limited to 'src/swarm/blob.rs')
-rw-r--r--src/swarm/blob.rs25
1 files changed, 21 insertions, 4 deletions
diff --git a/src/swarm/blob.rs b/src/swarm/blob.rs
index 6ff1618..8c891ae 100644
--- a/src/swarm/blob.rs
+++ b/src/swarm/blob.rs
@@ -2,8 +2,9 @@
//!
//! Large transfers can't go in one Mycelium message (it must arrive within Mycelium's
//! five-minute deadline), and a blob every node holds identically can come from many
-//! of them. Today the only kind of blob is an Automerge change by its hash, e.g. an
-//! epoch's snapshot change, which every node on that epoch holds byte for byte.
+//! of them. A blob is an Automerge change by its hash (e.g. an epoch's snapshot change,
+//! which every node on that epoch holds byte for byte), or content by its BLAKE3 hash
+//! (e.g. the new document of a `replace` or `import` remake).
//!
//! * Serving: a request without chunks gets the manifest (size, chunk size, a BLAKE3
//! hash per chunk); one with chunks gets each chunk as a message of its own. A node
@@ -62,7 +63,7 @@ pub(crate) struct Blobs {
}
struct Prepared {
- bytes: Vec<u8>,
+ bytes: Arc<Vec<u8>>,
hashes: Vec<[u8; 32]>,
}
@@ -152,8 +153,10 @@ async fn prepare(state: &AppState, id: BlobId) -> Option<Arc<Prepared>> {
})
.await
.ok()
- .flatten()?
+ .flatten()
+ .map(Arc::new)?
}
+ BlobId::Content(hash) => state.remake.content(&hash)?,
};
let chunk_size = state.blobs.chunk_size;
let prepared = tokio::task::spawn_blocking(move || {
@@ -454,6 +457,20 @@ fn expected_len(manifest: &Manifest, slot: usize) -> usize {
}
/// Downloads change `hash` from `peers` and checks it.
+/// Downloads the content with BLAKE3 hash `hash` from `peers` and checks it.
+pub(crate) async fn fetch_content(
+ state: &AppState,
+ hash: [u8; 32],
+ peers: Vec<String>,
+) -> Result<Vec<u8>> {
+ let id = BlobId::Content(hash);
+ let bytes = fetch(state, id, peers).await?;
+ if *blake3::hash(&bytes).as_bytes() != hash {
+ bail!("downloaded {id} doesn't match its hash");
+ }
+ Ok(bytes)
+}
+
pub(crate) async fn fetch_change(
state: &AppState,
hash: ChangeHash,