diff --git a/backend/src/models/block.js b/backend/src/models/block.js new file mode 100644 index 0000000..8e728d3 --- /dev/null +++ b/backend/src/models/block.js @@ -0,0 +1,15 @@ +import mongoose from 'mongoose'; + +const BlockSchema = new mongoose.Schema({ + blockNumber: { + type: Number, + required: true + }, + blockTime: { + type: Number, + required: true + } +}, { timestamps: false }); + +const Block = mongoose.model('BlockSchema', BlockSchema); +export default Block; \ No newline at end of file diff --git a/backend/src/models/event.js b/backend/src/models/event.js index 3584ad7..0c0233d 100644 --- a/backend/src/models/event.js +++ b/backend/src/models/event.js @@ -24,8 +24,12 @@ const EventSchema = new mongoose.Schema({ blockNumber: { type: Number, required: true + }, + blockTime: { + type: Number, + required: true } -}, { timestamps: true }); +}, { timestamps: false }); const Event = mongoose.model('Event', EventSchema); export default Event; \ No newline at end of file diff --git a/backend/src/routes/livepeer.js b/backend/src/routes/livepeer.js index 978c0d1..c181d03 100644 --- a/backend/src/routes/livepeer.js +++ b/backend/src/routes/livepeer.js @@ -1,5 +1,6 @@ import express from "express"; import Event from '../models/event'; +import Block from '../models/block'; const apiRouter = express.Router(); import { API_CMC, API_L1_HTTP, API_L2_HTTP, API_L2_WS @@ -78,6 +79,27 @@ const BondingManagerTargetAbi = JSON.parse(BondingManagerTargetJson); const BondingManagerProxyAddr = "0x35Bcf3c30594191d53231E4FF333E8A770453e40"; const contractInstance = new web3layer2WS.eth.Contract(BondingManagerTargetAbi.abi, BondingManagerProxyAddr); +let blockCache = []; +const getBlock = async function (blockNumber) { + // See if it is cached + for (const thisBlock of blockCache) { + if (thisBlock.number === blockNumber) { + return thisBlock; + } + } + // Else get it and cache it + const thisBlock = await web3layer2.eth.getBlock(blockNumber); + console.log("Caching new block " + thisBlock.number + " mined at " + thisBlock.timestamp); + const blockObj = { + blockNumber: thisBlock.number, + blockTime: thisBlock.timestamp + }; + blockCache.push(blockObj); + const dbObj = new Block(blockObj); + await dbObj.save(); + return thisBlock; +} + // If fullsync: drop collection on DB if (fullSync) { console.log("dropping old data due to full synchronization"); @@ -97,6 +119,7 @@ var BondingManagerProxyListener = contractInstance.events.allEvents(async (error } else { console.log('Received new Event on block ' + event.blockNumber); } + const thisBlock = await getBlock(event.blockNumber); // Push obj of event to cache and create a new entry for it in the DB const eventObj = { address: event.address, @@ -104,13 +127,14 @@ var BondingManagerProxyListener = contractInstance.events.allEvents(async (error transactionUrl: "https://arbiscan.io/tx/" + event.transactionHash, name: event.event, data: event.returnValues, - blockNumber: event.blockNumber + blockNumber: thisBlock.number, + blockTime: thisBlock.timestamp } - if(!isSyncing){ + if (!isSyncing) { const dbObj = new Event(eventObj); await dbObj.save(); eventsCache.push(eventObj); - }else{ + } else { syncCache.push(eventObj); } } @@ -136,13 +160,15 @@ const doSync = function () { if (event.blockNumber > lastBlockDataAdded) { lastBlockDataAdded = event.blockNumber; } + const thisBlock = await getBlock(event.blockNumber); const eventObj = { address: event.address, transactionHash: event.transactionHash, transactionUrl: "https://arbiscan.io/tx/" + event.transactionHash, name: event.event, data: event.returnValues, - blockNumber: event.blockNumber + blockNumber: thisBlock.number, + blockTime: thisBlock.timestamp } const dbObj = new Event(eventObj); await dbObj.save(); @@ -170,6 +196,7 @@ const handleSync = async function () { name: 1, data: 1, blockNumber: 1, + blockTime: 1, _id: 0 }); console.log("Retrieved existing Events of size " + eventsCache.length); @@ -186,12 +213,18 @@ const handleSync = async function () { latestMissedDuringSync = latestBlock; } console.log("Parsed up to block " + lastBlockDataAdded + " out of " + latestMissedDuringSync + " blocks"); + // Get all parsed blocks + blockCache = await Block.find({}, { + blockNumber: 1, + blockTime: 1 + }); + console.log("Retrieved existing Blocks of size " + blockCache.length); doSync(); while (isSyncRunning) { await sleep(1000); console.log("Parsed " + lastBlockDataAdded + " out of " + latestMissedDuringSync + " blocks"); } - while(syncCache.length){ + while (syncCache.length) { const liveEvents = syncCache; syncCache = []; for (const eventObj of liveEvents) { diff --git a/src/BlockViewer.js b/src/BlockViewer.js index 2e9df55..585ca35 100644 --- a/src/BlockViewer.js +++ b/src/BlockViewer.js @@ -1,13 +1,23 @@ import React from "react"; const Block = (obj) => { + const thisEpoch = obj.time; + var dateObj = new Date(0); + dateObj.setUTCSeconds(thisEpoch); + const [thisDate, thisTime] = dateObj.toISOString().split('T'); return (
📅{thisDate} - {thisTime.split('.')[0]}