From 448bd44a41fa0734feb50cd0d21b74cfa7622231 Mon Sep 17 00:00:00 2001 From: Andre Staltz Date: Fri, 7 Apr 2023 17:57:53 +0300 Subject: [PATCH] lipmaa in multi-author tangles --- lib/feed-v1/index.js | 26 ++++++++--- test/feed-v1-tangles.test.js | 86 ++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 7 deletions(-) diff --git a/lib/feed-v1/index.js b/lib/feed-v1/index.js index 70b2cc0..6079547 100644 --- a/lib/feed-v1/index.js +++ b/lib/feed-v1/index.js @@ -86,11 +86,19 @@ function toPlaintextBuffer(opts) { return Buffer.from(stringify(opts.content), 'utf8') } -function calculateDepth(existing) { +function readDepth(msg, tangleId = null) { + if (tangleId) { + return msg.metadata.tangles?.[tangleId]?.depth ?? 0 + } else { + return msg.metadata.depth + }} + +function calculateDepth(existing, tangleId = null) { let max = -1 for (const msg of existing.values()) { - if (msg.metadata.depth > max) { - max = msg.metadata.depth + const depth = readDepth(msg, tangleId) + if (depth > max) { + max = depth } } return max + 1 @@ -124,10 +132,10 @@ function lipmaa(n) { return n - po3 } -function calculatePrev(existing, depth, lipmaaDepth) { +function calculatePrev(existing, depth, lipmaaDepth, tangleId = null) { const prev = [] for (const msg of existing.values()) { - const msgDepth = msg.metadata.depth + const msgDepth = readDepth(msg, tangleId) if (msgDepth === lipmaaDepth || msgDepth === depth - 1) { prev.push(getMsgHash(msg)) } @@ -168,6 +176,9 @@ function prevalidateExisting(existing, tangleId = null) { } else { hasDepthZeroMsg = true } + } else if (!p.metadata.tangles?.[tangleId]) { + // prettier-ignore + return new Error(`existing must refer to the tangleId ${tangleId}`) } } } @@ -197,9 +208,10 @@ function create(opts) { if ((err = validateMsgHash(rootId))) throw err const existing = opts.tangles[rootId] if ((err = prevalidateExisting(existing, rootId))) throw err - const depth = calculateDepth(existing) + + const depth = calculateDepth(existing, rootId) const lipmaaDepth = lipmaa(depth + 1) - 1 - const prev = calculatePrev(existing, depth, lipmaaDepth) + const prev = calculatePrev(existing, depth, lipmaaDepth, rootId) tangles ??= {} tangles[rootId] = { depth, prev } } diff --git a/test/feed-v1-tangles.test.js b/test/feed-v1-tangles.test.js index f3509d4..da39951 100644 --- a/test/feed-v1-tangles.test.js +++ b/test/feed-v1-tangles.test.js @@ -37,3 +37,89 @@ tape('simple multi-author tangle', (t) => { t.end() }) + +tape('lipmaa in multi-author tangle', (t) => { + const keysA = generateKeypair('alice') + const keysB = generateKeypair('bob') + + const content = { text: 'Hello world!' } + const when = 1652037377204 + const existingA = new Map() + const existingB = new Map() + const tangleExisting = new Map() + + const msg1 = FeedV1.create({ + keys: keysA, + content, + type: 'post', + existing: existingA, + when: when + 1, + }) + const msgHash1 = FeedV1.getMsgHash(msg1) + existingA.set(msgHash1, msg1) + tangleExisting.set(msgHash1, msg1) + + t.notOk(msg1.metadata.tangles, 'A:msg1 has no extra tangles') + + const msg2 = FeedV1.create({ + keys: keysB, + content, + type: 'post', + existing: existingB, + tangles: { + [msgHash1]: tangleExisting, + }, + when: when + 2, + }) + const msgHash2 = FeedV1.getMsgHash(msg2) + existingB.set(msgHash2, msg2) + tangleExisting.set(msgHash2, msg2) + + t.deepEquals( + msg2.metadata.tangles[msgHash1].prev, + [msgHash1], + 'B:msg2 points to A:msg1' + ) + + const msg3 = FeedV1.create({ + keys: keysB, + content, + type: 'post', + existing: existingB, + tangles: { + [msgHash1]: tangleExisting, + }, + when: when + 3, + }) + const msgHash3 = FeedV1.getMsgHash(msg3) + existingB.set(msgHash3, msg3) + tangleExisting.set(msgHash3, msg3) + + t.deepEquals( + msg3.metadata.tangles[msgHash1].prev, + [msgHash2], + 'B:msg3 points to B:msg2' + ) + + const msg4 = FeedV1.create({ + keys: keysA, + content, + type: 'post', + existing: existingA, + tangles: { + [msgHash1]: tangleExisting, + }, + when: when + 4, + }) + const msgHash4 = FeedV1.getMsgHash(msg4) + existingB.set(msgHash4, msg4) + tangleExisting.set(msgHash4, msg4) + + t.deepEquals( + msg4.metadata.tangles[msgHash1].prev, + [msgHash1, msgHash3], + 'A:msg4 points to A:msg1,B:msg3' + ) + + t.end() +})