// Autobase requires apply to be DETERMINISTIC: it is replayed on every boot
// and every reorg, and each peer runs it independently to build its own view.
// If apply stamps non-deterministic values, two peers replaying identical ops
// write DIFFERENT view bytes and their views can never agree.
//
// hyper-rooms (lib/room.js) — the reference implementation on this same
// substrate — puts the timestamp in the OP (:220,260,273) and has apply read
// `op.timestamp || Date.now()` (:418). This module must do the same.
//
// CONTROL first: an op that stores only op-provided fields must replay
// byte-identically, proving the harness itself is deterministic.
import test from 'brittle'
import Corestore from 'corestore'
import Hyperbee from 'hyperbee'
import path from '#node:path'
import os from '#node:os'
import crypto from 'hypercore-crypto'
import b4a from 'b4a'
import { createApplyFunction } from '../lib/auth/identity-apply.js'
import { encodeOp, OpTypes } from '../lib/auth/identity-operations.js'
const stubHost = { addWriter: async () => {}, removeWriter: async () => {} }
const node = (op) => ({ value: encodeOp(op), from: { key: b4a.alloc(32) } })
const sleep = (ms) => new Promise(r => setTimeout(r, ms))
// Run the real apply over a batch into a fresh in-memory view, return the
// stored value at `key`.
async function applyAndRead (batch, key) {
const store = new Corestore(
path.join(os.tmpdir(), 'hyper-identity-determinism-' + crypto.randomBytes(8).toString('hex'))
)
await store.ready()
const bee = new Hyperbee(store.get({ name: 'identity-view' }), {
keyEncoding: 'utf-8', valueEncoding: 'json'
})
await bee.ready()
const apply = createApplyFunction({})
await apply(batch, bee, stubHost)
const entry = await bee.get(key)
const value = entry ? entry.value : null
await bee.close()
await store.close()
return value
}
test('CONTROL: an op storing only op-provided fields replays byte-identically', async (t) => {
const identity = {
identityId: 'ident-control',
method: 'web-identity',
publicKey: 'ff'.repeat(32),
userId: 'user-control',
createdAt: 1700000000000
}
const batch = [node({ type: OpTypes.REGISTER_IDENTITY, identity })]
const a = await applyAndRead(batch, 'identity:ident-control')
await sleep(25)
const b = await applyAndRead(batch, 'identity:ident-control')
t.ok(a && b, 'both replays stored the record')
t.alike(a, b, 'control replays byte-identical — harness is deterministic')
})
test('ADD_WRITER replays deterministically', async (t) => {
const writerKey = 'ab'.repeat(32)
const batch = [node({
type: OpTypes.ADD_WRITER,
writerKey,
role: 'writer',
addedBy: 'test',
timestamp: 1700000000001
})]
const a = await applyAndRead(batch, 'writer:' + writerKey)
await sleep(25)
const b = await applyAndRead(batch, 'writer:' + writerKey)
t.ok(a && b, 'both replays stored the writer record')
t.alike(a, b, 'identical ADD_WRITER op produces identical view bytes on replay')
t.is(a.addedAt, 1700000000001, 'addedAt comes from the OP, not from apply')
})
test('REGISTER_MIRROR_WRITERS replays deterministically', async (t) => {
const devicePubkey = 'cd'.repeat(32)
const batch = [node({
type: OpTypes.REGISTER_MIRROR_WRITERS,
devicePubkey,
keys: { orgs: 'ef'.repeat(32) },
timestamp: 1700000000002
})]
const a = await applyAndRead(batch, 'mirror-writers:' + devicePubkey)
await sleep(25)
const b = await applyAndRead(batch, 'mirror-writers:' + devicePubkey)
t.ok(a && b, 'both replays stored the announcement')
t.alike(a, b, 'identical REGISTER_MIRROR_WRITERS op produces identical view bytes')
t.is(a.recordedAt, 1700000000002, 'recordedAt comes from the OP, not from apply')
})