Improve Availability test
This commit is contained in:
parent
6ad293b5b8
commit
fc3138adab
|
@ -3,3 +3,23 @@
|
|||
- Receiving payments
|
||||
- Distributing payments to participants
|
||||
- Computing updates to forum graph
|
||||
|
||||
## Receiving payments
|
||||
|
||||
Business SC will need to implement a financial model.
|
||||
|
||||
# Excerpts from DeSciPubDAOArchit22July19PrintCut.pdf
|
||||
|
||||
> With today’s prices, however, we will begin by programming this all off-chain and simplify the reputation tokens to be less dynamic in their evaluation. Next iteration improves the decentralization commensurate with practical realities.
|
||||
|
||||
# Questions
|
||||
|
||||
## Validation pool termination
|
||||
|
||||
How do we want to handle this?
|
||||
The validation pool specifies a duration.
|
||||
We don't want to compute results until the end of this duration.
|
||||
We're currently supporting anonymous voting.
|
||||
With anonymous voting, we need to wait until the end of the vote duration,
|
||||
and then have a separate interval in which voters reveal their identities.
|
||||
For now, we can let anonymous voters reveal their identities at any time
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Forum</title>
|
||||
<title>Availability test</title>
|
||||
<script type="module" src="./availability-test.js" defer></script>
|
||||
<link type="text/css" rel="stylesheet" href="./index.css" />
|
||||
</head>
|
||||
|
|
|
@ -6,17 +6,32 @@ import { Business } from './classes/business.js';
|
|||
import { Availability } from './classes/availability.js';
|
||||
import { delay } from './util.js';
|
||||
import { Forum } from './classes/forum.js';
|
||||
import { Public } from './classes/public.js';
|
||||
|
||||
const DELAY_INTERVAL = 500;
|
||||
|
||||
const rootElement = document.getElementById('availability-test');
|
||||
const rootBox = new Box('rootBox', rootElement).flex();
|
||||
|
||||
const scene = window.scene = new Scene('Availability test', rootBox).log('sequenceDiagram');
|
||||
const member1 = window.member1 = await new Member('Member1', scene).initialize();
|
||||
const member2 = window.member2 = await new Member('Member2', scene).initialize();
|
||||
|
||||
const members = window.members = [];
|
||||
const newMember = async () => {
|
||||
const index = members.length;
|
||||
const name = `Member${index + 1}`;
|
||||
const member = await new Member(name, scene).initialize();
|
||||
members.push(member);
|
||||
return member;
|
||||
};
|
||||
|
||||
const member1 = await newMember();
|
||||
const member2 = await newMember();
|
||||
await newMember();
|
||||
const bench = window.bench = new Bench('Bench', scene);
|
||||
const forum = window.forum = new Forum(bench, 'Forum', scene);
|
||||
const availability = window.bench = new Availability(bench, 'Availability', scene);
|
||||
const business = window.bench = new Business(bench, forum, availability, 'Business', scene);
|
||||
const business = window.business = new Business(bench, forum, availability, 'Business', scene);
|
||||
const requestor = window.requestor = new Public('Public', scene);
|
||||
|
||||
const updateDisplayValues = async () => {
|
||||
member1.setValue('rep', bench.reputations.getTokens(member1.reputationPublicKey));
|
||||
|
@ -25,44 +40,65 @@ const updateDisplayValues = async () => {
|
|||
await scene.renderSequenceDiagram();
|
||||
};
|
||||
|
||||
updateDisplayValues();
|
||||
const updateDisplayValuesAndDelay = async () => {
|
||||
await updateDisplayValues();
|
||||
await delay(DELAY_INTERVAL);
|
||||
};
|
||||
|
||||
// const post1 = window.post1 = new PostContent({ message: 'hi' });
|
||||
// const post2 = window.post2 = new PostContent({ message: 'hello' }).addCitation(window.post1.id, 1.0);
|
||||
const getActiveWorker = async () => {
|
||||
let worker;
|
||||
let request;
|
||||
for (const member of members) {
|
||||
request = await member.getAssignedWork(availability, business);
|
||||
if (request) {
|
||||
worker = member;
|
||||
worker.actions.getAssignedWork.log(worker, availability);
|
||||
worker.activate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { worker, request };
|
||||
};
|
||||
|
||||
const voteForWorkEvidence = async (worker, pool) => {
|
||||
for (const member of members) {
|
||||
if (member !== worker) {
|
||||
await member.castVote(pool, { position: true, stake: 1, anonymous: false });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await updateDisplayValuesAndDelay();
|
||||
|
||||
// Populate availability pool
|
||||
availability.register(member1.reputationPublicKey, 1);
|
||||
availability.register(member2.reputationPublicKey, 1);
|
||||
|
||||
await delay(500);
|
||||
await member1.registerAvailability(availability, 1);
|
||||
await member2.registerAvailability(availability, 1);
|
||||
await updateDisplayValuesAndDelay();
|
||||
|
||||
// Submit work request
|
||||
const requestId = await business.submitRequest(100, { please: 'do some work' });
|
||||
await scene.renderSequenceDiagram();
|
||||
await delay(500);
|
||||
await requestor.submitRequest(business, { fee: 100 }, { please: 'do some work' });
|
||||
await updateDisplayValuesAndDelay();
|
||||
|
||||
// Receive work request
|
||||
const { worker, request } = await getActiveWorker();
|
||||
|
||||
// Submit work evidence
|
||||
const pool = await business.submitWork(member1.reputationPublicKey, requestId, {
|
||||
const pool = await worker.submitWork(business, request.id, {
|
||||
here: 'is some evidence of work product',
|
||||
}, {
|
||||
tokenLossRatio: 1,
|
||||
duration: 1000,
|
||||
});
|
||||
|
||||
await scene.renderSequenceDiagram();
|
||||
await delay(500);
|
||||
worker.deactivate();
|
||||
await updateDisplayValuesAndDelay();
|
||||
|
||||
// Vote on work evidence
|
||||
await member2.castVote(pool, { position: true, stake: 1 });
|
||||
await scene.renderSequenceDiagram();
|
||||
await delay(500);
|
||||
await voteForWorkEvidence(worker, pool);
|
||||
await updateDisplayValuesAndDelay();
|
||||
|
||||
await member2.revealIdentity(pool);
|
||||
await scene.renderSequenceDiagram();
|
||||
await delay(500);
|
||||
// Wait for validation pool duration to elapse
|
||||
await delay(1000);
|
||||
|
||||
await member1.revealIdentity(pool, member1.reputationPublicKey);
|
||||
await scene.renderSequenceDiagram();
|
||||
|
||||
// Distribute reputation awards
|
||||
// Distribute fees
|
||||
// Distribute reputation awards and fees
|
||||
await pool.evaluateWinningConditions();
|
||||
await updateDisplayValuesAndDelay();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { Action } from './action.js';
|
||||
import { Actor } from './actor.js';
|
||||
|
||||
class Worker {
|
||||
|
@ -21,6 +22,10 @@ export class Availability extends Actor {
|
|||
constructor(bench, name, scene) {
|
||||
super(name, scene);
|
||||
this.bench = bench;
|
||||
|
||||
this.actions = {
|
||||
assignWork: new Action('assign work', scene),
|
||||
};
|
||||
}
|
||||
|
||||
register(reputationPublicKey, stake) {
|
||||
|
@ -44,6 +49,11 @@ export class Availability extends Actor {
|
|||
const worker = this.availableWorkers[index];
|
||||
worker.available = false;
|
||||
worker.assignedRequestId = requestId;
|
||||
// TOOD: Notify assignee
|
||||
// TODO: Notify assignee
|
||||
}
|
||||
|
||||
async getAssignedWork(reputationPublicKey) {
|
||||
const worker = this.workers.get(reputationPublicKey);
|
||||
return worker.assignedRequestId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ export class Bench extends Actor {
|
|||
contentiousDebate,
|
||||
signingPublicKey,
|
||||
authorStake,
|
||||
anonymous,
|
||||
},
|
||||
) {
|
||||
const validationPoolNumber = this.validationPools.size + 1;
|
||||
|
@ -79,6 +80,7 @@ export class Bench extends Actor {
|
|||
contentiousDebate,
|
||||
signingPublicKey,
|
||||
authorStake,
|
||||
anonymous,
|
||||
},
|
||||
`pool${validationPoolNumber}`,
|
||||
this.scene,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { Action } from './action.js';
|
||||
import { Actor } from './actor.js';
|
||||
import { CryptoUtil } from './crypto.js';
|
||||
import { PostContent } from './post.js';
|
||||
|
@ -21,6 +22,12 @@ export class Business extends Actor {
|
|||
this.bench = bench;
|
||||
this.forum = forum;
|
||||
this.availability = availability;
|
||||
|
||||
this.actions = {
|
||||
assignWork: new Action('assign work', scene),
|
||||
addPost: new Action('add post', scene),
|
||||
initiateValidationPool: new Action('initiate validation pool', scene),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,29 +40,41 @@ export class Business extends Actor {
|
|||
async submitRequest(fee, content) {
|
||||
const request = new Request(fee, content);
|
||||
this.requests.set(request.id, request);
|
||||
this.actions.assignWork.log(this, this.availability);
|
||||
await this.availability.assignWork(request.id);
|
||||
return request.id;
|
||||
}
|
||||
|
||||
async getRequest(requestId) {
|
||||
const request = this.requests.get(requestId);
|
||||
return request;
|
||||
}
|
||||
|
||||
async submitWork(reputationPublicKey, requestId, workEvidence, { tokenLossRatio, duration }) {
|
||||
const { fee } = this.requests.get(requestId);
|
||||
const request = this.requests.get(requestId);
|
||||
if (!request) {
|
||||
throw new Error(`Request not found! id: ${requestId}`);
|
||||
}
|
||||
|
||||
// Create a post representing this submission.
|
||||
const post = new PostContent({
|
||||
requestId,
|
||||
workEvidence,
|
||||
});
|
||||
this.actions.addPost.log(this, this.forum);
|
||||
await this.forum.addPost(reputationPublicKey, post);
|
||||
|
||||
// Initiate a validation pool for this work evidence.
|
||||
// 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, {
|
||||
postId: post.id,
|
||||
fee,
|
||||
fee: request.fee,
|
||||
duration,
|
||||
tokenLossRatio,
|
||||
signingPublicKey: reputationPublicKey,
|
||||
anonymous: false,
|
||||
});
|
||||
|
||||
// When the validation pool concludes,
|
||||
|
|
|
@ -34,14 +34,6 @@ export class Forum extends Actor {
|
|||
for (const { postId: citedPostId, weight } of postContent.citations) {
|
||||
this.posts.addEdge('citation', post.id, citedPostId, { weight });
|
||||
}
|
||||
// this.applyReputationEffects(post);
|
||||
// initiateValidationPool(authorId, {postId, fee, duration, tokenLossRatio, contentiousDebate, signingPublicKey}) {
|
||||
|
||||
// const pool = await this.bench.initiateValidationPool(authorId, {
|
||||
// ...poolParams,
|
||||
// postId,
|
||||
// });
|
||||
// return pool;
|
||||
}
|
||||
|
||||
getPost(postId) {
|
||||
|
|
|
@ -12,6 +12,9 @@ export class Member extends Actor {
|
|||
initiateValidationPool: new Action('initiate validation pool', scene),
|
||||
castVote: new Action('cast vote', scene),
|
||||
revealIdentity: new Action('reveal identity', scene),
|
||||
registerAvailability: new Action('register availability', scene),
|
||||
getAssignedWork: new Action('get assigned work', scene),
|
||||
submitWork: new Action('submit work evidence', scene),
|
||||
};
|
||||
this.validationPools = new Map();
|
||||
}
|
||||
|
@ -51,30 +54,49 @@ export class Member extends Actor {
|
|||
return pool;
|
||||
}
|
||||
|
||||
async castVote(validationPool, { position, stake, lockingTime }) {
|
||||
async castVote(validationPool, {
|
||||
position, stake, lockingTime, anonymous = true,
|
||||
}) {
|
||||
let signingPublicKey;
|
||||
if (anonymous) {
|
||||
const signingKey = await CryptoUtil.generateAsymmetricKey();
|
||||
const signingPublicKey = await CryptoUtil.exportKey(signingKey.publicKey);
|
||||
signingPublicKey = await CryptoUtil.exportKey(signingKey.publicKey);
|
||||
this.validationPools.set(validationPool.id, { signingPublicKey });
|
||||
} else {
|
||||
signingPublicKey = this.reputationPublicKey;
|
||||
}
|
||||
// TODO: encrypt vote
|
||||
// TODO: sign message
|
||||
this.actions.castVote.log(
|
||||
this,
|
||||
validationPool,
|
||||
`(${position ? 'for' : 'against'}, stake: ${stake})`,
|
||||
`(${position ? 'for' : 'against'}, stake: ${stake}, anonymous: ${anonymous})`,
|
||||
);
|
||||
validationPool.castVote(signingPublicKey, position, stake, lockingTime);
|
||||
return validationPool.castVote(signingPublicKey, {
|
||||
position, stake, lockingTime, anonymous,
|
||||
});
|
||||
}
|
||||
|
||||
async revealIdentity(validationPool, signingPublicKey) {
|
||||
if (!signingPublicKey) {
|
||||
signingPublicKey = this.validationPools.get(validationPool.id).signingPublicKey;
|
||||
}
|
||||
async revealIdentity(validationPool) {
|
||||
const { signingPublicKey } = this.validationPools.get(validationPool.id);
|
||||
// TODO: sign message
|
||||
this.actions.revealIdentity.log(this, validationPool);
|
||||
validationPool.revealIdentity(signingPublicKey, this.reputationPublicKey);
|
||||
}
|
||||
|
||||
async submitWork(business, requestId, evidence, { tokenLossRatio }) {
|
||||
await business.submitWork(this.reputationPublicKey, requestId, evidence, { tokenLossRatio });
|
||||
async registerAvailability(availability, stake) {
|
||||
this.actions.registerAvailability.log(this, availability, `(stake: ${stake})`);
|
||||
await availability.register(this.reputationPublicKey, stake);
|
||||
}
|
||||
|
||||
async getAssignedWork(availability, business) {
|
||||
const requestId = await availability.getAssignedWork(this.reputationPublicKey);
|
||||
const request = await business.getRequest(requestId);
|
||||
return request;
|
||||
}
|
||||
|
||||
async submitWork(business, requestId, evidence, { tokenLossRatio, duration }) {
|
||||
this.actions.submitWork.log(this, business);
|
||||
return business.submitWork(this.reputationPublicKey, requestId, evidence, { tokenLossRatio, duration });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { Action } from './action.js';
|
||||
import { Actor } from './actor.js';
|
||||
|
||||
export class Public extends Actor {
|
||||
constructor(name, scene) {
|
||||
super(name, scene);
|
||||
this.actions = {
|
||||
submitRequest: new Action('submit work request', scene),
|
||||
};
|
||||
}
|
||||
|
||||
async submitRequest(business, { fee }, content) {
|
||||
this.actions.submitRequest.log(this, business, `(fee: ${fee})`);
|
||||
return business.submitRequest(fee, content);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import params from './params.js';
|
|||
const ValidationPoolStates = Object.freeze({
|
||||
OPEN: 'OPEN',
|
||||
CLOSED: 'CLOSED',
|
||||
RESOLVED: 'RESOLVED',
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -24,6 +25,7 @@ export class ValidationPool extends Actor {
|
|||
tokenLossRatio,
|
||||
contentiousDebate = false,
|
||||
authorStake = 0,
|
||||
anonymous = true,
|
||||
},
|
||||
name,
|
||||
scene,
|
||||
|
@ -71,10 +73,19 @@ export class ValidationPool extends Actor {
|
|||
// tokens minted "for" the post go toward stake of author voting for their own post
|
||||
// also, author can provide additional stakes, e.g. availability stakes for work evidence post
|
||||
console.log('initiateValidationPool casting vote', { signingPublicKey });
|
||||
this.castVote(signingPublicKey, true, this.tokens.for + authorStake, 0);
|
||||
this.castVote(signingPublicKey, {
|
||||
position: true,
|
||||
stake: this.tokens.for + authorStake,
|
||||
anonymous,
|
||||
});
|
||||
}
|
||||
|
||||
castVote(signingPublicKey, position, stake, lockingTime) {
|
||||
async castVote(signingPublicKey, {
|
||||
position, stake, lockingTime = 0, anonymous = true,
|
||||
}) {
|
||||
console.log('castVote', {
|
||||
signingPublicKey, position, stake, anonymous,
|
||||
});
|
||||
const vote = new Vote(position, stake, lockingTime);
|
||||
if (this.state === ValidationPoolStates.CLOSED) {
|
||||
throw new Error(`Validation pool ${this.id} is closed`);
|
||||
|
@ -85,6 +96,10 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
listVotes(position) {
|
||||
|
@ -95,7 +110,7 @@ export class ValidationPool extends Actor {
|
|||
);
|
||||
}
|
||||
|
||||
revealIdentity(signingPublicKey, reputationPublicKey) {
|
||||
async revealIdentity(signingPublicKey, reputationPublicKey) {
|
||||
if (!this.votes.get(signingPublicKey)) {
|
||||
throw new Error('Must vote before revealing identity');
|
||||
}
|
||||
|
@ -104,23 +119,6 @@ export class ValidationPool extends Actor {
|
|||
voter.addVoteRecord(this);
|
||||
this.bench.voters.set(reputationPublicKey, voter);
|
||||
this.voters.set(signingPublicKey, voter);
|
||||
if (this.votes.size === this.voters.size) {
|
||||
// All voters have revealed their reputation public keys
|
||||
// Now we can evaluate winning conditions
|
||||
this.state = ValidationPoolStates.CLOSED;
|
||||
this.setStatus('Closed');
|
||||
const result = this.evaluateWinningConditions();
|
||||
if (result === null) {
|
||||
this.setStatus('Closed - Quorum not met');
|
||||
this.scene.log(`note over ${this.name} : Quorum not met`);
|
||||
} else {
|
||||
this.setStatus(`Closed - ${result ? 'Won' : 'Lost'}`);
|
||||
this.scene.log(`note over ${this.name} : ${result ? 'Win' : 'Lose'}`);
|
||||
this.applyTokenLocking();
|
||||
this.distributeTokens(result);
|
||||
}
|
||||
this.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
getTokenLossRatio() {
|
||||
|
@ -163,7 +161,21 @@ export class ValidationPool extends Actor {
|
|||
}
|
||||
}
|
||||
|
||||
evaluateWinningConditions() {
|
||||
async evaluateWinningConditions() {
|
||||
if (this.state === ValidationPoolStates.RESOLVED) {
|
||||
throw new Error('Validation pool has already been resolved!');
|
||||
}
|
||||
const elapsed = new Date() - this.dateStart;
|
||||
if (elapsed < this.duration) {
|
||||
throw new Error(`Validation pool duration has not yet elapsed! ${this.duration - elapsed} ms remaining.`);
|
||||
}
|
||||
if (this.voters.size < this.votes.size) {
|
||||
throw new Error('Not all voters have revealed their reputation public keys!');
|
||||
}
|
||||
// Now we can evaluate winning conditions
|
||||
this.state = ValidationPoolStates.CLOSED;
|
||||
this.setStatus('Closed');
|
||||
|
||||
const getVoteValue = ({ stake, lockingTime }) => stake * lockingTime ** params.lockingTimeExponent;
|
||||
const getTotalValue = (position) => Array.from(this.listVotes(position).values())
|
||||
.map(getVoteValue)
|
||||
|
@ -175,7 +187,21 @@ export class ValidationPool extends Actor {
|
|||
const votePasses = upvoteValue >= params.winningRatio * downvoteValue;
|
||||
const quorumMet = upvoteValue + downvoteValue >= params.quorum * activeAvailableReputation;
|
||||
|
||||
return quorumMet ? votePasses : null;
|
||||
const result = quorumMet ? votePasses : null;
|
||||
|
||||
if (result === null) {
|
||||
this.setStatus('Resolved - Quorum not met');
|
||||
this.scene.log(`note over ${this.name} : Quorum not met`);
|
||||
} else {
|
||||
this.setStatus(`Resolved - ${result ? 'Won' : 'Lost'}`);
|
||||
this.scene.log(`note over ${this.name} : ${result ? 'Win' : 'Lose'}`);
|
||||
this.applyTokenLocking();
|
||||
this.distributeTokens(result);
|
||||
}
|
||||
this.deactivate();
|
||||
this.state = ValidationPoolStates.RESOLVED;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
distributeTokens(result) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Forum Graph</title>
|
||||
<title>Forum Graph: Debounce test</title>
|
||||
<script type="module" src="./debounce-test.js" defer></script>
|
||||
<link type="text/css" rel="stylesheet" href="./index.css" />
|
||||
</head>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Forum</title>
|
||||
<title>Forum Network test</title>
|
||||
<script type="module" src="./forum-network-test.js" defer></script>
|
||||
<link type="text/css" rel="stylesheet" href="./index.css" />
|
||||
</head>
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Forum Network</title>
|
||||
<title>Mermaid test</title>
|
||||
<link type="text/css" rel="stylesheet" href="./index.css" />
|
||||
|
||||
<script type="module" defer>
|
||||
// import mermaid from './mermaid.mjs';
|
||||
import mermaid from 'https://unpkg.com/mermaid@9.2.2/dist/mermaid.esm.mjs';
|
||||
import mermaid from "https://unpkg.com/mermaid@9.2.2/dist/mermaid.esm.mjs";
|
||||
mermaid.mermaidAPI.initialize({ startOnLoad: false });
|
||||
// Example of using the API var
|
||||
const element = document.querySelector('#graphDiv');
|
||||
const element = document.querySelector("#graphDiv");
|
||||
const insertSvg = function (svgCode, bindFunctions) {
|
||||
element.innerHTML = svgCode;
|
||||
};
|
||||
const graphDefinition = 'graph TB\na-->b';
|
||||
const graph = await mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg);
|
||||
const div = document.createElement('div');
|
||||
const graphDefinition = "graph TB\na-->b";
|
||||
const graph = await mermaid.mermaidAPI.render(
|
||||
"graphDiv",
|
||||
graphDefinition,
|
||||
insertSvg
|
||||
);
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = graph;
|
||||
document.body.append(div);
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Forum</title>
|
||||
<title>Validation Pool test</title>
|
||||
<script type="module" src="./validation-pool-test.js" defer></script>
|
||||
<link type="text/css" rel="stylesheet" href="./index.css" />
|
||||
</head>
|
||||
|
|
|
@ -30,8 +30,9 @@ await delay(1000);
|
|||
// First member can self-approve
|
||||
{
|
||||
const pool = await member1.initiateValidationPool(bench, { fee: 7, duration: 1000, tokenLossRatio: 1 });
|
||||
// await member1.castVote(pool, true, 0, 0);
|
||||
await member1.revealIdentity(pool); // Vote passes
|
||||
await member1.revealIdentity(pool);
|
||||
await delay(1000);
|
||||
await pool.evaluateWinningConditions(); // Vote passes
|
||||
await updateDisplayValues();
|
||||
await delay(1000);
|
||||
}
|
||||
|
@ -39,7 +40,9 @@ await delay(1000);
|
|||
// Failure example: second member can not self-approve
|
||||
try {
|
||||
const pool = await member2.initiateValidationPool(bench, { fee: 1, duration: 1000, tokenLossRatio: 1 });
|
||||
await member2.revealIdentity(pool); // Quorum not met!
|
||||
await member2.revealIdentity(pool);
|
||||
await delay(1000);
|
||||
await pool.evaluateWinningConditions(); // Quorum not met!
|
||||
await updateDisplayValues();
|
||||
await delay(1000);
|
||||
} catch (e) {
|
||||
|
@ -56,7 +59,9 @@ try {
|
|||
const pool = await member2.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); // Vote passes
|
||||
await member2.revealIdentity(pool);
|
||||
await delay(1000);
|
||||
await pool.evaluateWinningConditions(); // Vote passes
|
||||
await updateDisplayValues();
|
||||
await delay(1000);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue