rollup is working
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 32s Details

This commit is contained in:
Ladd Hoffman 2024-05-02 19:08:53 -05:00
parent 9c95e813a2
commit f7afd0105f
25 changed files with 222 additions and 412 deletions

View File

@ -1,14 +1,14 @@
{
"localhost": {
"DAO": "0xc7E04c11eD94E375857b885b3e6E1Db30C061348",
"Work1": "0x1bEffEB10E9f5714a8e385FfcA84046688677eA8",
"Onboarding": "0xFC40076c675693441C6e553FEdDD3A3348db81E4",
"Proposals": "0xa1349A27D43d0F71CeDD75904ACc8f8CF8F81582",
"Rollup": "0x1361c87D5972a71cBCA34f6EAD928358deaC750D",
"Work2": "0x691Bcb6a8378Cec103BE58Dfa037DC57E6FFf4d1",
"Reputation": "0xfC979dbae6Cd0f35CC240889663B523B35c5F101",
"Forum": "0xaf247e316A081871e713F492279D2360bd162401",
"Bench": "0xC8BCE8171e626d07E5095256F703B1df23a67362"
"DAO": "0x1d63FDe5B461106729fE1e5e38A02fc68C518Af5",
"Work1": "0xB8f0cd092979F273b752FDa060F82BF2745f192e",
"Onboarding": "0x8F00038542C87A5eAf18d5938B7723bF2A04A4e4",
"Proposals": "0x6c18eb38b7450F8DaE5A5928A40fcA3952493Ee4",
"Rollup": "0x57BDFFf79108E5198dec6268A6BFFD8B62ECfA38",
"Work2": "0x42b79f8d8408c36aD4347ab72f826684440a7a8F",
"Reputation": "0x8d914D38dD301FC4606f5aa9fEcF8A76389020d3",
"Forum": "0x050C420Cc4995B41217Eba1B54B82Fd5687e9139",
"Bench": "0xfe58B9EB03F75A603de1B286584f5E9532ab8fB5"
},
"sepolia": {
"DAO": "0x8e5bd58B2ca8910C5F9be8de847d6883B15c60d2",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,7 @@ const {
appState,
proposalEventIds,
} = require('../util/db');
const { submitRollup, resetBatch } = require('./rollup');
const {
BOT_INSTANCE_ID,
@ -19,6 +20,8 @@ const handleCommand = async (client, roomId, event) => {
const helloRegex = /^!hello\b/i;
const targetRegex = /^!target (.*)\b/i;
const proposalRegex = /\bprop(|osal) ([0-9]+)\b/i;
const submitRollupRegex = /^!submitBatch\b/i;
const resetBatchRegex = /^!resetBatch (.*)\b/i;
const { body } = event.content;
@ -51,6 +54,22 @@ const handleCommand = async (client, roomId, event) => {
} catch (e) {
// Not found
}
} else if (submitRollupRegex.test(body)) {
console.log('!submitBatch');
const { batchPostId, batchItems, authors } = await submitRollup();
if (batchItems.length) {
await client.replyText(roomId, event, `Submitted batch, post ${batchPostId} with ${batchItems.length} posts by ${authors.length} authors`);
} else {
await client.replyText(roomId, event, 'No matrix pools have finished since the last batch was submitted');
}
} else if (resetBatchRegex.test(body)) {
const [, instanceId] = resetBatchRegex.exec(body);
console.log(`!resetBatch roomId ${roomId} instanceId ${instanceId}`);
if (instanceId === BOT_INSTANCE_ID) {
console.log('!resetBatch');
const batchItems = await resetBatch();
await client.replyText(roomId, event, `Reset batch, now contains ${batchItems.length} items`);
}
}
};

View File

@ -17,15 +17,30 @@ const {
ROLLUP_AVAILABILITY_STAKE_DURATION,
} = process.env;
const rollupBatchSize = ROLLUP_BATCH_SIZE || 1;
const rollupBatchSize = ROLLUP_BATCH_SIZE || 10;
const availabilityStakeDuration = ROLLUP_AVAILABILITY_STAKE_DURATION || 600;
let batchWorker;
let batchItems;
const resetBatch = async () => {
batchItems = [];
// Read from Rollup.items
const itemCount = await rollup.itemCount();
const promises = [];
for (let i = 0; i < itemCount; i += 1) {
promises.push(rollup.items(i));
}
batchItems = await Promise.all(promises);
await applicationData.put('batchItems', batchItems);
return batchItems;
};
const stakeRollupAvailability = async () => {
const currentRep = await dao.balanceOf(await wallet.getAddress());
await dao.stakeAvailability(rollup.target, currentRep, availabilityStakeDuration);
if (currentRep) {
await dao.stakeAvailability(rollup.target, currentRep, availabilityStakeDuration);
}
};
const getBatchPostAuthorWeights = async (batchItems_) => {
@ -43,25 +58,28 @@ const getBatchPostAuthorWeights = async (batchItems_) => {
// TODO: Rewards for policing
// TODO: Propagation via references
});
// Rescale author weights so they sum to 1000000
const sumOfWeights = Object.values(weights).reduce((t, v) => t + v, 0);
const scaledWeights = weights
.map((weight) => Math.floor((weight * 1000000) / sumOfWeights));
const sumOfScaledWeights = Object.values(scaledWeights).reduce((t, v) => t + v, 0);
scaledWeights[0] += 1000000 - sumOfScaledWeights;
const authors = Object.entries(scaledWeights)
.map(([authorAddress, weightPPM]) => ({ authorAddress, weightPPM }));
return authors;
});
// Rescale author weights so they sum to 1000000
const sumOfWeights = Object.values(weights).reduce((t, v) => t + v, 0);
const scaledWeights = Object.values(weights)
.map((weight) => Math.floor((weight * 1000000) / sumOfWeights));
const sumOfScaledWeights = Object.values(scaledWeights).reduce((t, v) => t + v, 0);
scaledWeights[0] += 1000000 - sumOfScaledWeights;
const authors = Object.keys(weights)
.map((authorAddress, i) => ({ authorAddress, weightPPM: scaledWeights[i] }));
return authors;
};
const submitBatchPost = async () => {
const submitRollup = async () => {
if (!batchItems.length) {
return { batchItems: [] };
}
const authors = await getBatchPostAuthorWeights(batchItems);
// TODO: Compute citations as aggregate of the citations of posts in the batch
const citations = [];
const content = `Batch of ${batchItems.length} items`;
const embeddedData = {
matrixPools: batchItems.map((x) => x.postId),
batchItems,
nonce: uuidv4().replace(/-/i, ''),
};
const sender = await wallet.getAddress();
@ -80,9 +98,15 @@ const submitBatchPost = async () => {
await rollup.submitBatch(batchPostId, batchItems.length, poolDuration);
// Send matrix event
await sendMatrixEvent('io.dgov.rollup.submit', { batchPostId, batchItems, authors });
console.log('Submitted batch', { batchPostId, batchItems, authors });
// Clear the batch in preparation for next batch
batchItems = [];
return batchPostId;
await applicationData.put('batchItems', batchItems);
return {
batchPostId,
batchItems,
authors,
};
};
const evaluateMatrixPoolOutcome = async (postId, { dryRun } = {}) => {
@ -96,8 +120,8 @@ const evaluateMatrixPoolOutcome = async (postId, { dryRun } = {}) => {
.filter((x) => !x.inFavor)
.reduce((total, { amount }) => total + amount, 0);
const votePasses = stakedFor * winRatio[1] >= (stakedFor + stakedAgainst) * winRatio[0];
const totalSupply = await dao.totalSupply();
const quorumMet = BigInt(stakedFor + stakedAgainst) * quorum[1] >= totalSupply * quorum[0];
const totalSupply = Number(await dao.totalSupply());
const quorumMet = (stakedFor + stakedAgainst) * quorum[1] >= totalSupply * quorum[0];
const result = {
stakedFor, stakedAgainst, totalSupply, votePasses, quorumMet,
};
@ -126,7 +150,7 @@ const evaluateMatrixPoolOutcome = async (postId, { dryRun } = {}) => {
}
if (submitBatch) {
await stakeRollupAvailability();
await submitBatchPost();
await submitRollup();
}
}
return result;
@ -150,6 +174,29 @@ const validateWorkEvidence = async (sender, post) => {
return valid;
};
const validatePost = async ({
sender, post, postId, roomId, eventId, ...params
}) => {
const currentRep = Number(await dao.balanceOf(await wallet.getAddress()));
const valid = await validateWorkEvidence(sender, post);
const stake = { amount: currentRep, account: await wallet.getAddress(), inFavor: valid };
sendMatrixEvent('io.dgov.pool.stake', { postId, amount: currentRep, inFavor: valid });
console.log('matrixPool', {
postId,
roomId,
eventId,
...params,
stakes: [stake],
});
await matrixPools.put(postId, {
postId,
roomId,
eventId,
...params,
stakes: [stake],
});
};
const start = async () => {
console.log('registering validation pool decider for rollup');
registerDecider(async (pool, post) => {
@ -159,17 +206,19 @@ const start = async () => {
// A rollup post should contain
// - a list of off-chain validation pools
// - authorship corresponding to the result of those off-chain pools
if (!post.embeddedData?.matrixPools) return false;
if (!post.embeddedData?.batchItems) return false;
// Our task here is to check whether the posted result agrees with our own computations
let expectedAuthors;
try {
expectedAuthors = await getBatchPostAuthorWeights(post.embeddedData.matrixPools);
expectedAuthors = await getBatchPostAuthorWeights(post.embeddedData.batchItems);
} catch (e) {
console.error('Error calculating batch post author weights', e);
return false;
}
return authorsMatch(post.authors, expectedAuthors);
const valid = authorsMatch(post.authors, expectedAuthors);
console.log(`batch post ${pool.postId} is ${valid ? 'valid' : 'invalid'}`);
return valid;
});
// Even if we're not the current batch worker, keep track of batch items
@ -181,15 +230,15 @@ const start = async () => {
// Check for an assigned batch worker
batchWorker = await rollup.batchWorker();
console.log('At startup', { batchWorker });
console.log('At startup, batch worker:', batchWorker);
// Stake availability and set an interval to maintain it
await stakeRollupAvailability();
setInterval(stakeRollupAvailability, availabilityStakeDuration * 1000);
rollup.on('BatchWorkerAssigned', async (batchWorker_) => {
console.log('Batch worker assigned:', batchWorker);
batchWorker = batchWorker_;
console.log('Batch worker assigned:', batchWorker);
if (batchWorker === await wallet.getAddress()) {
console.log('This instance is the new batch worker');
}
@ -204,7 +253,11 @@ const start = async () => {
const quorum = [1, 3];
const winRatio = [1, 2];
const params = {
sender, fee, duration, quorum, winRatio,
sender,
fee: Number(fee),
duration,
quorum,
winRatio,
};
let post;
@ -228,16 +281,8 @@ const start = async () => {
...params,
});
// Register our own stake and send a message
const currentRep = await dao.balanceOf(await wallet.getAddress());
const valid = await validateWorkEvidence(sender, post);
const stake = { amount: currentRep, account: await wallet.getAddress(), inFavor: valid };
sendMatrixEvent('io.dgov.pool.stake', { postId, amount: currentRep, inFavor: valid });
await matrixPools.put(postId, {
postId,
roomId,
eventId,
...params,
stakes: [stake],
await validatePost({
sender, post, postId, roomId, eventId, ...params,
});
} else {
throw e;
@ -267,12 +312,8 @@ const start = async () => {
console.error(`Post ID ${postId} not found`);
break;
}
const currentRep = await dao.balanceOf(await wallet.getAddress());
const valid = await validateWorkEvidence(sender, post);
const stake = { amount: currentRep, account: await wallet.getAddress(), inFavor: valid };
sendMatrixEvent('io.dgov.pool.stake', { postId, amount: currentRep, inFavor: valid });
await matrixPools.put(postId, {
roomId, eventId, ...params, stakes: [stake],
await validatePost({
sender, post, postId, roomId, eventId, ...params,
});
break;
}
@ -322,6 +363,8 @@ const start = async () => {
}
matrixPool.result = result;
await matrixPools.put(postId, matrixPool);
batchItems.push(postId);
await applicationData.put('batchItems', batchItems);
break;
}
case 'io.dgov.rollup.submit': {
@ -340,6 +383,10 @@ const start = async () => {
if (!authorsMatch(authors, expectedAuthors)) {
sendMatrixText(`Unexpected result for batch post ${batchPostId}`);
}
// Reset batchItems in preparation for next batch
const nextBatchItems = batchItems.filter((postId) => !batchPostIds.includes(postId));
batchItems = nextBatchItems;
await applicationData.put('batchItems', batchItems);
break;
}
default:
@ -349,4 +396,6 @@ const start = async () => {
module.exports = {
start,
submitRollup,
resetBatch,
};

View File

@ -12,7 +12,6 @@ const setTargetRoomId = async (roomId) => {
};
const processOutboundQueue = async ({ type, ...args }) => {
console.log('processing outbound queue item', { type, args });
if (!targetRoomId) return;
switch (type) {
case 'MatrixEvent': {
@ -47,9 +46,10 @@ const startOutboundQueue = async (matrixClient_) => {
outboundQueue.resume();
};
const sendMatrixEvent = async (type, content) => new Promise((resolve) => {
const sendMatrixEvent = async (eventType, content) => new Promise((resolve) => {
outboundQueue.push({
eventType: 'MatrixEvent',
type: 'MatrixEvent',
eventType,
content,
onSend: ((roomId, eventId) => {
resolve({ roomId, eventId });
@ -59,7 +59,7 @@ const sendMatrixEvent = async (type, content) => new Promise((resolve) => {
const sendMatrixText = async (text) => new Promise((resolve) => {
outboundQueue.push({
eventType: 'MatrixText',
type: 'MatrixText',
text,
onSend: ((roomId, eventId) => {
resolve({ roomId, eventId });

View File

@ -1,14 +1,14 @@
{
"localhost": {
"DAO": "0xc7E04c11eD94E375857b885b3e6E1Db30C061348",
"Work1": "0x1bEffEB10E9f5714a8e385FfcA84046688677eA8",
"Onboarding": "0xFC40076c675693441C6e553FEdDD3A3348db81E4",
"Proposals": "0xa1349A27D43d0F71CeDD75904ACc8f8CF8F81582",
"Rollup": "0x1361c87D5972a71cBCA34f6EAD928358deaC750D",
"Work2": "0x691Bcb6a8378Cec103BE58Dfa037DC57E6FFf4d1",
"Reputation": "0xfC979dbae6Cd0f35CC240889663B523B35c5F101",
"Forum": "0xaf247e316A081871e713F492279D2360bd162401",
"Bench": "0xC8BCE8171e626d07E5095256F703B1df23a67362"
"DAO": "0x1d63FDe5B461106729fE1e5e38A02fc68C518Af5",
"Work1": "0xB8f0cd092979F273b752FDa060F82BF2745f192e",
"Onboarding": "0x8F00038542C87A5eAf18d5938B7723bF2A04A4e4",
"Proposals": "0x6c18eb38b7450F8DaE5A5928A40fcA3952493Ee4",
"Rollup": "0x57BDFFf79108E5198dec6268A6BFFD8B62ECfA38",
"Work2": "0x42b79f8d8408c36aD4347ab72f826684440a7a8F",
"Reputation": "0x8d914D38dD301FC4606f5aa9fEcF8A76389020d3",
"Forum": "0x050C420Cc4995B41217Eba1B54B82Fd5687e9139",
"Bench": "0xfe58B9EB03F75A603de1B286584f5E9532ab8fB5"
},
"sepolia": {
"DAO": "0x8e5bd58B2ca8910C5F9be8de847d6883B15c60d2",

View File

@ -56,7 +56,7 @@ contract Rollup is Availability {
}
// initiate a validation pool for this batch
uint fee;
for (uint i = 0; i < itemCount; i++) {
for (uint i = 0; i < batchSize; i++) {
fee += items[i].fee;
}
poolIndex = dao.initiateValidationPool{value: fee}(
@ -70,7 +70,7 @@ contract Rollup is Availability {
""
);
// Include all the availability stakes from the batched work
for (uint i = 0; i < itemCount; i++) {
for (uint i = 0; i < batchSize; i++) {
dao.delegatedStakeOnValidationPool(
poolIndex,
items[i].worker,

View File

@ -1,14 +1,14 @@
{
"localhost": {
"DAO": "0xc7E04c11eD94E375857b885b3e6E1Db30C061348",
"Work1": "0x1bEffEB10E9f5714a8e385FfcA84046688677eA8",
"Onboarding": "0xFC40076c675693441C6e553FEdDD3A3348db81E4",
"Proposals": "0xa1349A27D43d0F71CeDD75904ACc8f8CF8F81582",
"Rollup": "0x1361c87D5972a71cBCA34f6EAD928358deaC750D",
"Work2": "0x691Bcb6a8378Cec103BE58Dfa037DC57E6FFf4d1",
"Reputation": "0xfC979dbae6Cd0f35CC240889663B523B35c5F101",
"Forum": "0xaf247e316A081871e713F492279D2360bd162401",
"Bench": "0xC8BCE8171e626d07E5095256F703B1df23a67362"
"DAO": "0x1d63FDe5B461106729fE1e5e38A02fc68C518Af5",
"Work1": "0xB8f0cd092979F273b752FDa060F82BF2745f192e",
"Onboarding": "0x8F00038542C87A5eAf18d5938B7723bF2A04A4e4",
"Proposals": "0x6c18eb38b7450F8DaE5A5928A40fcA3952493Ee4",
"Rollup": "0x57BDFFf79108E5198dec6268A6BFFD8B62ECfA38",
"Work2": "0x42b79f8d8408c36aD4347ab72f826684440a7a8F",
"Reputation": "0x8d914D38dD301FC4606f5aa9fEcF8A76389020d3",
"Forum": "0x050C420Cc4995B41217Eba1B54B82Fd5687e9139",
"Bench": "0xfe58B9EB03F75A603de1B286584f5E9532ab8fB5"
},
"sepolia": {
"DAO": "0x8e5bd58B2ca8910C5F9be8de847d6883B15c60d2",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long