From 8980885881b0df88fd6a667b7446afdae77d6644 Mon Sep 17 00:00:00 2001 From: Ladd Hoffman Date: Wed, 4 Jan 2023 15:18:29 -0600 Subject: [PATCH] Additional cleanup in preparation for forum test --- forum-network/notes/notes.md | 4 +- forum-network/src/classes/actor.js | 3 + forum-network/src/classes/bench.js | 24 ++++---- forum-network/src/classes/business.js | 2 +- forum-network/src/classes/expert.js | 26 ++++++--- forum-network/src/classes/scene.js | 1 - forum-network/src/classes/validation-pool.js | 13 ++++- forum-network/src/index.css | 3 +- forum-network/src/tests/availability.html | 36 ++++++------ forum-network/src/tests/forum.html | 59 +++++++++++++------- forum-network/src/tests/validation-pool.html | 34 +++++------ 11 files changed, 117 insertions(+), 88 deletions(-) diff --git a/forum-network/notes/notes.md b/forum-network/notes/notes.md index 7225657..16b5053 100644 --- a/forum-network/notes/notes.md +++ b/forum-network/notes/notes.md @@ -40,7 +40,7 @@ Should availability registration encumber reputation? - Is a particular availability stake amount required? -Currently I support updating the staked amount. +Currently we support updating the staked amount. Seems like a soft protocol thing. A given DAO can have a formula for deciding appropriate amounts. @@ -59,7 +59,7 @@ The following was a code comment on `Business.submitRequest(fee, ...)`: Does the following make sense? We will link the forum to the bench An author of a forum post /_ ? is always? can be? _/ a reputation holder. -This is what we call a member. Let's update that terminology to be `reputationHolder`. +This is what we call a expert. Let's update that terminology to be `reputationHolder`. That's too long, though. Let's rename it to `expert`. So we want to aim for the situation where the author of a forum post is an expert. For now let's try thinking of them as experts no matter what; diff --git a/forum-network/src/classes/actor.js b/forum-network/src/classes/actor.js index 97a9b0e..2aa1496 100644 --- a/forum-network/src/classes/actor.js +++ b/forum-network/src/classes/actor.js @@ -57,6 +57,9 @@ export class Actor { } setValue(label, value) { + if (typeof value === 'number') { + value = value.toFixed(2); + } let displayValue = this.values.get(label); if (!displayValue) { displayValue = this.scene.addDisplayValue(`${this.name} ${label}`); diff --git a/forum-network/src/classes/bench.js b/forum-network/src/classes/bench.js index 1c9206e..e06d9da 100644 --- a/forum-network/src/classes/bench.js +++ b/forum-network/src/classes/bench.js @@ -55,23 +55,19 @@ export class Bench extends Actor { .reduce((acc, cur) => (acc += cur), 0); } - initiateValidationPool( - authorId, - { - postId, - fee, - duration, - tokenLossRatio, - contentiousDebate, - signingPublicKey, - authorStake, - anonymous, - }, - ) { + initiateValidationPool({ + postId, + fee, + duration, + tokenLossRatio, + contentiousDebate, + signingPublicKey, + authorStake, + anonymous, + }) { const validationPoolNumber = this.validationPools.size + 1; const validationPool = new ValidationPool( this, - authorId, { postId, fee, diff --git a/forum-network/src/classes/business.js b/forum-network/src/classes/business.js index 5a2997a..00d5fe8 100644 --- a/forum-network/src/classes/business.js +++ b/forum-network/src/classes/business.js @@ -61,7 +61,7 @@ export class Business extends Actor { // Validation pool supports secret ballots but we aren't using that here, since we want // the post to be attributable to the reputation holder. this.actions.initiateValidationPool.log(this, this.bench); - const pool = await this.bench.initiateValidationPool(reputationPublicKey, { + const pool = await this.bench.initiateValidationPool({ postId: post.id, fee: request.fee, duration, diff --git a/forum-network/src/classes/expert.js b/forum-network/src/classes/expert.js index 0b69740..312585e 100644 --- a/forum-network/src/classes/expert.js +++ b/forum-network/src/classes/expert.js @@ -44,20 +44,28 @@ export class Expert extends Actor { return forum.addPost(this.reputationPublicKey, postContent); } - async initiateValidationPool(bench, options) { + async submitPostWithFee(bench, forum, postContent, poolOptions) { + this.actions.submitPost.log(this, forum); + const postId = await forum.addPost(this.reputationPublicKey, postContent); + const pool = await this.initiateValidationPool(bench, { ...poolOptions, postId, anonymous: false }); + return { postId, pool }; + } + + async initiateValidationPool(bench, poolOptions) { // For now, directly call bench.initiateValidationPool(); - const signingKey = await CryptoUtil.generateAsymmetricKey(); - const signingPublicKey = await CryptoUtil.exportKey(signingKey.publicKey); + if (poolOptions.anonymous) { + const signingKey = await CryptoUtil.generateAsymmetricKey(); + poolOptions.signingPublicKey = await CryptoUtil.exportKey(signingKey.publicKey); + } else { + poolOptions.signingPublicKey = this.reputationPublicKey; + } this.actions.initiateValidationPool.log( this, bench, - `(fee: ${options.fee})`, + `(fee: ${poolOptions.fee})`, ); - const pool = bench.initiateValidationPool(this.reputationPublicKey, { - ...options, - signingPublicKey, - }); - this.validationPools.set(pool.id, { signingPublicKey }); + const pool = bench.initiateValidationPool(poolOptions); + this.validationPools.set(pool.id, poolOptions); return pool; } diff --git a/forum-network/src/classes/scene.js b/forum-network/src/classes/scene.js index 2bed7ef..4b53489 100644 --- a/forum-network/src/classes/scene.js +++ b/forum-network/src/classes/scene.js @@ -28,7 +28,6 @@ export class Scene { darkMode: true, primaryColor: '#2a5b6c', primaryTextColor: '#b6b6b6', - fontFamily: 'monospace', noteBkgColor: '#516f77', noteTextColor: '#cecece', }, diff --git a/forum-network/src/classes/validation-pool.js b/forum-network/src/classes/validation-pool.js index 28e9c9d..addb45c 100644 --- a/forum-network/src/classes/validation-pool.js +++ b/forum-network/src/classes/validation-pool.js @@ -16,7 +16,6 @@ const ValidationPoolStates = Object.freeze({ export class ValidationPool extends Actor { constructor( bench, - authorId, { postId, signingPublicKey, @@ -61,7 +60,8 @@ export class ValidationPool extends Actor { this.bench = bench; this.id = CryptoUtil.randomUUID(); this.dateStart = new Date(); - this.authorId = authorId; + this.authorSigningPublicKey = signingPublicKey; + this.anonymous = anonymous; this.fee = fee; this.duration = duration; this.tokenLossRatio = tokenLossRatio; @@ -201,10 +201,17 @@ export class ValidationPool extends Actor { } distributeTokens(result) { + let authorReputationPublicKey; + if (this.anonymous) { + const author = this.voters.get(this.authorSigningPublicKey); + authorReputationPublicKey = author.reputationPublicKey; + } else { + authorReputationPublicKey = this.authorSigningPublicKey; + } // Reward the author // TODO: If the vote fails, distribute tokens.author among winning voters if (result === true) { - this.bench.reputations.addTokens(this.authorId, this.tokens.for); + this.bench.reputations.addTokens(authorReputationPublicKey, this.tokens.for); // Reward the vote winners, in proportion to their stakes const tokensForWinners = this.tokens.against; const winningVotes = this.listVotes(result); diff --git a/forum-network/src/index.css b/forum-network/src/index.css index 2a469d3..83daf58 100644 --- a/forum-network/src/index.css +++ b/forum-network/src/index.css @@ -1,6 +1,5 @@ body { - background-color: #1b3d49; - background-color: #114754; + background-color: #09343f; color: #b6b6b6; font-family: monospace; font-size: 8pt; diff --git a/forum-network/src/tests/availability.html b/forum-network/src/tests/availability.html index a2494ec..380e9f1 100644 --- a/forum-network/src/tests/availability.html +++ b/forum-network/src/tests/availability.html @@ -26,17 +26,17 @@ "sequenceDiagram" )); - const members = (window.members = []); + const experts = (window.experts = []); const newExpert = async () => { - const index = members.length; + const index = experts.length; const name = `Expert${index + 1}`; - const member = await new Expert(name, scene).initialize(); - members.push(member); - return member; + const expert = await new Expert(name, scene).initialize(); + experts.push(expert); + return expert; }; - const member1 = await newExpert(); - const member2 = await newExpert(); + 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)); @@ -55,10 +55,10 @@ const requestor = new Public("Public", scene); const updateDisplayValues = async () => { - for (const member of members) { - member.setValue( + for (const expert of experts) { + expert.setValue( "rep", - bench.reputations.getTokens(member.reputationPublicKey) + bench.reputations.getTokens(expert.reputationPublicKey) ); } bench.setValue("total rep", bench.getTotalReputation()); @@ -73,10 +73,10 @@ const getActiveWorker = async () => { let worker; let request; - for (const member of members) { - request = await member.getAssignedWork(availability, business); + for (const expert of experts) { + request = await expert.getAssignedWork(availability, business); if (request) { - worker = member; + worker = expert; worker.actions.getAssignedWork.log(worker, availability); worker.activate(); break; @@ -86,9 +86,9 @@ }; const voteForWorkEvidence = async (worker, pool) => { - for (const member of members) { - if (member !== worker) { - await member.castVote(pool, { + for (const expert of experts) { + if (expert !== worker) { + await expert.castVote(pool, { position: true, stake: 1, anonymous: false, @@ -100,8 +100,8 @@ await updateDisplayValuesAndDelay(); // Populate availability pool - await member1.registerAvailability(availability, 1); - await member2.registerAvailability(availability, 1); + await expert1.registerAvailability(availability, 1); + await expert2.registerAvailability(availability, 1); await updateDisplayValuesAndDelay(); // Submit work request diff --git a/forum-network/src/tests/forum.html b/forum-network/src/tests/forum.html index ffebf07..04a1237 100644 --- a/forum-network/src/tests/forum.html +++ b/forum-network/src/tests/forum.html @@ -27,33 +27,26 @@ "sequenceDiagram" )); - const members = (window.members = []); + const experts = (window.experts = []); const newExpert = async () => { - const index = members.length; + const index = experts.length; const name = `Expert${index + 1}`; - const member = await new Expert(name, scene).initialize(); - members.push(member); - return member; + const expert = await new Expert(name, scene).initialize(); + experts.push(expert); + return expert; }; - const posts = (window.posts = []); - const newPost = async (author, content, citations) => { - const postContent = new PostContent({ hello: "there" }); - const postId = await member1.submitPost(forum, postContent1); - return postId; - }; - - const member1 = await newExpert(); - const member2 = await newExpert(); + 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 updateDisplayValues = async () => { - for (const member of members) { - member.setValue( + for (const expert of experts) { + expert.setValue( "rep", - bench.reputations.getTokens(member.reputationPublicKey) + bench.reputations.getTokens(expert.reputationPublicKey) ); } bench.setValue("total rep", bench.getTotalReputation()); @@ -67,15 +60,39 @@ await updateDisplayValuesAndDelay(); - const postId1 = await member1.submitPost( + const { postId: postId1, pool: pool1 } = await expert1.submitPostWithFee( + bench, forum, - new PostContent({ hello: "there" }) + new PostContent({ hello: "there" }), + { + fee: 10, + duration: 1000, + tokenLossRatio: 1, + } ); await updateDisplayValuesAndDelay(); - const postId2 = await member1.submitPost( + await expert2.castVote(pool1, { position: true, stake: 1, anonymous: false }); + await updateDisplayValuesAndDelay(); + + await pool1.evaluateWinningConditions(); + await updateDisplayValuesAndDelay(); + + const { pool: pool2 } = await expert2.submitPostWithFee( + bench, forum, - new PostContent({ hello: "to you as well" }).addCitation(postId1, 0.5) + new PostContent({ hello: "to you as well" }).addCitation(postId1, 0.5), + { + fee: 10, + duration: 1000, + tokenLossRatio: 1, + } ); await updateDisplayValuesAndDelay(); + + await expert1.castVote(pool2, { position: true, stake: 1, anonymous: false }); + await updateDisplayValuesAndDelay(); + + await pool2.evaluateWinningConditions(); + await updateDisplayValuesAndDelay(); diff --git a/forum-network/src/tests/validation-pool.html b/forum-network/src/tests/validation-pool.html index bc170a2..d81fd88 100644 --- a/forum-network/src/tests/validation-pool.html +++ b/forum-network/src/tests/validation-pool.html @@ -19,24 +19,24 @@ const scene = (window.scene = new Scene("Validation Pool test", rootBox).log( "sequenceDiagram" )); - const member1 = (window.member1 = await new Expert( + const expert1 = (window.expert1 = await new Expert( "Expert1", scene ).initialize()); - const member2 = (window.member2 = await new Expert( + const expert2 = (window.expert2 = await new Expert( "Expert2", scene ).initialize()); const bench = (window.bench = new Bench("Bench", scene)); const updateDisplayValues = async () => { - member1.setValue( + expert1.setValue( "rep", - bench.reputations.getTokens(member1.reputationPublicKey) + bench.reputations.getTokens(expert1.reputationPublicKey) ); - member2.setValue( + expert2.setValue( "rep", - bench.reputations.getTokens(member2.reputationPublicKey) + bench.reputations.getTokens(expert2.reputationPublicKey) ); bench.setValue("total rep", bench.getTotalReputation()); // With params.lockingTimeExponent = 0 and params.activeVoterThreshold = null, @@ -50,14 +50,14 @@ updateDisplayValues(); await delay(1000); - // First member can self-approve + // First expert can self-approve { - const pool = await member1.initiateValidationPool(bench, { + const pool = await expert1.initiateValidationPool(bench, { fee: 7, duration: 1000, tokenLossRatio: 1, }); - await member1.revealIdentity(pool); + await expert1.revealIdentity(pool); // Attempting to evaluate winning conditions before the duration has expired // should result in an exception try { @@ -78,14 +78,14 @@ await delay(1000); } - // Failure example: second member can not self-approve + // Failure example: second expert can not self-approve try { - const pool = await member2.initiateValidationPool(bench, { + const pool = await expert2.initiateValidationPool(bench, { fee: 1, duration: 1000, tokenLossRatio: 1, }); - await member2.revealIdentity(pool); + await expert2.revealIdentity(pool); await delay(1000); await pool.evaluateWinningConditions(); // Quorum not met! await updateDisplayValues(); @@ -99,16 +99,16 @@ } } - // Second member must be approved by first member + // Second expert must be approved by first expert { - const pool = await member2.initiateValidationPool(bench, { + const pool = await expert2.initiateValidationPool(bench, { fee: 1, duration: 1000, tokenLossRatio: 1, }); - await member1.castVote(pool, { position: true, stake: 4, lockingTime: 0 }); - await member1.revealIdentity(pool); - await member2.revealIdentity(pool); + await expert1.castVote(pool, { position: true, stake: 4, lockingTime: 0 }); + await expert1.revealIdentity(pool); + await expert2.revealIdentity(pool); await delay(1000); await pool.evaluateWinningConditions(); // Vote passes await updateDisplayValues();