diff --git a/cloud_functions/scripts/deploy.sh b/cloud_functions/scripts/deploy.sh index e41ddeda..0abaab73 100755 --- a/cloud_functions/scripts/deploy.sh +++ b/cloud_functions/scripts/deploy.sh @@ -139,7 +139,7 @@ gcloud functions deploy compute-message-counts --entry-point computeMessageCount gcloud functions deploy latest-blocks --entry-point getLatestBlocks --runtime nodejs16 --trigger-http --allow-unauthenticated --timeout 300 --memory 256MB --region europe-west3 --set-env-vars CLOUD_FUNCTIONS_REFRESH_TIME_INTERVAL=$CLOUD_FUNCTIONS_REFRESH_TIME_INTERVAL,FIRESTORE_LATEST_COLLECTION=$FIRESTORE_LATEST_COLLECTION gcloud functions deploy compute-missing-vaas --entry-point computeMissingVaas --runtime nodejs16 --trigger-http --allow-unauthenticated --timeout 300 --memory 2GB --region europe-west3 --set-env-vars BIGTABLE_TABLE_ID=$BIGTABLE_TABLE_ID,BIGTABLE_INSTANCE_ID=$BIGTABLE_INSTANCE_ID,CLOUD_FUNCTIONS_REFRESH_TIME_INTERVAL=$CLOUD_FUNCTIONS_REFRESH_TIME_INTERVAL gcloud functions deploy missing-vaas --entry-point getMissingVaas --runtime nodejs16 --trigger-http --allow-unauthenticated --timeout 300 --memory 256MB --region europe-west3 -gcloud functions deploy alarm-missing-vaas --entry-point alarmMissingVaas --runtime nodejs16 --trigger-http --no-allow-unauthenticated --timeout 300 --memory 256MB --region europe-west3 --set-env-vars SLACK_CHANNEL_ID=$SLACK_CHANNEL_ID,SLACK_POST_URL=$SLACK_POST_URL,SLACK_BOT_TOKEN=$SLACK_BOT_TOKEN,FIRESTORE_ALARM_MISSING_VAAS_COLLECTION=$FIRESTORE_ALARM_MISSING_VAAS_COLLECTION +gcloud functions deploy alarm-missing-vaas --entry-point alarmMissingVaas --runtime nodejs16 --trigger-http --no-allow-unauthenticated --timeout 300 --memory 256MB --region europe-west3 --set-env-vars SLACK_CHANNEL_ID=$SLACK_CHANNEL_ID,SLACK_POST_URL=$SLACK_POST_URL,SLACK_BOT_TOKEN=$SLACK_BOT_TOKEN,FIRESTORE_ALARM_MISSING_VAAS_COLLECTION=$FIRESTORE_ALARM_MISSING_VAAS_COLLECTION,FIRESTORE_GOVERNOR_STATUS_COLLECTION=$FIRESTORE_GOVERNOR_STATUS_COLLECTION gcloud functions deploy vaas-by-tx-hash --entry-point getVaasByTxHash --runtime nodejs16 --trigger-http --allow-unauthenticated --timeout 300 --memory 256MB --region europe-west3 --set-env-vars BIGTABLE_INSTANCE_ID=$BIGTABLE_INSTANCE_ID,BIGTABLE_SIGNED_VAAS_TABLE_ID=$BIGTABLE_SIGNED_VAAS_TABLE_ID,BIGTABLE_VAAS_BY_TX_HASH_TABLE_ID=$BIGTABLE_VAAS_BY_TX_HASH_TABLE_ID gcloud functions deploy process-vaa --entry-point processVaa --runtime nodejs16 --timeout 300 --memory 256MB --region europe-west3 --trigger-topic $PUBSUB_SIGNED_VAA_TOPIC --set-env-vars BIGTABLE_INSTANCE_ID=$BIGTABLE_INSTANCE_ID,BIGTABLE_SIGNED_VAAS_TABLE_ID=$BIGTABLE_SIGNED_VAAS_TABLE_ID,BIGTABLE_VAAS_BY_TX_HASH_TABLE_ID=$BIGTABLE_VAAS_BY_TX_HASH_TABLE_ID,PG_USER=$PG_USER,PG_PASSWORD=$PG_PASSWORD,PG_DATABASE=$PG_DATABASE,PG_HOST=$PG_HOST,PG_TOKEN_TRANSFER_TABLE=$PG_TOKEN_TRANSFER_TABLE,PG_ATTEST_MESSAGE_TABLE=$PG_ATTEST_MESSAGE_TABLE,PG_TOKEN_METADATA_TABLE=$PG_TOKEN_METADATA_TABLE gcloud functions deploy refresh-todays-token-prices --entry-point refreshTodaysTokenPrices --runtime nodejs16 --trigger-http --no-allow-unauthenticated --timeout 300 --memory 256MB --region europe-west3 --set-env-vars PG_USER=$PG_USER,PG_PASSWORD=$PG_PASSWORD,PG_DATABASE=$PG_DATABASE,PG_HOST=$PG_HOST,PG_TOKEN_METADATA_TABLE=$PG_TOKEN_METADATA_TABLE,PG_TOKEN_PRICE_HISTORY_TABLE=$PG_TOKEN_PRICE_HISTORY_TABLE diff --git a/cloud_functions/src/alarmMissingVaas.ts b/cloud_functions/src/alarmMissingVaas.ts index db93f82d..050d85fc 100644 --- a/cloud_functions/src/alarmMissingVaas.ts +++ b/cloud_functions/src/alarmMissingVaas.ts @@ -5,6 +5,35 @@ import { ObservedMessage } from './types'; import { explorerBlock, explorerTx } from '@wormhole-foundation/wormhole-monitor-common'; import { Firestore } from 'firebase-admin/firestore'; +interface EnqueuedVAAResponse { + sequence: string; + releaseTime: number; + notionalValue: string; + txHash: string; +} + +interface Emitter { + emitterAddress: string; + enqueuedVaas: EnqueuedVAAResponse[]; + totalEnqueuedVaas: string; +} + +interface ChainStatus { + availableNotional: string; + chainId: number; + emitters: Emitter[]; +} + +interface GovernedVAA { + chainId: number; + emitterAddress: string; + sequence: string; + txHash: string; +} + +// The key is the vaaKey +type GovernedVAAMap = Map; + export async function alarmMissingVaas(req: any, res: any) { res.set('Access-Control-Allow-Origin', '*'); if (req.method === 'OPTIONS') { @@ -26,6 +55,9 @@ export async function alarmMissingVaas(req: any, res: any) { firestoreVAAs.push(vaa); }); + // Get governed VAAS + const governedVAAs: GovernedVAAMap = await getGovernedVaas(); + // attempting to retrieve missing VAAs... const messages: MissingVaasByChain = await commonGetMissingVaas(); if (messages) { @@ -42,7 +74,7 @@ export async function alarmMissingVaas(req: any, res: any) { const msg: ObservedMessage = msgs.messages[i]; if (msg.timestamp < twoHoursAgo) { let vaaKey: string = `${msg.chain}/${msg.emitter}/${msg.seq}`; - if (!firestoreMap.has(vaaKey)) { + if (!firestoreMap.has(vaaKey) && !governedVAAs.has(vaaKey)) { let firestoreMsg: FirestoreVAA = convert(msg); firestoreMap.set(vaaKey, firestoreMsg); firestoreVAAs.push(firestoreMsg); @@ -64,6 +96,44 @@ export async function alarmMissingVaas(req: any, res: any) { return; } +// This function gets all the enqueued VAAs from he governorStatus collection. +async function getGovernedVaas(): Promise { + const vaas: GovernedVAAMap = new Map(); + // Walk all the guardians and retrieve the enqueued VAAs + const firestore = new Firestore(); + const collection = firestore.collection( + assertEnvironmentVariable('FIRESTORE_GOVERNOR_STATUS_COLLECTION') + ); + const snapshot = await collection.get(); + snapshot.forEach(async (doc) => { + const data = doc.data(); + if (data) { + // data should be a ChainStatus[] + const chains: ChainStatus[] = data.chains; + chains.forEach((chain) => { + // chain should be a ChainStatus + const emitters: Emitter[] = chain.emitters; + emitters.forEach((emitter) => { + // emitter should be an Emitter + const enqueuedVaas: EnqueuedVAAResponse[] = emitter.enqueuedVaas; + enqueuedVaas.forEach((vaa) => { + // vaa should be an EnqueuedVAAResponse + const governedVAA: GovernedVAA = { + chainId: chain.chainId, + emitterAddress: emitter.emitterAddress, + sequence: vaa.sequence, + txHash: vaa.txHash, + }; + const key = `${chain.chainId}/${emitter.emitterAddress}/${vaa.sequence}`; + vaas.set(key, governedVAA); + }); + }); + }); + } + }); + return vaas; +} + // This function gets all the VAAs in the firestore table, // checks the timestamp (keeping any that are less than 2 hours old), // and returns a map of those VAAs.