Skip to content

Commit

Permalink
fix: Google Cloud Storage CheckpointSyncer checker implementation (#4971
Browse files Browse the repository at this point in the history
)

### Description

The current CLI command `hyperlane avs check` only checks when storage
location starts with `s3://`

This PR allow to retrieve and check the validator state on Google Cloud
Storage - when storage location starts with `gs://`

### Drive-by changes

* Use the latest location set during Validator registration & retrieve
it from ValidatorAnnounce.getAnnouncedStorageLocations

### Related issues

* None

### Backward compatibility

* Yes

### Testing

* Manual using locally compiled `yarn hyperlane avs check` command

Before

```bash
Operator name: Born to be wild
Operator address: 0xd38d980188604c7051dbce2980a0c6e38423fda4
Validator address: 0x58a607f46a481c9e5209ab27f45189411fA83D41
Validator is not validating on any chain
```

After

```bash
Operator name: Born to be wild
Operator address: 0xd38d980188604c7051dbce2980a0c6e38423fda4
Validator address: 0x58a607f46a481c9e5209ab27f45189411fA83D41
  Validating on...
  base
  Storage location: https://storage.googleapis.com/hyperlane_2pa2pyhawbcl35nnfr079f50iy7/gcsLatestIndexKey
  Latest merkle tree checkpoint index: 992526
  Latest validator checkpoint index: 992525
  ✅ Validator is signing latest checkpoint
  optimism
  Storage location: https://storage.googleapis.com/hyperlane_2okiqlhes2ki6lfsgsa0qlzaclx/gcsLatestIndexKey
  Latest merkle tree checkpoint index: 654920
  Latest validator checkpoint index: 654920
  ✅ Validator is signing latest checkpoint
```
  • Loading branch information
maximegris authored Dec 20, 2024
1 parent 70d9526 commit 1f2945b
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 19 deletions.
24 changes: 14 additions & 10 deletions typescript/cli/src/avs/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import {
MerkleTreeHook__factory,
ValidatorAnnounce__factory,
} from '@hyperlane-xyz/core';
import { ChainMap, ChainName, MultiProvider } from '@hyperlane-xyz/sdk';
import {
ChainMap,
ChainName,
MultiProvider,
isValidValidatorStorageLocation,
} from '@hyperlane-xyz/sdk';
import { Address, ProtocolType, isObjEmpty } from '@hyperlane-xyz/utils';

import { CommandContext } from '../context/types.js';
Expand Down Expand Up @@ -288,19 +293,18 @@ const setValidatorInfo = async (
const storageLocation = validatorStorageLocations[i];
const warnings: string[] = [];

// Skip if no storage location is found, address is not validating on this chain or if storage location string doesn't not start with s3://
if (
storageLocation.length === 0 ||
!storageLocation[0].startsWith('s3://')
) {
const lastStorageLocation =
storageLocation.length > 0 ? storageLocation.slice(-1)[0] : '';

// Skip if no storage location is found, address is not validating on this chain or if not a valid storage location
if (!isValidValidatorStorageLocation(lastStorageLocation)) {
continue;
}

const [latestValidatorCheckpointIndex, latestCheckpointUrl] =
(await getLatestValidatorCheckpointIndexAndUrl(storageLocation[0])) ?? [
undefined,
undefined,
];
(await getLatestValidatorCheckpointIndexAndUrl(
lastStorageLocation,
)) ?? [undefined, undefined];

if (!latestMerkleTreeCheckpointIndex) {
warnings.push(
Expand Down
17 changes: 9 additions & 8 deletions typescript/cli/src/validator/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { MerkleTreeHook, ValidatorAnnounce } from '@hyperlane-xyz/core';
import { S3Validator } from '@hyperlane-xyz/sdk';
import { getValidatorFromStorageLocation } from '@hyperlane-xyz/sdk';
import { BaseValidator } from '@hyperlane-xyz/utils';

import { logDebug } from '../logger.js';

Expand Down Expand Up @@ -36,23 +37,23 @@ export const getValidatorStorageLocations = async (
};

export const getLatestValidatorCheckpointIndexAndUrl = async (
s3StorageLocation: string,
storageLocation: string,
): Promise<[number, string] | undefined> => {
let s3Validator: S3Validator;
let validator: BaseValidator;
try {
s3Validator = await S3Validator.fromStorageLocation(s3StorageLocation);
validator = await getValidatorFromStorageLocation(storageLocation);
} catch (err) {
logDebug(
`Failed to instantiate S3Validator at location ${s3StorageLocation}: ${err}`,
`Failed to instantiate Validator at location ${storageLocation}: ${err}`,
);
return undefined;
}
try {
const latestCheckpointIndex = await s3Validator.getLatestCheckpointIndex();
return [latestCheckpointIndex, s3Validator.getLatestCheckpointUrl()];
const latestCheckpointIndex = await validator.getLatestCheckpointIndex();
return [latestCheckpointIndex, validator.getLatestCheckpointUrl()];
} catch (err) {
logDebug(
`Failed to get latest checkpoint index from S3Validator at location ${s3StorageLocation}: ${err}`,
`Failed to get latest checkpoint index from Validator at location ${storageLocation}: ${err}`,
);
return undefined;
}
Expand Down
5 changes: 4 additions & 1 deletion typescript/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,10 @@ export {
getSealevelAccountDataSchema,
} from './utils/sealevelSerialization.js';
export { getChainIdFromTxs } from './utils/transactions.js';
export { getValidatorFromStorageLocation } from './utils/validator.js';
export {
getValidatorFromStorageLocation,
isValidValidatorStorageLocation,
} from './utils/validator.js';
export {
FeeConstantConfig,
RouteBlacklist,
Expand Down
7 changes: 7 additions & 0 deletions typescript/sdk/src/utils/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,10 @@ export async function getValidatorFromStorageLocation(location: string) {
throw new Error('Invalid storage location');
}
}

export function isValidValidatorStorageLocation(location: string) {
return (
location?.startsWith(GCP_LOCATION_PREFIX) ||
location?.startsWith(S3_LOCATION_PREFIX)
);
}
12 changes: 12 additions & 0 deletions typescript/utils/src/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,16 @@ export class BaseValidator {
);
return eqAddress(address, this.config.address);
}

getLatestCheckpointIndex(): Promise<number> {
throw new Error('Not implemented');
}

storageLocation(): string {
throw new Error('Not implemented');
}

getLatestCheckpointUrl(): string {
throw new Error('Not implemented');
}
}

0 comments on commit 1f2945b

Please sign in to comment.