import { Box } from '../../classes/display/box.js'; import { Scene } from '../../classes/display/scene.js'; import { Expert } from '../../classes/actors/expert.js'; import { delay } from '../../util.js'; import { DAO } from '../../classes/actors/dao.js'; import { Public } from '../../classes/actors/public.js'; import { PostContent } from '../../classes/util/post-content.js'; const DELAY_INTERVAL = 100; const POOL_DURATION = 200; let dao; let experts; let requestor; let scene; const newExpert = async () => { const index = experts.length; const name = `Expert${index + 1}`; const expert = await new Expert(dao, name, scene).initialize(); expert.setValue( 'rep', () => dao.reputation.valueOwnedBy(expert.reputationPublicKey), ); experts.push(expert); return expert; }; const setup = async () => { const rootElement = document.getElementById('scene'); const rootBox = new Box('rootBox', rootElement).flex(); scene = new Scene('Availability test', rootBox); scene.withSequenceDiagram(); scene.withFlowchart(); scene.withTable(); dao = new DAO('DGF', scene); await dao.setValue('total rep', () => dao.reputation.getTotal()); experts = []; await newExpert(); await newExpert(); requestor = new Public('Public', scene); await delay(DELAY_INTERVAL); // Experts gain initial reputation by submitting a post with fee const { postId: postId1, pool: pool1 } = await experts[0].submitPostWithFee( new PostContent({ hello: 'there' }).setTitle('Post 1'), { fee: 10, duration: POOL_DURATION, tokenLossRatio: 1, }, ); await delay(POOL_DURATION); await pool1.evaluateWinningConditions(); await delay(DELAY_INTERVAL); dao.reputation.valueOwnedBy(experts[0].reputationPublicKey).should.equal(10); const { pool: pool2 } = await experts[1].submitPostWithFee( new PostContent({ hello: 'to you as well' }) .setTitle('Post 2') .addCitation(postId1, 0.5), { fee: 10, duration: POOL_DURATION, tokenLossRatio: 1, }, ); await delay(POOL_DURATION); await pool2.evaluateWinningConditions(); await delay(DELAY_INTERVAL); dao.reputation.valueOwnedBy(experts[0].reputationPublicKey).should.equal(15); dao.reputation.valueOwnedBy(experts[1].reputationPublicKey).should.equal(5); }; const getActiveWorker = async () => { let worker; let request; for (const expert of experts) { request = await expert.getAssignedWork(); if (request) { worker = expert; await worker.actions.getAssignedWork.log(worker, dao.availability); worker.activate(); break; } } return { worker, request }; }; const voteForWorkEvidence = async (worker, pool) => { for (const expert of experts) { if (expert !== worker) { await expert.stake(pool, { position: true, amount: 1, }); } } }; describe('Availability + Business', () => { before(async () => { await setup(); }); beforeEach(async () => { // await scene.sequence.startSection(); }); afterEach(async () => { // await scene.sequence.endSection(); }); it('Experts can register their availability for some duration', async () => { await experts[0].registerAvailability(1, 10000); await experts[1].registerAvailability(1, 10000); await delay(DELAY_INTERVAL); }); it('Public can submit a work request', async () => { await requestor.submitRequest( dao.business, { fee: 100 }, { please: 'do some work' }, ); await delay(DELAY_INTERVAL); }); it('Expert can submit work evidence', async () => { // Receive work request const { worker, request } = await getActiveWorker(); const pool3 = await worker.submitWork( request.id, { here: 'is some evidence of work product', }, { tokenLossRatio: 1, duration: POOL_DURATION, }, ); await worker.deactivate(); // Stake on work evidence await voteForWorkEvidence(worker, pool3); // Wait for validation pool duration to elapse await delay(POOL_DURATION); // Distribute reputation awards and fees await pool3.evaluateWinningConditions(); await delay(DELAY_INTERVAL); // This should throw an exception since the pool is already resolved try { await pool3.evaluateWinningConditions(); } catch (e) { e.should.match(/Validation pool has already been resolved/); } }).timeout(10000); });