Cleanup related to forum network test
Also misc minor stub additions
This commit is contained in:
parent
c24952497d
commit
ab63ad1868
|
@ -0,0 +1,43 @@
|
|||
# Primary
|
||||
|
||||
## Forum
|
||||
|
||||
## ValidationPool
|
||||
|
||||
## ReputationToken
|
||||
|
||||
## WDAG
|
||||
|
||||
# Secondary
|
||||
|
||||
## Availability
|
||||
|
||||
## Business
|
||||
|
||||
## ERC721
|
||||
|
||||
## Expert
|
||||
|
||||
## Bench
|
||||
|
||||
# Tertiary
|
||||
|
||||
## Actor
|
||||
|
||||
## Action
|
||||
|
||||
## Scene
|
||||
|
||||
# To Explore
|
||||
|
||||
## Exchange
|
||||
|
||||
## Storage
|
||||
|
||||
## Network
|
||||
|
||||
## Wallet
|
||||
|
||||
## Agent/UI
|
||||
|
||||
## BlockConsensus
|
|
@ -0,0 +1,3 @@
|
|||
export class BlockConsensus {
|
||||
|
||||
}
|
|
@ -31,7 +31,7 @@ export class Expert extends ReputationHolder {
|
|||
// TODO: Include fee
|
||||
const postMessage = new PostMessage({ post, stake });
|
||||
await postMessage.sign(this.reputationKey);
|
||||
await this.actions.submitPostViaNetwork.log(this, forumNode, null, { id: post.id });
|
||||
await this.actions.submitPostViaNetwork.log(this, forumNode);
|
||||
// For now, directly call forumNode.receiveMessage();
|
||||
await forumNode.receiveMessage(JSON.stringify(postMessage.toJSON()));
|
||||
}
|
||||
|
|
|
@ -34,7 +34,8 @@ 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
|
||||
await this.actions.peerMessage.log(this, forumNode, null, message.content);
|
||||
// await this.actions.peerMessage.log(this, forumNode, null, message.content);
|
||||
await this.actions.peerMessage.log(this, forumNode);
|
||||
await forumNode.receiveMessage(JSON.stringify(message.toJSON()));
|
||||
}
|
||||
}
|
||||
|
@ -61,14 +62,13 @@ export class ForumNode extends Actor {
|
|||
try {
|
||||
await Message.verify(messageJson);
|
||||
} catch (e) {
|
||||
await this.actions.processMessage.log(this, this, 'invalid signature', messageJson, '-x');
|
||||
await this.actions.processMessage.log(this, this, 'invalid signature', null, '-x');
|
||||
console.log(`${this.name}: received message with invalid signature`);
|
||||
return;
|
||||
}
|
||||
|
||||
const { publicKey } = messageJson;
|
||||
const message = messageFromJSON(messageJson);
|
||||
console.log(`${this.name}: processMessage`, message);
|
||||
|
||||
if (message instanceof PostMessage) {
|
||||
await this.processPostMessage(publicKey, message.content);
|
||||
|
@ -77,18 +77,16 @@ export class ForumNode extends Actor {
|
|||
} else {
|
||||
// Unknown message type
|
||||
// Penalize sender for wasting our time
|
||||
console.log(`${this.name}: penalizing sender for unknown message type ${message.type}`);
|
||||
this.forumView.incrementReputation(message.publicKey, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// Process an incoming post, received by whatever means
|
||||
async processPost(authorId, post, stake) {
|
||||
async processPost(authorId, post) {
|
||||
if (!post.id) {
|
||||
post.id = CryptoUtil.randomUUID();
|
||||
}
|
||||
await this.actions.storePost.log(this, this, null, { authorId, post, stake });
|
||||
this.forumView.addPost(authorId, post.id, post, stake);
|
||||
await this.actions.storePost.log(this, this);
|
||||
// this.forumView.addPost(authorId, post.id, post, stake);
|
||||
}
|
||||
|
||||
// Process a post we received in a message
|
||||
|
|
|
@ -51,12 +51,10 @@ export class ForumView {
|
|||
const { citations = [], content } = postContent;
|
||||
const author = this.getOrInitializeAuthor(authorId);
|
||||
const postVertex = new PostVertex(postId, author, stake, content, citations);
|
||||
console.log('addPost', { id: postId, postContent });
|
||||
this.posts.addVertex(postId, postVertex);
|
||||
for (const { postId: citedPostId, weight } of citations) {
|
||||
this.posts.addEdge('citation', postId, citedPostId, weight);
|
||||
}
|
||||
this.applyNonbindingReputationEffects(postVertex);
|
||||
}
|
||||
|
||||
getPost(postId) {
|
||||
|
@ -66,65 +64,4 @@ export class ForumView {
|
|||
getPosts() {
|
||||
return this.posts.getVertices();
|
||||
}
|
||||
|
||||
// We'll start with naieve implementations of the computations we need.
|
||||
|
||||
// We want to derive a value -- maybe call it a reputation score -- for each post.
|
||||
// This value is a recursive sum of contributions from citations.
|
||||
|
||||
// There should be a diminishment of effect upon each recursion,
|
||||
// perhaps following a geometric progression.
|
||||
|
||||
// Each post gets some initial score due to the reputation that the author stakes.
|
||||
|
||||
// Citations are weighted, and can be positive or negative.
|
||||
|
||||
// So each post has a reputation score. Each author also has a reputation score.
|
||||
// The value of the author's reputation score could be a factor in the magnitude of the effects of their citations.
|
||||
// Post_rep = (Author_rep * stake);
|
||||
//
|
||||
|
||||
// Options:
|
||||
// - update a state model incrementally with each action in the history (/unfolding present) of the forum,
|
||||
// in order to arrive at the current view.
|
||||
|
||||
// When an author stakes reputation on a post, if it's a non-binding stake, then it merely expresses opinion.
|
||||
// If it's a binding stake, then they may lose the staked reputation as a result of other posts
|
||||
// staking reputation against theirs.
|
||||
|
||||
citationFraction = 0.3;
|
||||
|
||||
applyNonbindingReputationEffects(newPost) {
|
||||
this.distributeNonbindingReputation(newPost, newPost, newPost.stake);
|
||||
}
|
||||
|
||||
distributeNonbindingReputation(newPost, post, amount, depth = 0) {
|
||||
console.log('distributeNonbindingReputation', { post, amount, depth });
|
||||
// Some of the incoming reputation goes to this post
|
||||
post.reputation += amount * (1 - this.citationFraction);
|
||||
this.setReputation(post.id, post.reputation);
|
||||
// Some of the incoming reputation gets distributed among cited posts
|
||||
const distributeAmongCitations = amount * this.citationFraction;
|
||||
|
||||
// citation weights can be interpreted as a ratio, or we can somehow constrain the input
|
||||
// to add up to some specified total.
|
||||
// It's easy enough to let them be on any arbitrary scale and just compute the ratios here.
|
||||
const totalWeight = post.citations
|
||||
?.map(({ weight }) => weight)
|
||||
.reduce((acc, cur) => (acc += cur), 0);
|
||||
|
||||
post.citations?.forEach((citation) => {
|
||||
const citedPost = this.getPost(citation.postId);
|
||||
if (!citedPost) {
|
||||
// TODO: Here is where we may want to engage our peer protocol to query for possible missing records
|
||||
throw new Error(`Post ${post.postId} cites unknown post ${citation.postId}`);
|
||||
}
|
||||
this.distributeNonbindingReputation(
|
||||
newPost,
|
||||
citedPost,
|
||||
(citation.weight / totalWeight) * distributeAmongCitations,
|
||||
depth + 1,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,8 +34,8 @@ class Post extends Actor {
|
|||
throw new Error('Post donation total exceeds revaluation limit '
|
||||
+ `(${donationTotal} > ${params.revaluationLimit})`);
|
||||
}
|
||||
if (this.citations.some(({ weight }) => Math.abs(weight) > 1)) {
|
||||
throw new Error('Each citation weight must be in the range [-1, 1]');
|
||||
if (this.citations.some(({ weight }) => Math.abs(weight) > params.revaluationLimit)) {
|
||||
throw new Error(`Each citation magnitude must not exceed revaluation limit ${params.revaluationLimit}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,68 +4,6 @@
|
|||
<link type="text/css" rel="stylesheet" href="../index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="forum-network"></div>
|
||||
<div id="scene"></div>
|
||||
</body>
|
||||
<script type="module">
|
||||
import { Box } from '../classes/box.js';
|
||||
import { Scene } from '../classes/scene.js';
|
||||
import { PostContent } from '../classes/post-content.js';
|
||||
import { Expert } from '../classes/expert.js';
|
||||
import { ForumNode } from '../classes/forum-node.js';
|
||||
import { ForumNetwork } from '../classes/forum-network.js';
|
||||
import { CryptoUtil } from '../classes/crypto.js';
|
||||
import { delay } from '../util.js';
|
||||
|
||||
const rootElement = document.getElementById('forum-network');
|
||||
const rootBox = new Box('rootBox', rootElement).flex();
|
||||
|
||||
window.scene = new Scene('Forum Network test', rootBox).withSequenceDiagram();
|
||||
|
||||
window.author1 = await new Expert('author1', window.scene).initialize();
|
||||
window.author2 = await new Expert('author2', window.scene).initialize();
|
||||
|
||||
window.forumNetwork = new ForumNetwork();
|
||||
|
||||
window.forumNode1 = await new ForumNode('node1', window.scene).initialize(
|
||||
window.forumNetwork,
|
||||
);
|
||||
window.forumNode2 = await new ForumNode('node2', window.scene).initialize(
|
||||
window.forumNetwork,
|
||||
);
|
||||
window.forumNode3 = await new ForumNode('node3', window.scene).initialize(
|
||||
window.forumNetwork,
|
||||
);
|
||||
|
||||
const processInterval = setInterval(async () => {
|
||||
await window.forumNode1.processNextMessage();
|
||||
await window.forumNode2.processNextMessage();
|
||||
await window.forumNode3.processNextMessage();
|
||||
|
||||
await window.scene.sequence.render();
|
||||
}, 100);
|
||||
|
||||
// const blockchain = new Blockchain();
|
||||
|
||||
window.post1 = new PostContent({ message: 'hi' });
|
||||
window.post1.id = CryptoUtil.randomUUID();
|
||||
window.post2 = new PostContent({ message: 'hello' }).addCitation(
|
||||
window.post1.id,
|
||||
1.0,
|
||||
);
|
||||
|
||||
await delay(1000);
|
||||
await window.author1.submitPostViaNetwork(
|
||||
window.forumNode1,
|
||||
window.post1,
|
||||
50,
|
||||
);
|
||||
await delay(1000);
|
||||
await window.author2.submitPostViaNetwork(
|
||||
window.forumNode2,
|
||||
window.post2,
|
||||
100,
|
||||
);
|
||||
|
||||
await delay(1000);
|
||||
clearInterval(processInterval);
|
||||
</script>
|
||||
<script type="module" src="./scripts/forum-network.test.js"></script>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<link type="text/css" rel="stylesheet" href="../index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="test"></div>
|
||||
<div id="scene"></div>
|
||||
</body>
|
||||
<script type="module">
|
||||
import { Box } from '../classes/box.js';
|
||||
|
@ -16,10 +16,10 @@ import { delay } from '../util.js';
|
|||
|
||||
const DEFAULT_DELAY_INTERVAL = 500;
|
||||
|
||||
const rootElement = document.getElementById('forum-test');
|
||||
const rootElement = document.getElementById('scene');
|
||||
const rootBox = new Box('rootBox', rootElement).flex();
|
||||
|
||||
const scene = (window.scene = new Scene('Forum test', rootBox));
|
||||
const scene = (window.scene = new Scene('Reputation test', rootBox));
|
||||
scene.withSequenceDiagram();
|
||||
scene.withFlowchart();
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
import { Box } from '../../classes/box.js';
|
||||
import { Scene } from '../../classes/scene.js';
|
||||
import { PostContent } from '../../classes/post-content.js';
|
||||
import { Expert } from '../../classes/expert.js';
|
||||
import { ForumNode } from '../../classes/forum-node.js';
|
||||
import { ForumNetwork } from '../../classes/forum-network.js';
|
||||
import { CryptoUtil } from '../../classes/crypto.js';
|
||||
import { delay } from '../../util.js';
|
||||
|
||||
const rootElement = document.getElementById('scene');
|
||||
const rootBox = new Box('rootBox', rootElement).flex();
|
||||
|
||||
window.scene = new Scene('Forum Network test', rootBox).withSequenceDiagram();
|
||||
|
||||
window.author1 = await new Expert('author1', window.scene).initialize();
|
||||
window.author2 = await new Expert('author2', window.scene).initialize();
|
||||
|
||||
window.forumNetwork = new ForumNetwork();
|
||||
|
||||
window.forumNode1 = await new ForumNode('node1', window.scene).initialize(
|
||||
window.forumNetwork,
|
||||
);
|
||||
window.forumNode2 = await new ForumNode('node2', window.scene).initialize(
|
||||
window.forumNetwork,
|
||||
);
|
||||
window.forumNode3 = await new ForumNode('node3', window.scene).initialize(
|
||||
window.forumNetwork,
|
||||
);
|
||||
|
||||
const processInterval = setInterval(async () => {
|
||||
await window.forumNode1.processNextMessage();
|
||||
await window.forumNode2.processNextMessage();
|
||||
await window.forumNode3.processNextMessage();
|
||||
}, 100);
|
||||
|
||||
// const blockchain = new Blockchain();
|
||||
|
||||
window.post1 = new PostContent({ message: 'hi' });
|
||||
window.post1.id = CryptoUtil.randomUUID();
|
||||
window.post2 = new PostContent({ message: 'hello' }).addCitation(
|
||||
window.post1.id,
|
||||
1.0,
|
||||
);
|
||||
|
||||
await delay(1000);
|
||||
await window.author1.submitPostViaNetwork(
|
||||
window.forumNode1,
|
||||
window.post1,
|
||||
50,
|
||||
);
|
||||
await delay(1000);
|
||||
await window.author2.submitPostViaNetwork(
|
||||
window.forumNode2,
|
||||
window.post2,
|
||||
100,
|
||||
);
|
||||
|
||||
await delay(1000);
|
||||
clearInterval(processInterval);
|
Loading…
Reference in New Issue