// test/e2e.js — P0 proof: the spec's core claim, no network.
//
// Two ComputeNodes share one optimistic Autobase (compute pool). The owner
// submits a content-addressed task; the worker executes it (T0 native); the
// result converges on BOTH peers via the deterministic fold; and a re-submit
// is a memo hit. Sync is driven by replicateAndSync (SPEC §P0).
const test = require('brittle')
const Corestore = require('corestore')
const tmp = require('test-tmp')
const { replicateAndSync } = require('autobase-test-helpers')
const b4a = require('b4a')
const crypto = require('hypercore-crypto')
const { ComputeNode } = require('../lib/node')
function inputHashOf (input) {
return b4a.toString(crypto.hash(b4a.from(JSON.stringify(input))), 'hex')
}
test('P0: submit -> execute -> result converges + memoizes', async (t) => {
// a DETERMINISTIC CPU task (square). codeHash stands in for the content hash
// of the executable artifact (SPEC §4.1).
const codeHash = 'square-v1'
const square = async (input) => input.n * input.n
const executors = { [codeHash]: square }
const owner = await ComputeNode.create(new Corestore(await tmp(t)), null, { executors })
await owner.grantSelf('owner')
const worker = await ComputeNode.create(new Corestore(await tmp(t)), owner.key, { executors })
// P0 membership: owner adds the worker as an autobase writer + grants it.
await owner.addWriter(worker.writerKey)
await owner.grant(worker.identity.publicKey, 'worker')
await replicateAndSync([owner.base, worker.base])
t.ok(worker.base.writable, 'worker became a writer after add-writer synced')
const input = { n: 7 }
const ih = inputHashOf(input)
// first submit = memo MISS -> a task op
const sub = await owner.submit(codeHash, ih, input)
t.is(sub.memoHit, false, 'first submit is a memo miss')
await replicateAndSync([owner.base, worker.base])
// worker sees the task via the fold, executes it (T0), appends the result
const n = await worker.runPendingTasks()
t.is(n, 1, 'worker executed exactly one pending task')
await replicateAndSync([owner.base, worker.base])
// result converged on BOTH peers (the deterministic fold = shared truth)
t.is(await owner.lookup(codeHash, ih), 49, 'owner sees result via the fold')
t.is(await worker.lookup(codeHash, ih), 49, 'worker sees result via the fold')
// re-submit = memo HIT (compute once, reuse everywhere — SPEC §4.1)
const again = await owner.submit(codeHash, ih, input)
t.is(again.memoHit, true, 're-submit is a memo hit')
t.is(again.output, 49, 'memoized output returned without recompute')
await owner.close()
await worker.close()
})
test('P0: a different input is a separate content-addressed chunk', async (t) => {
const codeHash = 'square-v1'
const executors = { [codeHash]: async (i) => i.n * i.n }
const owner = await ComputeNode.create(new Corestore(await tmp(t)), null, { executors })
await owner.grantSelf('owner')
const ih = inputHashOf({ n: 9 })
t.is((await owner.submit(codeHash, ih, { n: 9 })).memoHit, false, 'n=9 is a fresh task')
await owner.runPendingTasks()
t.is(await owner.lookup(codeHash, ih), 81, 'n=9 -> 81 computed and memoized')
await owner.close()
})