diff --git a/packages/gossiplog/src/AbstractGossipLog.ts b/packages/gossiplog/src/AbstractGossipLog.ts index 2c56a187..55022388 100644 --- a/packages/gossiplog/src/AbstractGossipLog.ts +++ b/packages/gossiplog/src/AbstractGossipLog.ts @@ -41,6 +41,15 @@ export type GossipLogEvents = { error: CustomEvent<{ error: Error }> } +type MessageEntry = { + id: string + signature: Signature + message: Message + hash: string + branch: number + clock: number +} + export abstract class AbstractGossipLog extends TypedEventEmitter> { public static schema = { $messages: { @@ -246,9 +255,30 @@ export abstract class AbstractGossipLog extends TypedEventEmi const hash = toString(hashEntry(key, value), "hex") - const branch = await this.getBranch(id, message) + const parentMessageEntries: MessageEntry[] = [] + for (const parentId of message.parents) { + const parentMessageEntry = await this.db.get>("$messages", parentId) + if (parentMessageEntry === null) { + throw new Error(`missing parent ${parentId} of message ${id}`) + } + parentMessageEntries.push(parentMessageEntry) + } - await new BranchMergeIndex(this.db).insertBranchMerges(id, branch, message) + const branch = await this.getBranch(id, parentMessageEntries) + + const branchMergeIndex = new BranchMergeIndex(this.db) + for (const parentMessageEntry of parentMessageEntries) { + if (parentMessageEntry.branch !== branch) { + await branchMergeIndex.insertBranchMerge({ + source_branch: parentMessageEntry.branch, + source_clock: parentMessageEntry.clock, + source_message_id: parentMessageEntry.id, + target_branch: branch, + target_clock: message.clock, + target_message_id: id, + }) + } + } await this.db.set("$messages", { id, signature, message, hash, branch, clock: message.clock }) @@ -268,18 +298,14 @@ export abstract class AbstractGossipLog extends TypedEventEmi this.dispatchEvent(new CustomEvent("message", { detail: { id, signature, message } })) } - private async getBranch(messageId: string, message: Message) { - if (message.parents.length == 0) { + private async getBranch(messageId: string, parentMessages: MessageEntry[]) { + if (parentMessages.length == 0) { return await new BranchIndex(this.db).createNewBranch() } let maxBranch = -1 let parentMessageWithMaxClock: any = null - for (const parentId of message.parents) { - const parentMessage = await this.db.get("$messages", parentId) - if (parentMessage == null) { - throw new Error(`Parent message ${parentId} not found`) - } + for (const parentMessage of parentMessages) { if (parentMessage.branch > maxBranch) { parentMessageWithMaxClock = parentMessage maxBranch = parentMessage.branch @@ -287,7 +313,7 @@ export abstract class AbstractGossipLog extends TypedEventEmi } const branch = maxBranch - const messagesAtBranchClockPosition = await this.db.query("$messages", { + const messagesAtBranchClockPosition = await this.db.query>("$messages", { where: { branch, clock: { diff --git a/packages/gossiplog/src/BranchMergeIndex.ts b/packages/gossiplog/src/BranchMergeIndex.ts index 7eb8cd34..e607d2ee 100644 --- a/packages/gossiplog/src/BranchMergeIndex.ts +++ b/packages/gossiplog/src/BranchMergeIndex.ts @@ -1,4 +1,3 @@ -import { Message } from "@canvas-js/interfaces" import type { AbstractModelDB, ModelsInit } from "@canvas-js/modeldb" export type BranchMergeEntry = { @@ -25,27 +24,6 @@ export class BranchMergeIndex { constructor(private readonly db: AbstractModelDB) {} - public async insertBranchMerges(id: string, branch: number, message: Message) { - for (const parentId of message.parents) { - const parentMessageResult = await this.db.get("$messages", parentId) - if (!parentMessageResult) { - throw new Error(`missing parent ${parentId} of message ${id}`) - } - const parentBranch = parentMessageResult.branch - const parentClock = parentMessageResult.message.clock - if (parentBranch !== branch) { - await this.insertBranchMerge({ - source_branch: parentBranch, - source_clock: parentClock, - source_message_id: parentId, - target_branch: branch, - target_clock: message.clock, - target_message_id: id, - }) - } - } - } - public async insertBranchMerge(entry: BranchMergeEntry) { const id = `${entry.source_branch}:${entry.source_message_id}:${entry.target_branch}:${entry.target_message_id}` await this.db.set("$branch_merges", { id, ...entry })