diff --git a/forum-network/notes/rep.md b/forum-network/notes/rep.md index 018ca2c..0574402 100644 --- a/forum-network/notes/rep.md +++ b/forum-network/notes/rep.md @@ -50,3 +50,9 @@ At a minimum this can be a list where each item includes the identifier of the c Each validation pool can then keep a record of the reputation staked by each voter, and the identifier of the corresponding post. --- + +So: If some incoming reputation can’t be propagated due to a constraint like this, the question is what should happen with that unspent power. I think right now, I have it so when that limit is reached on leaching from PostA, the extra reputation accrues evenly (because of +0.5 citation) equally to PostX and PostZ. + +Intuitively, we might want less value accruing to PostX, as it seems intended as a small utility post to transfer power. + +However, we can combine these mechanisms. PostX diff --git a/forum-network/src/classes/forum.js b/forum-network/src/classes/forum.js index ec6da68..d5010e0 100644 --- a/forum-network/src/classes/forum.js +++ b/forum-network/src/classes/forum.js @@ -53,7 +53,7 @@ export class Forum extends ReputationHolder { this.posts = new WDAG(scene); this.actions = { addPost: new Action('add post', scene), - propagateValue: new Action('propagate value', this.scene), + propagateValue: new Action('propagate', this.scene), transfer: new Action('transfer', this.scene), }; } @@ -122,7 +122,7 @@ export class Forum extends ReputationHolder { bench.reputation.transferFrom(this.id, post.authorPublicKey, post.tokenId); const toActor = this.scene.findActor((actor) => actor.reputationPublicKey === post.authorPublicKey); const value = bench.reputation.valueOf(post.tokenId); - this.actions.transfer.log(this, toActor, `(value: ${value})`); + this.actions.transfer.log(this, toActor, `(${value})`); this.deactivate(); } @@ -146,13 +146,12 @@ export class Forum extends ReputationHolder { if (params.referenceChainLimit === null || depth <= params.referenceChainLimit) { let totalOutboundAmount = 0; + let totalRefundFromOutbound = 0; for (const citationEdge of postVertex.getEdges(CITATION, true)) { const { to: citedPostVertex, weight } = citationEdge; let outboundAmount = weight * increment; - const balance = this.posts.getEdge(BALANCE, postVertex, citedPostVertex)?.weight || 0; - console.log('Citation', { - citationEdge, outboundAmount, balance, - }); + const balanceEdge = this.posts.getEdge(BALANCE, postVertex, citedPostVertex); + const balance = balanceEdge?.weight ?? 0; // We need to ensure that we propagate no more reputation than we leached if (depth > 0 && weight < 0) { outboundAmount = outboundAmount < 0 @@ -164,10 +163,34 @@ export class Forum extends ReputationHolder { increment: outboundAmount, depth: depth + 1, }); + totalRefundFromOutbound += Math.abs(refundFromOutbound); outboundAmount -= refundFromOutbound; - this.posts.setEdge(BALANCE, postVertex, citedPostVertex, balance + outboundAmount); + this.posts.setEdgeWeight(BALANCE, postVertex, citedPostVertex, balance + outboundAmount); + totalOutboundAmount += outboundAmount; } + + // Now that we know what value could not be propagated as negative citations, + // Let's see what happens if we redistribute it among the positive citations :) + + const positiveCitations = postVertex.getEdges(CITATION, true).filter(({ weight }) => weight > 0); + const totalPositiveCitationWeight = positiveCitations.reduce((total, { weight }) => total += weight, 0); + + for (const citationEdge of positiveCitations) { + const { to: citedPostVertex, weight } = citationEdge; + const outboundAmount = totalRefundFromOutbound * (weight / totalPositiveCitationWeight); + const balance = this.posts.getEdgeWeight(BALANCE, postVertex, citedPostVertex) ?? 0; + await this.propagateValue(citationEdge, { + rewardsAccumulator, + increment: outboundAmount, + depth: depth + 1, + }); + this.posts.setEdgeWeight(BALANCE, postVertex, citedPostVertex, balance + outboundAmount); + totalOutboundAmount += outboundAmount; + } + + // And what if they don't have any positive citations? The value should just accrue to this post. + increment -= totalOutboundAmount * params.leachingValue; } diff --git a/forum-network/src/classes/scene.js b/forum-network/src/classes/scene.js index 498e185..7afd507 100644 --- a/forum-network/src/classes/scene.js +++ b/forum-network/src/classes/scene.js @@ -114,6 +114,10 @@ export class Scene { activationBorderColor: '#569595', }, }); + + this.options = { + edgeNodeColor: '#4d585c', + }; } withSequenceDiagram() { @@ -131,6 +135,7 @@ export class Scene { const logBox = this.box.addBox('Flowchart text').addClass('dim'); this.flowchart = new MermaidDiagram(box, logBox); this.flowchart.log(`graph ${direction}`, false); + this.flowchart.log(`classDef edge fill:${this.options.edgeNodeColor}`, false); return this; } @@ -143,6 +148,7 @@ export class Scene { const logBox = container.addBox('Flowchart text').addClass('dim'); const flowchart = new MermaidDiagram(box, logBox); flowchart.log(`graph ${direction}`, false); + this.flowchart.log(`classDef edge fill:${this.options.edgeNodeColor}`, false); this.flowcharts.set(id, flowchart); return this; } diff --git a/forum-network/src/classes/validation-pool.js b/forum-network/src/classes/validation-pool.js index 5738882..ac2583d 100644 --- a/forum-network/src/classes/validation-pool.js +++ b/forum-network/src/classes/validation-pool.js @@ -265,7 +265,7 @@ export class ValidationPool extends ReputationHolder { // Transfer ownership of the minted token, from the pool to the forum this.bench.reputation.transferFrom(this.id, this.forum.id, this.tokenId); const value = this.bench.reputation.valueOf(this.tokenId); - this.actions.transfer.log(this, this.forum, `(value: ${value})`); + this.actions.transfer.log(this, this.forum, `(${value})`); // Recurse through forum to determine reputation effects await this.forum.onValidate({ diff --git a/forum-network/src/classes/wdag.js b/forum-network/src/classes/wdag.js index 2aca682..ace5beb 100644 --- a/forum-network/src/classes/wdag.js +++ b/forum-network/src/classes/wdag.js @@ -70,6 +70,19 @@ export class WDAG { return Array.from(this.vertices.values()).map(({ data }) => data); } + getEdgeLabel(label) { + return this.edgeLabels.get(label); + } + + getOrCreateEdgeLabel(label) { + let edges = this.getEdgeLabel(label); + if (!edges) { + edges = new Map(); + this.edgeLabels.set(label, edges); + } + return edges; + } + getEdge(label, from, to) { from = from instanceof Vertex ? from : this.getVertex(from); to = to instanceof Vertex ? to : this.getVertex(to); @@ -77,16 +90,41 @@ export class WDAG { return edges?.get(JSON.stringify([from.id, to.id])); } - setEdge(label, from, to, edge) { + getEdgeWeight(label, from, to) { + return this.getEdge(label, from, to)?.weight; + } + + static getEdgeKey({ from, to }) { + return btoa([from.id, to.id]).replaceAll(/[^A-Z]+/g, ''); + } + + getEdgeHtml({ from, to }) { + let html = '
${label} | ${weight} |