Fixes to validation pool

This commit is contained in:
Ladd Hoffman 2022-11-17 08:30:06 -06:00
parent a481710cde
commit e7120f87b1
7 changed files with 55 additions and 46 deletions

View File

@ -52,9 +52,9 @@ export class Bench extends Actor {
.reduce((acc, cur) => acc += cur, 0); .reduce((acc, cur) => acc += cur, 0);
} }
initiateValidationPool(authorId, {fee, duration, tokenLossRatio, contentiousDebate}) { initiateValidationPool(authorId, {fee, duration, tokenLossRatio, contentiousDebate, signingPublicKey}) {
const validationPoolNumber = this.validationPools.size + 1; const validationPoolNumber = this.validationPools.size + 1;
const validationPool = new ValidationPool(this, authorId, {fee, duration, tokenLossRatio, contentiousDebate}, const validationPool = new ValidationPool(this, authorId, {fee, duration, tokenLossRatio, contentiousDebate, signingPublicKey},
`pool${validationPoolNumber}`, scene); `pool${validationPoolNumber}`, scene);
this.validationPools.set(validationPool.id, validationPool); this.validationPools.set(validationPool.id, validationPool);
this.actions.createValidationPool.log(this, validationPool) this.actions.createValidationPool.log(this, validationPool)

View File

@ -17,7 +17,8 @@ export class Member extends Actor {
async initialize() { async initialize() {
this.reputationKey = await CryptoUtil.generateAsymmetricKey(); this.reputationKey = await CryptoUtil.generateAsymmetricKey();
this.reputationPublicKey = await CryptoUtil.exportKey(this.reputationKey.publicKey); // this.reputationPublicKey = await CryptoUtil.exportKey(this.reputationKey.publicKey);
this.reputationPublicKey = this.name;
this.status.set('Initialized'); this.status.set('Initialized');
this.activate(); this.activate();
return this; return this;
@ -32,13 +33,17 @@ export class Member extends Actor {
await forumNode.receiveMessage(JSON.stringify(postMessage.toJSON())); await forumNode.receiveMessage(JSON.stringify(postMessage.toJSON()));
} }
initiateValidationPool(bench, options) { async initiateValidationPool(bench, options) {
// For now, directly call bench.initiateValidationPool(); // For now, directly call bench.initiateValidationPool();
const signingKey = await CryptoUtil.generateAsymmetricKey();
const signingPublicKey = await CryptoUtil.exportKey(signingKey.publicKey)
this.actions.initiateValidationPool.log(this, bench); this.actions.initiateValidationPool.log(this, bench);
return bench.initiateValidationPool(this.reputationPublicKey, options); const pool = bench.initiateValidationPool(this.reputationPublicKey, {...options, signingPublicKey});
this.validationPools.set(pool.id, {signingPublicKey});
return pool;
} }
async castVote(validationPool, position, stake, lockingTime) { async castVote(validationPool, {position, stake, lockingTime}) {
const signingKey = await CryptoUtil.generateAsymmetricKey(); const signingKey = await CryptoUtil.generateAsymmetricKey();
const signingPublicKey = await CryptoUtil.exportKey(signingKey.publicKey) const signingPublicKey = await CryptoUtil.exportKey(signingKey.publicKey)
this.validationPools.set(validationPool.id, {signingPublicKey}); this.validationPools.set(validationPool.id, {signingPublicKey});

View File

@ -1,9 +1,9 @@
const params = { const params = {
mintingRatio: 1, // c1 mintingRatio: 1, // c1
stakeForWin: 0.5, // c2 stakeForWin: 0.5, // c2
stakeForAuthor: 0.5, // c3 // stakeForAuthor: 0.5, // c3 - For now we keep the default that stakeForAuthor = stakeForWin
winningRatio: 0.5, // c4 winningRatio: 0.5, // c4
quorum: 1, // c5 quorum: 0, // c5
activeVoterThreshold: null, // c6 activeVoterThreshold: null, // c6
voteDuration: { // c7 voteDuration: { // c7
min: 0, min: 0,

View File

@ -48,7 +48,6 @@ export class Scene {
deactivateAll() { deactivateAll() {
for (const actor of this.actors.values()) { for (const actor of this.actors.values()) {
console.log(actor);
while (actor.active) { while (actor.active) {
actor.deactivate(); actor.deactivate();
} }

View File

@ -10,7 +10,7 @@ const ValidationPoolStates = Object.freeze({
}); });
export class ValidationPool extends Actor { export class ValidationPool extends Actor {
constructor(bench, authorId, {fee, duration, tokenLossRatio, contentiousDebate = false}, name, scene) { constructor(bench, authorId, {signingPublicKey, fee, duration, tokenLossRatio, contentiousDebate = false}, name, scene) {
super(name, scene); super(name, scene);
// If contentiousDebate = true, we will follow the progression defined by getTokenLossRatio() // If contentiousDebate = true, we will follow the progression defined by getTokenLossRatio()
if (!contentiousDebate && (tokenLossRatio < 0 || tokenLossRatio > 1 || [null, undefined].includes(tokenLossRatio))) { if (!contentiousDebate && (tokenLossRatio < 0 || tokenLossRatio > 1 || [null, undefined].includes(tokenLossRatio))) {
@ -33,9 +33,10 @@ export class ValidationPool extends Actor {
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),
author: fee * params.mintingRatio * params.stakeForAuthor, // author: fee * params.mintingRatio * params.stakeForAuthor,
} }
// TODO: Consider availability stakes // TODO: Consider availability stakes
this.castVote(signingPublicKey, true, this.tokens.for, 0);
} }
castVote(signingPublicKey, position, stake, lockingTime) { castVote(signingPublicKey, position, stake, lockingTime) {
@ -120,6 +121,7 @@ export class ValidationPool extends Actor {
// TODO: If quorum is not met, what should happen? // TODO: If quorum is not met, what should happen?
if (!quorumMet) { if (!quorumMet) {
this.deactivate(); this.deactivate();
// console.log("Quorum is not met", {upvoteValue, downvoteValue, activeAvailableReputation});
throw new Error("Quorum is not met"); throw new Error("Quorum is not met");
} }
return votePasses && quorumMet; return votePasses && quorumMet;
@ -128,19 +130,23 @@ export class ValidationPool extends Actor {
distributeTokens(result) { distributeTokens(result) {
// Reward the author // Reward the author
// TODO: If the vote fails, distribute tokens.author among winning voters // TODO: If the vote fails, distribute tokens.author among winning voters
this.bench.reputations.addTokens(this.authorId, this.tokens.author); if (result === true) {
// Reward the vote winners, in proportion to their stakes // console.log("awarding to author", {id: this.authorId, tokens: this.tokens.for});
const tokensForWinners = result ? this.tokens.for : this.tokens.against; this.bench.reputations.addTokens(this.authorId, this.tokens.for);
const winningVotes = this.listVotes(result); // Reward the vote winners, in proportion to their stakes
const totalStakes = Array.from(winningVotes.values()) const tokensForWinners = this.tokens.against;
.map(({stake}) => stake).reduce((acc, cur) => acc += cur, 0); const winningVotes = this.listVotes(result);
if (!totalStakes) { const totalStakes = Array.from(winningVotes.values())
return; .map(({stake}) => stake).reduce((acc, cur) => acc += cur, 0);
} if (!totalStakes) {
for (const [signingPublicKey, {stake}] of winningVotes.entries()) { return;
const {reputationPublicKey} = this.voters.get(signingPublicKey); }
const reward = tokensForWinners * stake / totalStakes; for (const [signingPublicKey, {stake}] of winningVotes.entries()) {
this.bench.reputations.addTokens(reputationPublicKey, reward); const {reputationPublicKey} = this.voters.get(signingPublicKey);
const reward = tokensForWinners * stake / totalStakes;
// console.log("awarding to winning voter", {id: reputationPublicKey, tokens: reward, stake, totalStakes, tokensForWinners});
this.bench.reputations.addTokens(reputationPublicKey, reward);
}
} }
} }
} }

View File

@ -14,8 +14,6 @@
}; };
const graphDefinition = 'graph TB\na-->b'; const graphDefinition = 'graph TB\na-->b';
const graph = await mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg); const graph = await mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg);
console.log("executed...");
console.log(graph);
const div = document.createElement('div'); const div = document.createElement('div');
div.innerHTML = graph; div.innerHTML = graph;
document.body.append(div); document.body.append(div);

View File

@ -27,34 +27,35 @@ await delay(1000);
// First member can self-approve // First member can self-approve
{ {
const pool = member1.initiateValidationPool(bench, {fee: 1, duration: 1000, tokenLossRatio: 1}); const pool = await member1.initiateValidationPool(bench, {fee: 7, duration: 1000, tokenLossRatio: 1});
await member1.castVote(pool, true, 0, 0); // await member1.castVote(pool, true, 0, 0);
await member1.revealIdentity(pool); // Vote passes await member1.revealIdentity(pool); // Vote passes
await updateDisplayValues(); await updateDisplayValues();
await delay(1000); await delay(1000);
} }
// Failure example: second member can not self-approve // // Failure example: second member can not self-approve
try { // try {
const pool = member2.initiateValidationPool(bench, {fee: 1, duration: 1000, tokenLossRatio: 1}); // const pool = member2.initiateValidationPool(bench, {fee: 1, duration: 1000, tokenLossRatio: 1});
await member2.castVote(pool, true, 0, 0); // await member2.castVote(pool, true, 0, 0);
await member2.revealIdentity(pool); // Quorum not met! // await member2.revealIdentity(pool); // Quorum not met!
await updateDisplayValues(); // await updateDisplayValues();
await delay(1000); // await delay(1000);
} catch(e) { // } catch(e) {
if (e.message.match(/Quorum is not met/)) { // if (e.message.match(/Quorum is not met/)) {
console.log("Caught expected error: Quorum not met") // console.log("Caught expected error: Quorum not met")
} else { // } else {
console.error("Unexpected error") // console.error("Unexpected error")
throw e; // throw e;
} // }
} // }
// Second member must be approved by first member // Second member must be approved by first member
{ {
const pool = member2.initiateValidationPool(bench, {fee: 1, duration: 1000, tokenLossRatio: 1}); const pool = await member2.initiateValidationPool(bench, {fee: 1, duration: 1000, tokenLossRatio: 1});
await member1.castVote(pool, true, 0.5, 1); await member1.castVote(pool, {position: true, stake: 4, lockingTime: 0});
await member1.revealIdentity(pool); // Vote passes await member1.revealIdentity(pool);
await member2.revealIdentity(pool); // Vote passes
await updateDisplayValues(); await updateDisplayValues();
await delay(1000); await delay(1000);
} }