feat(cli): Add avs validator status command (#4056)
### Description <!-- What's included in this PR? --> - Command to check all operators on our AVS and show the chains that they are validating on - Already been reviewed here https://github.com/hyperlane-xyz/hyperlane-monorepo/pull/4004, this PR was to merge it main instead of cli-2.0 Example usage: ``` yarn hyperlane avs check --chain ethereum --registry $REGISTRY Hyperlane CLI Checking AVS validator status for ethereum, this may take up to a minute to run... ❗️ MerkleTreeHook is not deployed on anvil8545 Operator name: Abacus Works AVS Operator Operator address: 0xFe114FcC7609578f525219a8eF77e2CCe27C5357 Validator address: 0x03c842db86A6A3E524D4a6615390c1Ea8E2b9541 Validating on... ethereum Storage location: s3://hyperlane-mainnet3-ethereum-validator-0/us-east-1 Latest merkle tree checkpoint index: 8219 Latest validator checkpoint index: 8219 ✅ Validator is signing latest checkpoint Operator name: Kelp by Kiln Operator address: 0x96fC0751e0febe7296d4625500f8e4535a002c7d Validator address: 0xEa5f21513182e97D0169a4d2E7aC71Ae8827F5bC Validating on... ethereum Storage location: s3://kiln-mainnet-hyperlane-validator-signatures/eu-west-1/ethereum Latest merkle tree checkpoint index: 8219 ❌ Failed to fetch latest signed checkpoint index The following warnings were encountered: ❗️ Failed to fetch latest signed checkpoint index of validator on ethereum, this is likely due to failing to read an S3 bucket ``` ### Drive-by changes <!-- Are there any minor or drive-by changes also included? --> ### Related issues <!-- - Fixes #[issue number here] --> - Fixes #3976 ### Backward compatibility <!-- Are these changes backward compatible? Are there any infrastructure implications, e.g. changes that would prohibit deploying older commits using this infra tooling? Yes/No --> No ### Testing <!-- What kind of testing have these changes undergone? None/Manual/Unit Tests --> Manualpull/4034/head
parent
aecb65a986
commit
44cc9bf6b3
@ -0,0 +1,6 @@ |
||||
--- |
||||
'@hyperlane-xyz/cli': minor |
||||
'@hyperlane-xyz/core': minor |
||||
--- |
||||
|
||||
Add CLI command to support AVS validator status check |
@ -0,0 +1,69 @@ |
||||
import { MerkleTreeHook, ValidatorAnnounce } from '@hyperlane-xyz/core'; |
||||
import { S3Validator } from '@hyperlane-xyz/sdk'; |
||||
|
||||
import { logDebug } from '../logger.js'; |
||||
|
||||
export const getLatestMerkleTreeCheckpointIndex = async ( |
||||
merkleTreeHook: MerkleTreeHook, |
||||
chainName?: string, |
||||
): Promise<number | undefined> => { |
||||
try { |
||||
const [_, latestCheckpointIndex] = await merkleTreeHook.latestCheckpoint(); |
||||
return latestCheckpointIndex; |
||||
} catch (err) { |
||||
const debugMessage = `Failed to get latest checkpoint index from merkleTreeHook contract ${ |
||||
chainName ? `on ${chainName}` : '' |
||||
} : ${err}`;
|
||||
logDebug(debugMessage); |
||||
return undefined; |
||||
} |
||||
}; |
||||
|
||||
export const getValidatorStorageLocations = async ( |
||||
validatorAnnounce: ValidatorAnnounce, |
||||
validators: string[], |
||||
chainName?: string, |
||||
): Promise<string[][] | undefined> => { |
||||
try { |
||||
return await validatorAnnounce.getAnnouncedStorageLocations(validators); |
||||
} catch (err) { |
||||
const debugMessage = `Failed to get announced storage locations from validatorAnnounce contract ${ |
||||
chainName ? `on ${chainName}` : '' |
||||
} : ${err}`;
|
||||
logDebug(debugMessage); |
||||
return undefined; |
||||
} |
||||
}; |
||||
|
||||
export const getLatestValidatorCheckpointIndexAndUrl = async ( |
||||
s3StorageLocation: string, |
||||
): Promise<[number, string] | undefined> => { |
||||
let s3Validator: S3Validator; |
||||
try { |
||||
s3Validator = await S3Validator.fromStorageLocation(s3StorageLocation); |
||||
} catch (err) { |
||||
logDebug( |
||||
`Failed to instantiate S3Validator at location ${s3StorageLocation}: ${err}`, |
||||
); |
||||
return undefined; |
||||
} |
||||
try { |
||||
const latestCheckpointIndex = await s3Validator.getLatestCheckpointIndex(); |
||||
return [latestCheckpointIndex, s3Validator.getLatestCheckpointUrl()]; |
||||
} catch (err) { |
||||
logDebug( |
||||
`Failed to get latest checkpoint index from S3Validator at location ${s3StorageLocation}: ${err}`, |
||||
); |
||||
return undefined; |
||||
} |
||||
}; |
||||
|
||||
export const isValidatorSigningLatestCheckpoint = ( |
||||
latestValidatorCheckpointIndex: number, |
||||
latestMerkleTreeCheckpointIndex: number, |
||||
): boolean => { |
||||
const diff = Math.abs( |
||||
latestValidatorCheckpointIndex - latestMerkleTreeCheckpointIndex, |
||||
); |
||||
return diff < latestMerkleTreeCheckpointIndex / 100; |
||||
}; |
Loading…
Reference in new issue