OverviewFilesCommitsIssuesDocsReleasesPeers

hypercompute / test / e2e.js

79 lines · javascript ref:
// 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()
})