diff --git a/forum-network/src/classes/dao/forum.js b/forum-network/src/classes/dao/forum.js index 6a6db0f..e311e1f 100644 --- a/forum-network/src/classes/dao/forum.js +++ b/forum-network/src/classes/dao/forum.js @@ -3,7 +3,7 @@ import { Action } from '../display/action.js'; import { Actor } from '../display/actor.js'; import params from '../../params.js'; import { ReputationHolder } from '../reputation/reputation-holder.js'; -import { displayNumber, EPSILON } from '../../util.js'; +import { displayNumber, EPSILON, INCINERATOR_ADDRESS } from '../../util.js'; const CITATION = 'citation'; const BALANCE = 'balance'; @@ -27,11 +27,11 @@ class Post extends Actor { .reduce((total, { weight }) => total += weight, 0); if (leachingTotal > params.revaluationLimit) { throw new Error('Post leaching total exceeds revaluation limit ' - + `(${leachingTotal} > ${params.revaluationLimit})`); + + `(${leachingTotal} > ${params.revaluationLimit})`); } if (donationTotal > params.revaluationLimit) { throw new Error('Post donation total exceeds revaluation limit ' - + `(${donationTotal} > ${params.revaluationLimit})`); + + `(${donationTotal} > ${params.revaluationLimit})`); } if (this.citations.some(({ weight }) => Math.abs(weight) > params.revaluationLimit)) { throw new Error(`Each citation magnitude must not exceed revaluation limit ${params.revaluationLimit}`); @@ -70,9 +70,14 @@ export class Forum extends ReputationHolder { } async addPost(authorId, postContent) { + console.log('addPost', { authorId, postContent }); const post = new Post(this, authorId, postContent); this.posts.addVertex(post.id, post, post.getLabel()); for (const { postId: citedPostId, weight } of post.citations) { + // Special case: Incinerator + if (citedPostId === INCINERATOR_ADDRESS && !this.posts.getVertex(INCINERATOR_ADDRESS)) { + this.posts.addVertex(INCINERATOR_ADDRESS, { name: 'Incinerator' }, 'Incinerator'); + } this.posts.addEdge(CITATION, post.id, citedPostId, weight); } return post; @@ -171,22 +176,43 @@ export class Forum extends ReputationHolder { for (const citationEdge of citationEdges) { const { weight } = citationEdge; let outboundAmount = weight * increment; - const balanceToOutbound = this.posts.getEdgeWeight(BALANCE, citationEdge.from, citationEdge.to) ?? 0; - // We need to ensure that we at most undo the prior effects of this post - if (initialNegative) { - outboundAmount = outboundAmount < 0 - ? Math.max(outboundAmount, -balanceToOutbound) - : Math.min(outboundAmount, -balanceToOutbound); - } if (Math.abs(outboundAmount) > EPSILON) { - const refundFromOutbound = await this.propagateValue(citationEdge, { - rewardsAccumulator, - increment: outboundAmount, - depth: depth + 1, - initialNegative: initialNegative || (depth === 0 && outboundAmount < 0), - }); + const balanceToOutbound = this.posts.getEdgeWeight(BALANCE, citationEdge.from, citationEdge.to) ?? 0; + let refundFromOutbound = 0; - outboundAmount -= refundFromOutbound; + // Special case: Incineration. + if (citationEdge.to.id === INCINERATOR_ADDRESS) { + // Only a positive amount may be incinerated! Otherwise the sink could be used as a source. + if (outboundAmount < 0) { + throw new Error('Incinerator can only receive positive citations!'); + } + // Reputation sent to the incinerator is burned! This means it is deducted from the sender, + // without increasing the value of any other token. + this.actions.propagate.log(citationEdge.from.data, { name: 'Incinerator' }, `(${increment})`); + } else { + // We need to ensure that we at most undo the prior effects of this post + if (initialNegative) { + outboundAmount = outboundAmount < 0 + ? Math.max(outboundAmount, -balanceToOutbound) + : Math.min(outboundAmount, -balanceToOutbound); + } + + // Recursively propagate reputation effects + refundFromOutbound = await this.propagateValue(citationEdge, { + rewardsAccumulator, + increment: outboundAmount, + depth: depth + 1, + initialNegative: initialNegative || (depth === 0 && outboundAmount < 0), + }); + + // Any excess (negative) amount that could not be propagated, + // i.e. because a cited post has been reduced to zero value, + // is retained by the citing post. + outboundAmount -= refundFromOutbound; + } + + // Keep a record of the effect of the reputation transferred along this edge in the graph, + // so that later, negative citations can be constrained to at most undo these effects. this.posts.setEdgeWeight(BALANCE, citationEdge.from, citationEdge.to, balanceToOutbound + outboundAmount); totalOutboundAmount += outboundAmount; diff --git a/forum-network/src/index.html b/forum-network/src/index.html index b3836c6..bf69f47 100644 --- a/forum-network/src/index.html +++ b/forum-network/src/index.html @@ -22,6 +22,7 @@
  • Destroy a post after it has received positive citations
  • Initially zero-valued posts later receive citations
  • Negatively cite a zero-valued post
  • +
  • Incinerate reputation