| … | … | @@ -0,0 +1,43 @@ |
| 1 | // test/result-write-once.js — the canonical result is WRITE-ONCE. |
| 2 | // |
| 3 | // Two peers share a pool. The owner writes the canonical result for a content |
| 4 | // key; a second peer then appends a CONFLICTING result for the SAME |
| 5 | // (codeHash, inputHash). The fold must keep the first (canonical) result on |
| 6 | // BOTH peers — the conflict is ignored, not applied last-write-wins. This is |
| 7 | // the P0 floor that makes a memoized chunk trustworthy (SPEC §4.1). |
| 8 | |
| 9 | const test = require('brittle') |
| 10 | const Corestore = require('corestore') |
| 11 | const tmp = require('test-tmp') |
| 12 | const { replicateAndSync } = require('autobase-test-helpers') |
| 13 | const { ComputeNode } = require('../lib/node') |
| 14 | |
| 15 | const codeHash = 'square-v1' |
| 16 | const inputHash = 'deadbeefcafe' |
| 17 | |
| 18 | test('result is write-once: a later conflicting result cannot clobber the canonical chunk', async (t) => { |
| 19 | const owner = await ComputeNode.create(new Corestore(await tmp(t)), null, {}) |
| 20 | await owner.grantSelf('owner') |
| 21 | |
| 22 | const worker = await ComputeNode.create(new Corestore(await tmp(t)), owner.key, {}) |
| 23 | await owner.addWriter(worker.writerKey) |
| 24 | await replicateAndSync([owner.base, worker.base]) |
| 25 | t.ok(worker.base.writable, 'worker became a writer') |
| 26 | |
| 27 | // owner writes the canonical result first, and it fully linearizes before |
| 28 | // any conflict exists (so causal order pins it first in the fold). |
| 29 | await owner.base.append({ type: 'result', codeHash, inputHash, output: 49, worker: owner.idHex }) |
| 30 | await replicateAndSync([owner.base, worker.base]) |
| 31 | t.is(await owner.lookup(codeHash, inputHash), 49, 'canonical result present after first write') |
| 32 | |
| 33 | // worker appends a CONFLICTING result for the same content key |
| 34 | await worker.base.append({ type: 'result', codeHash, inputHash, output: 999, worker: worker.idHex }) |
| 35 | await replicateAndSync([owner.base, worker.base]) |
| 36 | |
| 37 | // write-once: the first result wins on BOTH peers; the conflict is dropped |
| 38 | t.is(await owner.lookup(codeHash, inputHash), 49, 'owner: canonical result NOT clobbered') |
| 39 | t.is(await worker.lookup(codeHash, inputHash), 49, 'worker: canonical result NOT clobbered') |
| 40 | |
| 41 | await owner.close() |
| 42 | await worker.close() |
| 43 | }) |