From 5aadf9727878fe36e4eca7476bcd3a48ae950624 Mon Sep 17 00:00:00 2001 From: Marco van Dijk Date: Sat, 5 Mar 2022 17:38:58 +0100 Subject: [PATCH] Now with block timestamps --- backend/src/models/block.js | 15 ++++++++++++ backend/src/models/event.js | 6 ++++- backend/src/routes/livepeer.js | 43 ++++++++++++++++++++++++++++++---- src/BlockViewer.js | 12 +++++++++- src/actions/livepeer.js | 21 ++++++++++++----- src/eventButton.js | 2 +- src/eventViewer.js | 1 + 7 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 backend/src/models/block.js 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 (
- Block {obj.block} + + 🔗{obj.block} + +

📅{thisDate} - {thisTime.split('.')[0]}

) } + + + export default Block; \ No newline at end of file diff --git a/src/actions/livepeer.js b/src/actions/livepeer.js index 6df6e6f..2367f01 100644 --- a/src/actions/livepeer.js +++ b/src/actions/livepeer.js @@ -63,6 +63,7 @@ export const getEvents = () => async dispatch => { let currentTx = ""; let currentUrl = ""; let currentBlock = 0; + let currentTime = 0; // Current Event we are processing let eventType = ""; // Named type: Withdraw, Update, Claim, Reward, Activate, Unbond, Stake let eventDescription = ""; // Descriptive text, also containing Amount, AmountOther and When @@ -89,6 +90,7 @@ export const getEvents = () => async dispatch => { currentTx = eventObj.transactionHash; currentUrl = eventObj.transactionUrl; currentBlock = eventObj.blockNumber; + currentTime = eventObj.blockTime; } // New transaction found if (currentTx !== eventObj.transactionHash) { @@ -150,7 +152,8 @@ export const getEvents = () => async dispatch => { eventColour, transactionHash: currentTx, transactionUrl: currentUrl, - transactionBlock: currentBlock + transactionBlock: currentBlock, + transactionTime: currentTime }); } @@ -176,6 +179,7 @@ export const getEvents = () => async dispatch => { currentTx = eventObj.transactionHash; currentUrl = eventObj.transactionUrl; currentBlock = eventObj.blockNumber; + currentTime = eventObj.blockTime; } // Always split off WithdrawStake as a separate Withdraw Event if (eventObj.name === "WithdrawStake") { @@ -193,7 +197,8 @@ export const getEvents = () => async dispatch => { eventColour: withdrawStakeColour, transactionHash: currentTx, transactionUrl: currentUrl, - transactionBlock: currentBlock + transactionBlock: currentBlock, + transactionTime: currentTime }); } else if (eventObj.name === "WithdrawFees") { const amount = parseFloat(eventObj.data.amount) / 1000000000000000000; @@ -210,7 +215,8 @@ export const getEvents = () => async dispatch => { eventColour: withdrawStakeColour, transactionHash: currentTx, transactionUrl: currentUrl, - transactionBlock: currentBlock + transactionBlock: currentBlock, + transactionTime: currentTime }); } // Always split off TranscoderUpdate as a separate Update Event @@ -228,7 +234,8 @@ export const getEvents = () => async dispatch => { eventColour: updateColour, transactionHash: currentTx, transactionUrl: currentUrl, - transactionBlock: currentBlock + transactionBlock: currentBlock, + transactionTime: currentTime }); } // Always split off EarningsClaimed as a separate Claim Event @@ -259,7 +266,8 @@ export const getEvents = () => async dispatch => { eventColour: claimColour, transactionHash: currentTx, transactionUrl: currentUrl, - transactionBlock: currentBlock + transactionBlock: currentBlock, + transactionTime: currentTime }); } // Always split off Reward as a separate Reward Event @@ -279,7 +287,8 @@ export const getEvents = () => async dispatch => { eventColour: rewardColour, transactionHash: currentTx, transactionUrl: currentUrl, - transactionBlock: currentBlock + transactionBlock: currentBlock, + transactionTime: currentTime }); } // Extract useful info from other types of Event diff --git a/src/eventButton.js b/src/eventButton.js index 967ea9d..8fb014a 100644 --- a/src/eventButton.js +++ b/src/eventButton.js @@ -44,7 +44,7 @@ const EventButton = (obj) => { let blockNumber; if (obj.isFirstOfBlock) { - blockNumber = + blockNumber = } diff --git a/src/eventViewer.js b/src/eventViewer.js index bff103a..319fbe1 100644 --- a/src/eventViewer.js +++ b/src/eventViewer.js @@ -141,6 +141,7 @@ const EventViewer = (obj) => { key={eventObj.transactionHash + idx} eventObj={eventObj} isFirstOfBlock={prevBlock} + time={eventObj.transactionTime} /> } }