OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-proto-peer / test / blob-pointer-wiring.test.mjs

125 lines · javascript ref:
// The daemon's blob stack, composed EXACTLY as device-node.js composes it:
//   DualBlobStore( BlobPointerStore(sb, OverlayBlobStore), legacy BlobStore )
//
// atproto-store's own blob-pointer test proves the cross-node semantics against a fake statebase and a
// fake overlay. This one closes the gap that fake leaves: it runs the composition against a REAL
// StateBaseV3, a REAL HyperOverlay, and — the point of test 2 — the REAL splitKey from atproto-room,
// rather than the predicate BlobPointerStore duplicates internally. If `__blob__/<cid>` ever stopped
// being rejected as a record it would be materialized into a signed commit and published to the relay.
//
// Worth stating plainly: NO test sets storeBackend:'overlay' at the bootSwarmDevice level, yet BOTH live
// DIDs run it. This covers the blob half of that untested path. Run: bare test/blob-pointer-wiring.test.mjs
import '../lib/bare-globals.js'
import test from 'brittle'
import crypto from 'hypercore-crypto'
import fs from 'bare-fs'
import b4a from 'b4a'
import { StateBaseV3 } from 'atproto-room/lib/state-base.js'
import { RepoBase } from 'atproto-room/lib/repo-base.js'
import { openCorestore } from 'atproto-store/lib/corestore.js'
import { BlobStore } from 'atproto-store/lib/blob-store.js'
import { OverlayBlobStore } from 'atproto-store/lib/overlay-blob-store.js'
import { BlobPointerStore } from 'atproto-store/lib/blob-pointer-store.js'
import { PointerSubstrate } from 'atproto-store/lib/pointer-substrate.js'
import { OverlayRepoStore } from 'atproto-store/lib/overlay-repo-store.js'
import { DualBlobStore } from '../lib/dual-blob-store.js'
import { HyperOverlay } from 'hyper-overlay'

const DID = 'did:plc:blobptrwiring0000000000'
const AVATAR = b4a.from('\xff\xd8\xff\xe0 avatar bytes', 'binary')
const tmp = () => { const d = '/tmp/hpp-blobptr-' + Math.floor(Math.random() * 1e9); fs.mkdirSync(d, { recursive: true }); return d }

// Build the daemon's stack over a real StateBase + real overlay.
async function mkStack (t) {
  const sb = new StateBaseV3(tmp(), crypto.randomBytes(32), { roomSeed: crypto.randomBytes(32), network: false })
  await sb.ready(); t.teardown(() => sb.close())

  const repoRoot = tmp()
  const ovStore = openCorestore(tmp())
  const overlay = new HyperOverlay(ovStore, { namespace: 'atproto-repo-overlay:' + DID, destDir: repoRoot + '/.fetch' })
  await overlay.ready(); t.teardown(() => overlay.close())

  const membraneStore = openCorestore(tmp())
  const legacy = await new BlobStore(membraneStore, { name: 'membrane-blobs:' + DID }).ready()
  const overlayBlobs = await new OverlayBlobStore(repoRoot + '/blobs', { overlay, indexStore: membraneStore, name: 'overlay-blobs:' + DID }).ready()
  const blobs = new DualBlobStore(new BlobPointerStore(sb, overlayBlobs, { did: DID }), legacy)

  return { sb, blobs, legacy, overlayBlobs, overlay, repoRoot }
}

test('an upload through the daemon stack publishes a SHARED blob pointer into the real StateBase', async (t) => {
  const { sb, blobs, repoRoot } = await mkStack(t)

  const { cid, size } = await blobs.put(AVATAR, 'image/jpeg')
  const cidStr = cid.toString()

  const ptr = await sb.get('__blob__/' + cidStr)
  t.ok(ptr, 'the pointer reached the real StateBase (this is what replicates to co-owners)')
  t.ok(ptr.$oid, 'it carries the overlay oid — the handle a peer fetches bytes by')
  t.is(ptr.mimeType, 'image/jpeg', 'mime type is shared, not stranded in the node-local bee')
  t.is(ptr.size, size, 'size is shared')
  t.not(ptr.$oid, cidStr, 'oid != atproto CID — a peer cannot recompute this mapping, it must replicate')
  t.ok(JSON.stringify(ptr).length < 200, `pointer is tiny (${JSON.stringify(ptr).length} bytes) — no balloon in the log`)

  t.ok(fs.existsSync(repoRoot + '/blobs/' + cidStr), 'the BYTES are a content-addressed file, not a bee value')
  t.ok(b4a.equals((await blobs.get(cidStr)).bytes, AVATAR), 'and the blob still serves through the full stack')

  await blobs.close()
})

test('blob pointers are rejected as records by the REAL splitKey (never reach a signed commit)', async (t) => {
  const { sb, blobs, overlay } = await mkStack(t)

  // A real record alongside the blob pointer, through the same substrate the daemon signs from.
  const repo = new RepoBase(new PointerSubstrate(sb, await new OverlayRepoStore(tmp(), { overlay }).ready()), { did: DID })
  await repo.putRecord('app.bsky.feed.post', '1', { $type: 'app.bsky.feed.post', text: 'hi', createdAt: '2026-07-26T00:00:00.000Z' })
  const { cid } = await blobs.put(AVATAR, 'image/jpeg')

  const records = await repo.listRecords()
  t.is(records.length, 1, 'exactly ONE record — the blob pointer is not counted as one')
  t.is(records[0].collection, 'app.bsky.feed.post', 'and it is the real post')
  t.ok(await sb.get('__blob__/' + cid.toString()), 'while the blob pointer IS present in the shared state')

  await blobs.close()
})

test('the legacy dual-read fallback still works (pre-migration avatars do not 404)', async (t) => {
  const { blobs, legacy } = await mkStack(t)

  // A pre-migration blob exists ONLY in the legacy Hyperbee store, with no shared pointer.
  const oldBytes = b4a.from('OLD pre-migration avatar')
  const { cid: oldCid } = await legacy.put(oldBytes, 'image/png')

  t.ok(b4a.equals((await blobs.get(oldCid.toString())).bytes, oldBytes), 'legacy blob still served through the pointer layer')
  t.ok(await blobs.has(oldCid.toString()), 'has() still sees the legacy store')
  t.is(await blobs.get('bafkreiabsent000000000000000000000000000000000000000000'), null, 'a genuinely absent cid is still null')

  await blobs.close()
})

test('operator repair through the daemon stack: announce un-pointed blobs, re-register the files', async (t) => {
  const { sb, blobs, overlayBlobs } = await mkStack(t)

  // Stored straight on the byte layer: bytes + local metadata, never announced. This is the state every
  // blob uploaded before the pointer layer existed is in — the reason the repair needs a backfill at all.
  const { cid } = await overlayBlobs.put(AVATAR, 'image/jpeg')
  const cidStr = cid.toString()
  t.absent(await sb.get('__blob__/' + cidStr), 'pre-migration state: bytes are here but nothing is announced')

  const p = await blobs.backfillPointers()
  t.is(p.written, 1, 'the un-announced blob was published')
  t.is(p.unpublishable, 0, 'it had a local oid to point at')
  const ptr = await sb.get('__blob__/' + cidStr)
  t.ok(ptr && ptr.$oid, 'the pointer is now in the real StateBase — co-owners can resolve it')
  t.is(ptr.mimeType, 'image/jpeg', 'with its true mime type, not a guess')

  t.is((await blobs.backfillPointers()).written, 0, 'idempotent — a second repair announces nothing new')

  const r = await blobs.reindexOverlay()
  t.is(r.registered, 1, 'the blob FILE was re-registered as servable-by-oid')
  t.is(r.failed, 0, 'no failures')
  t.ok(b4a.equals((await blobs.get(cidStr)).bytes, AVATAR), 'and the blob still serves after repair')

  await blobs.close()
})