Post value propagation

This commit is contained in:
Ladd Hoffman 2023-01-04 16:28:36 -06:00
parent 8980885881
commit cfa445471f
8 changed files with 58 additions and 30 deletions

View File

@ -8,8 +8,9 @@ import { Action } from './action.js';
* Purpose: Keep track of reputation holders * Purpose: Keep track of reputation holders
*/ */
export class Bench extends Actor { export class Bench extends Actor {
constructor(name, scene) { constructor(forum, name, scene) {
super(name, scene); super(name, scene);
this.forum = forum;
this.validationPools = new Map(); this.validationPools = new Map();
this.voters = new Map(); this.voters = new Map();
this.reputations = new Reputations(); this.reputations = new Reputations();
@ -68,6 +69,7 @@ export class Bench extends Actor {
const validationPoolNumber = this.validationPools.size + 1; const validationPoolNumber = this.validationPools.size + 1;
const validationPool = new ValidationPool( const validationPool = new ValidationPool(
this, this,
this.forum,
{ {
postId, postId,
fee, fee,
@ -78,7 +80,7 @@ export class Bench extends Actor {
authorStake, authorStake,
anonymous, anonymous,
}, },
`pool${validationPoolNumber}`, `Pool${validationPoolNumber}`,
this.scene, this.scene,
); );
this.validationPools.set(validationPool.id, validationPool); this.validationPools.set(validationPool.id, validationPool);

View File

@ -25,7 +25,7 @@ export class Business extends Actor {
this.actions = { this.actions = {
assignWork: new Action('assign work', scene), 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), initiateValidationPool: new Action('initiate validation pool', scene),
}; };
} }
@ -54,7 +54,7 @@ export class Business extends Actor {
requestId, requestId,
workEvidence, workEvidence,
}); });
this.actions.addPost.log(this, this.forum); this.actions.submitPost.log(this, this.forum);
await this.forum.addPost(reputationPublicKey, post); await this.forum.addPost(reputationPublicKey, post);
// Initiate a validation pool for this work evidence. // Initiate a validation pool for this work evidence.

View File

@ -12,6 +12,16 @@ class Post extends Actor {
this.id = postContent.id ?? CryptoUtil.randomUUID(); this.id = postContent.id ?? CryptoUtil.randomUUID();
this.authorId = authorId; this.authorId = authorId;
this.value = 0; 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 * Purpose: Maintain a directed, acyclic, weighted graph of posts referencing other posts
*/ */
export class Forum extends Actor { export class Forum extends Actor {
constructor(bench, name, scene) { constructor(name, scene) {
super(name, scene); super(name, scene);
this.bench = bench;
this.posts = new Graph(); this.posts = new Graph();
this.actions = { this.actions = {
addPost: new Action('add post', scene), addPost: new Action('add post', scene),
@ -46,11 +55,6 @@ export class Forum extends Actor {
return this.posts.getVertices(); return this.posts.getVertices();
} }
onValidate({ tokensMinted }) {
const initialValue = params.initialPostValueFunction({ tokensMinted });
this.distributeReputation(this, initialValue);
}
distributeReputation(post, amount, depth = 0) { distributeReputation(post, amount, depth = 0) {
console.log('distributeReputation', { post, amount, depth }); console.log('distributeReputation', { post, amount, depth });
// Add the given value to the current post // Add the given value to the current post

View File

@ -45,7 +45,6 @@ export class Graph {
throw new Error(`Vertex already exists with id: ${id}`); throw new Error(`Vertex already exists with id: ${id}`);
} }
const vertex = new Vertex(data); const vertex = new Vertex(data);
console.log('addVertex', vertex);
this.vertices.set(id, vertex); this.vertices.set(id, vertex);
return this; return this;
} }
@ -77,7 +76,6 @@ export class Graph {
} }
addEdge(label, from, to, data) { addEdge(label, from, to, data) {
console.log('addEdge', { from, to });
if (this.getEdge(label, from, to)) { if (this.getEdge(label, from, to)) {
throw new Error(`Edge ${label} from ${from} to ${to} already exists`); throw new Error(`Edge ${label} from ${from} to ${to} already exists`);
} }

View File

@ -19,7 +19,7 @@ const params = {
lockingTimeExponent: 0, // c11 lockingTimeExponent: 0, // c11
/* Forum parameters */ /* Forum parameters */
initialPostValueFunction: ({ tokensMinted }) => tokensMinted, // q1 initialPostValue: () => 1, // q1
citationFraction: 0.3, // q2 citationFraction: 0.3, // q2
}; };

View File

@ -16,6 +16,7 @@ const ValidationPoolStates = Object.freeze({
export class ValidationPool extends Actor { export class ValidationPool extends Actor {
constructor( constructor(
bench, bench,
forum,
{ {
postId, postId,
signingPublicKey, signingPublicKey,
@ -52,6 +53,7 @@ export class ValidationPool extends Actor {
}]; got ${duration}`, }]; got ${duration}`,
); );
} }
this.forum = forum;
this.postId = postId; this.postId = postId;
this.state = ValidationPoolStates.OPEN; this.state = ValidationPoolStates.OPEN;
this.setStatus('Open'); this.setStatus('Open');
@ -66,6 +68,7 @@ export class ValidationPool extends Actor {
this.duration = duration; this.duration = duration;
this.tokenLossRatio = tokenLossRatio; this.tokenLossRatio = tokenLossRatio;
this.contentiousDebate = contentiousDebate; this.contentiousDebate = contentiousDebate;
this.tokensMinted = fee * params.mintingRatio;
this.tokens = { this.tokens = {
for: fee * params.mintingRatio * params.stakeForWin, for: fee * params.mintingRatio * params.stakeForWin,
against: fee * params.mintingRatio * (1 - params.stakeForWin), against: fee * params.mintingRatio * (1 - params.stakeForWin),
@ -93,7 +96,6 @@ export class ValidationPool extends Actor {
} }
this.votes.set(signingPublicKey, vote); this.votes.set(signingPublicKey, vote);
if (!anonymous) { if (!anonymous) {
console.log('castVote: revealing identity since this is not an anonymous vote');
await this.revealIdentity(signingPublicKey, signingPublicKey); await this.revealIdentity(signingPublicKey, signingPublicKey);
} }
} }
@ -200,20 +202,33 @@ export class ValidationPool extends Actor {
return result; return result;
} }
distributeTokens(result) { propagateValue(nextPost, increment) {
let authorReputationPublicKey; const postValue = nextPost.getPostValue();
if (this.anonymous) { nextPost.setPostValue(postValue + increment);
const author = this.voters.get(this.authorSigningPublicKey); for (const { postId: citedPostId, weight } of nextPost.citations) {
authorReputationPublicKey = author.reputationPublicKey; console.log('citedPostId', citedPostId);
} else { const citedPost = this.forum.getPost(citedPostId);
authorReputationPublicKey = this.authorSigningPublicKey; 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) { 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 // Reward the vote winners, in proportion to their stakes
const tokensForWinners = this.tokens.against;
const winningVotes = this.listVotes(result); const winningVotes = this.listVotes(result);
const totalStakes = Array.from(winningVotes.values()) const totalStakes = Array.from(winningVotes.values())
.map(({ stake }) => stake) .map(({ stake }) => stake)
@ -226,6 +241,15 @@ export class ValidationPool extends Actor {
const reward = (tokensForWinners * stake) / totalStakes; const reward = (tokensForWinners * stake) / totalStakes;
this.bench.reputations.addTokens(reputationPublicKey, reward); 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!");
} }
} }
} }

View File

@ -38,8 +38,8 @@
const expert1 = await newExpert(); const expert1 = await newExpert();
const expert2 = await newExpert(); const expert2 = await newExpert();
await newExpert(); await newExpert();
const bench = (window.bench = new Bench("Bench", scene)); const forum = (window.forum = new Forum("Forum", scene));
const forum = (window.forum = new Forum(bench, "Forum", scene)); const bench = (window.bench = new Bench(forum, "Bench", scene));
const availability = (window.bench = new Availability( const availability = (window.bench = new Availability(
bench, bench,
"Availability", "Availability",

View File

@ -39,8 +39,8 @@
const expert1 = await newExpert(); const expert1 = await newExpert();
const expert2 = await newExpert(); const expert2 = await newExpert();
await newExpert(); await newExpert();
const bench = (window.bench = new Bench("Bench", scene)); const forum = (window.forum = new Forum("Forum", scene));
const forum = (window.forum = new Forum(bench, "Forum", scene)); const bench = (window.bench = new Bench(forum, "Bench", scene));
const updateDisplayValues = async () => { const updateDisplayValues = async () => {
for (const expert of experts) { for (const expert of experts) {