When propagating value, apply leaching before donations

This commit is contained in:
Ladd Hoffman 2023-01-31 09:28:06 -06:00
parent 5fc5bbe0b5
commit a48d14905c
5 changed files with 98 additions and 33 deletions

View File

@ -0,0 +1,37 @@
The communication protocol(s) among network nodes
Each communication protocol among network nodes
has its own purpose
has its own assumptions, expectations, requirements, constraints
I think it makes sense to identify the constraints for our protocols.
We need the general public to be able to reliably
- Query information about the reputation WDAG
- Submit requests and fees for work
- Obtain the products of the work submitted by forum experts
Suppose we want only the requestor to be able to access a given work product.
(Why might we want this?)
Then the (soft) protocol for reviewing the work product would consist of
validating a signature by the requestor, attesting to their acceptance of the work product.
Alternatively access could be permitted to some group, such as reputation holders (a.k.a. experts).
Otherwise, for maximum utility, we would want to make the work products available indefinitely, as valuable artifacts.
Value here can be equated to the expected fees that the work products will help attract, which can in turn be equated to
reputation awarded to authors and reviewers of the work products.
Thus, the work of making the artifacts available must be funded.
The work of participating in a gossip / forum node consensus protocol and validating forum chain blocks must also be funded.
Suppose we have a storage contract.
- There can be a market for specific pledges of storage.
- buy: (amount, duration, price)
- sell: (amount, duration, price)
- Governance: Management of storage price
- may negotiate via loose -> tight binding traversal forum post sequence
- reputation in accordance with majority opinions on price parameters
- Verification of storage must occur by (randomly) querying the storage nodes and validating their responses.

View File

@ -0,0 +1,19 @@
This system is meant to represent a body of experts receiving fees to perform work.
Experts register their availability to receive work via the availability contract.
Request and associated fees are sumbitted via the business contract.
Evidence of the work performed is submitted as a post to the forum.
A successful validation pool ratifies the post.
Reputation is minted and distributed.
Fees are distributed.
What if we want the work to be block production for a blockchain?
Then to perform this work, an expert will need to participate in a communications network
such that they can confidently arrive at a majority view of each block.
Or else must at least be able to attest that a proposed block is valid,
meaning that it
- does not conflict with what the node believes to be the majority view
- includes what the node believes must be included according to the majority view
note that with this scheme there be muliple possible valid proposed blocks.
---

View File

@ -144,8 +144,7 @@ export class Forum extends ReputationHolder {
}) { }) {
const postVertex = edge.to; const postVertex = edge.to;
const post = postVertex?.data; const post = postVertex?.data;
const balanceFromInbound = this.posts.getEdgeWeight(BALANCE, edge.from, edge.to) ?? 0; this.actions.propagateValue.log(edge.from.data, post, `(${increment})`);
this.actions.propagateValue.log(edge.from.data, post, `(${increment}) balance (${balanceFromInbound})`);
if (!!params.referenceChainLimit && depth > params.referenceChainLimit) { if (!!params.referenceChainLimit && depth > params.referenceChainLimit) {
this.actions.propagateValue.log( this.actions.propagateValue.log(
@ -164,37 +163,47 @@ export class Forum extends ReputationHolder {
depth, depth,
value: post.value, value: post.value,
increment, increment,
balanceFromInbound,
initialNegative, initialNegative,
}); });
let totalOutboundAmount = 0; const propagate = async (positive) => {
let totalOutboundAmount = 0;
for (const citationEdge of postVertex.getEdges(CITATION, true)) { const citationEdges = postVertex.getEdges(CITATION, true)
const { weight } = citationEdge; .filter(({ weight }) => (positive ? weight > 0 : weight < 0));
let outboundAmount = weight * increment; for (const citationEdge of citationEdges) {
const balanceToOutbound = this.posts.getEdgeWeight(BALANCE, citationEdge.from, citationEdge.to) ?? 0; const { weight } = citationEdge;
// We need to ensure that we propagate no more reputation than we leached let outboundAmount = weight * increment;
if (initialNegative) { const balanceToOutbound = this.posts.getEdgeWeight(BALANCE, citationEdge.from, citationEdge.to) ?? 0;
outboundAmount = outboundAmount < 0 // We need to ensure that we at most undo the prior effects of this post
? Math.max(outboundAmount, -balanceToOutbound) if (initialNegative) {
: Math.min(outboundAmount, -balanceToOutbound); outboundAmount = outboundAmount < 0
? Math.max(outboundAmount, -balanceToOutbound)
: Math.min(outboundAmount, -balanceToOutbound);
}
if (Math.abs(outboundAmount) > EPSILON) {
const refundFromOutbound = await this.propagateValue(citationEdge, {
rewardsAccumulator,
increment: outboundAmount,
depth: depth + 1,
initialNegative: initialNegative || (depth === 0 && outboundAmount < 0),
});
outboundAmount -= refundFromOutbound;
this.posts.setEdgeWeight(BALANCE, citationEdge.from, citationEdge.to, balanceToOutbound + outboundAmount);
totalOutboundAmount += outboundAmount;
}
} }
if (Math.abs(outboundAmount) > EPSILON) { return totalOutboundAmount;
const refundFromOutbound = await this.propagateValue(citationEdge, { };
rewardsAccumulator,
increment: outboundAmount,
depth: depth + 1,
initialNegative: initialNegative || (depth === 0 && outboundAmount < 0),
});
outboundAmount -= refundFromOutbound;
this.posts.setEdgeWeight(BALANCE, citationEdge.from, citationEdge.to, balanceToOutbound + outboundAmount);
totalOutboundAmount += outboundAmount;
}
}
increment -= totalOutboundAmount * params.leachingValue; // First, leach value via negative citations
const totalLeachingAmount = await propagate(false);
increment -= totalLeachingAmount * params.leachingValue;
// Now propagate value via positive citations
const totalDonationAmount = await propagate(true);
increment -= totalDonationAmount * params.leachingValue;
// Apply the remaining increment to the present post
const rawNewValue = post.value + increment; const rawNewValue = post.value + increment;
const newValue = Math.max(0, rawNewValue); const newValue = Math.max(0, rawNewValue);
const appliedIncrement = newValue - post.value; const appliedIncrement = newValue - post.value;

View File

@ -28,8 +28,8 @@ describe('Forum', () => {
{ postId: posts[1], weight: 1 }, { postId: posts[1], weight: 1 },
]); ]);
forum.getPost(posts[0]).value.should.equal(0); forum.getPost(posts[0]).value.should.equal(0);
forum.getPost(posts[1]).value.should.equal(20); forum.getPost(posts[1]).value.should.equal(30);
forum.getPost(posts[2]).value.should.equal(10); forum.getPost(posts[2]).value.should.equal(0);
}); });
}); });
}); });

View File

@ -44,8 +44,8 @@ describe('Forum', () => {
{ postId: posts[2], weight: 1 }, { postId: posts[2], weight: 1 },
]); ]);
forum.getPost(posts[0]).value.should.equal(0); forum.getPost(posts[0]).value.should.equal(0);
forum.getPost(posts[1]).value.should.equal(20); forum.getPost(posts[1]).value.should.equal(30);
forum.getPost(posts[2]).value.should.equal(10); forum.getPost(posts[2]).value.should.equal(0);
forum.getPost(posts[3]).value.should.equal(0); forum.getPost(posts[3]).value.should.equal(0);
}); });
@ -55,8 +55,8 @@ describe('Forum', () => {
]); ]);
console.log('test5', { posts }); console.log('test5', { posts });
forum.getPost(posts[0]).value.should.equal(0); forum.getPost(posts[0]).value.should.equal(0);
forum.getPost(posts[1]).value.should.equal(30); forum.getPost(posts[1]).value.should.equal(40);
forum.getPost(posts[2]).value.should.equal(10); forum.getPost(posts[2]).value.should.equal(0);
forum.getPost(posts[3]).value.should.equal(0); forum.getPost(posts[3]).value.should.equal(0);
forum.getPost(posts[4]).value.should.equal(0); forum.getPost(posts[4]).value.should.equal(0);
}); });