diff --git a/backend/src/api/import-from-matrix.js b/backend/src/api/import-from-matrix.js index 5bb6125..3d289b7 100644 --- a/backend/src/api/import-from-matrix.js +++ b/backend/src/api/import-from-matrix.js @@ -1,4 +1,4 @@ -const { getClient } = require('../matrix-bot'); +const { getMatrixClient } = require('../matrix-bot'); const { matrixUserToAuthorAddress } = require('../util/db'); const write = require('../util/forum/write'); const { dao, wallet } = require('../util/contracts'); @@ -43,7 +43,7 @@ module.exports = async (req, res) => { console.log('roomId', roomId); console.log('eventId', eventId); - const client = getClient(); + const client = getMatrixClient(); const event = await client.getEvent(roomId, eventId); console.log('event', event); diff --git a/backend/src/matrix-bot/index.js b/backend/src/matrix-bot/index.js index d2b0f5b..b867968 100644 --- a/backend/src/matrix-bot/index.js +++ b/backend/src/matrix-bot/index.js @@ -5,9 +5,6 @@ const { SimpleFsStorageProvider, } = require('matrix-bot-sdk'); -const { registerCommands } = require('./commands'); -const { registerRoomEventHandler } = require('./room-events'); - const { MATRIX_HOMESERVER_URL, MATRIX_ACCESS_TOKEN, @@ -17,32 +14,24 @@ const { const storageProvider = new SimpleFsStorageProvider(BOT_STORAGE_PATH); const cryptoProvider = new RustSdkCryptoStorageProvider(BOT_CRYPTO_STORAGE_PATH); -let client; +console.log('MATRIX_HOMESERVER_URL:', MATRIX_HOMESERVER_URL); +const client = new MatrixClient( + MATRIX_HOMESERVER_URL, + MATRIX_ACCESS_TOKEN, + storageProvider, + cryptoProvider, +); let joinedRooms; const { startOutboundQueue } = require('./outbound-queue'); const start = async () => { - console.log('MATRIX_HOMESERVER_URL:', MATRIX_HOMESERVER_URL); - client = new MatrixClient( - MATRIX_HOMESERVER_URL, - MATRIX_ACCESS_TOKEN, - storageProvider, - cryptoProvider, - ); - // Automatically join a room to which we are invited AutojoinRoomsMixin.setupOnClient(client); joinedRooms = await client.getJoinedRooms(); console.log('joined rooms:', joinedRooms); - // Before we start the bot, register our command handler - registerCommands(client); - - // Handler for custom events - registerRoomEventHandler(client); - client.start().then(() => { console.log('Bot started!'); // Start the outbound queue @@ -50,9 +39,22 @@ const start = async () => { }); }; -const getClient = () => client; +const registerMessageHandler = (eventHandler) => { + client.on('room.message', (roomId, event) => eventHandler(client, roomId, event)); +}; + +const registerEventHandler = (eventHandler) => { + client.on('room.event', (roomId, event) => { + if (event.state_key !== undefined) return; // state event + eventHandler(client, roomId, event); + }); +}; + +const getMatrixClient = () => client; module.exports = { start, - getClient, + getMatrixClient, + registerMessageHandler, + registerEventHandler, }; diff --git a/backend/src/matrix-bot/commands.js b/backend/src/topics/bot-commands.js similarity index 90% rename from backend/src/matrix-bot/commands.js rename to backend/src/topics/bot-commands.js index 8ea5a7d..d7ea015 100644 --- a/backend/src/matrix-bot/commands.js +++ b/backend/src/topics/bot-commands.js @@ -1,4 +1,5 @@ -const { setTargetRoomId } = require('./outbound-queue'); +const { registerMessageHandler } = require('../matrix-bot'); +const { setTargetRoomId } = require('../matrix-bot/outbound-queue'); const { appState, @@ -53,10 +54,10 @@ const handleCommand = async (client, roomId, event) => { } }; -const registerCommands = (client) => { - client.on('room.message', (roomId, event) => handleCommand(client, roomId, event)); +const start = () => { + registerMessageHandler(handleCommand); }; module.exports = { - registerCommands, + start, }; diff --git a/backend/src/topics/index.js b/backend/src/topics/index.js index 7aaf923..8df9fd1 100644 --- a/backend/src/topics/index.js +++ b/backend/src/topics/index.js @@ -2,12 +2,16 @@ const proposalsNotifier = require('./proposals-notifier'); const validationPools = require('./validation-pools'); const work1 = require('./work1'); const rollup = require('./rollup'); +const registerIdentity = require('./register-identity'); +const botCommands = require('./bot-commands'); const start = () => { proposalsNotifier.start(); validationPools.start(); work1.start(); rollup.start(); + registerIdentity.start(); + botCommands.start(); }; module.exports = { diff --git a/backend/src/matrix-bot/room-events.js b/backend/src/topics/register-identity.js similarity index 74% rename from backend/src/matrix-bot/room-events.js rename to backend/src/topics/register-identity.js index 27f7f08..b0a4ac0 100644 --- a/backend/src/matrix-bot/room-events.js +++ b/backend/src/topics/register-identity.js @@ -4,8 +4,10 @@ const { matrixUserToAuthorAddress, authorAddressToMatrixUser, } = require('../util/db'); +const { registerEventHandler } = require('../matrix-bot'); const handleRegisterIdentity = async (client, roomId, event) => { + if (event.type !== 'io.dgov.identity.register') return; const { message, signature } = event.content; console.log('Received request to register identity'); let account; @@ -31,20 +33,10 @@ const handleRegisterIdentity = async (client, roomId, event) => { } }; -const registerRoomEventHandler = (client) => { - client.on('room.event', (roomId, event) => { - // Note that state events can also be sent down this listener too - if (event.state_key !== undefined) return; // state event - - switch (event.type) { - case 'io.dgov.identity.register': - handleRegisterIdentity(client, roomId, event); - break; - default: - } - }); +const start = () => { + registerEventHandler(handleRegisterIdentity); }; module.exports = { - registerRoomEventHandler, + start, }; diff --git a/backend/src/topics/rollup.js b/backend/src/topics/rollup.js index 6df8520..de3079e 100644 --- a/backend/src/topics/rollup.js +++ b/backend/src/topics/rollup.js @@ -1,5 +1,7 @@ const { getContractAddressByNetworkName } = require('../util/contract-config'); const { registerDecider } = require('./validation-pools'); +const { registerEventHandler } = require('../matrix-bot'); +const { matrixPools } = require('../util/db'); const { ETH_NETWORK, @@ -13,10 +15,44 @@ const start = async () => { // If this is not sent by the work1 contract, it's not of interest here. if (pool.sender !== rollupAddress) return false; - // TODO: to derive the expected content here, we need information from Matrix. + // 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; + // TODO: Compute expected result by fetching off-chain pool matrix events + // TODO: Or precompute? Since we want to be computing that anyway. return false; }); + + // We can use LevelDB to store information about validation pools + + registerEventHandler(async (client, roomId, event) => { + switch (event.type) { + case 'io.dgov.pool.start': { + // Use the event id as the validation pool id + const poolId = event.event_id; + // TODO: This event should include validation pool params + console.log('Matrix pool started', { poolId }); + await matrixPools.put(poolId, {}); + break; + } + case 'io.dgov.pool.stake': { + // TODO: Keep track of stakes + break; + } + case 'io.dgov.pool.result': { + // This should be sent by the current batch worker + // TODO: Compare batch worker's result with ours to verify and provide early warning + break; + } + case 'io.dgov.rollup.submit': { + // TODO: Compare batch worker's result with ours to verify + break; + } + default: + } + }); }; module.exports = { diff --git a/backend/src/util/db.js b/backend/src/util/db.js index 722114a..1003c39 100644 --- a/backend/src/util/db.js +++ b/backend/src/util/db.js @@ -11,4 +11,5 @@ module.exports = { referendumEventIds: new Level(`${dataDir}/referendumEventIds`, { keyEncoding: 'json' }), matrixUserToAuthorAddress: new Level(`${dataDir}/matrixUserToAuthorAddress`), authorAddressToMatrixUser: new Level(`${dataDir}/authorAddressToMatrixUser`), + matrixPools: new Level(`${dataDir}/matrixPools`, { valueEncoding: 'json' }), }; diff --git a/ethereum/contracts/core/Bench.sol b/ethereum/contracts/core/Bench.sol index b12af80..e5d3e3e 100644 --- a/ethereum/contracts/core/Bench.sol +++ b/ethereum/contracts/core/Bench.sol @@ -63,6 +63,10 @@ contract Bench { uint256 amount, bool inFavor ) external { + require( + msg.sender == address(dao), + "Only DAO contract may call stakeOnValidationPool" + ); ValidationPool storage pool = validationPools[poolIndex]; require( block.timestamp <= pool.props.endTime,