Skip to content

Commit 73894c6

Browse files
committed
Add arbitrum monitoring (first pass)
1 parent da00765 commit 73894c6

File tree

1 file changed

+137
-3
lines changed

1 file changed

+137
-3
lines changed

scripts/status.js

+137-3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,23 @@ async function getRPCLatestBlock(url) {
5353
}
5454
}
5555

56+
async function getBlockIngestorLatestBlock(url) {
57+
const res = await fetch(url, {
58+
method: 'POST',
59+
headers: {
60+
'Content-Type': 'application/json',
61+
},
62+
body: JSON.stringify({
63+
"query": "query test {\n getIngestorStats(id: \"STATS\") {\n value\n }\n}\n",
64+
"variables": {},
65+
"operationName": "test"
66+
})
67+
});
68+
const output = await res.json()
69+
const stats = JSON.parse(output.data.getIngestorStats.value);
70+
return parseInt(stats.lastBlockNumber,10);
71+
}
72+
5673
async function getBlockscoutLatestBlock() {
5774
try {
5875
const blockScoutBlock = await fetch("https://blockscout.com/xdai/mainnet/api?module=block&action=eth_block_number")
@@ -64,6 +81,17 @@ async function getBlockscoutLatestBlock() {
6481
}
6582
}
6683

84+
async function getArbiscanLatestBlock() {
85+
try {
86+
const arbiscanBlock = await fetch(`https://api.arbiscan.io/api?module=proxy&action=eth_blockNumber&apikey=${process.env.ARBISCAN_API_KEY}`)
87+
const output = await arbiscanBlock.json()
88+
let arbiscanLatestBlock = parseInt(output.result,16)
89+
return arbiscanLatestBlock;
90+
} catch (err) {
91+
return NaN;
92+
}
93+
}
94+
6795
async function getBalance(account, url) {
6896
try {
6997
const balanceRes = await fetch(url, {
@@ -74,7 +102,7 @@ async function getBalance(account, url) {
74102
body: JSON.stringify({
75103
"jsonrpc":"2.0",
76104
"method":"eth_getBalance",
77-
"params":[account],
105+
"params":[account, "latest"],
78106
"id":1
79107
})
80108
})
@@ -112,8 +140,8 @@ module.exports = robot => {
112140
return "🔴";
113141
}
114142

115-
async function getMessage() {
116-
let message = ""
143+
async function getMessageGnosis() {
144+
let message = "**On Gnosis:**\n"
117145
// Get latest block from graph
118146
const graphNumberRes = getGraphLatestBlock("https://xdai.colony.io/graph/subgraphs/name/joinColony/subgraph")
119147

@@ -250,6 +278,87 @@ module.exports = robot => {
250278
return message
251279
}
252280

281+
async function getArbitrumMessage() {
282+
283+
const ARBITRUM_MINER_ADDRESS = "0xd090822a84e037Acc8a169C54a5943FF9fB82236"
284+
const ARBITRUM_BROADCASTER_ADDRESS = "0xf4ab92A14c7CBc232E8293C59DfFbd98Fbdf9b3E"
285+
const ARBITRUM_NETWORK_ADDRESS = "0xcccccdcc0ccf6c708d860e19353c5f9a49accccc"
286+
const ARBITRUM_GRAPH_URL = "https://app.colony.io/auth-proxy/graphql"
287+
const ourRPC = process.env.ARBITRUM_RPC
288+
const publicRPC = process.env.ARBITRUM_PUBLIC_RPC
289+
290+
291+
// Get latest block from our RPC
292+
const ourRpcPromise = getRPCLatestBlock(ourRPC);
293+
294+
// Get latest block from another RPC
295+
const publicRPCPromise = getRPCLatestBlock(publicRPC);
296+
297+
// Get latest block from block ingestor
298+
const blockIngestorNumberPromise = getBlockIngestorLatestBlock(ARBITRUM_GRAPH_URL);
299+
300+
// Get balance of miner
301+
const balancePromise = await getBalance(ARBITRUM_MINER_ADDRESS, ourRPC)
302+
303+
// Get balance of MTX Broadcaster
304+
const mtxBalancePromise = await getBalance(ARBITRUM_BROADCASTER_ADDRESS, ourRPC)
305+
306+
const arbiscanLatestBlockPromise = getArbiscanLatestBlock()
307+
308+
let [ourRpcBlock, publicRpcBlock, ingestorNumber, minerBalance, mtxBalance, arbiscanLatestBlock] = await Promise.all([ourRpcPromise, publicRPCPromise, blockIngestorNumberPromise, balancePromise, mtxBalancePromise, arbiscanLatestBlockPromise])
309+
310+
if (isNaN(arbiscanLatestBlock) && ourRpcBlock > 0) { arbiscanLatestBlock = ourRpcBlock }
311+
if (isNaN(publicRpcBlock) && ourRpcBlock > 0) { publicRpcBlock = ourRpcBlock }
312+
313+
const smallestRpcDiscrepancy = Math.min(
314+
Math.abs(ourRpcBlock-arbiscanLatestBlock),
315+
Math.abs(ourRpcBlock-publicRpcBlock)
316+
)
317+
318+
// Get time since last mining cycle completed
319+
// Get reputation mining cycle status
320+
let secondsSinceOpen = -1;
321+
let nSubmitted = -1;
322+
try {
323+
let provider;
324+
// Use our RPC if okay
325+
if (ourRpcBlock > 0){
326+
provider = new ethers.providers.JsonRpcProvider(ourRPC)
327+
} else {
328+
provider = new ethers.providers.JsonRpcProvider(publicRPC);
329+
}
330+
331+
const cn = new ethers.Contract(ARBITRUM_NETWORK_ADDRESS, networkABI, provider)
332+
const miningAddress = await cn.getReputationMiningCycle(true);
333+
334+
const rm = new ethers.Contract(miningAddress, miningABI, provider);
335+
const openTimestamp = await rm.getReputationMiningWindowOpenTimestamp();
336+
secondsSinceOpen = Math.floor(Date.now()/1000) - openTimestamp;
337+
338+
nSubmitted = await rm.getNUniqueSubmittedHashes();
339+
} catch (err) {
340+
// Use default values for anything not set
341+
}
342+
343+
let message = "**On Arbitrum:**\n"
344+
message += `Public RPC latest block: ${publicRpcBlock}\n`
345+
message += `Arbiscan latest block: ${arbiscanLatestBlock}\n`
346+
message += `${status(smallestRpcDiscrepancy, 60, 120)} Our RPC latest block: ${ourRpcBlock}\n`
347+
message += `${status(ingestorNumber-ourRpcBlock, 25*GRAPH_LAG_INCIDENT/2, 25*GRAPH_LAG_INCIDENT)} Our ingestor latest block: ${ingestorNumber}\n`
348+
message += `${status(-minerBalance, -0.05, -0.01)} Miner balance (\`${ARBITRUM_MINER_ADDRESS.slice(0, 6)}...${ARBITRUM_MINER_ADDRESS.slice(-4)}\`): ${minerBalance}\n`
349+
message += `${status(-mtxBalance, -0.1, -0.01)} Metatx broadcaster balance (\`${ARBITRUM_BROADCASTER_ADDRESS.slice(0, 6)}...${ARBITRUM_BROADCASTER_ADDRESS.slice(-4)}\`): ${mtxBalance}\n`
350+
message += `${status(secondsSinceOpen, 3600, 4500)} Time since last mining cycle completed: ${(secondsSinceOpen/60).toFixed(0)} minutes\n`
351+
message += `${status(nSubmitted, 2,10000)} ${nSubmitted} unique submissions so far this cycle\n`
352+
return message;
353+
}
354+
355+
async function getMessage() {
356+
const gnosisMessage = await getMessageGnosis();
357+
const arbitrumMessage = await getArbitrumMessage();
358+
return "\n" + arbitrumMessage + "\n" + gnosisMessage;
359+
}
360+
361+
253362
robot.hear(/^!status$/, async () => {
254363
const message = await getMessage();
255364
channel.send(message)
@@ -276,6 +385,17 @@ module.exports = robot => {
276385
}
277386
}
278387

388+
async function checkStatusArbitrum(){
389+
const message = await getArbitrumMessage();
390+
if (message.indexOf("🔴 Our graph latest block") != -1 && !ongoingGraphIncident) {
391+
ongoingGraphIncident = true;
392+
channel.send("There appears to be an incident with the graph. \n" + message)
393+
} else if (message.indexOf("🔴") != -1 && !ongoingGenericIncident && !ongoingGraphIncident){
394+
ongoingGenericIncident = true;
395+
channel.send("There appears to be a generic incident. \n" + message)
396+
}
397+
}
398+
279399
const setupCronJob = () => {
280400
const job = new CronJob({
281401
// Every minute
@@ -288,6 +408,20 @@ module.exports = robot => {
288408
timeZone: 'Pacific/Niue'
289409
})
290410
job.start()
411+
412+
413+
const arbitrumJob = new CronJob({
414+
// Every minute
415+
cronTime: '00 * * * * *',
416+
onTick: () => {
417+
checkStatusArbitrum()
418+
},
419+
start: true,
420+
// Last time zone of the day (UTC-11)
421+
timeZone: 'Pacific/Niue'
422+
})
423+
arbitrumJob.start()
424+
291425
}
292426
setupCronJob()
293427
}

0 commit comments

Comments
 (0)