Added business and availability SC
This commit is contained in:
parent
59c10f1ac2
commit
6ad293b5b8
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<head>
|
||||||
|
<title>Forum</title>
|
||||||
|
<script type="module" src="./availability-test.js" defer></script>
|
||||||
|
<link type="text/css" rel="stylesheet" href="./index.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="availability-test"></div>
|
||||||
|
</body>
|
||||||
|
<scr
|
|
@ -0,0 +1,68 @@
|
||||||
|
import { Box } from './classes/box.js';
|
||||||
|
import { Scene } from './classes/scene.js';
|
||||||
|
import { Member } from './classes/member.js';
|
||||||
|
import { Bench } from './classes/bench.js';
|
||||||
|
import { Business } from './classes/business.js';
|
||||||
|
import { Availability } from './classes/availability.js';
|
||||||
|
import { delay } from './util.js';
|
||||||
|
import { Forum } from './classes/forum.js';
|
||||||
|
|
||||||
|
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 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 updateDisplayValues = async () => {
|
||||||
|
member1.setValue('rep', bench.reputations.getTokens(member1.reputationPublicKey));
|
||||||
|
member2.setValue('rep', bench.reputations.getTokens(member2.reputationPublicKey));
|
||||||
|
bench.setValue('total rep', bench.getTotalReputation());
|
||||||
|
await scene.renderSequenceDiagram();
|
||||||
|
};
|
||||||
|
|
||||||
|
updateDisplayValues();
|
||||||
|
|
||||||
|
// const post1 = window.post1 = new PostContent({ message: 'hi' });
|
||||||
|
// const post2 = window.post2 = new PostContent({ message: 'hello' }).addCitation(window.post1.id, 1.0);
|
||||||
|
|
||||||
|
// Populate availability pool
|
||||||
|
availability.register(member1.reputationPublicKey, 1);
|
||||||
|
availability.register(member2.reputationPublicKey, 1);
|
||||||
|
|
||||||
|
await delay(500);
|
||||||
|
|
||||||
|
// Submit work request
|
||||||
|
const requestId = await business.submitRequest(100, { please: 'do some work' });
|
||||||
|
await scene.renderSequenceDiagram();
|
||||||
|
await delay(500);
|
||||||
|
|
||||||
|
// Submit work evidence
|
||||||
|
const pool = await business.submitWork(member1.reputationPublicKey, requestId, {
|
||||||
|
here: 'is some evidence of work product',
|
||||||
|
}, {
|
||||||
|
tokenLossRatio: 1,
|
||||||
|
duration: 1000,
|
||||||
|
});
|
||||||
|
|
||||||
|
await scene.renderSequenceDiagram();
|
||||||
|
await delay(500);
|
||||||
|
|
||||||
|
// Vote on work evidence
|
||||||
|
await member2.castVote(pool, { position: true, stake: 1 });
|
||||||
|
await scene.renderSequenceDiagram();
|
||||||
|
await delay(500);
|
||||||
|
|
||||||
|
await member2.revealIdentity(pool);
|
||||||
|
await scene.renderSequenceDiagram();
|
||||||
|
await delay(500);
|
||||||
|
|
||||||
|
await member1.revealIdentity(pool, member1.reputationPublicKey);
|
||||||
|
await scene.renderSequenceDiagram();
|
||||||
|
|
||||||
|
// Distribute reputation awards
|
||||||
|
// Distribute fees
|
|
@ -1,6 +1,49 @@
|
||||||
import { Actor } from './actor.js';
|
import { Actor } from './actor.js';
|
||||||
|
|
||||||
|
class Worker {
|
||||||
|
stake = 0;
|
||||||
|
|
||||||
|
available = true;
|
||||||
|
|
||||||
|
assignedRequestId = null;
|
||||||
|
|
||||||
|
constructor(reputationPublicKey) {
|
||||||
|
this.reputationPublicKey = reputationPublicKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Purpose: Enable staking reputation to enter the pool of workers
|
* Purpose: Enable staking reputation to enter the pool of workers
|
||||||
*/
|
*/
|
||||||
export class Availability extends Actor {}
|
export class Availability extends Actor {
|
||||||
|
workers = new Map();
|
||||||
|
|
||||||
|
constructor(bench, name, scene) {
|
||||||
|
super(name, scene);
|
||||||
|
this.bench = bench;
|
||||||
|
}
|
||||||
|
|
||||||
|
register(reputationPublicKey, stake) {
|
||||||
|
// ? Is a particular stake amount required?
|
||||||
|
const worker = this.workers.get(reputationPublicKey) ?? new Worker(reputationPublicKey);
|
||||||
|
if (!worker.available) {
|
||||||
|
throw new Error('Worker is already registered and busy. Cannot increase stake.');
|
||||||
|
}
|
||||||
|
worker.stake += stake;
|
||||||
|
// ? Interact with Bench contract to encumber reputation?
|
||||||
|
this.workers.set(reputationPublicKey, worker);
|
||||||
|
}
|
||||||
|
|
||||||
|
get availableWorkers() {
|
||||||
|
return Array.from(this.workers.values()).filter(({ available }) => !!available);
|
||||||
|
}
|
||||||
|
|
||||||
|
async assignWork(requestId) {
|
||||||
|
// Get random worker
|
||||||
|
const index = Math.floor(Math.random() * this.availableWorkers.length);
|
||||||
|
const worker = this.availableWorkers[index];
|
||||||
|
worker.available = false;
|
||||||
|
worker.assignedRequestId = requestId;
|
||||||
|
// TOOD: Notify assignee
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ export class Bench extends Actor {
|
||||||
tokenLossRatio,
|
tokenLossRatio,
|
||||||
contentiousDebate,
|
contentiousDebate,
|
||||||
signingPublicKey,
|
signingPublicKey,
|
||||||
|
authorStake,
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
const validationPoolNumber = this.validationPools.size + 1;
|
const validationPoolNumber = this.validationPools.size + 1;
|
||||||
|
@ -77,6 +78,7 @@ export class Bench extends Actor {
|
||||||
tokenLossRatio,
|
tokenLossRatio,
|
||||||
contentiousDebate,
|
contentiousDebate,
|
||||||
signingPublicKey,
|
signingPublicKey,
|
||||||
|
authorStake,
|
||||||
},
|
},
|
||||||
`pool${validationPoolNumber}`,
|
`pool${validationPoolNumber}`,
|
||||||
this.scene,
|
this.scene,
|
||||||
|
|
|
@ -1,10 +1,65 @@
|
||||||
import { Actor } from './actor.js';
|
import { Actor } from './actor.js';
|
||||||
|
import { CryptoUtil } from './crypto.js';
|
||||||
|
import { PostContent } from './post.js';
|
||||||
|
|
||||||
|
class Request {
|
||||||
|
constructor(fee, content) {
|
||||||
|
this.id = CryptoUtil.randomUUID();
|
||||||
|
this.fee = fee;
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Purpose: Enable fee-driven work requests, to be completed by workers from the availability pool
|
* Purpose: Enable fee-driven work requests, to be completed by workers from the availability pool
|
||||||
*/
|
*/
|
||||||
export class Business extends Actor {
|
export class Business extends Actor {
|
||||||
// constructor(name, scene) { super(name, scene); }
|
requests = new Map();
|
||||||
|
|
||||||
// submitRequest(fee) {}
|
constructor(bench, forum, availability, name, scene) {
|
||||||
|
super(name, scene);
|
||||||
|
this.bench = bench;
|
||||||
|
this.forum = forum;
|
||||||
|
this.availability = availability;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fee should be held in escrow.
|
||||||
|
* That means there should be specific conditions under which the fee will be refunded.
|
||||||
|
* That means the submission should include some time value to indicate when it expires.
|
||||||
|
* There could be separate thresholds to indicate the earliest that the job may be cancelled,
|
||||||
|
* and the time at which the job will be automatically cancelled.
|
||||||
|
*/
|
||||||
|
async submitRequest(fee, content) {
|
||||||
|
const request = new Request(fee, content);
|
||||||
|
this.requests.set(request.id, request);
|
||||||
|
await this.availability.assignWork(request.id);
|
||||||
|
return request.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
async submitWork(reputationPublicKey, requestId, workEvidence, { tokenLossRatio, duration }) {
|
||||||
|
const { fee } = this.requests.get(requestId);
|
||||||
|
|
||||||
|
// Create a post representing this submission.
|
||||||
|
const post = new PostContent({
|
||||||
|
requestId,
|
||||||
|
workEvidence,
|
||||||
|
});
|
||||||
|
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.
|
||||||
|
const pool = await this.bench.initiateValidationPool(reputationPublicKey, {
|
||||||
|
postId: post.id,
|
||||||
|
fee,
|
||||||
|
duration,
|
||||||
|
tokenLossRatio,
|
||||||
|
signingPublicKey: reputationPublicKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
// When the validation pool concludes,
|
||||||
|
// reputation should be awarded and fees should be distributed.
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,7 @@ class Author {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Consider merging with "client-side" Post class in `./post.js`
|
class PostVertex {
|
||||||
class Post {
|
|
||||||
constructor(id, author, stake, content, citations) {
|
constructor(id, author, stake, content, citations) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.author = author;
|
this.author = author;
|
||||||
|
@ -48,14 +47,15 @@ export class ForumView {
|
||||||
return author;
|
return author;
|
||||||
}
|
}
|
||||||
|
|
||||||
addPost(authorId, postId, { citations = [], content }, stake) {
|
addPost(authorId, postId, postContent, stake) {
|
||||||
|
const { citations = [], content } = postContent;
|
||||||
const author = this.getOrInitializeAuthor(authorId);
|
const author = this.getOrInitializeAuthor(authorId);
|
||||||
const post = new Post(postId, author, stake, content, citations);
|
const postVertex = new PostVertex(postId, author, stake, content, citations);
|
||||||
this.posts.addVertex(postId, post);
|
this.posts.addVertex(postId, postVertex);
|
||||||
for (const citation of citations) {
|
for (const citation of citations) {
|
||||||
this.posts.addEdge('citation', postId, citation.postId, citation);
|
this.posts.addEdge('citation', postId, citation.postId, citation);
|
||||||
}
|
}
|
||||||
this.applyNonbindingReputationEffects(post);
|
this.applyNonbindingReputationEffects(postVertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPost(postId) {
|
getPost(postId) {
|
||||||
|
|
|
@ -2,13 +2,13 @@ import { Actor } from './actor.js';
|
||||||
import { Graph, Vertex } from './graph.js';
|
import { Graph, Vertex } from './graph.js';
|
||||||
import params from './params.js';
|
import params from './params.js';
|
||||||
|
|
||||||
class Post extends Vertex {
|
class PostVertex extends Vertex {
|
||||||
constructor(forum, id, authorId, citations) {
|
constructor(forum, authorId, postContent) {
|
||||||
super();
|
super();
|
||||||
this.forum = forum;
|
this.forum = forum;
|
||||||
this.id = id;
|
this.id = postContent.id;
|
||||||
this.authorId = authorId;
|
this.authorId = authorId;
|
||||||
this.citations = citations;
|
this.citations = postContent.citations;
|
||||||
this.value = 0;
|
this.value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,21 +28,20 @@ export class Forum extends Actor {
|
||||||
this.posts = new Graph();
|
this.posts = new Graph();
|
||||||
}
|
}
|
||||||
|
|
||||||
async addPost({
|
async addPost(authorId, postContent) {
|
||||||
authorId, postId, citations = [], poolParams,
|
const post = new PostVertex(this, authorId, postContent);
|
||||||
}) {
|
this.posts.addVertex(post.id, post);
|
||||||
const post = new Post(this, postId, authorId);
|
for (const { postId: citedPostId, weight } of postContent.citations) {
|
||||||
this.posts.addVertex(postId, post);
|
this.posts.addEdge('citation', post.id, citedPostId, { weight });
|
||||||
for (const { postId: citedPostId, weight } of citations) {
|
|
||||||
this.posts.addEdge('citation', postId, citedPostId, { weight });
|
|
||||||
}
|
}
|
||||||
// this.applyReputationEffects(post);
|
// this.applyReputationEffects(post);
|
||||||
// initiateValidationPool(authorId, {postId, fee, duration, tokenLossRatio, contentiousDebate, signingPublicKey}) {
|
// initiateValidationPool(authorId, {postId, fee, duration, tokenLossRatio, contentiousDebate, signingPublicKey}) {
|
||||||
const pool = await this.bench.initiateValidationPool(authorId, {
|
|
||||||
...poolParams,
|
// const pool = await this.bench.initiateValidationPool(authorId, {
|
||||||
postId,
|
// ...poolParams,
|
||||||
});
|
// postId,
|
||||||
return pool;
|
// });
|
||||||
|
// return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPost(postId) {
|
getPost(postId) {
|
||||||
|
|
|
@ -65,10 +65,16 @@ export class Member extends Actor {
|
||||||
validationPool.castVote(signingPublicKey, position, stake, lockingTime);
|
validationPool.castVote(signingPublicKey, position, stake, lockingTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
async revealIdentity(validationPool) {
|
async revealIdentity(validationPool, signingPublicKey) {
|
||||||
const { signingPublicKey } = this.validationPools.get(validationPool.id);
|
if (!signingPublicKey) {
|
||||||
|
signingPublicKey = this.validationPools.get(validationPool.id).signingPublicKey;
|
||||||
|
}
|
||||||
// TODO: sign message
|
// TODO: sign message
|
||||||
this.actions.revealIdentity.log(this, validationPool);
|
this.actions.revealIdentity.log(this, validationPool);
|
||||||
validationPool.revealIdentity(signingPublicKey, this.reputationPublicKey);
|
validationPool.revealIdentity(signingPublicKey, this.reputationPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async submitWork(business, requestId, evidence, { tokenLossRatio }) {
|
||||||
|
await business.submitWork(this.reputationPublicKey, requestId, evidence, { tokenLossRatio });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { CryptoUtil } from './crypto.js';
|
import { CryptoUtil } from './crypto.js';
|
||||||
import { Post } from './post.js';
|
import { PostContent } from './post.js';
|
||||||
|
|
||||||
export class Message {
|
export class Message {
|
||||||
constructor(content) {
|
constructor(content) {
|
||||||
|
@ -9,7 +9,7 @@ export class Message {
|
||||||
async sign({ publicKey, privateKey }) {
|
async sign({ publicKey, privateKey }) {
|
||||||
this.publicKey = await CryptoUtil.exportKey(publicKey);
|
this.publicKey = await CryptoUtil.exportKey(publicKey);
|
||||||
// Call toJSON before signing, to match what we'll later send
|
// Call toJSON before signing, to match what we'll later send
|
||||||
this.signature = await CryptoUtil.sign(this.contentToJSON(this.content), privateKey);
|
this.signature = await CryptoUtil.sign(this.contentToJSON(), privateKey);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,18 +17,14 @@ export class Message {
|
||||||
return CryptoUtil.verify(content, publicKey, signature);
|
return CryptoUtil.verify(content, publicKey, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
static contentFromJSON(data) {
|
contentToJSON() {
|
||||||
return data;
|
return this.content;
|
||||||
}
|
|
||||||
|
|
||||||
static contentToJSON(content) {
|
|
||||||
return content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
return {
|
return {
|
||||||
type: this.type,
|
type: this.type,
|
||||||
content: this.contentToJSON(this.content),
|
content: this.contentToJSON(),
|
||||||
publicKey: this.publicKey,
|
publicKey: this.publicKey,
|
||||||
signature: this.signature,
|
signature: this.signature,
|
||||||
};
|
};
|
||||||
|
@ -38,17 +34,17 @@ export class Message {
|
||||||
export class PostMessage extends Message {
|
export class PostMessage extends Message {
|
||||||
type = 'post';
|
type = 'post';
|
||||||
|
|
||||||
static contentFromJSON({ post, stake }) {
|
constructor({ post, stake }) {
|
||||||
return {
|
super({
|
||||||
post: Post.fromJSON(post),
|
post: PostContent.fromJSON(post),
|
||||||
stake,
|
stake,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static contentToJSON({ post, stake }) {
|
contentToJSON() {
|
||||||
return {
|
return {
|
||||||
post: post.toJSON(),
|
post: this.content.post.toJSON(),
|
||||||
stake,
|
stake: this.content.stake,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +60,6 @@ const messageTypes = new Map([
|
||||||
|
|
||||||
export const messageFromJSON = ({ type, content }) => {
|
export const messageFromJSON = ({ type, content }) => {
|
||||||
const MessageType = messageTypes.get(type) || Message;
|
const MessageType = messageTypes.get(type) || Message;
|
||||||
const messageContent = MessageType.contentFromJSON(content);
|
// const messageContent = MessageType.contentFromJSON(content);
|
||||||
return new MessageType(messageContent);
|
return new MessageType(content);
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,7 @@ export class Citation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Post {
|
export class PostContent {
|
||||||
constructor(content) {
|
constructor(content) {
|
||||||
this.id = CryptoUtil.randomUUID();
|
this.id = CryptoUtil.randomUUID();
|
||||||
this.content = content;
|
this.content = content;
|
||||||
|
@ -40,7 +40,7 @@ export class Post {
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJSON({ id, content, citations }) {
|
static fromJSON({ id, content, citations }) {
|
||||||
const post = new Post(content);
|
const post = new PostContent(content);
|
||||||
post.id = id;
|
post.id = id;
|
||||||
post.citations = citations.map((citation) => Citation.fromJSON(citation));
|
post.citations = citations.map((citation) => Citation.fromJSON(citation));
|
||||||
return post;
|
return post;
|
||||||
|
|
|
@ -23,6 +23,7 @@ export class ValidationPool extends Actor {
|
||||||
duration,
|
duration,
|
||||||
tokenLossRatio,
|
tokenLossRatio,
|
||||||
contentiousDebate = false,
|
contentiousDebate = false,
|
||||||
|
authorStake = 0,
|
||||||
},
|
},
|
||||||
name,
|
name,
|
||||||
scene,
|
scene,
|
||||||
|
@ -66,10 +67,11 @@ export class ValidationPool extends Actor {
|
||||||
this.tokens = {
|
this.tokens = {
|
||||||
for: fee * params.mintingRatio * params.stakeForWin,
|
for: fee * params.mintingRatio * params.stakeForWin,
|
||||||
against: fee * params.mintingRatio * (1 - params.stakeForWin),
|
against: fee * params.mintingRatio * (1 - params.stakeForWin),
|
||||||
// author: fee * params.mintingRatio * params.stakeForAuthor,
|
|
||||||
};
|
};
|
||||||
// TODO: Consider availability stakes
|
// tokens minted "for" the post go toward stake of author voting for their own post
|
||||||
this.castVote(signingPublicKey, true, this.tokens.for, 0);
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
castVote(signingPublicKey, position, stake, lockingTime) {
|
castVote(signingPublicKey, position, stake, lockingTime) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<head>
|
<head>
|
||||||
<title>Forum</title>
|
<title>Forum</title>
|
||||||
<script type="module" src="./forum-test.js" defer></script>
|
<script type="module" src="./forum-network-test.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>
|
|
@ -1,6 +1,6 @@
|
||||||
import { Box } from './classes/box.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 { PostContent } from './classes/post.js';
|
||||||
import { Member } from './classes/member.js';
|
import { Member } from './classes/member.js';
|
||||||
import { ForumNode } from './classes/forum-node.js';
|
import { ForumNode } from './classes/forum-node.js';
|
||||||
import { ForumNetwork } from './classes/forum-network.js';
|
import { ForumNetwork } from './classes/forum-network.js';
|
||||||
|
@ -9,7 +9,7 @@ import { delay } from './util.js';
|
||||||
const rootElement = document.getElementById('forum-network');
|
const rootElement = document.getElementById('forum-network');
|
||||||
const rootBox = new Box('rootBox', rootElement).flex();
|
const rootBox = new Box('rootBox', rootElement).flex();
|
||||||
|
|
||||||
window.scene = new Scene('Forum test', rootBox).log('sequenceDiagram');
|
window.scene = new Scene('Forum Network test', rootBox).log('sequenceDiagram');
|
||||||
|
|
||||||
window.author1 = await new Member('author1', window.scene).initialize();
|
window.author1 = await new Member('author1', window.scene).initialize();
|
||||||
window.author2 = await new Member('author2', window.scene).initialize();
|
window.author2 = await new Member('author2', window.scene).initialize();
|
||||||
|
@ -30,8 +30,8 @@ const processInterval = setInterval(async () => {
|
||||||
|
|
||||||
// const blockchain = new Blockchain();
|
// const blockchain = new Blockchain();
|
||||||
|
|
||||||
window.post1 = new Post({ message: 'hi' });
|
window.post1 = new PostContent({ message: 'hi' });
|
||||||
window.post2 = new Post({ message: 'hello' }).addCitation(window.post1.id, 1.0);
|
window.post2 = new PostContent({ message: 'hello' }).addCitation(window.post1.id, 1.0);
|
||||||
|
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await window.author1.submitPost(window.forumNode1, window.post1, 50);
|
await window.author1.submitPost(window.forumNode1, window.post1, 50);
|
|
@ -6,10 +6,11 @@
|
||||||
<body>
|
<body>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="./basic.html">Basic test</a></li>
|
<li><a href="./basic.html">Basic test</a></li>
|
||||||
<li><a href="./forum-test.html">Forum test</a></li>
|
<li><a href="./forum-network-test.html">Forum Network test</a></li>
|
||||||
<li><a href="./graph-test.html">Graph 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>
|
<li><a href="./validation-pool-test.html">Validation Pool test</a></li>
|
||||||
<li><a href="./mermaid-test.html">Mermaid test</a></li>
|
<li><a href="./mermaid-test.html">Mermaid test</a></li>
|
||||||
<li><a href="./debounce-test.html">Debounce test</a></li>
|
<li><a href="./debounce-test.html">Debounce test</a></li>
|
||||||
|
<li><a href="./availability-test.html">Availability test</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -7,3 +7,4 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="validation-pool"></div>
|
<div id="validation-pool"></div>
|
||||||
</body>
|
</body>
|
||||||
|
<scr
|
||||||
|
|
Loading…
Reference in New Issue