Display rounds in the event viewer

This commit is contained in:
Marco van Dijk 2022-05-08 16:02:22 +02:00
parent fe2e75bb41
commit 2fb915fee4
12 changed files with 950 additions and 104 deletions

File diff suppressed because one or more lines are too long

View File

@ -5,51 +5,63 @@ const RoundSchema = new mongoose.Schema({
type: Number,
required: true
},
lengthBlocks: {
transactionHash: {
type: String,
required: true
},
blockNumber: {
type: Number,
required: true
},
blockTime: {
type: Number,
required: true
},
lengthBlocks: {
type: Number,
required: false
},
startBlock: {
type: Number,
required: true
required: false
},
endBlock: {
type: Number,
required: true
required: false
},
mintableTokens: {
type: Number,
required: true
required: false
},
volumeEth: {
type: Number,
required: true
required: false
},
volumeUsd: {
type: Number,
required: true
required: false
},
totalActiveStake: {
type: Number,
required: true
required: false
},
totalSupply: {
type: Number,
required: true
required: false
},
participationRate: {
type: Number,
required: true
required: false
},
movedStake: {
type: Number,
required: true
required: false
},
newStake: {
type: Number,
required: true
required: false
}
}, { timestamps: false });
const Round = mongoose.model('RoundSchema', RoundSchema);
const Round = mongoose.model('Round', RoundSchema);
export default Round;

View File

@ -79,6 +79,10 @@ let TicketBrokerTargetJson;
let TicketBrokerTargetAbi;
let TicketBrokerTargetAddr;
let ticketBrokerContract;
let RoundsManagerTargetJson;
let RoundsManagerTargetAbi;
let RoundsManagerTargetAddr;
let roundsManagerContract;
if (!CONF_SIMPLE_MODE) {
console.log("Loading contracts for smart contract events");
// Listen for events on the bonding manager contract
@ -91,6 +95,11 @@ if (!CONF_SIMPLE_MODE) {
TicketBrokerTargetAbi = JSON.parse(TicketBrokerTargetJson);
TicketBrokerTargetAddr = "0xa8bB618B1520E284046F3dFc448851A1Ff26e41B";
ticketBrokerContract = new web3layer2.eth.Contract(TicketBrokerTargetAbi.abi, TicketBrokerTargetAddr);
// Listen for events on the rounds manager contract
RoundsManagerTargetJson = fs.readFileSync('src/abi/RoundsManagerTarget.json');
RoundsManagerTargetAbi = JSON.parse(RoundsManagerTargetJson);
RoundsManagerTargetAddr = "0xdd6f56DcC28D3F5f27084381fE8Df634985cc39f";
roundsManagerContract = new web3layer2.eth.Contract(RoundsManagerTargetAbi.abi, RoundsManagerTargetAddr);
}
/*
@ -155,11 +164,14 @@ let startedInitSync = false;
let isSyncing = false;
let isEventSyncing = false;
let isTicketSyncing = false;
let isRoundSyncing = false;
let eventsCache = [];
let latestBlockInChain = 0;
let latestL1Block = 0;
let lastBlockEvents = 0;
let lastBlockTickets = 0;
let lastBlockRounds = 0;
let ticketsCache = [];
let alreadyHasAnyRefresh = {};
@ -1439,10 +1451,10 @@ Mutates the Event in the database to contain the round number
let roundCache = [];
const getRoundInfo = async function (blockNumber) {
const getRoundInfo = async function (roundNumber) {
// Get round info from gql
const roundQuery = gql`{
rounds(where: {startBlock_lte: "${blockNumber}"}) {
rounds(where: {id: "${roundNumber}"}) {
id
length
startBlock
@ -1460,56 +1472,97 @@ const getRoundInfo = async function (blockNumber) {
`;
const roundObj = await request("https://api.thegraph.com/subgraphs/name/livepeer/arbitrum-one", roundQuery);
// Not found
if (!roundObj) {
console.log("No round found at block " + blockNumber);
if (!roundObj || !roundObj.rounds || !roundObj.rounds.length) {
console.log("No round found with number " + roundNumber);
return {};
}
console.log("This functions is not implemented yet. Logging element to console...")
console.log(roundObj);
// TODO filter out down to 1 round
return roundObj;
const thisRoundObj = roundObj.rounds[0];
// Update cache
roundCache.push(roundObj);
// Only save if the endBlock is elapsed
if (latestBlockInChain > roundObj.endBlock) {
const data = {
number: roundObj.number,
var wasCached = false;
for (var idx = 0; idx < roundCache.length; idx++) {
if (roundCache[idx].number == roundNumber){
wasCached = true;
roundCache[idx].lengthBlocks = thisRoundObj.lengthBlocks;
roundCache[idx].startBlock = thisRoundObj.startBlock;
roundCache[idx].endBlock = thisRoundObj.endBlock;
roundCache[idx].mintableTokens = thisRoundObj.mintableTokens;
roundCache[idx].volumeEth = thisRoundObj.volumeETH;
roundCache[idx].volumeUsd = thisRoundObj.volumeUSD;
roundCache[idx].totalActiveStake = thisRoundObj.totalActiveStake;
roundCache[idx].totalSupply = thisRoundObj.totalSupply;
roundCache[idx].participationRate = thisRoundObj.participationRate;
roundCache[idx].movedStake = thisRoundObj.movedStake;
roundCache[idx].newStake = thisRoundObj.newStake;
}
}
// FindAndUpdate
if (!CONF_DISABLE_DB) {
// Update DB entry
const doc = await MonthlyStat.findOneAndUpdate({
number: roundNumber
}, {
lengthBlocks: roundObj.lengthBlocks,
startBlock: roundObj.startBlock,
endBlock: roundObj.endBlock,
mintableTokens: roundObj.mintableTokens,
volumeEth: roundObj.volumeEth,
volumeUsd: roundObj.volumeUsd,
volumeEth: roundObj.volumeETH,
volumeUsd: roundObj.volumeUSD,
totalActiveStake: roundObj.totalActiveStake,
totalSupply: roundObj.totalSupply,
participationRate: roundObj.participationRate,
movedStake: roundObj.movedStake,
newStake: roundObj.newStake
}
if (!CONF_DISABLE_DB) {
// TODO only create if nonexistent (find and update with upsert or something)
const dbObj = new Round(data);
await dbObj.save();
}, {
new: true
});
if (!wasCached){
roundCache.push({
number: doc.number,
transactionHash: doc.transactionHash,
blockNumber: doc.blockNumber,
lengthBlocks: doc.lengthBlocks,
startBlock: doc.startBlock,
endBlock: doc.endBlock,
mintableTokens: doc.mintableTokens,
volumeETH: doc.volumeETH,
volumeUSD: doc.volumeUSD,
totalActiveStake: doc.totalActiveStake,
totalSupply: doc.totalSupply,
participationRate: doc.participationRate,
movedStake: doc.movedStake,
newStake: doc.newStake
});
}
}
}
apiRouter.post("/getRoundAtBlock", async (req, res) => {
apiRouter.post("/getRoundInfo", async (req, res) => {
try {
const { blockNumber } = req.body;
if (blockNumber) {
console.log("Getting round info for block " + blockNumber);
const now = new Date().getTime();
const { roundNumber } = req.body;
if (roundNumber) {
console.log("Getting round info for round " + roundNumber);
// See if it is cached
for (const thisRound of roundCache) {
if (thisRound.startBlock <= blockNumber && thisRound.endBlock >= blockNumber) {
res.send(thisRound);
return;
if (thisRound.round == roundNumber) {
// Check if it contains one of the detailed fields
if (thisRound.endBlock) {
// Check timeout if the round has not elapsed
if (thisRound.endBlock >= latestL1Block
&& (now - thisRound.blockTime) > 1800000) {
console.log('Round should update round details');
break;
}
res.send(thisRound);
return;
} else {
console.log('Round should init round details');
break;
}
}
}
// Get block info from thegraph
console.log("Getting round info for block " + blockNumber);
const thisRoundInfo = await getRoundInfo(blockNumber);
const thisRoundInfo = await getRoundInfo(roundNumber);
res.send(thisRoundInfo);
return;
}
@ -1539,7 +1592,7 @@ let hasError = false;
// Syncs events database
const syncEvents = function (toBlock) {
console.log("Starting sync process for Bonding Manager events to block " + toBlock);
console.log("Starting sync process for Bonding Manager events for blocks " + lastBlockEvents + "->" + toBlock);
isEventSyncing = true;
let lastTxSynced = 0;
// Then do a sync from last found until latest known
@ -1601,7 +1654,7 @@ const syncEvents = function (toBlock) {
}
// Syncs tickets database
const syncTickets = function (toBlock) {
console.log("Starting sync process for Ticket Broker events to block " + toBlock);
console.log("Starting sync process for Ticket Broker events for blocks " + lastBlockTickets + "->" + toBlock);
isTicketSyncing = true;
// Then do a sync from last found until latest known
ticketBrokerContract.getPastEvents("allEvents", { fromBlock: lastBlockTickets + 1, toBlock: toBlock }, async (error, events) => {
@ -1650,6 +1703,58 @@ const syncTickets = function (toBlock) {
isTicketSyncing = false;
});
}
// Syncs rounds database
const syncRounds = function (toBlock) {
console.log("Starting sync process for Rounds Manager events for blocks " + lastBlockRounds + "->" + toBlock);
isRoundSyncing = true;
// Then do a sync from last found until latest known
roundsManagerContract.getPastEvents("allEvents", { fromBlock: lastBlockRounds + 1, toBlock: toBlock }, async (error, events) => {
try {
if (error) {
throw error
}
let size = events.length;
console.log("Parsing " + size + " rounds");
if (!size) {
if (toBlock == 'latest') {
lastBlockRounds = latestBlockInChain;
} else {
lastBlockRounds = toBlock;
}
}
for (const event of events) {
if (event.blockNumber > lastBlockRounds) {
lastBlockRounds = event.blockNumber;
}
// Only parse initRound events
if (event.event != 'NewRound') {
console.log('Skipping Round Event of type ' + event.event);
continue;
}
const thisBlock = await getBlock(event.blockNumber);
const eventObj = {
number: event.returnValues.round,
transactionHash: event.transactionHash,
blockNumber: thisBlock.number,
blockTime: thisBlock.timestamp
}
// Cache & store
if (!CONF_DISABLE_DB) {
const dbObj = new Round(eventObj);
await dbObj.save();
}
roundCache.push(eventObj);
}
}
catch (err) {
console.log("FATAL ERROR: ", err);
hasError = true;
isRoundSyncing = false;
return;
}
isRoundSyncing = false;
});
}
// Retrieves stuff from DB on first boot
const initSync = async function () {
@ -1863,6 +1968,9 @@ const initSync = async function () {
// Get all round info
roundCache = await Round.find({}, {
number: 1,
transactionHash: 1,
blockNumber: 1,
blockTime: 1,
lengthBlocks: 1,
startBlock: 1,
endBlock: 1,
@ -1876,6 +1984,15 @@ const initSync = async function () {
newStake: 1,
_id: 0
})
console.log("Retrieved existing rounds of size " + roundCache.length);
// Then determine latest block number parsed based on collection
for (var idx = 0; idx < roundCache.length; idx++) {
const thisRound = roundCache[idx];
if (thisRound.blockNumber > lastBlockRounds) {
lastBlockRounds = thisRound.blockNumber;
}
}
console.log("Latest Round block parsed is " + lastBlockRounds);
}
let cycle = 0;
@ -1889,8 +2006,13 @@ const handleSync = async function () {
cycle++;
console.log('Starting new sync cycle #' + cycle);
isSyncing = true;
// Get latest block in chain
const latestBlock = await web3layer2.eth.getBlockNumber();
// Get latest blocks in chain
var latestBlock = await web3layer1.eth.getBlockNumber();
if (latestBlock > latestL1Block) {
latestL1Block = latestBlock;
console.log("Latest L1 Eth block changed to " + latestL1Block);
}
latestBlock = await web3layer2.eth.getBlockNumber();
if (latestBlock > latestBlockInChain) {
latestBlockInChain = latestBlock;
console.log("Latest L2 Eth block changed to " + latestBlockInChain);
@ -1904,6 +2026,7 @@ const handleSync = async function () {
}
console.log("Needs to sync " + (latestBlockInChain - lastBlockEvents) + " blocks for Events sync");
console.log("Needs to sync " + (latestBlockInChain - lastBlockTickets) + " blocks for Tickets sync");
console.log("Needs to sync " + (latestBlockInChain - lastBlockRounds) + " blocks for Rounds sync");
// Batch requests when sync is large, mark if we are going to reach latestBlockInChain in this round
let getFinalTickets = false;
let toTickets = 'latest';
@ -1919,11 +2042,20 @@ const handleSync = async function () {
} else {
getFinalEvents = true;
}
let getFinalRounds = false;
let toRounds = 'latest';
if (latestBlock - lastBlockRounds > 1000000) {
toRounds = lastBlockRounds + 1000000;
} else {
getFinalRounds = true;
}
// Start initial sync for this sync round
syncTickets(toTickets);
syncEvents(toEvents);
syncRounds(toRounds);
// Then loop until we have reached the last known block
while (isEventSyncing || isTicketSyncing || !getFinalTickets || !getFinalEvents) {
while (isEventSyncing || isTicketSyncing || isRoundSyncing
|| !getFinalTickets || !getFinalEvents || !getFinalRounds) {
await sleep(500);
if (hasError) {
throw ("Error while syncing");
@ -1952,6 +2084,18 @@ const handleSync = async function () {
}
syncTickets(toTickets);
}
if (isRoundSyncing) {
console.log("Parsed " + lastBlockRounds + " out of " + latestBlockInChain + " blocks for Round sync");
} else if (!getFinalRounds) {
// Start next batch for tickets
toRounds = 'latest';
if (latestBlock - lastBlockRounds > 1000000) {
toRounds = lastBlockRounds + 1000000;
} else {
getFinalRounds = true;
}
syncRounds(toRounds);
}
}
isSyncing = false;
setTimeout(() => {
@ -1965,6 +2109,7 @@ const handleSync = async function () {
console.log("latestBlockInChain " + latestBlockInChain);
console.log("lastBlockEvents " + lastBlockEvents);
console.log("lastBlockTickets " + lastBlockTickets);
console.log("lastBlockRounds " + lastBlockRounds);
isSyncing = false;
setTimeout(() => {
handleSync();
@ -2305,7 +2450,7 @@ const mutateDynamicStatsFromDB = async function (orchestratorObj) {
latestCommission: 1,
latestTotalStake: 1
});
if (!doc){
if (!doc) {
return;
}
let oldFeeCommission = -1;

25
dumps/rounds.json Normal file
View File

@ -0,0 +1,25 @@
{
address: '0xdd6f56DcC28D3F5f27084381fE8Df634985cc39f',
blockHash: '0x733753ab3a1ecf3edbbebc075f85827b259295b3a7443d45c633b1b6c3672eef',
blockNumber: 8761883,
logIndex: 1,
removed: false,
transactionHash: '0xd8609ae0a52e0bb8a1eda28634e5a804607eb76a156e9e30682dd1ff748a107a',
transactionIndex: 0,
id: 'log_cbc32efd',
returnValues: Result {
'0': '2513',
'1': '0x2f180b9a2c759abc9c77372f2a339b16191fe782304318e818b0b3ed0706a216',
round: '2513',
blockHash: '0x2f180b9a2c759abc9c77372f2a339b16191fe782304318e818b0b3ed0706a216'
},
event: 'NewRound',
signature: '0x22f2fc17c5daf07db2379b3a03a8ef20a183f761097a58fce219c8a14619e786',
raw: {
data: '0x2f180b9a2c759abc9c77372f2a339b16191fe782304318e818b0b3ed0706a216',
topics: [
'0x22f2fc17c5daf07db2379b3a03a8ef20a183f761097a58fce219c8a14619e786',
'0x00000000000000000000000000000000000000000000000000000000000009d1'
]
}
}

View File

@ -29,7 +29,7 @@ export const SET_ALL_ACTIVATE_EVENTS = "SET_ALL_ACTIVATE_EVENTS";
export const SET_ALL_UNBOND_EVENTS = "SET_ALL_UNBOND_EVENTS";
export const SET_ALL_STAKE_EVENTS = "SET_ALL_STAKE_EVENTS";
export const SET_ALL_ROUNDS = "SET_ALL_ROUNDS";
export const SET_ADD_ROUNDS = "SET_ADD_ROUNDS";
export const SET_ROUND = "SET_ROUND";
const setQuotes = message => ({
type: RECEIVE_QUOTES, message
@ -131,8 +131,8 @@ const setAllRounds = message => ({
type: SET_ALL_ROUNDS, message
});
const setAddRound = message => ({
type: SET_ADD_ROUNDS, message
const populateRound = message => ({
type: SET_ROUND, message
});
export const getQuotes = () => async dispatch => {
@ -434,10 +434,10 @@ export const getAllRounds = () => async dispatch => {
return dispatch(receiveErrors(data));
};
export const getRoundAtBlock = (addr) => async dispatch => {
const response = await apiUtil.getRoundAtBlock(addr);
export const getRoundInfo = (round) => async dispatch => {
const response = await apiUtil.getRoundInfo(round);
const data = await response.json();
if (response.ok) {
return dispatch(setAddRound(data));
return dispatch(populateRound(data));
}
};

View File

@ -1,49 +1,12 @@
import React, { useEffect, useState } from "react";
import {
getRoundAtBlock
} from "../actions/livepeer";
import { useDispatch, useSelector } from 'react-redux';
import React from "react";
const Block = (obj) => {
const dispatch = useDispatch();
const livepeer = useSelector((state) => state.livepeerstate);
const [roundInfo, setRoundInfo] = useState(null);
const [hasRefreshed, setRefresh] = useState(false);
// useEffect(() => {
// let thisInfo = null;
// for (const round of livepeer.rounds) {
// if (round.startBlock <= obj.block && round.endBlock >= obj.block) {
// thisInfo = round;
// break;
// }
// }
// // If it was not cached at all
// if (thisInfo == null && !hasRefreshed) {
// console.log("Refresh due to non-existing round containing this block");
// setRefresh(true);
// dispatch(getRoundAtBlock(obj.block));
// }
// if (thisInfo && thisInfo != roundInfo) {
// console.log("Setting block info obj");
// setRoundInfo(thisInfo);
// }
// }, [livepeer.rounds]);
const thisEpoch = obj.time;
var dateObj = new Date(0);
dateObj.setUTCSeconds(thisEpoch);
const thisLocalDate = dateObj.toLocaleString();
const thisOffset = (-dateObj.getTimezoneOffset() / 60);
// Get round info
let thisRoundInfo;
if (roundInfo) {
thisRoundInfo = <p style={{ overflowWrap: 'break-word' }}>
Round {thisRoundInfo.number}
</p>
}
return (
<div className="rowAlignLeft" style={{ margin: 0, marginTop: '1em', width: '100%' }}>
<a className="selectOrch" style={{ cursor: 'alias', margin: 0 }} target="_blank" rel="noopener noreferrer" href={obj.url}>
@ -52,7 +15,6 @@ const Block = (obj) => {
<a className="selectOrch" style={{ cursor: 'alias', margin: 0 }} target="_blank" rel="noopener noreferrer" href={"https://arbiscan.io/block/" + obj.block}>
<h3 style={{ padding: '0.2em', cursor: 'alias' }}>🔗</h3>
</a>
{thisRoundInfo}
<span className="rowAlignRight darkText mobileSmallerFont" style={{ margin: 0 }}>
<p style={{ overflowWrap: 'break-word' }}>
📅&nbsp;{thisLocalDate}

View File

@ -0,0 +1,110 @@
import React, { useEffect, useState } from "react";
import {
getRoundInfo
} from "../actions/livepeer";
import { useDispatch, useSelector } from 'react-redux';
import { Popover } from '@mantine/core';
import { getOrchestratorByDelegator } from "../util/livepeer";
const Round = (obj) => {
const [opened, setOpened] = useState(false);
const dispatch = useDispatch();
const [hasRefreshed, setRefresh] = useState(false);
useEffect(() => {
// If it was not cached at all
if (obj.round && obj.round.number && !obj.round.endBlock && !hasRefreshed) {
console.log("Pulling round info for round " + obj.round.number);
setRefresh(true);
dispatch(getRoundInfo(obj.round.number));
}
}, []);
const thisEpoch = obj.time;
var dateObj = new Date(0);
dateObj.setUTCSeconds(thisEpoch);
const thisLocalDate = dateObj.toLocaleString();
const thisOffset = (-dateObj.getTimezoneOffset() / 60);
return (
<div className="row" style={{ paddingLeft: '1em', paddingRight: '1em' }}>
<div className="rowAlignLeft" style={{ margin: 0, marginTop: '1em', width: '100%' }}>
<a className="selectOrch" style={{ cursor: 'alias', margin: 0 }} target="_blank" rel="noopener noreferrer" href={"https://arbiscan.io/block/" + obj.round.blockNumber}>
<h3 style={{ padding: '0.2em', cursor: 'alias' }}>🔗</h3>
</a>
<Popover className="strokeSmollLeft" style={{ cursor: 'pointer', marginTop: '0.2em', marginBottom: '0.2em' }}
opened={opened}
onClose={() => setOpened(false)}
target={
<p className="darkText" style={{ overflowWrap: 'break-word' }} onClick={() => setOpened((o) => !o)}>
Round {obj.round.number}
</p>
}
width={260}
position="right"
withArrow
>
<div className="strokeSmollLeft">
<div className="row">
<p className="darkText" style={{ overflowWrap: 'break-word' }}>
Round {obj.round.number}
</p>
</div>
{
obj.round.mintableTokens ?
<div className="row">
<p className="darkText" style={{ overflowWrap: 'break-word' }}>
Has {obj.round.mintableTokens.toFixed(2)} mintable tokens
</p>
</div> : null
}
{
obj.round.volumeEth && obj.round.volumeUsd ?
<div className="row">
<p className="darkText" style={{ overflowWrap: 'break-word' }}>
A volume of {obj.round.volumeEth.toFixed(2)} Eth ({obj.round.volumeUsd.toFixed(2)}$)
</p>
</div> : null
}
{
obj.round.totalSupply && obj.round.totalActiveStake ?
<div className="row">
<p className="darkText" style={{ overflowWrap: 'break-word' }}>
A total supply of {obj.round.totalSupply.toFixed(2)} LPT, of which {obj.round.totalActiveStake.toFixed(2)} is staked ({(obj.round.participationRate * 100).toFixed(2)}%)
</p>
</div> : null
}
{
obj.round.newStake ?
<div className="row">
<p className="darkText" style={{ overflowWrap: 'break-word' }}>
{obj.round.newStake.toFixed(2)} LPT new stake
</p>
</div> : null
}
{
obj.round.movedStake ?
<div className="row">
<p className="darkText" style={{ overflowWrap: 'break-word' }}>
{obj.round.movedStake.toFixed(2)} LPT stake moved around
</p>
</div> : null
}
</div>
</Popover>
<span className="rowAlignRight darkText mobileSmallerFont" style={{ margin: 0 }}>
<p style={{ overflowWrap: 'break-word' }}>
📅&nbsp;{thisLocalDate}
</p>
{thisOffset != 0 ? <p className='darkTextSmoll' style={{ overflowWrap: 'break-word' }}>
({thisOffset > 0 ? "+" : ""}{thisOffset})
</p> : null
}
</span>
</div>
</div>
)
}
export default Round;

View File

@ -4,6 +4,7 @@ import ScrollContainer from 'react-indiana-drag-scroll';
import { Pagination, Title } from "@mantine/core";
import Filter from './filterComponent';
import { Dialog, Stack, Button, Group } from '@mantine/core';
import Round from "./RoundViewer";
const thresholdStaking = 0.001;
const thresholdFees = 0.00009;
@ -71,6 +72,7 @@ const EventViewer = (obj) => {
let unbondEventsIdx = obj.unbondEvents.length - 1;
let transferTicketEventsIdx = obj.transferTicketEvents.length - 1;
let redeemTicketEventsIdx = obj.redeemTicketEvents.length - 1;
let roundsIdx = obj.rounds.length - 1;
if (!filterActivated) {
filtered += activateEventsIdx + 1;
@ -119,7 +121,8 @@ const EventViewer = (obj) => {
redeemTicketEventsIdx >= 0 ||
activateEventsIdx >= 0 ||
unbondEventsIdx >= 0 ||
stakeEventsIdx >= 0) {
stakeEventsIdx >= 0 ||
roundsIdx >= 0) {
let latestTime = 0;
let thisEvent;
@ -214,6 +217,14 @@ const EventViewer = (obj) => {
latestType = "redeemTicket"
}
}
if (roundsIdx >= 0) {
const thisObj = obj.rounds[roundsIdx];
if (thisObj.blockTime > latestTime) {
latestTime = thisObj.blockTime;
thisEvent = thisObj;
latestType = "round"
}
}
// Decrement IDX and check filter
if (latestType == "update") {
@ -412,6 +423,15 @@ const EventViewer = (obj) => {
continue;
}
}
} else if (latestType == "round") {
roundsIdx--;
eventList.push(<Round
key={thisEvent.transactionHash + unfiltered + roundsIdx}
seed={thisEvent.transactionHash + unfiltered + roundsIdx}
round={thisEvent}
time={thisEvent.blockTime}
/>);
continue;
} else {
console.log("bork");
}

View File

@ -118,6 +118,7 @@ const Livepeer = (obj) => {
unbondEvents={livepeer.unbondEvents}
stakeEvents={livepeer.stakeEvents}
monthlyStats={livepeer.monthlyStats}
rounds={livepeer.rounds}
/>
</div>
</div>

View File

@ -10,7 +10,7 @@ import {
getAllClaimEvents, getAllWithdrawStakeEvents, getAllWithdrawFeesEvents,
getAllTransferTicketEvents, getAllRedeemTicketEvents, getAllActivateEvents,
getAllUnbondEvents, getAllStakeEvents, getAllCommissions, getAllTotalStakes,
hasAnyRefresh
hasAnyRefresh, getAllRounds
} from "../actions/livepeer";
import { login } from "../actions/session";
@ -91,6 +91,8 @@ const Startup = (obj) => {
dispatch(getAllActivateEvents(false));
dispatch(getAllUnbondEvents(false));
dispatch(getAllStakeEvents(false));
// TODO make it part of the hasAnyUpdate check
dispatch(getAllRounds());
});
}

View File

@ -27,7 +27,7 @@ import {
SET_ALL_UNBOND_EVENTS,
SET_ALL_STAKE_EVENTS,
SET_ALL_ROUNDS,
SET_ADD_ROUNDS
SET_ROUND
} from "../../actions/livepeer";
export default (state = {
@ -137,11 +137,23 @@ export default (state = {
return { ...state, stakeEvents: message };
case SET_ALL_ROUNDS:
return { ...state, rounds: message };
case SET_ADD_ROUNDS:
return {
...state,
rounds: [...state.rounds, message]
};
case SET_ROUND:
// Check to see if it is already cached
if (state.rounds) {
return {
...state,
contents: state.rounds.map(
(content) => {
if (content.number == message.number) {
return message;
} else {
return content;
}
}
)
}
}
return { ...state };
default:
return { ...state };
}

View File

@ -273,10 +273,10 @@ export const getAllRounds = () => (
})
);
export const getRoundAtBlock = (blockNumber) => (
fetch("api/livepeer/getRoundAtBlock", {
export const getRoundInfo = (roundNumber) => (
fetch("api/livepeer/getRoundInfo", {
method: "POST",
body: JSON.stringify({ blockNumber }),
body: JSON.stringify({ roundNumber }),
headers: {
'Content-Type': 'application/json'
}