OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-proto-peer / test / signer-failover.test.js

63 lines · javascript ref:
// S1 failover (TDD): sign() must gate on the StateBase's presence-based holdsSigner() — NOT the __lease__
// ts-heartbeat — so exactly the elected signer signs, the survivor takes over on failover continuing the
// chain (no fork), and NOTHING ever appends __lease__ to the log (the ~20MB/day leak is gone).
//
// Two SwarmDevices share ONE in-memory linearized view (a converged co-owned StateBase), each with its OWN
// holdsSigner() (its presence-election result). Writing test-FIRST: on the current lease-gated sign() this
// goes RED (devA.sign() returns null with no __lease__ claimed); the swap to holdsSigner() turns it green.
// Run: `bare test/signer-failover.test.js`
import '../lib/bare-globals.js'
import test from 'brittle'
import { secp256k1 } from '@noble/curves/secp256k1'
import { verifyCommit } from 'atproto-repo/lib/commit.js'
import { SwarmDevice } from '../lib/swarm-device.js'

const PRIV = new Uint8Array(Buffer.from('9085d2bef69286a6cbb51623c8fa258629945cd55ca705cc4e66700396894e0c', 'hex'))
const PUB = secp256k1.getPublicKey(PRIV, true)
const DID = 'did:plc:failover222222222222222'
const POST = 'app.bsky.feed.post'

// ONE shared Map (the converged view) behind two device sbs; records every set key so we can assert no __lease__.
function sharedView () {
  const m = new Map()
  const writes = []
  const base = {
    async set (k, v) { writes.push(k); m.set(k, v) },
    async del (k) { writes.push('del:' + k); m.delete(k) },
    async get (k) { return m.has(k) ? m.get(k) : null },
    async getNow (k) { return m.has(k) ? m.get(k) : null },
    async list (p = '') { const o = {}; for (const [k, v] of m) if (k.startsWith(p)) o[k] = v; return o },
    async listNow (p = '') { const o = {}; for (const [k, v] of m) if (k.startsWith(p)) o[k] = v; return o }
  }
  return { base, writes, map: m }
}
const withSigner = (base, holds) => ({ ...base, holdsSigner: () => holds() })

test('sign() gates on holdsSigner, fails over continuing the chain, and writes NO __lease__', async (t) => {
  const { base, writes, map } = sharedView()
  let aHolds = true; let bHolds = false
  const devA = new SwarmDevice(withSigner(base, () => aHolds), { did: DID, privateKey: PRIV, self: 'A', firehose: true })
  const devB = new SwarmDevice(withSigner(base, () => bHolds), { did: DID, privateKey: PRIV, self: 'B', firehose: true })

  // A is the elected signer, B is not.
  await devA.putRecord(POST, '3a', { $type: POST, text: 'a', createdAt: '2026-07-04T00:00:00.000Z' })
  t.is(await devB.sign(), null, 'B (not the elected signer) does NOT sign')
  const h1 = await devA.sign()
  t.ok(h1 && h1.commitCid, 'A (the elected signer) signs commit 1')
  t.ok(verifyCommit(h1.signedCommit, PUB), 'commit 1 verifies against the shared key')
  t.is(Object.keys(await base.list('__commit__/')).length, 1, 'exactly ONE commit — no double-sign')

  // FAILOVER: A dies, B is elected. B signs the next intent, continuing A's chain.
  aHolds = false; bHolds = true
  await devB.putRecord(POST, '3b', { $type: POST, text: 'b', createdAt: '2026-07-04T00:00:01.000Z' })
  t.is(await devA.sign(), null, 'A (no longer the signer) stops signing after failover')
  const h2 = await devB.sign()
  t.ok(h2 && h2.commitCid, 'B (new signer) signs commit 2 after failover')
  t.ok(h2.signedCommit.prev.equals(h1.commitCid), 'commit 2 continues A\'s chain (prev == commit 1) — NO fork')
  t.ok(verifyCommit(h2.signedCommit, PUB), 'commit 2 verifies against the same shared key')

  // THE LEAK IS GONE: not one __lease__ append across the whole run.
  t.absent(writes.some((k) => k.includes('__lease__')), 'ZERO __lease__ appends — the heartbeat leak is gone')
  t.absent([...map.keys()].some((k) => k.startsWith('__lease__')), 'no __lease__ key exists in the view')
})