From 979e18543942e25c15c7082777f5a0920a471a87 Mon Sep 17 00:00:00 2001 From: Paul Noel Date: Wed, 20 Nov 2024 17:07:47 -0600 Subject: [PATCH] watcher: make near archive watcher work --- watcher/scripts/backfillArbitrum.ts | 2 +- watcher/scripts/locateMessageGaps.ts | 4 +- watcher/src/consts.ts | 2 +- watcher/src/watchers/AlgorandWatcher.ts | 7 +- watcher/src/watchers/AptosWatcher.ts | 7 +- watcher/src/watchers/CosmwasmWatcher.ts | 7 +- watcher/src/watchers/EVMWatcher.ts | 12 +- .../src/watchers/InjectiveExplorerWatcher.ts | 7 +- watcher/src/watchers/NearArchiveWatcher.ts | 120 ++++++++++++++++-- watcher/src/watchers/NearWatcher.ts | 9 +- watcher/src/watchers/SeiExplorerWatcher.ts | 7 +- watcher/src/watchers/SolanaWatcher.ts | 7 +- watcher/src/watchers/SuiWatcher.ts | 7 +- watcher/src/watchers/TerraExplorerWatcher.ts | 7 +- watcher/src/watchers/Watcher.ts | 41 +++++- watcher/src/watchers/WormchainWatcher.ts | 7 +- .../__tests__/AlgorandWatcher.test.ts | 20 ++- .../watchers/__tests__/AptosWatcher.test.ts | 13 +- .../__tests__/ArbitrumWatcher.test.ts | 2 +- .../watchers/__tests__/BaseWatcher.test.ts | 4 +- .../__tests__/CosmwasmWatcher.test.ts | 16 +-- .../src/watchers/__tests__/EVMWatcher.test.ts | 8 +- .../__tests__/OptimismWatcher.test.ts | 2 +- .../watchers/__tests__/SolanaWatcher.test.ts | 26 ++-- .../src/watchers/__tests__/SuiWatcher.test.ts | 2 +- 25 files changed, 260 insertions(+), 86 deletions(-) diff --git a/watcher/scripts/backfillArbitrum.ts b/watcher/scripts/backfillArbitrum.ts index a66bd6f6..88b1642a 100644 --- a/watcher/scripts/backfillArbitrum.ts +++ b/watcher/scripts/backfillArbitrum.ts @@ -30,7 +30,7 @@ import { Chain, contracts } from '@wormhole-foundation/sdk-base'; const watcher = new ArbitrumWatcher('Mainnet'); for (const blockNumber of blockNumbers) { log.text = `Fetching block ${blockNumber}`; - const vaasByBlock = await watcher.getMessagesForBlocks(blockNumber, blockNumber); + const { vaasByBlock } = await watcher.getMessagesForBlocks(blockNumber, blockNumber); await db.storeVaasByBlock(chain, vaasByBlock); } log.succeed('Uploaded messages to db successfully'); diff --git a/watcher/scripts/locateMessageGaps.ts b/watcher/scripts/locateMessageGaps.ts index efa543a6..cf770b6f 100644 --- a/watcher/scripts/locateMessageGaps.ts +++ b/watcher/scripts/locateMessageGaps.ts @@ -115,7 +115,9 @@ import { ChainId, Network, toChain, toChainId } from '@wormhole-foundation/sdk-b while (fromBlock <= rangeEnd && !found) { const toBlock = Math.min(fromBlock + watcher.maximumBatchSize - 1, rangeEnd); const messages = await watcher.getMessagesForBlocks(fromBlock, toBlock); - for (const message of Object.entries(messages).filter(([key, value]) => value.length > 0)) { + for (const message of Object.entries(messages.vaasByBlock).filter( + ([key, value]) => value.length > 0 + )) { const locatedMessages = message[1].filter((msgKey) => { const [_transaction, vaaKey] = msgKey.split(':'); const [_chain, msgEmitter, msgSeq] = vaaKey.split('/'); diff --git a/watcher/src/consts.ts b/watcher/src/consts.ts index 20215079..55e120e2 100644 --- a/watcher/src/consts.ts +++ b/watcher/src/consts.ts @@ -3,7 +3,7 @@ import { Mode } from '@wormhole-foundation/wormhole-monitor-common'; import { AxiosRequestConfig } from 'axios'; export const TIMEOUT = 0.5 * 1000; -export const HB_INTERVAL = 5 * 60 * 1000; // 5 Minutes +export const HB_INTERVAL = 15 * 60 * 1000; // 15 Minutes export type WorkerData = { network: Network; chain: Chain; diff --git a/watcher/src/watchers/AlgorandWatcher.ts b/watcher/src/watchers/AlgorandWatcher.ts index 12edcdc9..ce1f1ab8 100644 --- a/watcher/src/watchers/AlgorandWatcher.ts +++ b/watcher/src/watchers/AlgorandWatcher.ts @@ -98,7 +98,10 @@ export class AlgorandWatcher extends Watcher { return messages; } - async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise { + async getMessagesForBlocks( + fromBlock: number, + toBlock: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { const txIds = await this.getApplicationLogTransactionIds(fromBlock, toBlock); const transactions = []; for (const txId of txIds) { @@ -124,6 +127,6 @@ export class AlgorandWatcher extends Watcher { if (!vaasByBlock[toBlockKey]) { vaasByBlock[toBlockKey] = []; } - return vaasByBlock; + return { vaasByBlock }; } } diff --git a/watcher/src/watchers/AptosWatcher.ts b/watcher/src/watchers/AptosWatcher.ts index daf16fd2..a08caf1e 100644 --- a/watcher/src/watchers/AptosWatcher.ts +++ b/watcher/src/watchers/AptosWatcher.ts @@ -40,7 +40,10 @@ export class AptosWatcher extends Watcher { ); } - async getMessagesForBlocks(fromSequence: number, toSequence: number): Promise { + async getMessagesForBlocks( + fromSequence: number, + toSequence: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { const limit = toSequence - fromSequence + 1; const events: AptosEvent[] = (await this.client.getEventsByEventHandle( this.coreBridgeAddress, @@ -63,7 +66,7 @@ export class AptosWatcher extends Watcher { vaasByBlock[blockKey] = [...(vaasByBlock[blockKey] ?? []), vaaKey]; }) ); - return vaasByBlock; + return { vaasByBlock }; } isValidBlockKey(key: string) { diff --git a/watcher/src/watchers/CosmwasmWatcher.ts b/watcher/src/watchers/CosmwasmWatcher.ts index c8374033..1febe79b 100644 --- a/watcher/src/watchers/CosmwasmWatcher.ts +++ b/watcher/src/watchers/CosmwasmWatcher.ts @@ -55,7 +55,10 @@ export class CosmwasmWatcher extends Watcher { throw new Error(`Unable to parse result of ${this.latestBlockTag} on ${this.rpc}`); } - async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise { + async getMessagesForBlocks( + fromBlock: number, + toBlock: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { const address = contracts.coreBridge.get(this.network, this.chain); if (!address) { throw new Error(`Core contract not defined for ${this.chain}`); @@ -153,7 +156,7 @@ export class CosmwasmWatcher extends Watcher { } } } - return vaasByBlock; + return { vaasByBlock }; } } diff --git a/watcher/src/watchers/EVMWatcher.ts b/watcher/src/watchers/EVMWatcher.ts index 4cfd6860..124f45ec 100644 --- a/watcher/src/watchers/EVMWatcher.ts +++ b/watcher/src/watchers/EVMWatcher.ts @@ -40,6 +40,7 @@ export class EVMWatcher extends Watcher { this.lastTimestamp = 0; this.latestFinalizedBlockNumber = 0; this.finalizedBlockTag = finalizedBlockTag; + // Special cases for batch size if (chain === 'Acala' || chain === 'Karura' || chain === 'Berachain') { this.maximumBatchSize = 50; } else if ( @@ -55,6 +56,10 @@ export class EVMWatcher extends Watcher { ) { this.maximumBatchSize = 10; } + // Special cases for watch loop delay + if (chain === 'Berachain') { + this.watchLoopDelay = 1000; + } } async getBlock(blockNumberOrTag: number | BlockTag): Promise { @@ -221,7 +226,10 @@ export class EVMWatcher extends Watcher { return block.number; } - async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise { + async getMessagesForBlocks( + fromBlock: number, + toBlock: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { const address = contracts.coreBridge.get(this.network, this.chain); if (!address) { throw new Error(`Core contract not defined for ${this.chain} on ${this.network}!`); @@ -252,6 +260,6 @@ export class EVMWatcher extends Watcher { const blockKey = makeBlockKey(blockNumber.toString(), timestampsByBlock[blockNumber]); vaasByBlock[blockKey] = [...(vaasByBlock[blockKey] || []), vaaKey]; } - return vaasByBlock; + return { vaasByBlock }; } } diff --git a/watcher/src/watchers/InjectiveExplorerWatcher.ts b/watcher/src/watchers/InjectiveExplorerWatcher.ts index 914ed16b..fcd1c6f2 100644 --- a/watcher/src/watchers/InjectiveExplorerWatcher.ts +++ b/watcher/src/watchers/InjectiveExplorerWatcher.ts @@ -47,7 +47,10 @@ export class InjectiveExplorerWatcher extends Watcher { // should be core, but the explorer doesn't support it yet // use "to": as the pagination key // compare block height ("block_number":) with what is passed in. - async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise { + async getMessagesForBlocks( + fromBlock: number, + toBlock: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { const coreAddress = contracts.coreBridge.get(this.network, this.chain); const address = contracts.tokenBridge.get(this.network, this.chain); if (!coreAddress || !address) { @@ -169,7 +172,7 @@ export class InjectiveExplorerWatcher extends Watcher { ); vaasByBlock[blockKey] = []; } - return vaasByBlock; + return { vaasByBlock }; } } diff --git a/watcher/src/watchers/NearArchiveWatcher.ts b/watcher/src/watchers/NearArchiveWatcher.ts index cef3c086..8ee6cd59 100644 --- a/watcher/src/watchers/NearArchiveWatcher.ts +++ b/watcher/src/watchers/NearArchiveWatcher.ts @@ -1,27 +1,29 @@ import { decode } from 'bs58'; import { Provider } from 'near-api-js/lib/providers'; -import { BlockResult } from 'near-api-js/lib/providers/provider'; +import { BlockResult, ExecutionStatus } from 'near-api-js/lib/providers/provider'; import { z } from 'zod'; import { VaasByBlock } from '../databases/types'; -import { makeBlockKey } from '../databases/utils'; +import { makeBlockKey, makeVaaKey } from '../databases/utils'; import { fetchBlockByBlockId, - getMessagesFromBlockResults, getNearProvider, getTimestampByBlock, + isWormholePublishEventLog, } from '../utils/near'; import { Watcher } from './Watcher'; import { assertEnvironmentVariable, sleep } from '@wormhole-foundation/wormhole-monitor-common'; import { Network, contracts } from '@wormhole-foundation/sdk-base'; import axios from 'axios'; -import { AXIOS_CONFIG_JSON } from '../consts'; +import { AXIOS_CONFIG_JSON, HB_INTERVAL } from '../consts'; +import { EventLog } from 'src/types/near'; export class NearArchiveWatcher extends Watcher { provider: Provider | null = null; constructor(network: Network) { super(network, 'Near'); - this.maximumBatchSize = 1000; + this.maximumBatchSize = 1_000_000; + this.watchLoopDelay = 60 * 60 * 1000; // 1 hour } async getFinalizedBlockNumber(): Promise { @@ -37,7 +39,11 @@ export class NearArchiveWatcher extends Watcher { } } - async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise { + async getMessagesForBlocks( + fromBlock: number, + toBlock: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { + const quittingTimestamp = Date.now() + HB_INTERVAL * 0.75; const origFromBlock = fromBlock; const origToBlock = toBlock; this.logger.info(`fetching info for blocks ${origFromBlock} to ${origToBlock}`); @@ -114,21 +120,26 @@ export class NearArchiveWatcher extends Watcher { } this.logger.info(`Fetched ${blocks.length} blocks`); - const vaasByBlock: VaasByBlock = await getMessagesFromBlockResults( + const response: ConstrainedResponse = await this.getMessagesFromBlockResultsConstrained( this.network, provider, blocks, - true + quittingTimestamp ); + // This is the case where there are no transactions in the time window. + if (response.lastBlockHeight === 0) { + response.lastBlockHeight = toBlock; + } + const lastBlockInfo = await fetchBlockByBlockId(provider, response.lastBlockHeight); // Make a block for the to_block, if it isn't already there const blockKey = makeBlockKey( - toBlockInfo.header.height.toString(), - new Date(toBlockInfo.header.timestamp / 1_000_000).toISOString() + response.lastBlockHeight.toString(), + new Date(lastBlockInfo.header.timestamp / 1_000_000).toISOString() ); - if (!vaasByBlock[blockKey]) { - vaasByBlock[blockKey] = []; + if (!response.vaasByBlock[blockKey]) { + response.vaasByBlock[blockKey] = []; } - return vaasByBlock; + return response; } async getProvider(): Promise { @@ -191,7 +202,90 @@ export class NearArchiveWatcher extends Watcher { } return txs.reverse(); } + + async getMessagesFromBlockResultsConstrained( + network: Network, + provider: Provider, + blocks: BlockResult[], + quittingTime: number + ): Promise { + const vaasByBlock: VaasByBlock = {}; + let lastBlockHeight = 0; + let prevLastBlockHeight = 0; + this.logger.debug(`Fetching messages from ${blocks.length} blocks...`); + try { + for (let i = 0; i < blocks.length; i++) { + this.logger.debug(`Fetching messages from block ${i + 1}/${blocks.length}...`); + const { height, timestamp } = blocks[i].header; + prevLastBlockHeight = lastBlockHeight; + lastBlockHeight = height; + const blockKey = makeBlockKey( + height.toString(), + new Date(timestamp / 1_000_000).toISOString() + ); + let localVaasByBlock: VaasByBlock = {}; + localVaasByBlock[blockKey] = []; + + const chunks = []; + this.logger.debug('attempting to fetch chunks'); + for (const chunk of blocks[i].chunks) { + chunks.push(await provider.chunk(chunk.chunk_hash)); + } + + const transactions = chunks.flatMap(({ transactions }) => transactions); + const coreBridge = contracts.coreBridge.get(network, 'Near'); + if (!coreBridge) { + throw new Error('Unable to get contract address for Near'); + } + this.logger.debug(`attempting to fetch ${transactions.length} transactions`); + const totTx = transactions.length; + let txCount = 1; + for (const tx of transactions) { + this.logger.debug(`fetching transaction ${txCount}/${totTx}`); + txCount++; + const outcome = await provider.txStatus(tx.hash, coreBridge); + const logs = outcome.receipts_outcome + .filter( + ({ outcome }) => + (outcome as any).executor_id === coreBridge && + (outcome.status as ExecutionStatus).SuccessValue + ) + .flatMap(({ outcome }) => outcome.logs) + .filter((log) => log.startsWith('EVENT_JSON:')) // https://nomicon.io/Standards/EventsFormat + .map((log) => JSON.parse(log.slice(11)) as EventLog) + .filter(isWormholePublishEventLog); + for (const log of logs) { + const vaaKey = makeVaaKey(tx.hash, 'Near', log.emitter, log.seq.toString()); + localVaasByBlock[blockKey] = [...localVaasByBlock[blockKey], vaaKey]; + } + } + this.logger.debug( + `Fetched ${localVaasByBlock[blockKey].length} messages from block ${blockKey}` + ); + vaasByBlock[blockKey] = localVaasByBlock[blockKey]; + if (Date.now() >= quittingTime) { + this.logger.warn(`Quitting early due to time constraint.`); + break; + } + } + } catch (e) { + this.logger.error(`Near block getMessagesFromBlockResultsConstrained error: ${e}`); + this.logger.warn(`Quitting early due to error.`); + lastBlockHeight = prevLastBlockHeight; + } + + const numMessages = Object.values(vaasByBlock).flat().length; + this.logger.debug(`Fetched ${numMessages} messages from ${blocks.length} blocks`); + + return { vaasByBlock, lastBlockHeight }; + } } + +type ConstrainedResponse = { + vaasByBlock: VaasByBlock; + lastBlockHeight: number; +}; + type GetTransactionsByAccountIdResponse = { txns: NearTxn[]; }; diff --git a/watcher/src/watchers/NearWatcher.ts b/watcher/src/watchers/NearWatcher.ts index 7ed889fd..ccb04045 100644 --- a/watcher/src/watchers/NearWatcher.ts +++ b/watcher/src/watchers/NearWatcher.ts @@ -22,7 +22,10 @@ export class NearWatcher extends Watcher { return block.header.height; } - async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise { + async getMessagesForBlocks( + fromBlock: number, + toBlock: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { // assume toBlock was retrieved from getFinalizedBlockNumber and is finalized this.logger.info(`fetching info for blocks ${fromBlock} to ${toBlock}`); const provider = await this.getProvider(); @@ -48,7 +51,9 @@ export class NearWatcher extends Watcher { } } - return getMessagesFromBlockResults(this.network, provider, blocks); + return { + vaasByBlock: await getMessagesFromBlockResults(this.network, provider, blocks), + }; } async getProvider(): Promise { diff --git a/watcher/src/watchers/SeiExplorerWatcher.ts b/watcher/src/watchers/SeiExplorerWatcher.ts index 21914c87..df6c6119 100644 --- a/watcher/src/watchers/SeiExplorerWatcher.ts +++ b/watcher/src/watchers/SeiExplorerWatcher.ts @@ -107,7 +107,10 @@ export class SeiExplorerWatcher extends CosmwasmWatcher { // retrieve blocks for core contract // compare block height with what is passed in - async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise { + async getMessagesForBlocks( + fromBlock: number, + toBlock: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { const address = contracts.coreBridge.get(this.network, this.chain); if (!address) { throw new Error(`Core contract not defined for ${this.chain}`); @@ -237,6 +240,6 @@ export class SeiExplorerWatcher extends CosmwasmWatcher { } // NOTE: this does not set an empty entry for the latest block since we don't know if the graphql response // is synced with the block height. Therefore, the latest block will only update when a new transaction appears. - return vaasByBlock; + return { vaasByBlock }; } } diff --git a/watcher/src/watchers/SolanaWatcher.ts b/watcher/src/watchers/SolanaWatcher.ts index 3426ab8f..62d27698 100644 --- a/watcher/src/watchers/SolanaWatcher.ts +++ b/watcher/src/watchers/SolanaWatcher.ts @@ -81,7 +81,10 @@ export class SolanaWatcher extends Watcher { return block; } - async getMessagesForBlocks(fromSlot: number, toSlot: number): Promise { + async getMessagesForBlocks( + fromSlot: number, + toSlot: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { // in the rare case of maximumBatchSize skipped blocks in a row, // you might hit this error due to the recursion below if (fromSlot > toSlot) throw new Error('solana: invalid block range'); @@ -251,7 +254,7 @@ export class SolanaWatcher extends Watcher { toSlot.toString(), new Date(toBlock.blockTime! * 1000).toISOString() ); - return { [lastBlockKey]: [], ...vaasByBlock }; + return { vaasByBlock: { [lastBlockKey]: [], ...vaasByBlock } }; } isValidVaaKey(key: string) { diff --git a/watcher/src/watchers/SuiWatcher.ts b/watcher/src/watchers/SuiWatcher.ts index 86c28cfd..01b62ea2 100644 --- a/watcher/src/watchers/SuiWatcher.ts +++ b/watcher/src/watchers/SuiWatcher.ts @@ -39,7 +39,10 @@ export class SuiWatcher extends Watcher { } // TODO: this might break using numbers, the whole service needs a refactor to use BigInt - async getMessagesForBlocks(fromCheckpoint: number, toCheckpoint: number): Promise { + async getMessagesForBlocks( + fromCheckpoint: number, + toCheckpoint: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { this.logger.info(`fetching info for checkpoints ${fromCheckpoint} to ${toCheckpoint}`); const vaasByBlock: VaasByBlock = {}; @@ -115,6 +118,6 @@ export class SuiWatcher extends Watcher { vaasByBlock[blockKey] = [...(vaasByBlock[blockKey] || []), vaaKey]; } } while (hasNextPage && lastCheckpoint && fromCheckpoint < lastCheckpoint); - return vaasByBlock; + return { vaasByBlock }; } } diff --git a/watcher/src/watchers/TerraExplorerWatcher.ts b/watcher/src/watchers/TerraExplorerWatcher.ts index 1cbb5522..4b87ee9e 100644 --- a/watcher/src/watchers/TerraExplorerWatcher.ts +++ b/watcher/src/watchers/TerraExplorerWatcher.ts @@ -43,7 +43,10 @@ export class TerraExplorerWatcher extends Watcher { // retrieve blocks for core contract. // use "next": as the pagination key // compare block height ("height":) with what is passed in. - async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise { + async getMessagesForBlocks( + fromBlock: number, + toBlock: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { const address = contracts.coreBridge.get(this.network, this.chain); if (!address) { throw new Error(`Core contract not defined for ${this.chain}`); @@ -159,7 +162,7 @@ export class TerraExplorerWatcher extends Watcher { ); vaasByBlock[blockKey] = []; } - return vaasByBlock; + return { vaasByBlock }; } } diff --git a/watcher/src/watchers/Watcher.ts b/watcher/src/watchers/Watcher.ts index b87b1a8f..c5c41fbd 100644 --- a/watcher/src/watchers/Watcher.ts +++ b/watcher/src/watchers/Watcher.ts @@ -4,7 +4,7 @@ import { sleep, } from '@wormhole-foundation/wormhole-monitor-common'; import { z } from 'zod'; -import { TIMEOUT } from '../consts'; +import { HB_INTERVAL, TIMEOUT } from '../consts'; import { VaasByBlock } from '../databases/types'; import { getResumeBlockByChain, storeLatestBlock, storeVaasByBlock } from '../databases/utils'; import { getLogger, WormholeLogger } from '../utils/logger'; @@ -17,6 +17,7 @@ export class Watcher { logger: WormholeLogger; maximumBatchSize: number = 100; mode: Mode; + watchLoopDelay: number = 0; // in milliseconds constructor(network: Network, chain: Chain, mode: Mode = 'vaa') { this.network = network; @@ -34,7 +35,10 @@ export class Watcher { throw new Error('Not Implemented'); } - async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise { + async getMessagesForBlocks( + fromBlock: number, + toBlock: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { throw new Error('Not Implemented'); } @@ -71,6 +75,7 @@ export class Watcher { let fromBlock: number | null = await getResumeBlockByChain(this.network, this.chain, this.mode); let retry = 0; + let firstTime = true; while (true) { try { this.logger.debug(`fromBlock = ${fromBlock}, toBlock = ${toBlock}`); @@ -85,8 +90,14 @@ export class Watcher { const blockKey = await this.getFtMessagesForBlocks(fromBlock, toBlock); await storeLatestBlock(this.chain, blockKey, this.mode); } else { - const vaasByBlock = await this.getMessagesForBlocks(fromBlock, toBlock); + const { vaasByBlock, optionalBlockHeight } = await this.getMessagesForBlocks( + fromBlock, + toBlock + ); await storeVaasByBlock(this.chain, vaasByBlock); + if (optionalBlockHeight) { + toBlock = optionalBlockHeight; + } } fromBlock = toBlock + 1; } @@ -109,7 +120,7 @@ export class Watcher { } } catch (e) { retry++; - this.logger.error(e); + this.logger.error(`error fetching messages: ${e}`); const expoBacko = TIMEOUT * 2 ** retry; this.logger.warn(`backing off for ${expoBacko}ms`); await sleep(expoBacko); @@ -117,6 +128,28 @@ export class Watcher { if (parentPort) { parentPort.postMessage('heartbeat'); } + if (this.watchLoopDelay > 0 && !firstTime) { + this.logger.info(`Using watchLoopDelay of ${this.watchLoopDelay}ms`); + const wakeupTime = Date.now() + this.watchLoopDelay; + let now = Date.now(); + while (now < wakeupTime) { + if (parentPort) { + parentPort.postMessage('heartbeat'); + } + const sleepInterval = Math.min(HB_INTERVAL / 2, wakeupTime - now); + await sleep(sleepInterval); + now = Date.now(); + } + // After sleeping for the extra loop delay, need to get the latest finalized block + try { + toBlock = await this.getFinalizedBlockNumber(); + this.logger.debug(`finalized block after the extra loop delay = ${toBlock}`); + } catch (e) { + this.logger.error(`error fetching finalized block after the extra loop delay: ${e}`); + // If this throws, the loop will continue and try again. + } + } + firstTime = false; } } } diff --git a/watcher/src/watchers/WormchainWatcher.ts b/watcher/src/watchers/WormchainWatcher.ts index c2b9916e..07e0379a 100644 --- a/watcher/src/watchers/WormchainWatcher.ts +++ b/watcher/src/watchers/WormchainWatcher.ts @@ -37,7 +37,10 @@ export class WormchainWatcher extends CosmwasmWatcher { throw new Error(`Unable to parse result of ${this.latestBlockTag} on ${this.rpc}`); } - async getMessagesForBlocks(fromBlock: number, toBlock: number): Promise { + async getMessagesForBlocks( + fromBlock: number, + toBlock: number + ): Promise<{ vaasByBlock: VaasByBlock; optionalBlockHeight?: number }> { const address = contracts.coreBridge.get(this.network, this.chain); if (!address) { throw new Error(`Core contract not defined for ${this.chain}`); @@ -135,7 +138,7 @@ export class WormchainWatcher extends CosmwasmWatcher { } } } - return vaasByBlock; + return { vaasByBlock }; } } diff --git a/watcher/src/watchers/__tests__/AlgorandWatcher.test.ts b/watcher/src/watchers/__tests__/AlgorandWatcher.test.ts index 634575eb..c3b8d99f 100644 --- a/watcher/src/watchers/__tests__/AlgorandWatcher.test.ts +++ b/watcher/src/watchers/__tests__/AlgorandWatcher.test.ts @@ -16,13 +16,16 @@ test('getFinalizedBlockNumber', async () => { test('getMessagesForBlocks', async () => { const watcher = new AlgorandWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(25692450, 25692450); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(25692450, 25692450); expect(messages).toMatchObject({ '25692450/2022-12-21T02:00:40.000Z': [] }); }); test('getMessagesForBlocks initial block', async () => { const watcher = new AlgorandWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(initialAlgorandBlock, initialAlgorandBlock); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks( + initialAlgorandBlock, + initialAlgorandBlock + ); expect(messages).toMatchObject({ '22931277/2022-08-19T15:10:48.000Z': [ '2RBQLCETCLFV4F3PQ7IHEWVWQV3MCP4UM5S5OFZM23XMC2O2DJ6A:8/67e93fa6c8ac5c819990aa7340c0c16b508abb1178be9b30d024b8ac25193d45/1', @@ -32,13 +35,16 @@ test('getMessagesForBlocks initial block', async () => { test('getMessagesForBlocks indexer pagination support', async () => { const watcher = new AlgorandWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(initialAlgorandBlock, 27069946); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks( + initialAlgorandBlock, + 27069946 + ); expect(Object.keys(messages).length).toEqual(420); }); test('getMessagesForBlocks seq < 192', async () => { const watcher = new AlgorandWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(25428873, 25428873); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(25428873, 25428873); expect(messages).toMatchObject({ '25428873/2022-12-09T18:10:08.000Z': [ 'M6QPEZ42P5O23II7SCWZTNZ7MHBSOH6KUNAPMH5YL3XHGNTEFUSQ:8/67e93fa6c8ac5c819990aa7340c0c16b508abb1178be9b30d024b8ac25193d45/191', @@ -48,7 +54,7 @@ test('getMessagesForBlocks seq < 192', async () => { test('getMessagesForBlocks seq = 192', async () => { const watcher = new AlgorandWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(25433218, 25433218); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(25433218, 25433218); expect(messages).toMatchObject({ '25433218/2022-12-09T22:40:55.000Z': [ '3PJPDBGTQK6JXAQEJNOYFE4NLLKFMCTKRY5FYNAXSEBDO25XUUJQ:8/67e93fa6c8ac5c819990aa7340c0c16b508abb1178be9b30d024b8ac25193d45/192', @@ -58,7 +64,7 @@ test('getMessagesForBlocks seq = 192', async () => { test('getMessagesForBlocks seq > 383', async () => { const watcher = new AlgorandWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(26856742, 26856742); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(26856742, 26856742); expect(messages).toMatchObject({ '26856742/2023-02-09T09:05:04.000Z': [ 'LJNYXPG5VLJNNTBLSZSHLZQ7XQWTSUPKGA7APVI53J3MAKHQN72Q:8/67e93fa6c8ac5c819990aa7340c0c16b508abb1178be9b30d024b8ac25193d45/384', @@ -68,6 +74,6 @@ test('getMessagesForBlocks seq > 383', async () => { test('getMessagesForBlocks on known empty block', async () => { const watcher = new AlgorandWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(23761195, 23761195); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(23761195, 23761195); expect(messages).toMatchObject({ '23761195/2022-09-28T21:42:30.000Z': [] }); }); diff --git a/watcher/src/watchers/__tests__/AptosWatcher.test.ts b/watcher/src/watchers/__tests__/AptosWatcher.test.ts index cf6ffe84..e553f01f 100644 --- a/watcher/src/watchers/__tests__/AptosWatcher.test.ts +++ b/watcher/src/watchers/__tests__/AptosWatcher.test.ts @@ -16,7 +16,7 @@ test('getFinalizedSequenceNumber', async () => { test('getMessagesForSequenceNumbers', async () => { const watcher = new AptosWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(0, 1); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(0, 1); expect(messages).toMatchObject({ '1095891/2022-10-19T00:55:54.676Z/0': [ '0x27b5808a7cfdb688e02be192ed334da683975b7487e8be7a09670b3088b58908:22/0000000000000000000000000000000000000000000000000000000000000001/0', @@ -32,12 +32,11 @@ test('getMessagesForSequenceNumbers', async () => { // test that block number, timestamp, and sequence number are all strictly increasing const latestSequenceNumber = await watcher.getFinalizedBlockNumber(); - const messageKeys = Object.keys( - await watcher.getMessagesForBlocks( - latestSequenceNumber - watcher.maximumBatchSize + 1, - latestSequenceNumber - ) - ).sort(); + const { vaasByBlock } = await watcher.getMessagesForBlocks( + latestSequenceNumber - watcher.maximumBatchSize + 1, + latestSequenceNumber + ); + const messageKeys = Object.keys(vaasByBlock).sort(); console.log(messageKeys); expect(messageKeys.length).toBe(watcher.maximumBatchSize); expect(Date.parse(messageKeys.at(-1)!.split('/')[1])).toBeLessThan(Date.now()); diff --git a/watcher/src/watchers/__tests__/ArbitrumWatcher.test.ts b/watcher/src/watchers/__tests__/ArbitrumWatcher.test.ts index 76b09e04..b1ab6b08 100644 --- a/watcher/src/watchers/__tests__/ArbitrumWatcher.test.ts +++ b/watcher/src/watchers/__tests__/ArbitrumWatcher.test.ts @@ -24,7 +24,7 @@ test('getFinalizedBlockNumber', async () => { test('getMessagesForBlocks', async () => { const watcher = new ArbitrumWatcher('Mainnet'); - const vaasByBlock = await watcher.getMessagesForBlocks(114500582, 114500584); + const { vaasByBlock } = await watcher.getMessagesForBlocks(114500582, 114500584); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(3); expect(entries.filter(([block, vaas]) => vaas.length === 0).length).toEqual(2); diff --git a/watcher/src/watchers/__tests__/BaseWatcher.test.ts b/watcher/src/watchers/__tests__/BaseWatcher.test.ts index 610b978e..f621921c 100644 --- a/watcher/src/watchers/__tests__/BaseWatcher.test.ts +++ b/watcher/src/watchers/__tests__/BaseWatcher.test.ts @@ -14,7 +14,7 @@ test('getFinalizedBlockNumber', async () => { test('getMessagesForBlocks', async () => { const watcher = new EVMWatcher('Mainnet', 'Base'); - const vaasByBlock = await watcher.getMessagesForBlocks(1544175, 1544185); + const { vaasByBlock } = await watcher.getMessagesForBlocks(1544175, 1544185); expect(vaasByBlock).toMatchObject({ '1544175/2023-07-20T18:28:17.000Z': [], '1544176/2023-07-20T18:28:19.000Z': [], @@ -32,7 +32,7 @@ test('getMessagesForBlocks', async () => { test('getMessagesForBlockWithWHMsg', async () => { const watcher = new EVMWatcher('Mainnet', 'Base'); - const vaasByBlock = await watcher.getMessagesForBlocks(1557420, 1557429); + const { vaasByBlock } = await watcher.getMessagesForBlocks(1557420, 1557429); expect(vaasByBlock).toMatchObject({ '1557420/2023-07-21T01:49:47.000Z': [], '1557421/2023-07-21T01:49:49.000Z': [], diff --git a/watcher/src/watchers/__tests__/CosmwasmWatcher.test.ts b/watcher/src/watchers/__tests__/CosmwasmWatcher.test.ts index 2a134ce7..70dba269 100644 --- a/watcher/src/watchers/__tests__/CosmwasmWatcher.test.ts +++ b/watcher/src/watchers/__tests__/CosmwasmWatcher.test.ts @@ -17,7 +17,7 @@ test.skip('getFinalizedBlockNumber(terra2)', async () => { test.skip('getMessagesForBlocks(terra2)', async () => { const watcher = new TerraExplorerWatcher('Mainnet', 'Terra2'); - const vaasByBlock = await watcher.getMessagesForBlocks(10847656, 10847657); + const { vaasByBlock } = await watcher.getMessagesForBlocks(10847656, 10847657); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(2); expect(entries.filter(([block, vaas]) => vaas.length === 0).length).toEqual(1); @@ -38,7 +38,7 @@ test('getFinalizedBlockNumber(terra explorer)', async () => { test('getMessagesForBlocks(terra explorer)', async () => { const watcher = new TerraExplorerWatcher('Mainnet', 'Terra'); - const vaasByBlock = await watcher.getMessagesForBlocks(14506733, 14506740); + const { vaasByBlock } = await watcher.getMessagesForBlocks(14506733, 14506740); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(2); expect(entries.filter(([block, vaas]) => vaas.length === 0).length).toEqual(1); @@ -54,7 +54,7 @@ test('getMessagesForBlocks(terra explorer)', async () => { // flaky rpc, skip test.skip('getMessagesForBlocks(terra explorer, no useful info)', async () => { const watcher = new TerraExplorerWatcher('Mainnet', 'Terra'); - const vaasByBlock = await watcher.getMessagesForBlocks(10975000, 10975010); + const { vaasByBlock } = await watcher.getMessagesForBlocks(10975000, 10975010); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(1); expect(entries.filter(([block, vaas]) => vaas.length === 0).length).toEqual(1); @@ -70,7 +70,7 @@ test('getFinalizedBlockNumber(xpla)', async () => { test('getMessagesForBlocks(xpla)', async () => { const watcher = new CosmwasmWatcher('Mainnet', 'Xpla'); - const vaasByBlock = await watcher.getMessagesForBlocks(1645812, 1645813); + const { vaasByBlock } = await watcher.getMessagesForBlocks(1645812, 1645813); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(2); expect(entries.filter(([block, vaas]) => vaas.length === 0).length).toEqual(1); @@ -91,7 +91,7 @@ test('getFinalizedBlockNumber(injective)', async () => { test.skip('getMessagesForBlocks(injective)', async () => { const watcher = new InjectiveExplorerWatcher('Mainnet'); - const vaasByBlock = await watcher.getMessagesForBlocks(61720293, 61720294); + const { vaasByBlock } = await watcher.getMessagesForBlocks(61720293, 61720294); const entries = Object.entries(vaasByBlock); // console.log(entries); // Leave this in for future debugging expect(entries.length).toEqual(2); @@ -115,7 +115,7 @@ test.skip('getFinalizedBlockNumber(sei)', async () => { // skipped because the SeiExplorerWatcher is used test.skip('getMessagesForBlocks(sei)', async () => { const watcher = new CosmwasmWatcher('Mainnet', 'Sei'); - const vaasByBlock = await watcher.getMessagesForBlocks(18907686, 18907687); + const { vaasByBlock } = await watcher.getMessagesForBlocks(18907686, 18907687); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(2); expect(entries.filter(([block, vaas]) => vaas.length === 0).length).toEqual(1); @@ -138,7 +138,7 @@ test('getFinalizedBlockNumber(sei explorer)', async () => { // skipped because it takes more and more time to paginate back test.skip('getMessagesForBlocks(sei explorer)', async () => { const watcher = new SeiExplorerWatcher('Mainnet'); - const vaasByBlock = await watcher.getMessagesForBlocks(19061244, 19061245); + const { vaasByBlock } = await watcher.getMessagesForBlocks(19061244, 19061245); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(1); expect(entries.filter(([block, vaas]) => vaas.length === 0).length).toEqual(0); @@ -161,7 +161,7 @@ test('getFinalizedBlockNumber(wormchain)', async () => { test('getMessagesForBlocks(wormchain)', async () => { const watcher = new WormchainWatcher('Mainnet'); - const vaasByBlock = await watcher.getMessagesForBlocks(8978585, 8978585); + const { vaasByBlock } = await watcher.getMessagesForBlocks(8978585, 8978585); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(1); expect(entries.filter(([block, vaas]) => vaas.length === 0).length).toEqual(0); diff --git a/watcher/src/watchers/__tests__/EVMWatcher.test.ts b/watcher/src/watchers/__tests__/EVMWatcher.test.ts index a1c10b12..3a2b3df2 100644 --- a/watcher/src/watchers/__tests__/EVMWatcher.test.ts +++ b/watcher/src/watchers/__tests__/EVMWatcher.test.ts @@ -72,7 +72,7 @@ test('getFinalizedBlockNumber', async () => { test('getMessagesForBlocks', async () => { const watcher = new EVMWatcher('Mainnet', 'Avalanche'); - const vaasByBlock = await watcher.getMessagesForBlocks(46997500, 46997599); + const { vaasByBlock } = await watcher.getMessagesForBlocks(46997500, 46997599); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(100); expect(entries.filter(([block, vaas]) => vaas.length === 0).length).toEqual(99); @@ -111,7 +111,7 @@ test('getBlock by number (Celo compatibility)', async () => { test('getMessagesForBlocks (Celo compatibility)', async () => { const watcher = new EVMWatcher('Mainnet', 'Celo'); - const vaasByBlock = await watcher.getMessagesForBlocks(13322450, 13322549); + const { vaasByBlock } = await watcher.getMessagesForBlocks(13322450, 13322549); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(100); expect(entries.filter(([block, vaas]) => vaas.length === 0).length).toEqual(98); @@ -142,7 +142,7 @@ test('getBlock by number (Karura compatibility)', async () => { test('getMessagesForBlocks (Karura compatibility)', async () => { const watcher = new EVMWatcher('Mainnet', 'Karura'); - const vaasByBlock = await watcher.getMessagesForBlocks(4582511, 4582513); + const { vaasByBlock } = await watcher.getMessagesForBlocks(4582511, 4582513); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(3); expect(entries[0][0]).toEqual('4582511/2023-06-19T15:54:48.000Z'); @@ -155,7 +155,7 @@ test('getMessagesForBlocks (Karura compatibility)', async () => { test('getMessagesForBlocks (Karura compatibility 2)', async () => { const watcher = new EVMWatcher('Mainnet', 'Karura'); await watcher.getFinalizedBlockNumber(); // This has the side effect of initializing the latestFinalizedBlockNumber - const vaasByBlock = await watcher.getMessagesForBlocks(4595356, 4595358); + const { vaasByBlock } = await watcher.getMessagesForBlocks(4595356, 4595358); const entries = Object.entries(vaasByBlock); expect(entries.length).toEqual(3); }); diff --git a/watcher/src/watchers/__tests__/OptimismWatcher.test.ts b/watcher/src/watchers/__tests__/OptimismWatcher.test.ts index ac3e023f..55dd73d5 100644 --- a/watcher/src/watchers/__tests__/OptimismWatcher.test.ts +++ b/watcher/src/watchers/__tests__/OptimismWatcher.test.ts @@ -17,7 +17,7 @@ test('getFinalizedBlockNumber', async () => { test('getMessagesForBlocks', async () => { const watcher = new EVMWatcher('Mainnet', 'Optimism'); - const vaasByBlock = await watcher.getMessagesForBlocks(105235070, 105235080); + const { vaasByBlock } = await watcher.getMessagesForBlocks(105235070, 105235080); expect(vaasByBlock).toMatchObject({ '105235070/2023-06-06T16:28:37.000Z': [], '105235071/2023-06-06T16:28:39.000Z': [], diff --git a/watcher/src/watchers/__tests__/SolanaWatcher.test.ts b/watcher/src/watchers/__tests__/SolanaWatcher.test.ts index ae4c2ddb..e8e2d83f 100644 --- a/watcher/src/watchers/__tests__/SolanaWatcher.test.ts +++ b/watcher/src/watchers/__tests__/SolanaWatcher.test.ts @@ -16,7 +16,7 @@ test('getFinalizedBlockNumber', async () => { test('getMessagesForBlocks - single block', async () => { const watcher = new SolanaWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(170799004, 170799004); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(170799004, 170799004); expect(Object.keys(messages).length).toBe(1); expect(messages).toMatchObject({ '170799004/2023-01-04T16:43:43.000Z': [ @@ -32,21 +32,21 @@ test('getMessagesForBlocks - single block', async () => { // temporary skip due to SolanaJSONRPCError: failed to get confirmed block: Block 171774030 cleaned up, does not exist on node. First available block: 176896202 test('getMessagesForBlocks - fromSlot is skipped slot', async () => { const watcher = new SolanaWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(171774030, 171774032); // 171774024 - 171774031 are skipped + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(171774030, 171774032); // 171774024 - 171774031 are skipped expect(Object.keys(messages).length).toBe(1); expect(messages).toMatchObject({ '171774032/2023-01-10T13:36:39.000Z': [] }); }); test('getMessagesForBlocks - toSlot is skipped slot', async () => { const watcher = new SolanaWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(171774023, 171774025); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(171774023, 171774025); expect(messages).toMatchObject({ '171774025/2023-01-10T13:36:34.000Z': [] }); }); test('getMessagesForBlocks - empty block', async () => { // Even if there are no messages, last block should still be returned const watcher = new SolanaWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(170979766, 170979766); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(170979766, 170979766); expect(Object.keys(messages).length).toBe(1); expect(messages).toMatchObject({ '170979766/2023-01-05T18:40:25.000Z': [] }); }); @@ -58,25 +58,25 @@ test('getMessagesForBlocks - block with no transactions', async () => { 'solana: invalid block range' ); - let messages = await watcher.getMessagesForBlocks(174108661, 174108861); + let { vaasByBlock: messages } = await watcher.getMessagesForBlocks(174108661, 174108861); expect(Object.keys(messages).length).toBe(1); expect(Object.values(messages).flat().length).toBe(0); - messages = await watcher.getMessagesForBlocks(174108863, 174109061); + ({ vaasByBlock: messages } = await watcher.getMessagesForBlocks(174108863, 174109061)); expect(Object.keys(messages).length).toBe(1); expect(Object.values(messages).flat().length).toBe(0); }); test('getMessagesForBlocks - multiple blocks', async () => { const watcher = new SolanaWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(171050470, 171050474); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(171050470, 171050474); expect(Object.keys(messages).length).toBe(2); expect(Object.values(messages).flat().length).toBe(2); }); test('getMessagesForBlocks - multiple blocks, last block empty', async () => { const watcher = new SolanaWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(170823000, 170825000); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(170823000, 170825000); expect(Object.keys(messages).length).toBe(3); expect(Object.values(messages).flat().length).toBe(2); // 2 messages, last block has no message }); @@ -84,16 +84,16 @@ test('getMessagesForBlocks - multiple blocks, last block empty', async () => { test('getMessagesForBlocks - multiple blocks containing more than `getSignaturesLimit` WH transactions', async () => { const watcher = new SolanaWatcher('Mainnet'); watcher.getSignaturesLimit = 10; - const messages = await watcher.getMessagesForBlocks(171582367, 171583452); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(171582367, 171583452); expect(Object.keys(messages).length).toBe(3); expect(Object.values(messages).flat().length).toBe(3); }); test('getMessagesForBlocks - multiple calls', async () => { const watcher = new SolanaWatcher('Mainnet'); - const messages1 = await watcher.getMessagesForBlocks(171773021, 171773211); - const messages2 = await watcher.getMessagesForBlocks(171773212, 171773250); - const messages3 = await watcher.getMessagesForBlocks(171773251, 171773500); + const { vaasByBlock: messages1 } = await watcher.getMessagesForBlocks(171773021, 171773211); + const { vaasByBlock: messages2 } = await watcher.getMessagesForBlocks(171773212, 171773250); + const { vaasByBlock: messages3 } = await watcher.getMessagesForBlocks(171773251, 171773500); const allMessageKeys = [ ...Object.keys(messages1), ...Object.keys(messages2), @@ -105,7 +105,7 @@ test('getMessagesForBlocks - multiple calls', async () => { test('getMessagesForBlocks - handle failed transactions', async () => { const watcher = new SolanaWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(94401321, 94501321); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(94401321, 94501321); expect(Object.keys(messages).length).toBe(6); expect(Object.values(messages).flat().length).toBe(5); expect( diff --git a/watcher/src/watchers/__tests__/SuiWatcher.test.ts b/watcher/src/watchers/__tests__/SuiWatcher.test.ts index 074d2874..6158f66f 100644 --- a/watcher/src/watchers/__tests__/SuiWatcher.test.ts +++ b/watcher/src/watchers/__tests__/SuiWatcher.test.ts @@ -19,7 +19,7 @@ test('getFinalizedSequenceNumber', async () => { // works backwards. This will cause a 429 until we clear that up. test.skip('getMessagesForBlocks', async () => { const watcher = new SuiWatcher('Mainnet'); - const messages = await watcher.getMessagesForBlocks(1581997, 1581997); + const { vaasByBlock: messages } = await watcher.getMessagesForBlocks(1581997, 1581997); console.log(messages); const entries = Object.entries(messages); expect(entries.length).toEqual(46);