Add support for flowchart diagrams alongside sequence
This commit is contained in:
parent
b644d6c119
commit
1066372371
|
@ -4,9 +4,9 @@ export class Action {
|
|||
this.scene = scene;
|
||||
}
|
||||
|
||||
log(src, dest, msg, obj, symbol = '->>') {
|
||||
async log(src, dest, msg, obj, symbol = '->>') {
|
||||
const logObj = false;
|
||||
this.scene.log(
|
||||
await this.scene.sequence.log(
|
||||
`${src.name} ${symbol} ${dest.name} : ${this.name} ${msg ?? ''} ${
|
||||
logObj && obj ? JSON.stringify(obj) : ''
|
||||
}`,
|
||||
|
|
|
@ -5,7 +5,6 @@ export class Actor {
|
|||
this.callbacks = new Map();
|
||||
this.status = this.scene.addDisplayValue(`${this.name} status`);
|
||||
this.status.set('New');
|
||||
this.scene.log(`participant ${this.name}`);
|
||||
this.values = new Map();
|
||||
this.active = 0;
|
||||
this.scene.registerActor(this);
|
||||
|
@ -13,31 +12,31 @@ export class Actor {
|
|||
|
||||
activate() {
|
||||
this.active += 1;
|
||||
this.scene.log(`activate ${this.name}`);
|
||||
this.scene.sequence.log(`activate ${this.name}`, false);
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
async deactivate() {
|
||||
if (!this.active) {
|
||||
throw new Error(`${this.name} is not active, can not deactivate`);
|
||||
}
|
||||
this.active -= 1;
|
||||
this.scene.log(`deactivate ${this.name}`);
|
||||
await this.scene.sequence.log(`deactivate ${this.name}`);
|
||||
}
|
||||
|
||||
send(dest, action, detail) {
|
||||
action.log(this, dest, detail ? JSON.stringify(detail) : '');
|
||||
dest.recv(this, action, detail);
|
||||
async send(dest, action, detail) {
|
||||
await action.log(this, dest, detail ? JSON.stringify(detail) : '');
|
||||
await dest.recv(this, action, detail);
|
||||
return this;
|
||||
}
|
||||
|
||||
recv(src, action, detail) {
|
||||
async recv(src, action, detail) {
|
||||
const cb = this.callbacks.get(action.name);
|
||||
if (!cb) {
|
||||
throw new Error(
|
||||
`[${this.scene.name} actor ${this.name} does not have a callback registered for ${action.name}`,
|
||||
);
|
||||
}
|
||||
cb(src, detail);
|
||||
await cb(src, detail);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -56,7 +55,7 @@ export class Actor {
|
|||
return this;
|
||||
}
|
||||
|
||||
setValue(label, value) {
|
||||
async setValue(label, value) {
|
||||
if (typeof value === 'number') {
|
||||
value = value.toFixed(2);
|
||||
}
|
||||
|
@ -66,7 +65,7 @@ export class Actor {
|
|||
this.values.set(label, displayValue);
|
||||
}
|
||||
if (value !== displayValue.get()) {
|
||||
this.scene.log(`note over ${this.name} : ${label} = ${value}`);
|
||||
await this.scene.sequence.log(`note over ${this.name} : ${label} = ${value}`);
|
||||
}
|
||||
displayValue.set(value);
|
||||
return this;
|
||||
|
|
|
@ -18,8 +18,6 @@ export class Bench extends Actor {
|
|||
this.actions = {
|
||||
createValidationPool: new Action('create validation pool', scene),
|
||||
};
|
||||
|
||||
this.activate();
|
||||
}
|
||||
|
||||
listValidationPools() {
|
||||
|
@ -56,7 +54,7 @@ export class Bench extends Actor {
|
|||
.reduce((acc, cur) => (acc += cur), 0);
|
||||
}
|
||||
|
||||
initiateValidationPool({
|
||||
async initiateValidationPool({
|
||||
postId,
|
||||
fee,
|
||||
duration,
|
||||
|
@ -84,7 +82,7 @@ export class Bench extends Actor {
|
|||
this.scene,
|
||||
);
|
||||
this.validationPools.set(validationPool.id, validationPool);
|
||||
this.actions.createValidationPool.log(this, validationPool);
|
||||
await this.actions.createValidationPool.log(this, validationPool);
|
||||
validationPool.activate();
|
||||
return validationPool;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
import { DisplayValue } from './display-value.js';
|
||||
import { CryptoUtil } from './crypto.js';
|
||||
|
||||
export class Box {
|
||||
constructor(name, parentEl, elementType = 'div') {
|
||||
this.name = name;
|
||||
this.el = document.createElement(elementType);
|
||||
this.el.id = `box_${CryptoUtil.randomUUID().replaceAll('-', '').slice(0, 8)}`;
|
||||
this.el.classList.add('box');
|
||||
if (name) {
|
||||
this.el.setAttribute('box-name', name);
|
||||
}
|
||||
if (parentEl) {
|
||||
parentEl.appendChild(this.el);
|
||||
}
|
||||
|
@ -27,8 +31,7 @@ export class Box {
|
|||
}
|
||||
|
||||
addBox(name, elementType) {
|
||||
const box = new Box(name, null, elementType);
|
||||
this.el.appendChild(box.el);
|
||||
const box = new Box(name, this.el, elementType);
|
||||
return box;
|
||||
}
|
||||
|
||||
|
@ -46,11 +49,6 @@ export class Box {
|
|||
return this.el.innerText;
|
||||
}
|
||||
|
||||
setId(id) {
|
||||
this.el.id = (id || this.name).replace(/ /g, '');
|
||||
return this;
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.el.id;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ 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.actions.assignWork.log(this, this.availability);
|
||||
this.worker = await this.availability.assignWork(request.id);
|
||||
return request.id;
|
||||
}
|
||||
|
@ -54,13 +54,13 @@ export class Business extends Actor {
|
|||
requestId,
|
||||
workEvidence,
|
||||
});
|
||||
this.actions.submitPost.log(this, this.forum);
|
||||
await this.actions.submitPost.log(this, this.forum);
|
||||
const postId = 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);
|
||||
await this.actions.initiateValidationPool.log(this, this.bench);
|
||||
const pool = await this.bench.initiateValidationPool({
|
||||
postId,
|
||||
fee: request.fee,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { Actor } from './actor.js';
|
||||
|
||||
import { Action } from './action.js';
|
||||
import { PostMessage } from './message.js';
|
||||
import { CryptoUtil } from './crypto.js';
|
||||
|
@ -25,7 +24,6 @@ export class Expert extends Actor {
|
|||
// this.reputationPublicKey = await CryptoUtil.exportKey(this.reputationKey.publicKey);
|
||||
this.reputationPublicKey = this.name;
|
||||
this.status.set('Initialized');
|
||||
this.activate();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -33,19 +31,19 @@ export class Expert extends Actor {
|
|||
// TODO: Include fee
|
||||
const postMessage = new PostMessage({ post, stake });
|
||||
await postMessage.sign(this.reputationKey);
|
||||
this.actions.submitPostViaNetwork.log(this, forumNode, null, { id: post.id });
|
||||
await this.actions.submitPostViaNetwork.log(this, forumNode, null, { id: post.id });
|
||||
// For now, directly call forumNode.receiveMessage();
|
||||
await forumNode.receiveMessage(JSON.stringify(postMessage.toJSON()));
|
||||
}
|
||||
|
||||
async submitPost(forum, postContent) {
|
||||
// TODO: Include fee
|
||||
this.actions.submitPost.log(this, forum);
|
||||
await this.actions.submitPost.log(this, forum);
|
||||
return forum.addPost(this.reputationPublicKey, postContent);
|
||||
}
|
||||
|
||||
async submitPostWithFee(bench, forum, postContent, poolOptions) {
|
||||
this.actions.submitPost.log(this, forum);
|
||||
await 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 };
|
||||
|
@ -59,12 +57,12 @@ export class Expert extends Actor {
|
|||
} else {
|
||||
poolOptions.signingPublicKey = this.reputationPublicKey;
|
||||
}
|
||||
this.actions.initiateValidationPool.log(
|
||||
await this.actions.initiateValidationPool.log(
|
||||
this,
|
||||
bench,
|
||||
`(fee: ${poolOptions.fee})`,
|
||||
);
|
||||
const pool = bench.initiateValidationPool(poolOptions);
|
||||
const pool = await bench.initiateValidationPool(poolOptions);
|
||||
this.validationPools.set(pool.id, poolOptions);
|
||||
return pool;
|
||||
}
|
||||
|
@ -82,7 +80,7 @@ export class Expert extends Actor {
|
|||
}
|
||||
// TODO: encrypt vote
|
||||
// TODO: sign message
|
||||
this.actions.castVote.log(
|
||||
await this.actions.castVote.log(
|
||||
this,
|
||||
validationPool,
|
||||
`(${position ? 'for' : 'against'}, stake: ${stake}, anonymous: ${anonymous})`,
|
||||
|
@ -95,12 +93,12 @@ export class Expert extends Actor {
|
|||
async revealIdentity(validationPool) {
|
||||
const { signingPublicKey } = this.validationPools.get(validationPool.id);
|
||||
// TODO: sign message
|
||||
this.actions.revealIdentity.log(this, validationPool);
|
||||
await this.actions.revealIdentity.log(this, validationPool);
|
||||
validationPool.revealIdentity(signingPublicKey, this.reputationPublicKey);
|
||||
}
|
||||
|
||||
async registerAvailability(availability, stake) {
|
||||
this.actions.registerAvailability.log(this, availability, `(stake: ${stake})`);
|
||||
await this.actions.registerAvailability.log(this, availability, `(stake: ${stake})`);
|
||||
await availability.register(this.reputationPublicKey, stake);
|
||||
}
|
||||
|
||||
|
@ -111,7 +109,7 @@ export class Expert extends Actor {
|
|||
}
|
||||
|
||||
async submitWork(business, requestId, evidence, { tokenLossRatio, duration }) {
|
||||
this.actions.submitWork.log(this, business);
|
||||
await this.actions.submitWork.log(this, business);
|
||||
return business.submitWork(this.reputationPublicKey, requestId, evidence, { tokenLossRatio, duration });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ export class ForumNode extends Actor {
|
|||
.filter((forumNode) => forumNode.keyPair.publicKey !== this.keyPair.publicKey);
|
||||
for (const forumNode of otherForumNodes) {
|
||||
// For now just call receiveMessage on the target node
|
||||
this.actions.peerMessage.log(this, forumNode, null, message.content);
|
||||
await this.actions.peerMessage.log(this, forumNode, null, message.content);
|
||||
await forumNode.receiveMessage(JSON.stringify(message.toJSON()));
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ export class ForumNode extends Actor {
|
|||
try {
|
||||
await Message.verify(messageJson);
|
||||
} catch (e) {
|
||||
this.actions.processMessage.log(this, this, 'invalid signature', messageJson, '-x');
|
||||
await this.actions.processMessage.log(this, this, 'invalid signature', messageJson, '-x');
|
||||
console.log(`${this.name}: received message with invalid signature`);
|
||||
return;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ export class ForumNode extends Actor {
|
|||
if (!post.id) {
|
||||
post.id = CryptoUtil.randomUUID();
|
||||
}
|
||||
this.actions.storePost.log(this, this, null, { authorId, post, stake });
|
||||
await this.actions.storePost.log(this, this, null, { authorId, post, stake });
|
||||
this.forumView.addPost(authorId, post.id, post, stake);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ class Post extends Actor {
|
|||
this.authorPublicKey = authorPublicKey;
|
||||
this.value = 0;
|
||||
this.citations = postContent.citations;
|
||||
this.title = postContent.title;
|
||||
this.totalCitationWeight = this.citations.reduce((total, { weight }) => total += weight, 0);
|
||||
if (this.totalCitationWeight > params.revaluationLimit) {
|
||||
throw new Error('Post total citation weight exceeds revaluation limit '
|
||||
|
@ -23,8 +24,8 @@ class Post extends Actor {
|
|||
}
|
||||
}
|
||||
|
||||
setPostValue(value) {
|
||||
this.setValue('value', value);
|
||||
async setPostValue(value) {
|
||||
await this.setValue('value', value);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
@ -39,7 +40,7 @@ class Post extends Actor {
|
|||
export class Forum extends Actor {
|
||||
constructor(name, scene) {
|
||||
super(name, scene);
|
||||
this.posts = new Graph();
|
||||
this.posts = new Graph(scene);
|
||||
this.actions = {
|
||||
addPost: new Action('add post', scene),
|
||||
};
|
||||
|
@ -47,9 +48,9 @@ export class Forum extends Actor {
|
|||
|
||||
async addPost(authorId, postContent) {
|
||||
const post = new Post(this, authorId, postContent);
|
||||
this.actions.addPost.log(this, post);
|
||||
this.posts.addVertex(post.id, post);
|
||||
for (const { postId: citedPostId, weight } of postContent.citations) {
|
||||
await this.actions.addPost.log(this, post);
|
||||
this.posts.addVertex(post.id, post, post.title);
|
||||
for (const { postId: citedPostId, weight } of post.citations) {
|
||||
this.posts.addEdge('citation', post.id, citedPostId, { weight });
|
||||
}
|
||||
return post.id;
|
||||
|
@ -63,7 +64,7 @@ export class Forum extends Actor {
|
|||
return this.posts.getVertices();
|
||||
}
|
||||
|
||||
propagateValue(postId, increment, depth = 0) {
|
||||
async propagateValue(postId, increment, depth = 0) {
|
||||
if (depth > params.maxPropagationDepth) {
|
||||
return [];
|
||||
}
|
||||
|
@ -78,7 +79,7 @@ export class Forum extends Actor {
|
|||
|
||||
// Increment the value of the given post
|
||||
const postValue = post.getPostValue();
|
||||
post.setPostValue(postValue + increment);
|
||||
await post.setPostValue(postValue + increment);
|
||||
|
||||
// Award reputation to post author
|
||||
console.log('reward for post author', post.authorPublicKey, increment);
|
||||
|
@ -86,7 +87,7 @@ export class Forum extends Actor {
|
|||
|
||||
// Recursively distribute reputation to citations, according to weights
|
||||
for (const { postId: citedPostId, weight } of post.citations) {
|
||||
addRewards(this.propagateValue(citedPostId, weight * increment, depth + 1));
|
||||
addRewards(await this.propagateValue(citedPostId, weight * increment, depth + 1));
|
||||
}
|
||||
|
||||
return rewards;
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
import mermaid from 'https://unpkg.com/mermaid@9.2.2/dist/mermaid.esm.min.mjs';
|
||||
import { debounce } from '../util.js';
|
||||
|
||||
export class Vertex {
|
||||
constructor(data) {
|
||||
this.data = data;
|
||||
|
@ -29,13 +26,14 @@ export class Edge {
|
|||
export class CategorizedEdges {}
|
||||
|
||||
export class Graph {
|
||||
constructor() {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
this.vertices = new Map();
|
||||
this.edgeLabels = new Map();
|
||||
this.nextVertexId = 0;
|
||||
}
|
||||
|
||||
addVertex(id, data) {
|
||||
addVertex(id, data, label) {
|
||||
// Support simple case of auto-incremented numeric ids
|
||||
if (typeof id === 'object') {
|
||||
data = id;
|
||||
|
@ -46,6 +44,9 @@ export class Graph {
|
|||
}
|
||||
const vertex = new Vertex(data);
|
||||
this.vertices.set(id, vertex);
|
||||
if (this.scene.flowchart) {
|
||||
this.scene.flowchart.log(`${id}[${label ?? id}]`);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -83,6 +84,9 @@ export class Graph {
|
|||
this.setEdge(label, from, to, edge);
|
||||
this.getVertex(from).edges.from.push(edge);
|
||||
this.getVertex(to).edges.to.push(edge);
|
||||
if (this.scene.flowchart) {
|
||||
this.scene.flowchart.log(`${from} --> ${to}`);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -101,20 +105,4 @@ export class Graph {
|
|||
countVertices() {
|
||||
return this.vertices.size;
|
||||
}
|
||||
|
||||
async renderGraph() {
|
||||
const render = async () => {
|
||||
const dateStart = new Date();
|
||||
const graph = await mermaid.mermaidAPI.render(
|
||||
this.seqDiagramElement.getId(),
|
||||
this.logBox.getInnerText(),
|
||||
);
|
||||
this.seqDiagramBox.setInnerHTML(graph);
|
||||
if (!this.dateLastRender) {
|
||||
this.dateLastRender = new Date();
|
||||
}
|
||||
this.dateLastRender = dateStart;
|
||||
};
|
||||
debounce(render, 100);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,18 +28,27 @@ export class PostContent {
|
|||
return this;
|
||||
}
|
||||
|
||||
setTitle(title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
content: this.content,
|
||||
citations: this.citations.map((citation) => citation.toJSON()),
|
||||
...(this.id ? { id: this.id } : {}),
|
||||
title: this.title,
|
||||
};
|
||||
}
|
||||
|
||||
static fromJSON({ id, content, citations }) {
|
||||
static fromJSON({
|
||||
id, content, citations, title,
|
||||
}) {
|
||||
const post = new PostContent(content);
|
||||
post.citations = citations.map((citation) => Citation.fromJSON(citation));
|
||||
post.id = id;
|
||||
post.title = title;
|
||||
return post;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,24 +3,47 @@ import { Actor } from './actor.js';
|
|||
import { Action } from './action.js';
|
||||
import { debounce } from '../util.js';
|
||||
|
||||
class MermaidDiagram {
|
||||
constructor(box) {
|
||||
this.box = box;
|
||||
this.container = this.box.addBox('Container');
|
||||
this.element = this.box.addBox('Element');
|
||||
this.renderBox = this.box.addBox('Render');
|
||||
this.box.addBox('Spacer').setInnerHTML(' ');
|
||||
this.logBox = this.box.addBox('Log');
|
||||
}
|
||||
|
||||
async log(msg, render = true) {
|
||||
this.logBox.addBox().setInnerHTML(msg).monospace();
|
||||
if (render) {
|
||||
await this.render();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
async render() {
|
||||
const render = async () => {
|
||||
const innerText = this.logBox.getInnerText();
|
||||
const graph = await mermaid.mermaidAPI.render(
|
||||
this.element.getId(),
|
||||
innerText,
|
||||
);
|
||||
this.renderBox.setInnerHTML(graph);
|
||||
};
|
||||
await debounce(render, 100);
|
||||
}
|
||||
}
|
||||
|
||||
export class Scene {
|
||||
constructor(name, rootBox) {
|
||||
this.name = name;
|
||||
this.box = rootBox.addBox(name);
|
||||
this.titleBox = this.box.addBox().setInnerHTML(name);
|
||||
this.titleBox = this.box.addBox('Title').setInnerHTML(name);
|
||||
this.box.addBox('Spacer').setInnerHTML(' ');
|
||||
this.displayValuesBox = this.box.addBox(`${this.name}-values`);
|
||||
this.displayValuesBox = this.box.addBox('Values');
|
||||
this.box.addBox('Spacer').setInnerHTML(' ');
|
||||
this.actors = new Set();
|
||||
this.seqDiagramContainer = this.box.addBox(
|
||||
`${this.name}-seq-diagram-container`,
|
||||
);
|
||||
this.seqDiagramElement = this.box
|
||||
.addBox(`${this.name}-seq-diagram-element`)
|
||||
.setId();
|
||||
this.seqDiagramBox = this.box.addBox(`${this.name}-seq-diagram`);
|
||||
this.box.addBox('Spacer').setInnerHTML(' ');
|
||||
this.logBox = this.box.addBox(`${this.name}-log`);
|
||||
|
||||
mermaid.mermaidAPI.initialize({
|
||||
startOnLoad: false,
|
||||
theme: 'base',
|
||||
|
@ -28,18 +51,37 @@ export class Scene {
|
|||
darkMode: true,
|
||||
primaryColor: '#2a5b6c',
|
||||
primaryTextColor: '#b6b6b6',
|
||||
// lineColor: '#349cbd',
|
||||
lineColor: '#57747d',
|
||||
signalColor: '#57747d',
|
||||
// signalColor: '#349cbd',
|
||||
noteBkgColor: '#516f77',
|
||||
noteTextColor: '#cecece',
|
||||
activationBkgColor: '#1d3f49',
|
||||
activationBorderColor: '#569595',
|
||||
signalColor: '#57747d',
|
||||
},
|
||||
});
|
||||
this.dateLastRender = null;
|
||||
}
|
||||
|
||||
addActor(name) {
|
||||
withSequenceDiagram() {
|
||||
const box = this.box.addBox('Sequence diagram');
|
||||
this.sequence = new MermaidDiagram(box);
|
||||
this.sequence.log('sequenceDiagram', false);
|
||||
return this;
|
||||
}
|
||||
|
||||
withFlowchart(direction = 'BT') {
|
||||
const box = this.box.addBox('Flowchart');
|
||||
this.flowchart = new MermaidDiagram(box);
|
||||
this.flowchart.log(`graph ${direction}`, false);
|
||||
return this;
|
||||
}
|
||||
|
||||
async addActor(name) {
|
||||
const actor = new Actor(name, this);
|
||||
if (this.sequence) {
|
||||
await this.scene.sequence.log(`participant ${name}`);
|
||||
}
|
||||
return actor;
|
||||
}
|
||||
|
||||
|
@ -57,12 +99,6 @@ export class Scene {
|
|||
return dv;
|
||||
}
|
||||
|
||||
log(msg) {
|
||||
this.logBox.addBox().setInnerHTML(msg).monospace();
|
||||
this.renderSequenceDiagram();
|
||||
return this;
|
||||
}
|
||||
|
||||
deactivateAll() {
|
||||
for (const actor of this.actors.values()) {
|
||||
while (actor.active) {
|
||||
|
@ -70,20 +106,4 @@ export class Scene {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
async renderSequenceDiagram() {
|
||||
const render = async () => {
|
||||
const dateStart = new Date();
|
||||
const graph = await mermaid.mermaidAPI.render(
|
||||
this.seqDiagramElement.getId(),
|
||||
this.logBox.getInnerText(),
|
||||
);
|
||||
this.seqDiagramBox.setInnerHTML(graph);
|
||||
if (!this.dateLastRender) {
|
||||
this.dateLastRender = new Date();
|
||||
}
|
||||
this.dateLastRender = dateStart;
|
||||
};
|
||||
debounce(render, 100);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,12 +193,12 @@ export class ValidationPool extends Actor {
|
|||
|
||||
if (quorumMet) {
|
||||
this.setStatus(`Resolved - ${result ? 'Won' : 'Lost'}`);
|
||||
this.scene.log(`note over ${this.name} : ${result ? 'Win' : 'Lose'}`);
|
||||
this.scene.sequence.log(`note over ${this.name} : ${result ? 'Win' : 'Lose'}`);
|
||||
this.applyTokenLocking();
|
||||
this.distributeTokens(result);
|
||||
await this.distributeTokens(result);
|
||||
} else {
|
||||
this.setStatus('Resolved - Quorum not met');
|
||||
this.scene.log(`note over ${this.name} : Quorum not met`);
|
||||
this.scene.sequence.log(`note over ${this.name} : Quorum not met`);
|
||||
}
|
||||
|
||||
this.deactivate();
|
||||
|
@ -206,7 +206,7 @@ export class ValidationPool extends Actor {
|
|||
return result;
|
||||
}
|
||||
|
||||
distributeTokens({ votePasses }) {
|
||||
async distributeTokens({ votePasses }) {
|
||||
const rewards = new Map();
|
||||
const addReward = (id, value) => rewards.set(id, (rewards.get(id) ?? 0) + value);
|
||||
|
||||
|
@ -231,7 +231,7 @@ export class ValidationPool extends Actor {
|
|||
|
||||
if (votePasses && !!this.forum) {
|
||||
// Recurse through forum to determine reputation effects
|
||||
const forumReputationEffects = this.forum.propagateValue(this.postId, this.tokensMinted);
|
||||
const forumReputationEffects = await this.forum.propagateValue(this.postId, this.tokensMinted);
|
||||
for (const [id, value] of forumReputationEffects) {
|
||||
addReward(id, value);
|
||||
}
|
||||
|
|
|
@ -14,5 +14,6 @@
|
|||
<li><a href="/tests/debounce.html">Debounce</a></li>
|
||||
<li><a href="/tests/availability.html">Availability</a></li>
|
||||
<li><a href="/tests/forum.html">Forum</a></li>
|
||||
<li><a href="/tests/flowchart.html">Flowchart</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
|
|
|
@ -56,13 +56,13 @@
|
|||
|
||||
const updateDisplayValues = async () => {
|
||||
for (const expert of experts) {
|
||||
expert.setValue(
|
||||
await expert.setValue(
|
||||
"rep",
|
||||
bench.reputations.getTokens(expert.reputationPublicKey)
|
||||
);
|
||||
}
|
||||
bench.setValue("total rep", bench.getTotalReputation());
|
||||
await scene.renderSequenceDiagram();
|
||||
await bench.setValue("total rep", bench.getTotalReputation());
|
||||
await scene.sequence.render();
|
||||
};
|
||||
|
||||
const updateDisplayValuesAndDelay = async () => {
|
||||
|
@ -77,7 +77,7 @@
|
|||
request = await expert.getAssignedWork(availability, business);
|
||||
if (request) {
|
||||
worker = expert;
|
||||
worker.actions.getAssignedWork.log(worker, availability);
|
||||
await worker.actions.getAssignedWork.log(worker, availability);
|
||||
worker.activate();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Debounce test</title>
|
||||
<link type="text/css" rel="stylesheet" href="/index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="debounce-test"></div>
|
||||
</body>
|
||||
<script type="module">
|
||||
import { Box } from "/classes/box.js";
|
||||
import { Scene } from "/classes/scene.js";
|
||||
import { debounce, delay } from "/util.js";
|
||||
|
||||
const rootElement = document.getElementById("debounce-test");
|
||||
const rootBox = new Box("rootBox", rootElement).flex();
|
||||
|
||||
const scene = (window.scene = new Scene("Debounce test", rootBox));
|
||||
|
||||
let eventCount = 0;
|
||||
const event = () => {
|
||||
eventCount++;
|
||||
console.log(`event ${eventCount}`);
|
||||
};
|
||||
await debounce(event, 500);
|
||||
await debounce(event, 500);
|
||||
await delay(500);
|
||||
await debounce(event, 500);
|
||||
await debounce(event, 500);
|
||||
if (eventCount !== 2) {
|
||||
throw new Error(`Expected 2 events, got ${eventCount}`);
|
||||
}
|
||||
console.log(`eventCount: ${eventCount}`);
|
||||
</script>
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Flowchart test</title>
|
||||
<link type="text/css" rel="stylesheet" href="/index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="flowchart-test"></div>
|
||||
</body>
|
||||
<script type="module">
|
||||
import { Box } from "/classes/box.js";
|
||||
import { Scene } from "/classes/scene.js";
|
||||
import { Actor } from "/classes/actor.js";
|
||||
import { Action } from "/classes/action.js";
|
||||
import { Expert } from "/classes/expert.js";
|
||||
import { delay } from "/util.js";
|
||||
|
||||
const DEFAULT_DELAY_INTERVAL = 500;
|
||||
|
||||
const rootElement = document.getElementById("flowchart-test");
|
||||
const rootBox = new Box("rootBox", rootElement).flex();
|
||||
|
||||
const scene = (window.scene = new Scene("Flowchart test", rootBox));
|
||||
scene.withSequenceDiagram();
|
||||
|
||||
const actor1 = new Actor("A", scene);
|
||||
const actor2 = new Actor("B", scene);
|
||||
const action1 = new Action("Action 1", scene);
|
||||
await action1.log(actor1, actor2);
|
||||
await actor1.setValue("value", 1);
|
||||
|
||||
await scene.withFlowchart();
|
||||
await scene.flowchart.log("A --> B");
|
||||
|
||||
await delay(DEFAULT_DELAY_INTERVAL);
|
||||
action1.log(actor1, actor2);
|
||||
|
||||
await delay(DEFAULT_DELAY_INTERVAL);
|
||||
await scene.flowchart.log("A --> C");
|
||||
</script>
|
|
@ -43,7 +43,7 @@
|
|||
await window.forumNode2.processNextMessage();
|
||||
await window.forumNode3.processNextMessage();
|
||||
|
||||
await window.scene.renderSequenceDiagram();
|
||||
await window.scene.sequence.render();
|
||||
}, 100);
|
||||
|
||||
// const blockchain = new Blockchain();
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
const rootElement = document.getElementById("forum-test");
|
||||
const rootBox = new Box("rootBox", rootElement).flex();
|
||||
|
||||
const scene = (window.scene = new Scene("Forum test", rootBox).log(
|
||||
"sequenceDiagram"
|
||||
));
|
||||
const scene = (window.scene = new Scene("Forum test", rootBox));
|
||||
scene.withSequenceDiagram();
|
||||
scene.withFlowchart();
|
||||
|
||||
const experts = (window.experts = []);
|
||||
const newExpert = async () => {
|
||||
|
@ -44,13 +44,12 @@
|
|||
|
||||
const updateDisplayValues = async () => {
|
||||
for (const expert of experts) {
|
||||
expert.setValue(
|
||||
await expert.setValue(
|
||||
"rep",
|
||||
bench.reputations.getTokens(expert.reputationPublicKey)
|
||||
);
|
||||
}
|
||||
bench.setValue("total rep", bench.getTotalReputation());
|
||||
await scene.renderSequenceDiagram();
|
||||
await bench.setValue("total rep", bench.getTotalReputation());
|
||||
};
|
||||
|
||||
const updateDisplayValuesAndDelay = async (delayMs) => {
|
||||
|
@ -63,7 +62,7 @@
|
|||
const { postId: postId1, pool: pool1 } = await expert1.submitPostWithFee(
|
||||
bench,
|
||||
forum,
|
||||
new PostContent({ hello: "there" }),
|
||||
new PostContent({ hello: "there" }).setTitle("Post 1"),
|
||||
{
|
||||
fee: 10,
|
||||
duration: 1000,
|
||||
|
@ -81,7 +80,9 @@
|
|||
const { postId: postId2, 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" })
|
||||
.setTitle("Post 2")
|
||||
.addCitation(postId1, 0.5),
|
||||
{
|
||||
fee: 10,
|
||||
duration: 1000,
|
||||
|
@ -99,7 +100,9 @@
|
|||
const { pool: pool3 } = await expert3.submitPostWithFee(
|
||||
bench,
|
||||
forum,
|
||||
new PostContent({ hello: "y'all" }).addCitation(postId2, 0.5),
|
||||
new PostContent({ hello: "y'all" })
|
||||
.setTitle("Post 3")
|
||||
.addCitation(postId2, 0.5),
|
||||
{
|
||||
fee: 10,
|
||||
duration: 1000,
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Forum Graph</title>
|
||||
<link type="text/css" rel="stylesheet" href="/index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="graph-test"></div>
|
||||
</body>
|
||||
<script type="module">
|
||||
import { Box } from "/classes/box.js";
|
||||
import { Scene } from "/classes/scene.js";
|
||||
import { Graph } from "/classes/graph.js";
|
||||
|
||||
const rootElement = document.getElementById("graph-test");
|
||||
const rootBox = new Box("rootBox", rootElement).flex();
|
||||
|
||||
window.scene = new Scene("Graph test", rootBox);
|
||||
|
||||
window.graph = new Graph();
|
||||
|
||||
window.v = [];
|
||||
function addVertex() {
|
||||
const vertex = window.graph.addVertex({ seq: window.v.length });
|
||||
window.v.push(vertex);
|
||||
}
|
||||
addVertex();
|
||||
addVertex();
|
||||
addVertex();
|
||||
addVertex();
|
||||
addVertex();
|
||||
|
||||
window.graph.addEdge("e1", 0, 1);
|
||||
</script>
|
|
@ -17,9 +17,8 @@
|
|||
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 scene = (window.scene = new Scene("Validation Pool test", rootBox));
|
||||
await scene.withSequenceDiagram();
|
||||
const expert1 = (window.expert1 = await new Expert(
|
||||
"Expert1",
|
||||
scene
|
||||
|
@ -31,21 +30,21 @@
|
|||
const bench = (window.bench = new Bench(undefined, "Bench", scene));
|
||||
|
||||
const updateDisplayValues = async () => {
|
||||
expert1.setValue(
|
||||
await expert1.setValue(
|
||||
"rep",
|
||||
bench.reputations.getTokens(expert1.reputationPublicKey)
|
||||
);
|
||||
expert2.setValue(
|
||||
await expert2.setValue(
|
||||
"rep",
|
||||
bench.reputations.getTokens(expert2.reputationPublicKey)
|
||||
);
|
||||
bench.setValue("total rep", bench.getTotalReputation());
|
||||
await bench.setValue("total rep", bench.getTotalReputation());
|
||||
// With params.lockingTimeExponent = 0 and params.activeVoterThreshold = null,
|
||||
// these next 3 propetries are all equal to total rep
|
||||
// bench.setValue('available rep', bench.getTotalAvailableReputation());
|
||||
// bench.setValue('active rep', bench.getTotalActiveReputation());
|
||||
// bench.setValue('active available rep', bench.getTotalActiveAvailableReputation());
|
||||
await scene.renderSequenceDiagram();
|
||||
// await bench.setValue('available rep', bench.getTotalAvailableReputation());
|
||||
// await bench.setValue('active rep', bench.getTotalActiveReputation());
|
||||
// await bench.setValue('active available rep', bench.getTotalActiveAvailableReputation());
|
||||
await scene.sequence.render();
|
||||
};
|
||||
|
||||
updateDisplayValues();
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
const timeouts = new Map();
|
||||
const timers = new Map();
|
||||
|
||||
export const debounce = (fn, delay) => {
|
||||
const key = fn.toString();
|
||||
if (!timeouts.get(key)) {
|
||||
timeouts.set(key, setTimeout(async () => {
|
||||
timeouts.delete(key);
|
||||
await fn();
|
||||
}, delay));
|
||||
export const debounce = async (fn, delayMs) => {
|
||||
const timer = timers.get(fn);
|
||||
if (timer) {
|
||||
return timer.result;
|
||||
}
|
||||
const result = await fn();
|
||||
timers.set(fn, { result });
|
||||
setTimeout(() => {
|
||||
timers.delete(fn);
|
||||
}, delayMs);
|
||||
return result;
|
||||
};
|
||||
|
||||
export const delay = async (ms) => {
|
||||
export const delay = async (delayMs) => {
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
setTimeout(resolve, delayMs);
|
||||
});
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue