Skip to content

Commit fe88b63

Browse files
authored
Merge branch 'main' into bing/historical_uptime_guardian_heartbeats
2 parents 36aeec2 + 0138d57 commit fe88b63

File tree

9 files changed

+94
-21
lines changed

9 files changed

+94
-21
lines changed

dashboard/src/components/Home.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ function Home({
4141
<Divider />
4242
<MonitorSettingsProvider>
4343
<CollapsibleSection header="Monitor">
44-
<Monitor />
44+
<Monitor governorInfo={governorInfo} />
4545
</CollapsibleSection>
4646
</MonitorSettingsProvider>
4747
</>

dashboard/src/components/Monitor.tsx

+15-4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
explorerVaa,
2626
} from '@wormhole-foundation/wormhole-monitor-common';
2727
import { Environment, useCurrentEnvironment, useNetworkContext } from '../contexts/NetworkContext';
28+
import { CloudGovernorInfo } from '../hooks/useCloudGovernorInfo';
2829

2930
type LastBlockByChain = { [chainId: string]: string };
3031
type CountsByChain = {
@@ -291,7 +292,7 @@ function ReobserveCode({ misses }: { misses: MissesByChain | null }) {
291292
) : null;
292293
}
293294

294-
function Misses() {
295+
function Misses({ governorInfo }: { governorInfo?: CloudGovernorInfo | null }) {
295296
const { currentNetwork } = useNetworkContext();
296297
const { showAllMisses } = useSettings();
297298
const [missesWrapper, setMissesWrapper] = useState<DataWrapper<MissesByChain>>(
@@ -329,7 +330,17 @@ function Misses() {
329330
.map(([chain, info]) => {
330331
const filteredMisses = showAllMisses
331332
? info.messages
332-
: info.messages.filter((message) => message.timestamp < twoHoursAgo);
333+
: info.messages
334+
.filter((message) => message.timestamp < twoHoursAgo)
335+
.filter(
336+
(message) =>
337+
!governorInfo?.enqueuedVAAs.some(
338+
(enqueuedVAA) =>
339+
enqueuedVAA.emitterChain === message.chain &&
340+
enqueuedVAA.emitterAddress === message.emitter &&
341+
enqueuedVAA.sequence === message.seq
342+
)
343+
);
333344
return filteredMisses.length === 0 ? null : (
334345
<CollapsibleSection
335346
key={chain}
@@ -400,7 +411,7 @@ function SettingsButton() {
400411
);
401412
}
402413

403-
function Monitor() {
414+
function Monitor({ governorInfo }: { governorInfo?: CloudGovernorInfo | null }) {
404415
const { currentNetwork } = useNetworkContext();
405416
const [lastBlockByChainWrapper, setLastBlockByChainWrapper] = useState<
406417
DataWrapper<LastBlockByChain>
@@ -466,7 +477,7 @@ function Monitor() {
466477
<SettingsButton />
467478
</Box>
468479
<Box mb={2}>
469-
<Misses />
480+
<Misses governorInfo={governorInfo} />
470481
</Box>
471482
<Typography variant="h4">Chains</Typography>
472483
<Box pl={0.5}>

watcher/src/consts.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export const RPCS_BY_CHAIN: { [key in Environment]: { [key in ChainName]?: strin
8080
base: process.env.BASE_RPC,
8181
sei: process.env.SEI_RPC,
8282
wormchain: process.env.WORMCHAIN_RPC,
83+
sepolia: process.env.SEPOLIA_RPC,
8384
},
8485
['devnet']: {},
8586
};
@@ -135,8 +136,12 @@ export const ALGORAND_INFO: { [key in Environment]: AlgorandInfo } = {
135136
},
136137
};
137138

138-
export const SEI_EXPLORER_GRAPHQL = 'https://pacific-1-graphql.alleslabs.dev/v1/graphql';
139-
export const SEI_EXPLORER_TXS = 'https://celatone-api-prod.alleslabs.dev/v1/sei/pacific-1/txs/';
139+
export const SEI_EXPLORER_GRAPHQL_MAINNET = 'https://pacific-1-graphql.alleslabs.dev/v1/graphql';
140+
export const SEI_EXPLORER_TXS_MAINNET =
141+
'https://celatone-api-prod.alleslabs.dev/v1/sei/pacific-1/txs/';
142+
export const SEI_EXPLORER_GRAPHQL_TESTNET = 'https://atlantic-2-graphql.alleslabs.dev/v1/graphql';
143+
export const SEI_EXPLORER_TXS_TESTNET =
144+
'https://celatone-api-prod.alleslabs.dev/v1/sei/atlantic-2/txs/';
140145

141146
export const DB_SOURCE =
142147
process.env.NODE_ENV === 'test' ? 'local' : process.env.DB_SOURCE || 'local';

watcher/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const supportedChains: ChainName[] =
4242
'base',
4343
'sei',
4444
// 'wormchain',
45+
'sepolia',
4546
]
4647
: [
4748
// This is the list of chains supported in MAINNET.

watcher/src/watchers/ArbitrumWatcher.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ export class ArbitrumWatcher extends EVMWatcher {
1717
if (!this.rpc) {
1818
throw new Error(`${this.chain} RPC is not defined!`);
1919
}
20-
this.evmWatcher = new EVMWatcher(network, 'ethereum', 'finalized');
20+
this.evmWatcher =
21+
network === 'mainnet'
22+
? new EVMWatcher(network, 'ethereum', 'finalized')
23+
: new EVMWatcher(network, 'sepolia', 'finalized');
2124
this.latestL2Finalized = 0;
2225
this.l1L2Map = new Map<number, number>();
2326
this.lastEthTime = 0;

watcher/src/watchers/EVMWatcher.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Implementation__factory } from '@certusone/wormhole-sdk/lib/cjs/ethers-contracts/factories/Implementation__factory';
2-
import { CONTRACTS, EVMChainName } from '@certusone/wormhole-sdk/lib/cjs/utils/consts';
2+
import { CONTRACTS, Contracts, EVMChainName } from '@certusone/wormhole-sdk/lib/cjs/utils/consts';
33
import { Log } from '@ethersproject/abstract-provider';
44
import axios from 'axios';
55
import { BigNumber } from 'ethers';
@@ -206,7 +206,13 @@ export class EVMWatcher extends Watcher {
206206
}
207207

208208
async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise<VaasByBlock> {
209-
const address = CONTRACTS.MAINNET[this.chain].core;
209+
const contracts: Contracts =
210+
this.network === 'mainnet'
211+
? CONTRACTS.MAINNET[this.chain]
212+
: this.network === 'testnet'
213+
? CONTRACTS.TESTNET[this.chain]
214+
: CONTRACTS.DEVNET[this.chain];
215+
const address = contracts.core;
210216
if (!address) {
211217
throw new Error(`Core contract not defined for ${this.chain}`);
212218
}

watcher/src/watchers/SeiExplorerWatcher.ts

+55-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
import { CONTRACTS } from '@certusone/wormhole-sdk/lib/cjs/utils/consts';
1+
import { CONTRACTS, Contracts } from '@certusone/wormhole-sdk/lib/cjs/utils/consts';
22
import axios from 'axios';
3-
import { AXIOS_CONFIG_JSON, SEI_EXPLORER_GRAPHQL, SEI_EXPLORER_TXS } from '../consts';
3+
import {
4+
AXIOS_CONFIG_JSON,
5+
SEI_EXPLORER_GRAPHQL_MAINNET,
6+
SEI_EXPLORER_GRAPHQL_TESTNET,
7+
SEI_EXPLORER_TXS_MAINNET,
8+
SEI_EXPLORER_TXS_TESTNET,
9+
} from '../consts';
410
import { VaasByBlock } from '../databases/types';
511
import { makeBlockKey, makeVaaKey } from '../databases/utils';
612
import { CosmwasmHashResult, CosmwasmWatcher } from './CosmwasmWatcher';
@@ -29,33 +35,65 @@ type SeiExplorerAccountTransactionsResponse = {
2935
};
3036

3137
export class SeiExplorerWatcher extends CosmwasmWatcher {
38+
explorerGraphql: string;
39+
explorerTxs: string;
40+
accountId: number;
41+
3242
constructor(network: Environment) {
3343
super(network, 'sei');
3444
// arbitrarily large since the code here is capable of pulling all logs from all via indexer pagination
3545
this.maximumBatchSize = 1_000_000;
46+
this.explorerGraphql =
47+
network === 'mainnet'
48+
? SEI_EXPLORER_GRAPHQL_MAINNET
49+
: network === 'testnet'
50+
? SEI_EXPLORER_GRAPHQL_TESTNET
51+
: '';
52+
this.explorerTxs =
53+
network === 'mainnet'
54+
? SEI_EXPLORER_TXS_MAINNET
55+
: network === 'testnet'
56+
? SEI_EXPLORER_TXS_TESTNET
57+
: '';
58+
this.accountId = network === 'mainnet' ? 42 : network === 'testnet' ? 3254150 : 0;
59+
// 42 is the account id of sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn <-- mainnet
60+
// MAINNET:
61+
// curl https://pacific-1-graphql.alleslabs.dev/v1/graphql \
62+
// -X POST \
63+
// -H "Content-Type: application/json" \
64+
// --data '{"query":"query getAccountIdByAddressQueryDocument($address: String!) {accounts_by_pk(address: $address) {id}}", "variables":{"address":"sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn"}, "operationName":"getAccountIdByAddressQueryDocument"}'
65+
// {"data":{"accounts_by_pk":{"id":42}}}
66+
//
67+
// 3254150 is the account number of sei1nna9mzp274djrgzhzkac2gvm3j27l402s4xzr08chq57pjsupqnqaj0d5s <-- testnet
68+
// TESTNET:
69+
// curl https://atlantic-2-graphql.alleslabs.dev/v1/graphql \
70+
// -X POST \
71+
// -H "Content-Type: application/json" \
72+
// --data '{"query":"query getAccountIdByAddressQueryDocument($address: String!) {accounts_by_pk(address: $address) {id}}", "variables":{"address":"sei1nna9mzp274djrgzhzkac2gvm3j27l402s4xzr08chq57pjsupqnqaj0d5s"}, "operationName":"getAccountIdByAddressQueryDocument"}'
73+
// {"data":{"accounts_by_pk":{"id":3254150}}}
74+
// returned by getAccountIdByAddressQueryDocument
3675
}
3776

3877
makeGraphQLQuery(offset: number, pageSize: number) {
3978
return {
4079
query:
4180
'query getTxsByAddressPagination($expression: account_transactions_bool_exp, $offset: Int!, $pageSize: Int!) {\n account_transactions(\n where: $expression\n order_by: {block_height: desc}\n offset: $offset\n limit: $pageSize\n ) {\n block {\n height\n timestamp\n }\n transaction {\n account {\n address\n }\n hash\n success\n messages\n is_clear_admin\n is_execute\n is_ibc\n is_instantiate\n is_migrate\n is_send\n is_store_code\n is_update_admin\n }\n is_signer\n }\n}',
42-
variables: { expression: { account_id: { _eq: 42 } }, offset, pageSize },
43-
// 42 is the account id of sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn
44-
// returned by getAccountIdByAddressQueryDocument
81+
variables: { expression: { account_id: { _eq: this.accountId } }, offset, pageSize },
4582
operationName: 'getTxsByAddressPagination',
4683
};
4784
}
4885

4986
async getFinalizedBlockNumber(): Promise<number> {
5087
const query = this.makeGraphQLQuery(0, 1);
51-
this.logger.debug(`Query string = ${JSON.stringify(query)}`);
88+
// this.logger.debug(`Query string = ${JSON.stringify(query)}`);
5289
const bulkTxnResult = (
5390
await axios.post<SeiExplorerAccountTransactionsResponse>(
54-
SEI_EXPLORER_GRAPHQL,
91+
this.explorerGraphql,
5592
query,
5693
AXIOS_CONFIG_JSON
5794
)
5895
).data;
96+
this.logger.debug(`bulkTxnResult = ${JSON.stringify(bulkTxnResult)}`);
5997
const blockHeight = bulkTxnResult?.data?.account_transactions?.[0]?.block?.height;
6098
if (blockHeight) {
6199
if (blockHeight !== this.latestBlockHeight) {
@@ -70,7 +108,13 @@ export class SeiExplorerWatcher extends CosmwasmWatcher {
70108
// retrieve blocks for core contract
71109
// compare block height with what is passed in
72110
async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise<VaasByBlock> {
73-
const address = CONTRACTS.MAINNET[this.chain].core;
111+
const contracts: Contracts =
112+
this.network === 'mainnet'
113+
? CONTRACTS.MAINNET[this.chain]
114+
: this.network === 'testnet'
115+
? CONTRACTS.TESTNET[this.chain]
116+
: CONTRACTS.DEVNET[this.chain];
117+
const address = contracts.core;
74118
if (!address) {
75119
throw new Error(`Core contract not defined for ${this.chain}`);
76120
}
@@ -83,10 +127,10 @@ export class SeiExplorerWatcher extends CosmwasmWatcher {
83127
let skip: number = 0;
84128
while (!done) {
85129
const query = this.makeGraphQLQuery(skip, limit);
86-
this.logger.debug(`Query string = ${JSON.stringify(query)}`);
130+
// this.logger.debug(`Query string = ${JSON.stringify(query)}`);
87131
const bulkTxnResult = (
88132
await axios.post<SeiExplorerAccountTransactionsResponse>(
89-
SEI_EXPLORER_GRAPHQL,
133+
this.explorerGraphql,
90134
query,
91135
AXIOS_CONFIG_JSON
92136
)
@@ -130,7 +174,7 @@ export class SeiExplorerWatcher extends CosmwasmWatcher {
130174
} catch (e: any) {
131175
if (e?.response?.status === 404) {
132176
// the node is mysteriously missing some transactions, but so is this ='(
133-
hashResult = (await axios.get(`${SEI_EXPLORER_TXS}${hash}`, AXIOS_CONFIG_JSON))
177+
hashResult = (await axios.get(`${this.explorerTxs}${hash}`, AXIOS_CONFIG_JSON))
134178
.data;
135179
}
136180
}

watcher/src/watchers/Watcher.ts

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ export class Watcher {
7474
fromBlock = toBlock;
7575
}
7676
retry = 0;
77+
this.logger.debug(`fromBlock = ${fromBlock}, toBlock = ${toBlock}`);
7778
await sleep(TIMEOUT);
7879
} catch (e) {
7980
// skip attempting to fetch messages until getting the finalized block succeeds

watcher/src/watchers/utils.ts

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ export function makeFinalizedWatcher(network: Environment, chainName: ChainName)
5656
return new SuiWatcher(network);
5757
} else if (chainName === 'wormchain') {
5858
return new WormchainWatcher(network);
59+
} else if (chainName === 'sepolia' && network === 'testnet') {
60+
return new EVMWatcher(network, chainName, 'finalized');
5961
} else {
6062
throw new Error(`Attempted to create finalized watcher for unsupported chain ${chainName}`);
6163
}

0 commit comments

Comments
 (0)