rollup: use time rather than count for interval; add resetBatchWorker method

This commit is contained in:
Ladd Hoffman 2024-05-09 11:47:05 -05:00
parent 837b972149
commit f7dcf0ec5e
8 changed files with 50 additions and 14 deletions

View File

@ -32,7 +32,8 @@ Our work contract normally triggeres a validation pool when the customer submits
The `Rollup` contract itself uses the `Availability` contract to assign a batch worker. This worker is responsible for making sure off-chain pools are conducted.
When ready, the worker submits the current batch on-chain by creating a batch post and a validation pool targeting the batch post.
When ready, the worker submits the current batch on-chain by calling `DAO.addPost()` to create a batch post and then calling `Rollup.submitBatch()`, which initiates a validation pool targeting the batch post.
```mermaid
sequenceDiagram
participant client as Staking client

View File

@ -1,6 +1,7 @@
const { rollup, wallet } = require('../../util/contracts');
let batchWorker;
let batchStart;
const getCurrentBatchWorker = () => batchWorker;
@ -11,6 +12,7 @@ const initializeBatchWorker = async () => {
rollup.on('BatchWorkerAssigned', async (batchWorker_) => {
batchWorker = batchWorker_;
batchStart = new Date();
console.log('Batch worker assigned:', batchWorker);
if (batchWorker === await wallet.getAddress()) {
console.log('This instance is the new batch worker');
@ -22,8 +24,11 @@ const setBatchWorker = (batchWorker_) => {
batchWorker = batchWorker_;
};
const getBatchAge = (new Date() - batchStart) / 1000;
module.exports = {
getCurrentBatchWorker,
initializeBatchWorker,
setBatchWorker,
getBatchAge,
};

View File

@ -1,9 +1,9 @@
const {
ROLLUP_BATCH_SIZE,
ROLLUP_AVAILABILITY_STAKE_DURATION,
ROLLUP_INTERVAL,
} = process.env;
module.exports = {
rollupBatchSize: ROLLUP_BATCH_SIZE || 10,
rollupInterval: ROLLUP_INTERVAL,
availabilityStakeDuration: ROLLUP_AVAILABILITY_STAKE_DURATION || 600,
};

View File

@ -2,9 +2,9 @@ const { sendMatrixEvent } = require('../../../matrix-bot');
const { wallet } = require('../../../util/contracts');
const { matrixPools } = require('../../../util/db');
const { addBatchItem, getBatchItems } = require('../batch-items');
const { getCurrentBatchWorker } = require('../batch-worker');
const { getCurrentBatchWorker, getBatchAge } = require('../batch-worker');
const computeMatrixPoolResult = require('./compute-result');
const { rollupBatchSize } = require('../config');
const { rollupInterval } = require('../config');
const submitRollup = require('../submit-rollup');
const { stakeRollupAvailability } = require('../utils');
@ -28,9 +28,10 @@ const evaluateMatrixPoolOutcome = async (postId) => {
} else if (batchWorker === await wallet.getAddress()) {
// If we are the batch worker, we should wait an appropriate amout of time /
// number of matrix pools before submitting a batch.
const batchAge = getBatchAge();
const batchItems = getBatchItems();
if (batchItems.length === rollupBatchSize) {
console.log(`Batch size = ${batchItems.length}. Submitting batch.`);
if (batchAge > rollupInterval && batchItems.length) {
console.log(`Batch age = ${batchAge}, size = ${batchItems.length}. Submitting batch.`);
submitBatch = true;
}
}

View File

@ -6,4 +6,5 @@ MAINNET_PRIVATE_KEY=
SEED_PHRASE=
ETHERSCAN_API_KEY=
WORK1_PRICE="0.001"
ONBOARDING_PRICE="0.001"
ONBOARDING_PRICE="0.001"
ROLLUP_INTERVAL=120

View File

@ -5,8 +5,6 @@ import "./core/DAO.sol";
import "./Availability.sol";
contract Rollup is Availability {
constructor(DAO dao) Availability(dao) {}
struct BatchItem {
address sender;
address worker;
@ -19,10 +17,18 @@ contract Rollup is Availability {
uint public itemCount;
address public batchWorker;
uint batchWorkerStakeIndex;
uint public immutable batchInterval;
uint public batchStart;
uint lastWorkerReset;
uint constant minResetInterval = 120;
event BatchItemAdded(string postId, address sender, uint fee);
event BatchWorkerAssigned(address batchWorker);
constructor(DAO dao, uint batchInterval_) Availability(dao) {
batchInterval = batchInterval_;
}
/// Instead of initiating a validation pool, call this method to include
/// the stakes and fee in the next batch validation pool
function addItem(
@ -106,9 +112,28 @@ contract Rollup is Availability {
// Reset item count so we can start the next batch
itemCount = 0;
}
// Select the next worker
// Select the next batch worker
batchWorkerStakeIndex = assignWork();
batchWorker = stakes[batchWorkerStakeIndex].worker;
batchStart = block.timestamp;
emit BatchWorkerAssigned(batchWorker);
}
/// If the batch worker fails to submit the batch, a new batch worker may be selected
function resetBatchWorker() public {
require(
block.timestamp - batchStart > batchInterval,
"Current batch interval has not yet elapsed"
);
require(itemCount > 0, "Current batch is empty");
require(
lastWorkerReset == 0 ||
block.timestamp - lastWorkerReset >= minResetInterval,
"Mininum reset interval has not elapsed since last batch worker reset"
);
// TODO: Should the current batch worker's availability stakes be forfeit?
// Select a new batch worker
batchWorkerStakeIndex = assignWork();
batchWorker = stakes[batchWorkerStakeIndex].worker;
}
}

View File

@ -1,11 +1,14 @@
require('dotenv').config();
const deployDAOContract = require('./util/deploy-dao-contract');
const deployWorkContract = require('./util/deploy-work-contract');
const deployRollableWorkContract = require('./util/deploy-rollable-work-contract');
const deployCoreContracts = require('./util/deploy-core-contracts');
const { ROLLUP_INTERVAL } = process.env;
async function main() {
await deployCoreContracts();
await deployDAOContract('Rollup');
await deployDAOContract('Rollup', [ROLLUP_INTERVAL]);
await deployDAOContract('Proposals');
await deployWorkContract('Work1');
await deployWorkContract('Onboarding');

View File

@ -6,8 +6,8 @@ require('dotenv').config();
const network = process.env.HARDHAT_NETWORK;
const deployDAOContract = async (name) => {
await deployContract(name, [contractAddresses[network].DAO]);
const deployDAOContract = async (name, args = []) => {
await deployContract(name, [contractAddresses[network].DAO, ...args]);
};
module.exports = deployDAOContract;