Validation pool initial implementation
This commit is contained in:
parent
715943ec77
commit
beb1a069d7
|
@ -0,0 +1,9 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<head>
|
||||||
|
<title>Forum Network</title>
|
||||||
|
<script type="module" src="./basic.js" defer></script>
|
||||||
|
<link type="text/css" rel="stylesheet" href="./index.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="basic"></div>
|
||||||
|
</body>
|
|
@ -1,4 +1,7 @@
|
||||||
const rootElement = document.getElementById('forum-network');
|
import { Box } from "./classes/box.js";
|
||||||
|
import { Scene } from "./classes/scene.js";
|
||||||
|
|
||||||
|
const rootElement = document.getElementById('basic');
|
||||||
const rootBox = new Box('rootBox', rootElement).flex();
|
const rootBox = new Box('rootBox', rootElement).flex();
|
||||||
|
|
||||||
function randomDelay(min, max) {
|
function randomDelay(min, max) {
|
|
@ -0,0 +1,15 @@
|
||||||
|
export class Action {
|
||||||
|
constructor(name, scene) {
|
||||||
|
this.name = name;
|
||||||
|
this.scene = scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(src, dest, msg, obj, symbol = '->>') {
|
||||||
|
const logObj = false;
|
||||||
|
this.scene.log(
|
||||||
|
`${src.name} ${symbol} ${dest.name} : ${this.name} ${msg ?? ''} ${
|
||||||
|
logObj && obj ? JSON.stringify(obj) : ''
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +1,3 @@
|
||||||
export class Action {
|
|
||||||
constructor(name, scene) {
|
|
||||||
this.name = name;
|
|
||||||
this.scene = scene;
|
|
||||||
}
|
|
||||||
|
|
||||||
log(src, dest, msg, obj, symbol = '->>') {
|
|
||||||
const logObj = false;
|
|
||||||
this.scene.log(
|
|
||||||
`${src.name} ${symbol} ${dest.name} : ${this.name} ${msg ?? ''} ${
|
|
||||||
logObj && obj ? JSON.stringify(obj) : ''
|
|
||||||
}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Actor {
|
export class Actor {
|
||||||
constructor(name, scene) {
|
constructor(name, scene) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
import {DisplayValue} from "./display-value.js";
|
||||||
|
|
||||||
|
export class Box {
|
||||||
|
constructor(name, parentEl, elementType = 'div') {
|
||||||
|
this.name = name;
|
||||||
|
this.el = document.createElement(elementType);
|
||||||
|
this.el.classList.add('box');
|
||||||
|
this.el.setAttribute('box-name', name);
|
||||||
|
if (parentEl) {
|
||||||
|
parentEl.appendChild(this.el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flex() {
|
||||||
|
this.el.classList.add('flex');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
monospace() {
|
||||||
|
this.el.classList.add('monospace');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
addClass(className) {
|
||||||
|
this.el.classList.add(className);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
addBox(name, elementType) {
|
||||||
|
const box = new Box(name, null, elementType);
|
||||||
|
this.el.appendChild(box.el);
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
addDisplayValue(value) {
|
||||||
|
const box = this.addBox(value.name).flex();
|
||||||
|
return new DisplayValue(value, box);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInnerHTML(html) {
|
||||||
|
this.el.innerHTML = html;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInnerText() {
|
||||||
|
return this.el.innerText;
|
||||||
|
}
|
||||||
|
|
||||||
|
setId(id) {
|
||||||
|
this.el.id = id || this.name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getId() {
|
||||||
|
return this.el.id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,45 +21,3 @@ export class DisplayValue {
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Box {
|
|
||||||
constructor(name, parentEl) {
|
|
||||||
this.el = document.createElement('div');
|
|
||||||
this.el.classList.add('box');
|
|
||||||
this.el.setAttribute('box-name', name);
|
|
||||||
if (parentEl) {
|
|
||||||
parentEl.appendChild(this.el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flex() {
|
|
||||||
this.el.classList.add('flex');
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
monospace() {
|
|
||||||
this.el.classList.add('monospace');
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
addClass(className) {
|
|
||||||
this.el.classList.add(className);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
addBox(name) {
|
|
||||||
const box = new Box(name);
|
|
||||||
this.el.appendChild(box.el);
|
|
||||||
return box;
|
|
||||||
}
|
|
||||||
|
|
||||||
addDisplayValue(value) {
|
|
||||||
const box = this.addBox(value.name).flex();
|
|
||||||
return new DisplayValue(value, box);
|
|
||||||
}
|
|
||||||
|
|
||||||
setInnerHTML(html) {
|
|
||||||
this.el.innerHTML = html;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Actor, Action } from './actor.js';
|
import { Actor } from './actor.js';
|
||||||
|
import { Action } from './action.js';
|
||||||
import { Message, PostMessage, PeerMessage } from './message.js';
|
import { Message, PostMessage, PeerMessage } from './message.js';
|
||||||
import { CryptoUtil } from './crypto.js';
|
import { CryptoUtil } from './crypto.js';
|
||||||
import { ForumView } from './forum-view.js';
|
import { ForumView } from './forum-view.js';
|
||||||
|
|
|
@ -26,8 +26,12 @@ export class ForumView {
|
||||||
this.authors = new Map();
|
this.authors = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
getReputation(publicKey) {
|
getReputation(id) {
|
||||||
return this.reputations.get(publicKey);
|
return this.reputations.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
setReputation(id, reputation) {
|
||||||
|
this.reputations.set(id, reputation);
|
||||||
}
|
}
|
||||||
|
|
||||||
incrementReputation(publicKey, increment, reason) {
|
incrementReputation(publicKey, increment, reason) {
|
||||||
|
@ -96,6 +100,7 @@ export class ForumView {
|
||||||
console.log('distributeNonbindingReputation', { post, amount, depth });
|
console.log('distributeNonbindingReputation', { post, amount, depth });
|
||||||
// Some of the incoming reputation goes to this post
|
// Some of the incoming reputation goes to this post
|
||||||
post.reputation += amount * (1 - this.citationFraction);
|
post.reputation += amount * (1 - this.citationFraction);
|
||||||
|
this.setReputation(post.id, post.reputation);
|
||||||
// Some of the incoming reputation gets distributed among cited posts
|
// Some of the incoming reputation gets distributed among cited posts
|
||||||
const distributeAmongCitations = amount * this.citationFraction;
|
const distributeAmongCitations = amount * this.citationFraction;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,11 @@ export class Edge {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class CategorizedEdges {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export class Graph {
|
export class Graph {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.vertices = new Map();
|
this.vertices = new Map();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Actor, Action } from './actor.js';
|
import { Actor } from './actor.js';
|
||||||
|
import { Action } from './action.js';
|
||||||
import { PostMessage } from './message.js';
|
import { PostMessage } from './message.js';
|
||||||
import { CryptoUtil } from './crypto.js';
|
import { CryptoUtil } from './crypto.js';
|
||||||
|
|
||||||
|
@ -7,7 +8,11 @@ export class Member extends Actor {
|
||||||
super(name, scene);
|
super(name, scene);
|
||||||
this.actions = {
|
this.actions = {
|
||||||
submitPost: new Action('submit post', scene),
|
submitPost: new Action('submit post', scene),
|
||||||
|
initiateVote: new Action('initiate vote', scene),
|
||||||
|
castVote: new Action('cast vote', scene),
|
||||||
|
revealIdentity: new Action('reveal identity', scene),
|
||||||
};
|
};
|
||||||
|
this.votes = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
async initialize() {
|
async initialize() {
|
||||||
|
@ -23,4 +28,19 @@ export class Member extends Actor {
|
||||||
// For now, directly call forumNode.receiveMessage();
|
// For now, directly call forumNode.receiveMessage();
|
||||||
await forumNode.receiveMessage(JSON.stringify(postMessage.toJSON()));
|
await forumNode.receiveMessage(JSON.stringify(postMessage.toJSON()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async castVote(validationPool, voteId, position, stake) {
|
||||||
|
const signingKey = await CryptoUtil.generateSigningKey();
|
||||||
|
this.votes.set(voteId, {signingKey});
|
||||||
|
// TODO: signed CastVoteMessage
|
||||||
|
this.actions.castVote.log(this, validationPool);
|
||||||
|
validationPool.castVote(voteId, signingKey.publicKey, position, stake);
|
||||||
|
}
|
||||||
|
|
||||||
|
async revealIdentity(validationPool, voteId) {
|
||||||
|
const {signingKey} = this.votes.get(voteId);
|
||||||
|
// TODO: signed RevealIdentityMessage
|
||||||
|
this.actions.revealIdentity.log(this, validationPool);
|
||||||
|
validationPool.revealIdentity(voteId, signingKey.publicKey, this.keyPair.publicKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { Actor, Action } from './actor.js';
|
import { Actor } from './actor.js';
|
||||||
|
import { Action } from './action.js';
|
||||||
|
// import mermaid from 'https://unpkg.com/mermaid@9.2.2/dist/mermaid.esm.mjs';
|
||||||
|
|
||||||
export class Scene {
|
export class Scene {
|
||||||
constructor(name, rootBox) {
|
constructor(name, rootBox) {
|
||||||
|
@ -9,6 +11,9 @@ export class Scene {
|
||||||
this.displayValuesBox = this.box.addBox(`${this.name}-values`);
|
this.displayValuesBox = this.box.addBox(`${this.name}-values`);
|
||||||
this.box.addBox('Spacer').setInnerHTML(' ');
|
this.box.addBox('Spacer').setInnerHTML(' ');
|
||||||
this.logBox = this.box.addBox(`${this.name}-log`);
|
this.logBox = this.box.addBox(`${this.name}-log`);
|
||||||
|
// this.seqDiagramContainer = this.box.addBox(`${this.name}-seq-diagram-container`);
|
||||||
|
// this.seqDiagramBox = this.box.addBox(`${this.name}-seq-diagram`);
|
||||||
|
// mermaid.mermaidAPI.initialize({ startOnLoad: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
addActor(name) {
|
addActor(name) {
|
||||||
|
@ -30,4 +35,17 @@ export class Scene {
|
||||||
this.logBox.addBox().setInnerHTML(msg).monospace();
|
this.logBox.addBox().setInnerHTML(msg).monospace();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// async renderSequenceDiagram() {
|
||||||
|
// await mermaid.mermaidAPI.render(
|
||||||
|
// `${this.name}-seq-diagram-element`,
|
||||||
|
// this.logBox.getInnerText(),
|
||||||
|
// this.insertSvg,
|
||||||
|
// this.seqDiagramContainer.el
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// insertSvg (svgCode) {
|
||||||
|
// this.seqDiagramBox.setInnerHTML(svgCode);
|
||||||
|
// };
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
import { Actor } from "./actor.js";
|
||||||
|
import { Action } from "./action.js";
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
mintingRatio: 1, // c1
|
||||||
|
stakeForWin: 0.5, // c2
|
||||||
|
stakeForAuthor: 0.5, // c3
|
||||||
|
winningRatio: 0.5, // c4
|
||||||
|
quorum: 1, // c5
|
||||||
|
activeVoterThreshold: null, // c6
|
||||||
|
voteDuration: { // c7
|
||||||
|
min: 0,
|
||||||
|
max: null,
|
||||||
|
},
|
||||||
|
// NOTE: c8 is the token loss ratio, which is specified as a runtime argument
|
||||||
|
contentiousDebate: {
|
||||||
|
period: 5000, // c9
|
||||||
|
stages: 3, // c10
|
||||||
|
},
|
||||||
|
lockingTimeExponent: 0, // c11
|
||||||
|
};
|
||||||
|
|
||||||
|
function getTokenLossRatio(elapsed) {
|
||||||
|
let stageDuration = params.contentiousDebate.period / 2;
|
||||||
|
let stage = 0;
|
||||||
|
let t = 0;
|
||||||
|
while (true) {
|
||||||
|
t += stageDuration;
|
||||||
|
stageDuration /= 2;
|
||||||
|
if (t > elapsed) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stage += 1;
|
||||||
|
if (stage >= params.contentiousDebate.stages - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stage / (params.contentiousDebate.stages - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Voter {
|
||||||
|
constructor(reputationPublicKey) {
|
||||||
|
this.reputationPublicKey = reputationPublicKey;
|
||||||
|
this.voteHistory = [];
|
||||||
|
this.reputation = 0;
|
||||||
|
this.dateLastVote = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
addVoteRecord(vote) {
|
||||||
|
this.voteHistory.push(vote);
|
||||||
|
if (!this.dateLastVote || vote.dateStart > this.dateLastVote) {
|
||||||
|
this.dateLastVote = vote.dateStart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getReputation() {
|
||||||
|
return this.reputation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Vote {
|
||||||
|
constructor(validationPool, {fee, duration, tokenLossRatio, contentiousDebate = false}) {
|
||||||
|
if (tokenLossRatio < 0 || tokenLossRatio > 1) {
|
||||||
|
throw new Error(`Token loss ratio must be in the range [0, 1]; got ${tokenLossRatio}`)
|
||||||
|
}
|
||||||
|
if (duration < params.voteDuration.min || duration > params.voteDuration.max) {
|
||||||
|
throw new Error(`Duration must be in the range [${params.voteDuration.min}, ${params.voteDuration.max ?? 'Inf'}]; got ${duration}`);
|
||||||
|
}
|
||||||
|
this.votes = new Map();
|
||||||
|
this.voters = new Map();
|
||||||
|
this.validationPool = validationPool;
|
||||||
|
this.id = window.crypto.randomUUID();
|
||||||
|
this.dateStart = new Date();
|
||||||
|
this.fee = fee;
|
||||||
|
this.duration = duration;
|
||||||
|
this.tokenLossRatio = tokenLossRatio;
|
||||||
|
this.contentiousDebate = contentiousDebate;
|
||||||
|
|
||||||
|
this.tokens = {
|
||||||
|
win: fee * params.mintingRatio * params.stakeForWin,
|
||||||
|
lose: fee * params.mintingRatio * (1 - params.stakeForWin),
|
||||||
|
author: fee * params.mintingRatio * params.stakeForAuthor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
castVote(signingPublicKey, position, stake, lockingTime) {
|
||||||
|
if (this.duration && new Date() - this.dateStart > this.duration) {
|
||||||
|
throw new Error(`Vote ${this.id} has expired, no new votes may be cast`);
|
||||||
|
}
|
||||||
|
this.votes.set(signingPublicKey, { position, stake, lockingTime });
|
||||||
|
}
|
||||||
|
|
||||||
|
revealIdentity(signingPublicKey, voter) {
|
||||||
|
if (!this.votes.get(signingPublicKey)) {
|
||||||
|
throw new Error("Must vote before revealing identity");
|
||||||
|
}
|
||||||
|
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.applyTokenLocking();
|
||||||
|
this.evaluateWinningConditions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getTokenLossRatio() {
|
||||||
|
if (!this.contentiousDebate) {
|
||||||
|
return this.tokenLossRatio;
|
||||||
|
}
|
||||||
|
const elapsed = new Date() - this.dateStart;
|
||||||
|
let stageDuration = params.contentiousDebate.period / 2;
|
||||||
|
let stage = 0;
|
||||||
|
let t = 0;
|
||||||
|
while (true) {
|
||||||
|
t += stageDuration;
|
||||||
|
stageDuration /= 2;
|
||||||
|
if (t > elapsed) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stage += 1;
|
||||||
|
if (stage >= params.contentiousDebate.stages - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stage / (params.contentiousDebate.stages - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyTokenLocking() {
|
||||||
|
// Before evaluating the winning conditions,
|
||||||
|
// we need to make sure any staked tokens are locked for the
|
||||||
|
// specified amounts of time.
|
||||||
|
// TODO: Implement token locking
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluateWinningConditions() {
|
||||||
|
let upvotes = 0;
|
||||||
|
let downvotes = 0;
|
||||||
|
|
||||||
|
for (const {position, stake, lockingTime} of this.votes.values()) {
|
||||||
|
const value = stake * Math.pow(lockingTime, params.lockingTimeExponent);
|
||||||
|
if (position === true) {
|
||||||
|
upvotes += value;
|
||||||
|
} else {
|
||||||
|
downvotes += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeVoterCount = this.validationPool.countActiveVoters();
|
||||||
|
const votePasses = upvotes >= params.winningRatio * downvotes;
|
||||||
|
const quorumMet = upvotes + downvotes >= params.quorum * activeVoterCount;
|
||||||
|
|
||||||
|
if (votePasses && quorumMet) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listVoters() {
|
||||||
|
return Array.from(this.voters.values());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ValidationPool extends Actor {
|
||||||
|
constructor(name, scene) {
|
||||||
|
super(name, scene);
|
||||||
|
this.votes = [];
|
||||||
|
this.voters = new Map();
|
||||||
|
|
||||||
|
this.actions = {
|
||||||
|
initializeVote: new Action('initialize vote', scene),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
listVotes() {
|
||||||
|
Array.from(this.votes.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
listActiveVoters() {
|
||||||
|
const now = new Date();
|
||||||
|
return Array.from(this.voters.values()).filter(voter => {
|
||||||
|
if (!params.activeVoterThreshold) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!voter.dateLastVote) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return now - voter.dateLastVote >= params.activeVoterThreshold;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
countActiveVoters() {
|
||||||
|
return this.listActiveVoters().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
initiateVote({fee, duration, tokenLossRatio, contentiousDebate}) {
|
||||||
|
const vote = new Vote(this, {fee, duration, tokenLossRatio, contentiousDebate});
|
||||||
|
this.actions.initializeVote.log(this, this);
|
||||||
|
this.votes.set(vote.id, vote);
|
||||||
|
return vote.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
castVote(voteId, signingPublicKey, position, stake, lockingTime) {
|
||||||
|
// TODO: Implement vote encryption
|
||||||
|
const vote = this.votes.get(voteId);
|
||||||
|
vote.castVote(signingPublicKey, position, stake, lockingTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
revealIdentity(voteId, signingPublicKey, reputationPublicKey) {
|
||||||
|
const vote = this.votes.get(voteId);
|
||||||
|
const voter = this.voters.get(reputationPublicKey) ?? new Voter(reputationPublicKey);
|
||||||
|
voter.addVoteRecord(vote);
|
||||||
|
this.voters.set(reputationPublicKey, voter);
|
||||||
|
vote.revealIdentity(signingPublicKey, voter);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { Box } from './classes/display-value.js';
|
import { Box } from './classes/box.js';
|
||||||
import { Scene } from './classes/scene.js';
|
import { Scene } from './classes/scene.js';
|
||||||
import { Post } from './classes/post.js';
|
import { Post } from './classes/post.js';
|
||||||
import { Member } from './classes/member.js';
|
import { Member } from './classes/member.js';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Box } from './classes/display-value.js';
|
import { Box } from './classes/box.js';
|
||||||
import { Scene } from './classes/scene.js';
|
import { Scene } from './classes/scene.js';
|
||||||
import { Graph } from './classes/graph.js';
|
import { Graph } from './classes/graph.js';
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
.box {
|
.box {
|
||||||
// border: 1px #eee solid;
|
/* border: 1px #eee solid; */
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
}
|
}
|
||||||
.box .name {
|
.box .name {
|
||||||
width: 10em;
|
width: 12em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
margin-right: 6pt;
|
margin-right: 6pt;
|
||||||
}
|
}
|
||||||
.box .value {
|
.box .value {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
// border: 0px;
|
/* border: 0px; */
|
||||||
}
|
}
|
||||||
.flex {
|
.flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
.monospace {
|
.monospace {
|
||||||
// border: 0px;
|
/* border: 0px; */
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 11pt;
|
font-size: 11pt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<head>
|
<head>
|
||||||
<title>Forum Network</title>
|
<title>Forum Network</title>
|
||||||
<script src="./classes/display-value.js"></script>
|
<script type="module" src="./index.js" defer></script>
|
||||||
<script src="./classes/actor.js"></script>
|
|
||||||
<script src="./classes/scene.js"></script>
|
|
||||||
<script src="./classes/reputation.js"></script>
|
|
||||||
<script src="./classes/forum.js"></script>
|
|
||||||
<script src="./index.js" defer></script>
|
|
||||||
<link type="text/css" rel="stylesheet" href="./index.css" />
|
<link type="text/css" rel="stylesheet" href="./index.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="forum-network"></div>
|
<ul>
|
||||||
|
<li><a href="./basic.html">Basic test</a></li>
|
||||||
|
<li><a href="./forum-test.html">Forum test</a></li>
|
||||||
|
<li><a href="./graph-test.html">Graph test</a></li>
|
||||||
|
<li><a href="./validation-pool-test.html">Validation Pool test</a></li>
|
||||||
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<head>
|
||||||
|
<title>Forum</title>
|
||||||
|
<script type="module" src="./validation-pool-test.js" defer></script>
|
||||||
|
<link type="text/css" rel="stylesheet" href="./index.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="validation-pool"></div>
|
||||||
|
</body>
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { Box } from './classes/box.js';
|
||||||
|
import { Scene } from './classes/scene.js';
|
||||||
|
import { Member } from './classes/member.js';
|
||||||
|
import { ValidationPool } from './classes/validation-pool.js';
|
||||||
|
|
||||||
|
const rootElement = document.getElementById('validation-pool');
|
||||||
|
const rootBox = new Box('rootBox', rootElement).flex();
|
||||||
|
|
||||||
|
const scene = window.scene = new Scene('Validation Pool test', rootBox).log('sequenceDiagram');
|
||||||
|
|
||||||
|
const pool = window.validationPool = new ValidationPool("validationPool", scene);
|
||||||
|
|
||||||
|
const member1 = window.member1 = await new Member("member1", scene).initialize();
|
||||||
|
const member2 = window.member2 = await new Member("member2", scene).initialize();
|
||||||
|
|
||||||
|
const voteId = pool.initiateVote({fee: 1, duration: 1, isBinding: false});
|
||||||
|
|
||||||
|
await member1.castVote(pool, voteId, true, 50);
|
||||||
|
await member2.castVote(pool, voteId, true, 50);
|
||||||
|
|
||||||
|
await member1.revealIdentity(pool, voteId);
|
||||||
|
await member2.revealIdentity(pool, voteId);
|
||||||
|
|
||||||
|
// await scene.renderSequenceDiagram();
|
Loading…
Reference in New Issue