OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-proto-peer / test / creator-writer-backfill.probe.mjs

62 lines · javascript ref:
// PROBE (viability of Mechanism A): can a FRESH store, holding the same writable keypair as an existing
// populated core, BACKFILL that core from a peer (instead of forking it), then continue at the tip?
//
// This is the linchpin for healing a poisoned CREATOR: its genesis writer key is deterministic
// (_gsKeyPair), so a fresh corestore re-opens the SAME writable core EMPTY. If hypercore lets that empty
// writable core replicate the existing history from a peer (the healthy copy tabertron holds) BEFORE any
// local append, the creator can CONTINUE the one history (no fork). If hypercore REFUSES to backfill a
// writable core, Mechanism A is dead and we must rebuild from CAR (Mechanism B).
import '../lib/bare-globals.js'
import test from 'brittle'
import Hypercore from 'hypercore'
import crypto from 'hypercore-crypto'
import b4a from 'b4a'
import fs from 'bare-fs'

const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
const tmp = () => { const d = '/tmp/hpp-backfill-' + Math.floor(Math.random() * 1e9); fs.mkdirSync(d, { recursive: true }); return d }

test('fresh writable core can BACKFILL its own history from a peer before continuing (Mechanism A viability)', { timeout: 60000 }, async (t) => {
  const kp = crypto.keyPair() // the deterministic _gsKeyPair analog (shared genesis writer key)

  // P = the existing populated genesis-writer core (the healthy copy a peer holds)
  const P = new Hypercore(tmp(), { keyPair: kp })
  await P.ready()
  for (let i = 0; i < 5; i++) await P.append(b4a.from('block-' + i))
  t.is(P.length, 5, 'peer P holds the genesis writer at length 5')

  // F = a FRESH store opening the SAME writable key, EMPTY (the resync side store's genesis writer)
  const F = new Hypercore(tmp(), { keyPair: kp })
  await F.ready()
  t.is(F.length, 0, 'fresh F opens the same writable key at length 0')
  t.ok(F.writable, 'F is writable (holds the keypair)')

  // Replicate P <-> F BEFORE F writes anything. Does F backfill to 5?
  const s1 = P.replicate(true); const s2 = F.replicate(false)
  s1.pipe(s2).pipe(s1)
  s1.on('error', () => {}); s2.on('error', () => {})

  let backfilled = false
  for (let i = 0; i < 30 && !backfilled; i++) {
    await F.update().catch(() => {})
    if (F.length >= 5) backfilled = true; else await sleep(300)
  }
  t.ok(backfilled, 'RESULT: F backfilled its own writable core from P to length 5 (Mechanism A is viable)')

  if (backfilled) {
    let ok = true
    for (let i = 0; i < 5; i++) { const b = await F.get(i).catch(() => null); if (!b || b4a.toString(b) !== 'block-' + i) ok = false }
    t.ok(ok, 'F reads back the peer\'s 5 blocks correctly (same history, not a fork)')
    // continue at the tip
    let appended = false
    try { await F.append(b4a.from('block-5')); appended = true } catch (e) { t.comment('append after backfill threw: ' + e.message) }
    t.ok(appended && F.length === 6, 'F continued the SINGLE history at the tip (length 6) — no fork')
    // P must accept F's continuation (no conflict)
    let pGot6 = false
    for (let i = 0; i < 20 && !pGot6; i++) { await P.update().catch(() => {}); if (P.length >= 6) pGot6 = true; else await sleep(300) }
    t.ok(pGot6, 'P received F\'s continuation (length 6) — the two agree, no conflict')
  }

  await P.close(); await F.close()
})