Minor refactoring
This commit is contained in:
parent
e20a864738
commit
f475742cbf
|
@ -30,4 +30,18 @@ module.exports = {
|
|||
'no-constant-condition': ['off'],
|
||||
'no-await-in-loop': ['off'],
|
||||
},
|
||||
globals: {
|
||||
_: 'readonly',
|
||||
chai: 'readonly',
|
||||
expect: 'readonly',
|
||||
mocha: 'readonly',
|
||||
describe: 'readonly',
|
||||
context: 'readonly',
|
||||
it: 'readonly',
|
||||
specify: 'readonly',
|
||||
before: 'readonly',
|
||||
after: 'readonly',
|
||||
beforeEach: 'readonly',
|
||||
afterEach: 'readonly',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Graph } from './graph.js';
|
||||
import { WDAG } from './wdag.js';
|
||||
|
||||
class Author {
|
||||
constructor() {
|
||||
|
@ -21,7 +21,7 @@ class PostVertex {
|
|||
export class ForumView {
|
||||
constructor() {
|
||||
this.reputations = new Map();
|
||||
this.posts = new Graph();
|
||||
this.posts = new WDAG();
|
||||
this.authors = new Map();
|
||||
}
|
||||
|
||||
|
@ -53,8 +53,8 @@ export class ForumView {
|
|||
const postVertex = new PostVertex(postId, author, stake, content, citations);
|
||||
console.log('addPost', { id: postId, postContent });
|
||||
this.posts.addVertex(postId, postVertex);
|
||||
for (const citation of citations) {
|
||||
this.posts.addEdge('citation', postId, citation.postId, citation);
|
||||
for (const { postId: citedPostId, weight } of citations) {
|
||||
this.posts.addEdge('citation', postId, citedPostId, weight);
|
||||
}
|
||||
this.applyNonbindingReputationEffects(postVertex);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
import { Actor } from './actor.js';
|
||||
import { Graph } from './graph.js';
|
||||
import { WDAG } from './wdag.js';
|
||||
import { Action } from './action.js';
|
||||
import { CryptoUtil } from './crypto.js';
|
||||
import params from '../params.js';
|
||||
import { ReputationHolder } from './reputation-holder.js';
|
||||
import { displayNumber } from '../util.js';
|
||||
|
||||
const CITATION = 'citation';
|
||||
const BALANCE = 'balance';
|
||||
|
||||
class Post extends Actor {
|
||||
constructor(forum, authorPublicKey, postContent) {
|
||||
const index = forum.posts.countVertices();
|
||||
const name = `Post${index + 1}`;
|
||||
super(name, forum.scene);
|
||||
this.id = postContent.id ?? `post_${CryptoUtil.randomUUID()}`;
|
||||
this.id = postContent.id ?? `post_${CryptoUtil.randomUUID().slice(0, 4)}`;
|
||||
this.authorPublicKey = authorPublicKey;
|
||||
this.value = 0;
|
||||
this.initialValue = 0;
|
||||
|
@ -47,7 +50,7 @@ export class Forum extends ReputationHolder {
|
|||
constructor(name, scene) {
|
||||
super(`forum_${CryptoUtil.randomUUID()}`, name, scene);
|
||||
this.id = this.reputationPublicKey;
|
||||
this.posts = new Graph(scene);
|
||||
this.posts = new WDAG(scene);
|
||||
this.actions = {
|
||||
addPost: new Action('add post', scene),
|
||||
propagateValue: new Action('propagate value', this.scene),
|
||||
|
@ -60,7 +63,7 @@ export class Forum extends ReputationHolder {
|
|||
await this.actions.addPost.log(this, post);
|
||||
this.posts.addVertex(post.id, post, post.getLabel());
|
||||
for (const { postId: citedPostId, weight } of post.citations) {
|
||||
this.posts.addEdge('citation', post.id, citedPostId, { weight });
|
||||
this.posts.addEdge(CITATION, post.id, citedPostId, weight);
|
||||
}
|
||||
return post.id;
|
||||
}
|
||||
|
@ -88,7 +91,8 @@ export class Forum extends ReputationHolder {
|
|||
}) {
|
||||
this.activate();
|
||||
const initialValue = bench.reputation.valueOf(tokenId);
|
||||
const post = this.getPost(postId);
|
||||
const postVertex = this.posts.getVertex(postId);
|
||||
const post = postVertex.data;
|
||||
post.setStatus('Validated');
|
||||
post.initialValue = initialValue;
|
||||
this.posts.setVertexLabel(post.id, post.getLabel());
|
||||
|
@ -97,9 +101,13 @@ export class Forum extends ReputationHolder {
|
|||
// so that its value can be updated by future validated posts.
|
||||
post.tokenId = tokenId;
|
||||
|
||||
// Compute rewards
|
||||
const rewardsAccumulator = new Map();
|
||||
await this.propagateValue(rewardsAccumulator, this, post, initialValue);
|
||||
|
||||
// Compute rewards
|
||||
await this.propagateValue(
|
||||
{ to: postVertex, from: { data: this } },
|
||||
{ rewardsAccumulator, increment: initialValue },
|
||||
);
|
||||
|
||||
// Apply computed rewards to update values of tokens
|
||||
for (const [id, value] of rewardsAccumulator) {
|
||||
|
@ -118,46 +126,62 @@ export class Forum extends ReputationHolder {
|
|||
this.deactivate();
|
||||
}
|
||||
|
||||
async propagateValue(rewardsAccumulator, fromActor, post, increment, depth = 0) {
|
||||
this.actions.propagateValue.log(fromActor, post, `(${increment})`);
|
||||
/**
|
||||
* @param {Edge} edge
|
||||
* @param {Object} opaqueData
|
||||
*/
|
||||
async propagateValue(edge, { rewardsAccumulator, increment, depth = 0 }) {
|
||||
const postVertex = edge.to;
|
||||
const post = postVertex?.data;
|
||||
|
||||
this.actions.propagateValue.log(edge.from.data, post, `(${increment})`);
|
||||
|
||||
console.log('propagateValue start', {
|
||||
from: edge.from.id,
|
||||
to: edge.to.id,
|
||||
depth,
|
||||
value: post.value,
|
||||
increment,
|
||||
});
|
||||
|
||||
// Recursively distribute reputation to citations, according to weights
|
||||
let totalOutboundAmount = 0;
|
||||
if (params.referenceChainLimit === null || depth <= params.referenceChainLimit) {
|
||||
for (const { postId: citedPostId, weight } of post.citations) {
|
||||
const citedPost = this.getPost(citedPostId);
|
||||
for (const citationEdge of this.posts.getEdges(CITATION, post)) {
|
||||
const { to: citedPostVertex, data: { weight } } = citationEdge;
|
||||
const citedPost = citedPostVertex.data;
|
||||
let outboundAmount = weight * increment;
|
||||
// If this is a negative citation, it must not bring the target below zero value.
|
||||
const balance = this.posts.getEdge(BALANCE, postVertex, citedPostVertex)?.data || 0;
|
||||
console.log('Citation', {
|
||||
citationEdge, outboundAmount, balance, citedPostValue: citedPost.value,
|
||||
});
|
||||
// We need to ensure that we propagate no more reputation than we leached
|
||||
if (outboundAmount < 0) {
|
||||
const citedPostTotalCitationWeight = citedPost.citations.reduce((t, { weight: w }) => t += w, 0);
|
||||
const citedPostCapacity = citedPost.value / (1 - citedPostTotalCitationWeight);
|
||||
outboundAmount = Math.max(outboundAmount, -citedPostCapacity);
|
||||
outboundAmount = Math.max(outboundAmount, -citedPost.value);
|
||||
if (depth > 0) {
|
||||
outboundAmount = Math.max(outboundAmount, -balance);
|
||||
}
|
||||
}
|
||||
const refundFromOutbound = await this.propagateValue(
|
||||
increment -= outboundAmount * params.leachingValue;
|
||||
this.posts.setEdge(BALANCE, postVertex, citedPostVertex, balance + outboundAmount);
|
||||
await this.propagateValue(citationEdge, {
|
||||
rewardsAccumulator,
|
||||
post,
|
||||
citedPost,
|
||||
outboundAmount,
|
||||
depth + 1,
|
||||
);
|
||||
totalOutboundAmount += outboundAmount - refundFromOutbound;
|
||||
increment: outboundAmount,
|
||||
depth: depth + 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Apply leaching value
|
||||
const incrementAfterLeaching = increment - totalOutboundAmount * params.leachingValue;
|
||||
const newValue = post.value + increment;
|
||||
|
||||
const rawNewValue = post.value + incrementAfterLeaching;
|
||||
const newValue = Math.max(0, rawNewValue);
|
||||
const appliedIncrement = newValue - post.value;
|
||||
const refundToInbound = increment - appliedIncrement;
|
||||
console.log('propagateValue end', {
|
||||
depth,
|
||||
increment,
|
||||
newValue,
|
||||
});
|
||||
|
||||
// Award reputation to post author
|
||||
rewardsAccumulator.set(post.tokenId, appliedIncrement);
|
||||
rewardsAccumulator.set(post.tokenId, increment);
|
||||
|
||||
// Increment the value of the post
|
||||
await this.setPostValue(post, newValue);
|
||||
|
||||
return refundToInbound;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
export class List {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
}
|
||||
|
||||
add(item) {
|
||||
this.items.push(item);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import mermaid from 'https://unpkg.com/mermaid@9.2.2/dist/mermaid.esm.min.mjs';
|
|||
import { Actor } from './actor.js';
|
||||
import { Action } from './action.js';
|
||||
import { debounce, hexToRGB } from '../util.js';
|
||||
import { CryptoUtil } from './crypto.js';
|
||||
|
||||
class MermaidDiagram {
|
||||
constructor(box, logBox) {
|
||||
|
@ -90,10 +91,11 @@ export class Scene {
|
|||
this.box.addBox('Spacer').setInnerHTML(' ');
|
||||
this.topSection = this.box.addBox('Top section').flex();
|
||||
this.displayValuesBox = this.topSection.addBox('Values');
|
||||
this.middleSection = this.box.addBox('Middle section').flex();
|
||||
this.middleSection = this.box.addBox('Middle section');
|
||||
this.box.addBox('Spacer').setInnerHTML(' ');
|
||||
this.actors = new Set();
|
||||
this.dateStart = new Date();
|
||||
this.flowcharts = new Map();
|
||||
|
||||
mermaid.mermaidAPI.initialize({
|
||||
startOnLoad: false,
|
||||
|
@ -117,26 +119,49 @@ export class Scene {
|
|||
withSequenceDiagram() {
|
||||
const box = this.box.addBox('Sequence diagram');
|
||||
this.box.addBox('Spacer').setInnerHTML(' ');
|
||||
const logBox = this.box.addBox('Sequence diagram text');
|
||||
const logBox = this.box.addBox('Sequence diagram text').addClass('dim');
|
||||
this.sequence = new MermaidDiagram(box, logBox);
|
||||
this.sequence.log('sequenceDiagram', false);
|
||||
return this;
|
||||
}
|
||||
|
||||
withFlowchart(direction = 'BT') {
|
||||
const box = this.topSection.addBox('Flowchart');
|
||||
this.box.addBox('Spacer').setInnerHTML(' ');
|
||||
const logBox = this.box.addBox('Flowchart text');
|
||||
withFlowchart({ direction = 'BT' } = {}) {
|
||||
const box = this.topSection.addBox('Flowchart').addClass('padded');
|
||||
const logBox = this.topSection.addBox('Flowchart text').addClass('dim');
|
||||
this.flowchart = new MermaidDiagram(box, logBox);
|
||||
this.flowchart.log(`graph ${direction}`, false);
|
||||
return this;
|
||||
}
|
||||
|
||||
withAdditionalFlowchart({ id, name, direction = 'BT' } = {}) {
|
||||
const index = this.flowcharts.size;
|
||||
name = name ?? `Flowchart ${index}`;
|
||||
id = id ?? `flowchart_${CryptoUtil.randomUUID().slice(0, 4)}`;
|
||||
const container = this.middleSection.addBox(name).flex();
|
||||
const box = container.addBox('Flowchart').addClass('padded');
|
||||
const logBox = container.addBox('Flowchart text').addClass('dim');
|
||||
const flowchart = new MermaidDiagram(box, logBox);
|
||||
flowchart.log(`graph ${direction}`, false);
|
||||
this.flowcharts.set(id, flowchart);
|
||||
return this;
|
||||
}
|
||||
|
||||
lastFlowchart() {
|
||||
if (!this.flowcharts.size) {
|
||||
if (this.flowchart) {
|
||||
return this.flowchart;
|
||||
}
|
||||
throw new Error('lastFlowchart: No additional flowcharts have been added.');
|
||||
}
|
||||
const flowcharts = Array.from(this.flowcharts.values());
|
||||
return flowcharts[flowcharts.length - 1];
|
||||
}
|
||||
|
||||
withTable() {
|
||||
if (this.table) {
|
||||
return this;
|
||||
}
|
||||
const box = this.middleSection.addBox('Table');
|
||||
const box = this.middleSection.addBox('Table').addClass('padded');
|
||||
this.box.addBox('Spacer').setInnerHTML(' ');
|
||||
this.table = new Table(box);
|
||||
return this;
|
||||
|
|
|
@ -16,20 +16,27 @@ class Vertex {
|
|||
}
|
||||
|
||||
class Edge {
|
||||
constructor(label, from, to, data) {
|
||||
constructor(label, from, to, weight) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.label = label;
|
||||
this.data = data;
|
||||
this.weight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
export class Graph {
|
||||
export class WDAG {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
this.vertices = new Map();
|
||||
this.edgeLabels = new Map();
|
||||
this.nextVertexId = 0;
|
||||
this.flowchart = scene?.flowchart ?? null;
|
||||
}
|
||||
|
||||
withFlowchart() {
|
||||
this.scene.withAdditionalFlowchart();
|
||||
this.flowchart = this.scene.lastFlowchart();
|
||||
return this;
|
||||
}
|
||||
|
||||
addVertex(id, data, label) {
|
||||
|
@ -43,16 +50,12 @@ export class Graph {
|
|||
}
|
||||
const vertex = new Vertex(id, data);
|
||||
this.vertices.set(id, vertex);
|
||||
if (this.scene && this.scene.flowchart) {
|
||||
this.scene.flowchart.log(`${id}[${label ?? id}]`);
|
||||
}
|
||||
this.flowchart?.log(`${id}[${label ?? id}]`);
|
||||
return this;
|
||||
}
|
||||
|
||||
setVertexLabel(id, label) {
|
||||
if (this.scene && this.scene.flowchart) {
|
||||
this.scene.flowchart.log(`${id}[${label}]`);
|
||||
}
|
||||
this.flowchart?.log(`${id}[${label}]`);
|
||||
}
|
||||
|
||||
getVertex(id) {
|
||||
|
@ -68,36 +71,43 @@ export class Graph {
|
|||
}
|
||||
|
||||
getEdge(label, from, to) {
|
||||
from = from instanceof Vertex ? from : this.getVertex(from);
|
||||
to = to instanceof Vertex ? to : this.getVertex(to);
|
||||
const edges = this.edgeLabels.get(label);
|
||||
return edges?.get(JSON.stringify({ from, to }));
|
||||
return edges?.get(JSON.stringify([from.id, to.id]));
|
||||
}
|
||||
|
||||
setEdge(label, from, to, edge) {
|
||||
from = from instanceof Vertex ? from : this.getVertex(from);
|
||||
to = to instanceof Vertex ? to : this.getVertex(to);
|
||||
if (!(edge instanceof Edge)) {
|
||||
edge = new Edge(edge);
|
||||
}
|
||||
let edges = this.edgeLabels.get(label);
|
||||
if (!edges) {
|
||||
edges = new Map();
|
||||
this.edgeLabels.set(label, edges);
|
||||
}
|
||||
edges.set(JSON.stringify({ from, to }), edge);
|
||||
edges.set(JSON.stringify([from.id, to.id]), edge);
|
||||
}
|
||||
|
||||
addEdge(label, from, to, data) {
|
||||
addEdge(label, from, to, weight) {
|
||||
from = from instanceof Vertex ? from : this.getVertex(from);
|
||||
to = to instanceof Vertex ? to : this.getVertex(to);
|
||||
if (this.getEdge(label, from, to)) {
|
||||
throw new Error(`Edge ${label} from ${from} to ${to} already exists`);
|
||||
}
|
||||
const edge = new Edge(label, from, to, data);
|
||||
const edge = new Edge(label, from, to, weight);
|
||||
this.setEdge(label, from, to, edge);
|
||||
const fromVertex = this.getVertex(from);
|
||||
fromVertex.edges.from.push(edge);
|
||||
const toVertex = this.getVertex(to);
|
||||
toVertex.edges.to.push(edge);
|
||||
if (this.scene && this.scene.flowchart) {
|
||||
this.scene.flowchart.log(`${fromVertex.id} -- ${data.weight} --> ${toVertex.id}`);
|
||||
}
|
||||
from.edges.from.push(edge);
|
||||
to.edges.to.push(edge);
|
||||
this.flowchart?.log(`${from.id} -- ${weight} --> ${to.id}`);
|
||||
return this;
|
||||
}
|
||||
|
||||
getEdges(label, from, to) {
|
||||
from = from instanceof Vertex ? from : this.getVertex(from);
|
||||
to = to instanceof Vertex ? to : this.getVertex(to);
|
||||
const edgeLabels = label ? [label] : Array.from(this.edgeLabels.keys());
|
||||
return edgeLabels.flatMap((edgeLabel) => {
|
||||
const edges = this.edgeLabels.get(edgeLabel);
|
|
@ -29,6 +29,12 @@ a:visited {
|
|||
font-family: monospace;
|
||||
font-size: 8pt;
|
||||
}
|
||||
.dim {
|
||||
opacity: 0.25;
|
||||
}
|
||||
.padded {
|
||||
padding: 20px;
|
||||
}
|
||||
svg {
|
||||
width: 800px;
|
||||
}
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
<h2>Tests</h2>
|
||||
<h3>Primary</h3>
|
||||
<ul>
|
||||
<li><a href="./tests/validation-pool.html">Validation Pool</a></li>
|
||||
<li><a href="./tests/availability.html">Availability + Business</a></li>
|
||||
<li><a href="./tests/forum.html">Forum</a></li>
|
||||
<li><a href="./tests/validation-pool.test.html">Validation Pool</a></li>
|
||||
<li><a href="./tests/availability.test.html">Availability + Business</a></li>
|
||||
<li><a href="./tests/forum.test.html">Forum</a></li>
|
||||
</ul>
|
||||
<h3>Secondary</h3>
|
||||
<ul>
|
||||
<li><a href="./tests/forum-network.html">Forum Network</a></li>
|
||||
<li><a href="./tests/forum-network.test.html">Forum Network</a></li>
|
||||
</ul>
|
||||
<h3>Tertiary</h3>
|
||||
<ul>
|
||||
<li><a href="./tests/basic.html">Basic</a></li>
|
||||
<li><a href="./tests/graph.html">Graph</a></li>
|
||||
<li><a href="./tests/debounce.html">Debounce</a></li>
|
||||
<li><a href="./tests/flowchart.html">Flowchart</a></li>
|
||||
<li><a href="./tests/basic.test.html">Basic Sequencing</a></li>
|
||||
<li><a href="./tests/wdag.test.html">WDAG</a></li>
|
||||
<li><a href="./tests/debounce.test.html">Debounce</a></li>
|
||||
<li><a href="./tests/flowchart.test.html">Flowchart</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Forum test</title>
|
||||
<link type="text/css" rel="stylesheet" href="../index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="forum-test"></div>
|
||||
</body>
|
||||
<script type="module" src="./forum/forum.test.js"></script>
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Forum test</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<div id="scene"></div>
|
||||
</body>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/radash/10.7.0/radash.js" integrity="sha512-S207zKWG3iqXqe6msO7/Mr8X3DzzF4u8meFlokHjGtBPTGUhgzVo0lpcqEy0GoiMUdcoct+H+SqzoLsxXbynzg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://unpkg.com/chai/chai.js"></script>
|
||||
<script src="https://unpkg.com/mocha/mocha.js"></script>
|
||||
<script class="mocha-init">
|
||||
mocha.setup({
|
||||
ui: 'bdd',
|
||||
globals: ['scene', 'bench', 'forum', 'experts', 'posts', '__REACT_DEVTOOLS_*'],
|
||||
});
|
||||
mocha.checkLeaks();
|
||||
chai.should();
|
||||
</script>
|
||||
<script type="module" src="./scripts/forum.test.js"></script>
|
||||
<script class="mocha-exec">
|
||||
mocha.run();
|
||||
</script>
|
|
@ -1,79 +0,0 @@
|
|||
import { Box } from '../../classes/box.js';
|
||||
import { Scene } from '../../classes/scene.js';
|
||||
import { Expert } from '../../classes/expert.js';
|
||||
import { Bench } from '../../classes/bench.js';
|
||||
import { delay } from '../../util.js';
|
||||
import { Forum } from '../../classes/forum.js';
|
||||
import { PostContent } from '../../classes/post-content.js';
|
||||
import params from '../../params.js';
|
||||
|
||||
const DEFAULT_DELAY_INTERVAL = 500;
|
||||
|
||||
const rootElement = document.getElementById('forum-test');
|
||||
const rootBox = new Box('rootBox', rootElement).flex();
|
||||
|
||||
const scene = (window.scene = new Scene('Forum test', rootBox));
|
||||
scene.withSequenceDiagram();
|
||||
scene.withFlowchart();
|
||||
scene.withTable();
|
||||
|
||||
scene.addDisplayValue('c3. stakeForAuthor').set(params.stakeForAuthor);
|
||||
scene.addDisplayValue('q2. revaluationLimit').set(params.revaluationLimit);
|
||||
scene
|
||||
.addDisplayValue('q3. referenceChainLimit')
|
||||
.set(params.referenceChainLimit);
|
||||
scene.addDisplayValue('q4. leachingValue').set(params.leachingValue);
|
||||
scene.addDisplayValue(' ');
|
||||
|
||||
const experts = (window.experts = []);
|
||||
const newExpert = async () => {
|
||||
const index = experts.length;
|
||||
const name = `Expert${index + 1}`;
|
||||
const expert = await new Expert(name, scene).initialize();
|
||||
experts.push(expert);
|
||||
return expert;
|
||||
};
|
||||
|
||||
const forum = (window.forum = new Forum('Forum', scene));
|
||||
const bench = (window.bench = new Bench(forum, 'Bench', scene));
|
||||
const expert1 = await newExpert();
|
||||
const expert2 = await newExpert();
|
||||
const expert3 = await newExpert();
|
||||
|
||||
bench.addValue('total rep', () => bench.reputation.getTotal());
|
||||
forum.addValue('total value', () => forum.getTotalValue());
|
||||
|
||||
for (const expert of experts) {
|
||||
expert.addValue('rep', () => bench.reputation.valueOwnedBy(expert.reputationPublicKey));
|
||||
}
|
||||
|
||||
const addPost = async (author, title, fee, citations = []) => {
|
||||
await scene.startSection();
|
||||
|
||||
const postContent = new PostContent({}).setTitle(title);
|
||||
for (const { postId, weight } of citations) {
|
||||
postContent.addCitation(postId, weight);
|
||||
}
|
||||
|
||||
const { pool, postId } = await author.submitPostWithFee(
|
||||
bench,
|
||||
forum,
|
||||
postContent,
|
||||
{
|
||||
fee,
|
||||
duration: 1000,
|
||||
tokenLossRatio: 1,
|
||||
},
|
||||
);
|
||||
await delay(1000);
|
||||
await pool.evaluateWinningConditions();
|
||||
await scene.endSection();
|
||||
await delay(DEFAULT_DELAY_INTERVAL);
|
||||
return postId;
|
||||
};
|
||||
|
||||
const postId1 = await addPost(expert1, 'Post 1', 20);
|
||||
const postId2 = await addPost(expert2, 'Post 2', 10, [{ postId: postId1, weight: 0.5 }]);
|
||||
const postId3 = await addPost(expert3, 'Post 3', 10, [{ postId: postId1, weight: -1 }]);
|
||||
await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
||||
await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
|
@ -1,33 +0,0 @@
|
|||
<!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>
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Mocha Tests</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<div id="scene"></div>
|
||||
|
||||
<script src="https://unpkg.com/chai/chai.js"></script>
|
||||
<script src="https://unpkg.com/mocha/mocha.js"></script>
|
||||
|
||||
<script class="mocha-init">
|
||||
mocha.setup({
|
||||
ui: 'bdd',
|
||||
});
|
||||
mocha.checkLeaks();
|
||||
chai.should();
|
||||
</script>
|
||||
<script src="./scripts/mocha.test.js"></script>
|
||||
<script class="mocha-exec">
|
||||
mocha.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -9,9 +9,9 @@
|
|||
<script type="module">
|
||||
import { Box } from '../classes/box.js';
|
||||
import { Scene } from '../classes/scene.js';
|
||||
import { ValidationPool } from '../classes/validation-pool.js';
|
||||
import { TokenHolder } from '../classes/token-holder.js';
|
||||
import { ReputationToken } from '../classes/reputation-token.js';
|
||||
// import { ValidationPool } from '../classes/validation-pool.js';
|
||||
// import { TokenHolder } from '../classes/token-holder.js';
|
||||
// import { ReputationToken } from '../classes/reputation-token.js';
|
||||
import { delay } from '../util.js';
|
||||
|
||||
const DEFAULT_DELAY_INTERVAL = 500;
|
||||
|
@ -23,8 +23,8 @@ const scene = (window.scene = new Scene('Forum test', rootBox));
|
|||
scene.withSequenceDiagram();
|
||||
scene.withFlowchart();
|
||||
|
||||
const pool = new ValidationPool();
|
||||
const repToken = new ReputationToken();
|
||||
// const pool = new ValidationPool();
|
||||
// const repToken = new ReputationToken();
|
||||
|
||||
// const tokenMinter = new TokenHolder('TokenMinter', scene);
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
import { Box } from '../../classes/box.js';
|
||||
import { Scene } from '../../classes/scene.js';
|
||||
import { Expert } from '../../classes/expert.js';
|
||||
import { Bench } from '../../classes/bench.js';
|
||||
import { delay } from '../../util.js';
|
||||
import { Forum } from '../../classes/forum.js';
|
||||
import { PostContent } from '../../classes/post-content.js';
|
||||
import params from '../../params.js';
|
||||
|
||||
const DEFAULT_DELAY_MS = 1;
|
||||
const POOL_DURATION_MS = 50;
|
||||
|
||||
let rootElement;
|
||||
let rootBox;
|
||||
let scene;
|
||||
let forum;
|
||||
let bench;
|
||||
let experts;
|
||||
let posts;
|
||||
|
||||
async function newExpert() {
|
||||
const index = experts.length;
|
||||
const name = `Expert${index + 1}`;
|
||||
const expert = await new Expert(name, scene).initialize();
|
||||
experts.push(expert);
|
||||
return expert;
|
||||
}
|
||||
|
||||
async function addPost(author, fee, citations = []) {
|
||||
const postIndex = posts.length;
|
||||
const title = `posts[${postIndex}]`;
|
||||
await scene.startSection();
|
||||
|
||||
const postContent = new PostContent({}).setTitle(title);
|
||||
for (const { postId, weight } of citations) {
|
||||
postContent.addCitation(postId, weight);
|
||||
}
|
||||
|
||||
const { pool, postId } = await author.submitPostWithFee(
|
||||
bench,
|
||||
forum,
|
||||
postContent,
|
||||
{
|
||||
fee,
|
||||
duration: POOL_DURATION_MS,
|
||||
tokenLossRatio: 1,
|
||||
},
|
||||
);
|
||||
posts.push(postId);
|
||||
await delay(POOL_DURATION_MS);
|
||||
await pool.evaluateWinningConditions();
|
||||
await scene.endSection();
|
||||
await delay(DEFAULT_DELAY_MS);
|
||||
return postId;
|
||||
}
|
||||
|
||||
async function setup() {
|
||||
rootElement = document.getElementById('scene');
|
||||
rootBox = new Box('rootBox', rootElement).flex();
|
||||
|
||||
scene = (window.scene = new Scene('Forum test', rootBox));
|
||||
scene.withSequenceDiagram();
|
||||
|
||||
scene.addDisplayValue('c3. stakeForAuthor').set(params.stakeForAuthor);
|
||||
scene.addDisplayValue('q2. revaluationLimit').set(params.revaluationLimit);
|
||||
scene
|
||||
.addDisplayValue('q3. referenceChainLimit')
|
||||
.set(params.referenceChainLimit);
|
||||
scene.addDisplayValue('q4. leachingValue').set(params.leachingValue);
|
||||
scene.addDisplayValue(' ');
|
||||
|
||||
forum = (window.forum = new Forum('Forum', scene));
|
||||
bench = (window.bench = new Bench(forum, 'Bench', scene));
|
||||
experts = (window.experts = []);
|
||||
posts = (window.posts = []);
|
||||
|
||||
forum.posts.withFlowchart();
|
||||
|
||||
scene.withTable();
|
||||
|
||||
await newExpert();
|
||||
// await newExpert();
|
||||
// await newExpert();
|
||||
|
||||
// bench.addValue('total rep', () => bench.reputation.getTotal());
|
||||
forum.addValue('total value', () => forum.getTotalValue());
|
||||
|
||||
// for (const expert of experts) {
|
||||
// expert.addValue('rep', () => bench.reputation.valueOwnedBy(expert.reputationPublicKey));
|
||||
// }
|
||||
}
|
||||
|
||||
describe('Negative citation of a negative citation', async () => {
|
||||
before(async () => {
|
||||
await setup();
|
||||
await addPost(experts[0], 10);
|
||||
await addPost(experts[0], 10, [{ postId: posts[0], weight: -1 }]);
|
||||
await addPost(experts[0], 10, [{ postId: posts[1], weight: -1 }]);
|
||||
});
|
||||
it('Should restore original post to its initial value', () => {
|
||||
forum.getPost(posts[0]).value.should.equal(10);
|
||||
});
|
||||
});
|
||||
|
||||
// await addPost(experts[0], 10);
|
||||
// await addPost(experts[0], 10, [{ postId: posts[3], weight: -1 }]);
|
||||
// await addPost(experts[0], 10, [{ postId: posts[4], weight: -1 }]);
|
||||
|
||||
// await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]);
|
||||
// await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]);
|
|
@ -0,0 +1,23 @@
|
|||
describe('Array', () => {
|
||||
before(() => {
|
||||
// ...
|
||||
});
|
||||
|
||||
describe('#indexOf()', () => {
|
||||
context('when not present', () => {
|
||||
it('should not throw an error', () => {
|
||||
(function aFunc() {
|
||||
[1, 2, 3].indexOf(4);
|
||||
}.should.not.throw());
|
||||
});
|
||||
it('should return -1', () => {
|
||||
[1, 2, 3].indexOf(4).should.equal(-1);
|
||||
});
|
||||
});
|
||||
context('when present', () => {
|
||||
it('should return the index where the element first appears in the array', () => {
|
||||
[1, 2, 3].indexOf(3).should.equal(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
import { Box } from '../../classes/box.js';
|
||||
import { Scene } from '../../classes/scene.js';
|
||||
import { WDAG } from '../../classes/wdag.js';
|
||||
|
||||
const rootElement = document.getElementById('scene');
|
||||
const rootBox = new Box('rootBox', rootElement).flex();
|
||||
window.scene = new Scene('WDAG test', rootBox);
|
||||
const graph = (window.graph = new WDAG(window.scene).withFlowchart());
|
||||
const v = (window.v = []);
|
||||
function addVertex() {
|
||||
const vertex = graph.addVertex({ seq: window.v.length });
|
||||
v.push(vertex);
|
||||
}
|
||||
addVertex();
|
||||
addVertex();
|
||||
addVertex();
|
||||
addVertex();
|
||||
addVertex();
|
||||
|
||||
graph.addEdge('e1', 0, 1, 1);
|
||||
graph.addEdge('e1', 2, 1, 0.5);
|
||||
graph.addEdge('e1', 3, 1, 0.25);
|
||||
graph.addEdge('e1', 1, 4, 0.125);
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Forum WDAG</title>
|
||||
<link type="text/css" rel="stylesheet" href="../index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="scene"></div>
|
||||
</body>
|
||||
<script type="module" src="./scripts/wdag.test.js"></script>
|
Loading…
Reference in New Issue