From cfa445471f0d0a396f637fd6845c1980002bea71 Mon Sep 17 00:00:00 2001 From: Ladd Hoffman Date: Wed, 4 Jan 2023 16:28:36 -0600 Subject: [PATCH] Post value propagation --- forum-network/src/classes/bench.js | 6 ++- forum-network/src/classes/business.js | 4 +- forum-network/src/classes/forum.js | 18 +++++--- forum-network/src/classes/graph.js | 2 - forum-network/src/classes/params.js | 2 +- forum-network/src/classes/validation-pool.js | 48 +++++++++++++++----- forum-network/src/tests/availability.html | 4 +- forum-network/src/tests/forum.html | 4 +- 8 files changed, 58 insertions(+), 30 deletions(-) diff --git a/forum-network/src/classes/bench.js b/forum-network/src/classes/bench.js index e06d9da..59fa8ad 100644 --- a/forum-network/src/classes/bench.js +++ b/forum-network/src/classes/bench.js @@ -8,8 +8,9 @@ import { Action } from './action.js'; * Purpose: Keep track of reputation holders */ export class Bench extends Actor { - constructor(name, scene) { + constructor(forum, name, scene) { super(name, scene); + this.forum = forum; this.validationPools = new Map(); this.voters = new Map(); this.reputations = new Reputations(); @@ -68,6 +69,7 @@ export class Bench extends Actor { const validationPoolNumber = this.validationPools.size + 1; const validationPool = new ValidationPool( this, + this.forum, { postId, fee, @@ -78,7 +80,7 @@ export class Bench extends Actor { authorStake, anonymous, }, - `pool${validationPoolNumber}`, + `Pool${validationPoolNumber}`, this.scene, ); this.validationPools.set(validationPool.id, validationPool); diff --git a/forum-network/src/classes/business.js b/forum-network/src/classes/business.js index 00d5fe8..e9cffbd 100644 --- a/forum-network/src/classes/business.js +++ b/forum-network/src/classes/business.js @@ -25,7 +25,7 @@ export class Business extends Actor { this.actions = { assignWork: new Action('assign work', scene), - addPost: new Action('add post', scene), + submitPost: new Action('submit post', scene), initiateValidationPool: new Action('initiate validation pool', scene), }; } @@ -54,7 +54,7 @@ export class Business extends Actor { requestId, workEvidence, }); - this.actions.addPost.log(this, this.forum); + this.actions.submitPost.log(this, this.forum); await this.forum.addPost(reputationPublicKey, post); // Initiate a validation pool for this work evidence. diff --git a/forum-network/src/classes/forum.js b/forum-network/src/classes/forum.js index 7cf197f..da1c0f4 100644 --- a/forum-network/src/classes/forum.js +++ b/forum-network/src/classes/forum.js @@ -12,6 +12,16 @@ class Post extends Actor { this.id = postContent.id ?? CryptoUtil.randomUUID(); this.authorId = authorId; this.value = 0; + this.citations = postContent.citations; + } + + setPostValue(value) { + this.setValue('value', value); + this.value = value; + } + + getPostValue() { + return this.value; } } @@ -19,9 +29,8 @@ class Post extends Actor { * Purpose: Maintain a directed, acyclic, weighted graph of posts referencing other posts */ export class Forum extends Actor { - constructor(bench, name, scene) { + constructor(name, scene) { super(name, scene); - this.bench = bench; this.posts = new Graph(); this.actions = { addPost: new Action('add post', scene), @@ -46,11 +55,6 @@ export class Forum extends Actor { return this.posts.getVertices(); } - onValidate({ tokensMinted }) { - const initialValue = params.initialPostValueFunction({ tokensMinted }); - this.distributeReputation(this, initialValue); - } - distributeReputation(post, amount, depth = 0) { console.log('distributeReputation', { post, amount, depth }); // Add the given value to the current post diff --git a/forum-network/src/classes/graph.js b/forum-network/src/classes/graph.js index 2b22613..303c2c1 100644 --- a/forum-network/src/classes/graph.js +++ b/forum-network/src/classes/graph.js @@ -45,7 +45,6 @@ export class Graph { throw new Error(`Vertex already exists with id: ${id}`); } const vertex = new Vertex(data); - console.log('addVertex', vertex); this.vertices.set(id, vertex); return this; } @@ -77,7 +76,6 @@ export class Graph { } addEdge(label, from, to, data) { - console.log('addEdge', { from, to }); if (this.getEdge(label, from, to)) { throw new Error(`Edge ${label} from ${from} to ${to} already exists`); } diff --git a/forum-network/src/classes/params.js b/forum-network/src/classes/params.js index 4d1eb64..6018106 100644 --- a/forum-network/src/classes/params.js +++ b/forum-network/src/classes/params.js @@ -19,7 +19,7 @@ const params = { lockingTimeExponent: 0, // c11 /* Forum parameters */ - initialPostValueFunction: ({ tokensMinted }) => tokensMinted, // q1 + initialPostValue: () => 1, // q1 citationFraction: 0.3, // q2 }; diff --git a/forum-network/src/classes/validation-pool.js b/forum-network/src/classes/validation-pool.js index addb45c..136a268 100644 --- a/forum-network/src/classes/validation-pool.js +++ b/forum-network/src/classes/validation-pool.js @@ -16,6 +16,7 @@ const ValidationPoolStates = Object.freeze({ export class ValidationPool extends Actor { constructor( bench, + forum, { postId, signingPublicKey, @@ -52,6 +53,7 @@ export class ValidationPool extends Actor { }]; got ${duration}`, ); } + this.forum = forum; this.postId = postId; this.state = ValidationPoolStates.OPEN; this.setStatus('Open'); @@ -66,6 +68,7 @@ export class ValidationPool extends Actor { this.duration = duration; this.tokenLossRatio = tokenLossRatio; this.contentiousDebate = contentiousDebate; + this.tokensMinted = fee * params.mintingRatio; this.tokens = { for: fee * params.mintingRatio * params.stakeForWin, against: fee * params.mintingRatio * (1 - params.stakeForWin), @@ -93,7 +96,6 @@ export class ValidationPool extends Actor { } this.votes.set(signingPublicKey, vote); if (!anonymous) { - console.log('castVote: revealing identity since this is not an anonymous vote'); await this.revealIdentity(signingPublicKey, signingPublicKey); } } @@ -200,20 +202,33 @@ export class ValidationPool extends Actor { return result; } - distributeTokens(result) { - let authorReputationPublicKey; - if (this.anonymous) { - const author = this.voters.get(this.authorSigningPublicKey); - authorReputationPublicKey = author.reputationPublicKey; - } else { - authorReputationPublicKey = this.authorSigningPublicKey; + propagateValue(nextPost, increment) { + const postValue = nextPost.getPostValue(); + nextPost.setPostValue(postValue + increment); + for (const { postId: citedPostId, weight } of nextPost.citations) { + console.log('citedPostId', citedPostId); + const citedPost = this.forum.getPost(citedPostId); + this.propagateValue(citedPost, weight * increment); } - // Reward the author - // TODO: If the vote fails, distribute tokens.author among winning voters + } + + distributeTokens(result) { + const authorReputationPublicKey = this.anonymous + ? this.voters.get(this.authorSigningPublicKey).reputationPublicKey + : this.authorSigningPublicKey; + + // TODO: Take tokenLossRatio into account + if (result === true) { - this.bench.reputations.addTokens(authorReputationPublicKey, this.tokens.for); + // Take initialValue into account + const initialPostValue = params.initialPostValue() * this.tokensMinted; + const tokensForAuthor = initialPostValue * params.stakeForWin; + const tokensForWinners = initialPostValue * (1 - params.stakeForWin); + + // Reward the author + this.bench.reputations.addTokens(authorReputationPublicKey, tokensForAuthor); + // Reward the vote winners, in proportion to their stakes - const tokensForWinners = this.tokens.against; const winningVotes = this.listVotes(result); const totalStakes = Array.from(winningVotes.values()) .map(({ stake }) => stake) @@ -226,6 +241,15 @@ export class ValidationPool extends Actor { const reward = (tokensForWinners * stake) / totalStakes; this.bench.reputations.addTokens(reputationPublicKey, reward); } + + // Update the forum post to set its (initial) value + const post = this.forum.getPost(this.postId); + + // Recursively update values of referenced posts + this.propagateValue(post, initialPostValue); + } else { + // TODO: If the vote fails, distribute tokens.author among winning voters. + throw new Error("Vote did not pass -- we don't currently handle that!"); } } } diff --git a/forum-network/src/tests/availability.html b/forum-network/src/tests/availability.html index 380e9f1..bcda9f5 100644 --- a/forum-network/src/tests/availability.html +++ b/forum-network/src/tests/availability.html @@ -38,8 +38,8 @@ const expert1 = await newExpert(); const expert2 = await newExpert(); await newExpert(); - const bench = (window.bench = new Bench("Bench", scene)); - const forum = (window.forum = new Forum(bench, "Forum", scene)); + const forum = (window.forum = new Forum("Forum", scene)); + const bench = (window.bench = new Bench(forum, "Bench", scene)); const availability = (window.bench = new Availability( bench, "Availability", diff --git a/forum-network/src/tests/forum.html b/forum-network/src/tests/forum.html index 04a1237..ae596ab 100644 --- a/forum-network/src/tests/forum.html +++ b/forum-network/src/tests/forum.html @@ -39,8 +39,8 @@ const expert1 = await newExpert(); const expert2 = await newExpert(); await newExpert(); - const bench = (window.bench = new Bench("Bench", scene)); - const forum = (window.forum = new Forum(bench, "Forum", scene)); + const forum = (window.forum = new Forum("Forum", scene)); + const bench = (window.bench = new Bench(forum, "Bench", scene)); const updateDisplayValues = async () => { for (const expert of experts) {