@@ -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+
5673async 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+
6795async 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://arbitrum.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 ( / ^ ! s t a t u s $ / , 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