Add ValidatorAnnounce to HyperlaneCoreDeploy (#1560)

submodules-1.0.0
Asa Oines 2 years ago committed by GitHub
parent 63376c0ffb
commit c0e2c512ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      rust/agents/validator/src/submit.rs
  2. 17
      rust/config/test/test_config.json
  3. 4
      rust/hyperlane-base/src/traits/checkpoint_syncer.rs
  4. 8
      rust/hyperlane-base/src/types/local_storage.rs
  5. 12
      rust/hyperlane-base/src/types/s3_storage.rs
  6. 14
      rust/hyperlane-core/src/types/announcement.rs
  7. 25
      rust/utils/run-locally/src/main.rs
  8. 42
      typescript/infra/hardhat.config.ts
  9. 1
      typescript/infra/package.json
  10. 1
      typescript/infra/src/config/agent.ts
  11. 17
      typescript/infra/src/core/deploy.ts
  12. 27
      typescript/sdk/src/consts/environments/test.json
  13. 4
      typescript/sdk/src/core/contracts.ts
  14. 20
      typescript/sdk/src/deploy/core/HyperlaneCoreDeployer.ts

@ -46,9 +46,10 @@ impl ValidatorSubmitter {
async fn main_task(self) -> Result<()> { async fn main_task(self) -> Result<()> {
// Sign and post the validator announcement // Sign and post the validator announcement
let announcement = Announcement { let announcement = Announcement {
validator: self.signer.eth_address(),
mailbox_address: self.mailbox.address(), mailbox_address: self.mailbox.address(),
mailbox_domain: self.mailbox.domain().id(), mailbox_domain: self.mailbox.domain().id(),
storage_metadata: self.checkpoint_syncer.announcement_metadata(), storage_location: self.checkpoint_syncer.announcement_location(),
}; };
let signed_announcement = self.signer.sign(announcement).await?; let signed_announcement = self.signer.sign(announcement).await?;
self.checkpoint_syncer self.checkpoint_syncer

@ -6,7 +6,8 @@
"domain": "13371", "domain": "13371",
"addresses": { "addresses": {
"mailbox": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", "mailbox": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853",
"interchainGasPaymaster": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" "interchainGasPaymaster": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707",
"validatorAnnounce": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6"
}, },
"signer": null, "signer": null,
"protocol": "ethereum", "protocol": "ethereum",
@ -23,8 +24,9 @@
"name": "test2", "name": "test2",
"domain": "13372", "domain": "13372",
"addresses": { "addresses": {
"mailbox": "0x0B306BF915C4d645ff596e518fAf3F9669b97016", "mailbox": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1",
"interchainGasPaymaster": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82" "interchainGasPaymaster": "0x9A676e781A523b5d0C0e43731313A708CB607508",
"validatorAnnounce": "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE"
}, },
"signer": null, "signer": null,
"protocol": "ethereum", "protocol": "ethereum",
@ -34,15 +36,16 @@
"url": "" "url": ""
}, },
"index": { "index": {
"from": "12" "from": "13"
} }
}, },
"test3": { "test3": {
"name": "test3", "name": "test3",
"domain": "13373", "domain": "13373",
"addresses": { "addresses": {
"mailbox": "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44", "mailbox": "0x4A679253410272dd5232B3Ff7cF5dbB88f295319",
"interchainGasPaymaster": "0x59b670e9fA9D0A427751Af201D676719a970857b" "interchainGasPaymaster": "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44",
"validatorAnnounce": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F"
}, },
"signer": null, "signer": null,
"protocol": "ethereum", "protocol": "ethereum",
@ -52,7 +55,7 @@
"url": "" "url": ""
}, },
"index": { "index": {
"from": "20" "from": "23"
} }
} }
}, },

@ -16,6 +16,6 @@ pub trait CheckpointSyncer: Debug + Send + Sync {
async fn write_checkpoint(&self, signed_checkpoint: &SignedCheckpoint) -> Result<()>; async fn write_checkpoint(&self, signed_checkpoint: &SignedCheckpoint) -> Result<()>;
/// Write the signed announcement to this syncer /// Write the signed announcement to this syncer
async fn write_announcement(&self, signed_announcement: &SignedAnnouncement) -> Result<()>; async fn write_announcement(&self, signed_announcement: &SignedAnnouncement) -> Result<()>;
/// Return the announcement storage metadata for this syncer /// Return the announcement storage location for this syncer
fn announcement_metadata(&self) -> String; fn announcement_location(&self) -> String;
} }

@ -101,9 +101,9 @@ impl CheckpointSyncer for LocalStorage {
Ok(()) Ok(())
} }
fn announcement_metadata(&self) -> String { fn announcement_location(&self) -> String {
let mut metadata: String = "file://".to_owned(); let mut location: String = "file://".to_owned();
metadata.push_str(self.announcement_file_path().as_ref()); location.push_str(self.announcement_file_path().as_ref());
metadata location
} }
} }

@ -188,11 +188,11 @@ impl CheckpointSyncer for S3Storage {
.await?; .await?;
Ok(()) Ok(())
} }
fn announcement_metadata(&self) -> String { fn announcement_location(&self) -> String {
let mut metadata: String = "s3://".to_owned(); let mut location: String = "s3://".to_owned();
metadata.push_str(self.bucket.as_ref()); location.push_str(self.bucket.as_ref());
metadata.push('/'); location.push('/');
metadata.push_str(self.region.name()); location.push_str(self.region.name());
metadata location
} }
} }

@ -2,25 +2,27 @@ use async_trait::async_trait;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha3::{digest::Update, Digest, Keccak256}; use sha3::{digest::Update, Digest, Keccak256};
use crate::{utils::domain_hash, Signable, SignedType, H256}; use crate::{utils::domain_hash, Signable, SignedType, H160, H256};
/// An Hyperlane checkpoint /// An Hyperlane checkpoint
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Announcement { pub struct Announcement {
/// The validator address
pub validator: H160,
/// The mailbox address /// The mailbox address
pub mailbox_address: H256, pub mailbox_address: H256,
/// The mailbox chain /// The mailbox chain
pub mailbox_domain: u32, pub mailbox_domain: u32,
/// The checkpointed root /// The location of signed checkpoints
pub storage_metadata: String, pub storage_location: String,
} }
impl std::fmt::Display for Announcement { impl std::fmt::Display for Announcement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!( write!(
f, f,
"Announcement(domain: {}, mailbox: {:x}, metadata: {})", "Announcement(domain: {}, mailbox: {:x}, location: {})",
self.mailbox_domain, self.mailbox_address, self.storage_metadata self.mailbox_domain, self.mailbox_address, self.storage_location
) )
} }
} }
@ -33,7 +35,7 @@ impl Signable for Announcement {
H256::from_slice( H256::from_slice(
Keccak256::new() Keccak256::new()
.chain(domain_hash(self.mailbox_address, self.mailbox_domain)) .chain(domain_hash(self.mailbox_address, self.mailbox_domain))
.chain(&self.storage_metadata) .chain(&self.storage_location)
.finalize() .finalize()
.as_slice(), .as_slice(),
) )

@ -313,6 +313,31 @@ fn main() -> ExitCode {
})); }));
state.validator = Some(validator); state.validator = Some(validator);
// Rebuild the SDK to pick up the deployed contracts
println!("Rebuilding sdk...");
build_cmd(
&["yarn", "build"],
&build_log,
log_all,
Some("../typescript/sdk"),
);
// Register the validator announcement
println!("Announcing validator...");
let mut announce = Command::new("yarn");
announce.arg("announce");
announce.args([
"--checkpointsdir",
checkpoints_dir.path().to_str().unwrap(),
"--chain",
"test1",
]);
announce
.current_dir("../typescript/infra")
.stdout(Stdio::piped())
.spawn()
.expect("Failed to announce validator");
println!("Setup complete! Agents running in background..."); println!("Setup complete! Agents running in background...");
println!("Ctrl+C to end execution..."); println!("Ctrl+C to end execution...");

@ -1,7 +1,10 @@
import '@nomiclabs/hardhat-etherscan'; import '@nomiclabs/hardhat-etherscan';
import '@nomiclabs/hardhat-waffle'; import '@nomiclabs/hardhat-waffle';
import { ethers } from 'ethers';
import { readFileSync } from 'fs';
import { task } from 'hardhat/config'; import { task } from 'hardhat/config';
import { HardhatRuntimeEnvironment } from 'hardhat/types'; import { HardhatRuntimeEnvironment } from 'hardhat/types';
import * as path from 'path';
import { TestSendReceiver__factory } from '@hyperlane-xyz/core'; import { TestSendReceiver__factory } from '@hyperlane-xyz/core';
import { import {
@ -35,6 +38,45 @@ const chainSummary = async <Chain extends ChainName>(
return summary; return summary;
}; };
task('announce', 'Registers validator announcement')
.addParam('checkpointsdir', 'Directory containing announcement json file')
.addParam('chain', 'Chain to announce on')
.setAction(
async (
taskArgs: { checkpointsdir: string; chain: ChainName },
hre: HardhatRuntimeEnvironment,
) => {
const environment = 'test';
const config = getCoreEnvironmentConfig(environment);
const [signer] = await hre.ethers.getSigners();
const multiProvider = getTestMultiProvider(
signer,
config.transactionConfigs,
);
const core = HyperlaneCore.fromEnvironment(environment, multiProvider);
const announcementFilepath = path.join(
taskArgs.checkpointsdir,
'announcement.json',
);
const announcement = JSON.parse(
readFileSync(announcementFilepath, 'utf-8'),
);
const signature = ethers.utils.hexConcat([
announcement.signature.r,
announcement.signature.s,
ethers.utils.hexValue(announcement.signature.v),
]);
const tx = await core
.getContracts(taskArgs.chain)
.validatorAnnounce.announce(
announcement.announcement.validator,
announcement.announcement.storage_location,
signature,
);
await tx.wait();
},
);
task('kathy', 'Dispatches random hyperlane messages') task('kathy', 'Dispatches random hyperlane messages')
.addParam( .addParam(
'rounds', 'rounds',

@ -62,6 +62,7 @@
"clean": "rm -rf ./dist ./cache", "clean": "rm -rf ./dist ./cache",
"check": "tsc --noEmit", "check": "tsc --noEmit",
"kathy": "hardhat kathy --network localhost", "kathy": "hardhat kathy --network localhost",
"announce": "hardhat announce --network localhost",
"node": "hardhat node", "node": "hardhat node",
"prettier": "prettier --write *.ts ./src ./config ./scripts ./test", "prettier": "prettier --write *.ts ./src ./config ./scripts ./test",
"test": "hardhat test" "test": "hardhat test"

@ -251,6 +251,7 @@ export type RustConnection =
export type RustCoreAddresses = { export type RustCoreAddresses = {
mailbox: types.Address; mailbox: types.Address;
interchainGasPaymaster: types.Address; interchainGasPaymaster: types.Address;
validatorAnnounce: types.Address;
}; };
export type RustChainSetup = { export type RustChainSetup = {

@ -4,6 +4,7 @@ import {
InterchainGasPaymaster, InterchainGasPaymaster,
Mailbox, Mailbox,
ProxyAdmin, ProxyAdmin,
ValidatorAnnounce,
} from '@hyperlane-xyz/core'; } from '@hyperlane-xyz/core';
import { import {
ChainMap, ChainMap,
@ -70,6 +71,19 @@ export class HyperlaneCoreInfraDeployer<
); );
} }
async deployValidatorAnnounce<LocalChain extends Chain>(
chain: LocalChain,
mailboxAddress: types.Address,
): Promise<ValidatorAnnounce> {
const deployOpts = {
create2Salt: ethers.utils.solidityKeccak256(
['string', 'string', 'uint8'],
[this.environment, 'validatorAnnounce', 1],
),
};
return super.deployValidatorAnnounce(chain, mailboxAddress, deployOpts);
}
writeRustConfigs(directory: string) { writeRustConfigs(directory: string) {
const rustConfig: RustConfig<Chain> = { const rustConfig: RustConfig<Chain> = {
environment: this.environment, environment: this.environment,
@ -88,7 +102,7 @@ export class HyperlaneCoreInfraDeployer<
contracts == undefined || contracts == undefined ||
contracts.mailbox == undefined || contracts.mailbox == undefined ||
contracts.interchainGasPaymaster == undefined || contracts.interchainGasPaymaster == undefined ||
contracts.multisigIsm == undefined contracts.validatorAnnounce == undefined
) { ) {
return; return;
} }
@ -99,6 +113,7 @@ export class HyperlaneCoreInfraDeployer<
addresses: { addresses: {
mailbox: contracts.mailbox.contract.address, mailbox: contracts.mailbox.contract.address,
interchainGasPaymaster: contracts.interchainGasPaymaster.address, interchainGasPaymaster: contracts.interchainGasPaymaster.address,
validatorAnnounce: contracts.validatorAnnounce.address,
}, },
signer: null, signer: null,
protocol: 'ethereum', protocol: 'ethereum',

@ -1,5 +1,6 @@
{ {
"test1": { "test1": {
"validatorAnnounce": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6",
"proxyAdmin": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", "proxyAdmin": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9",
"interchainGasPaymaster": { "interchainGasPaymaster": {
"kind": "Transparent", "kind": "Transparent",
@ -14,31 +15,33 @@
"multisigIsm": "0x5FbDB2315678afecb367f032d93F642f64180aa3" "multisigIsm": "0x5FbDB2315678afecb367f032d93F642f64180aa3"
}, },
"test2": { "test2": {
"proxyAdmin": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e", "validatorAnnounce": "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE",
"proxyAdmin": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0",
"interchainGasPaymaster": { "interchainGasPaymaster": {
"kind": "Transparent", "kind": "Transparent",
"proxy": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82", "proxy": "0x9A676e781A523b5d0C0e43731313A708CB607508",
"implementation": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0" "implementation": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82"
}, },
"mailbox": { "mailbox": {
"kind": "Transparent", "kind": "Transparent",
"proxy": "0x0B306BF915C4d645ff596e518fAf3F9669b97016", "proxy": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1",
"implementation": "0x9A676e781A523b5d0C0e43731313A708CB607508" "implementation": "0x0B306BF915C4d645ff596e518fAf3F9669b97016"
}, },
"multisigIsm": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" "multisigIsm": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318"
}, },
"test3": { "test3": {
"proxyAdmin": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c", "validatorAnnounce": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F",
"proxyAdmin": "0x59b670e9fA9D0A427751Af201D676719a970857b",
"interchainGasPaymaster": { "interchainGasPaymaster": {
"kind": "Transparent", "kind": "Transparent",
"proxy": "0x59b670e9fA9D0A427751Af201D676719a970857b", "proxy": "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44",
"implementation": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d" "implementation": "0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1"
}, },
"mailbox": { "mailbox": {
"kind": "Transparent", "kind": "Transparent",
"proxy": "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44", "proxy": "0x4A679253410272dd5232B3Ff7cF5dbB88f295319",
"implementation": "0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1" "implementation": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f"
}, },
"multisigIsm": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1" "multisigIsm": "0x68B1D87F95878fE05B998F19b66F4baba5De1aed"
} }
} }

@ -10,6 +10,8 @@ import {
MultisigIsm__factory, MultisigIsm__factory,
ProxyAdmin, ProxyAdmin,
ProxyAdmin__factory, ProxyAdmin__factory,
ValidatorAnnounce,
ValidatorAnnounce__factory,
} from '@hyperlane-xyz/core'; } from '@hyperlane-xyz/core';
import { ProxiedContract, TransparentProxyAddresses } from '../proxy'; import { ProxiedContract, TransparentProxyAddresses } from '../proxy';
@ -25,11 +27,13 @@ export type CoreContracts = ConnectionClientContracts & {
mailbox: ProxiedContract<Mailbox, TransparentProxyAddresses>; mailbox: ProxiedContract<Mailbox, TransparentProxyAddresses>;
multisigIsm: MultisigIsm; multisigIsm: MultisigIsm;
proxyAdmin: ProxyAdmin; proxyAdmin: ProxyAdmin;
validatorAnnounce: ValidatorAnnounce;
}; };
export const coreFactories = { export const coreFactories = {
interchainAccountRouter: new InterchainAccountRouter__factory(), interchainAccountRouter: new InterchainAccountRouter__factory(),
interchainQueryRouter: new InterchainQueryRouter__factory(), interchainQueryRouter: new InterchainQueryRouter__factory(),
validatorAnnounce: new ValidatorAnnounce__factory(),
create2Factory: new Create2Factory__factory(), create2Factory: new Create2Factory__factory(),
proxyAdmin: new ProxyAdmin__factory(), proxyAdmin: new ProxyAdmin__factory(),
interchainGasPaymaster: new InterchainGasPaymaster__factory(), interchainGasPaymaster: new InterchainGasPaymaster__factory(),

@ -7,6 +7,7 @@ import {
MultisigIsm, MultisigIsm,
Ownable, Ownable,
ProxyAdmin, ProxyAdmin,
ValidatorAnnounce,
} from '@hyperlane-xyz/core'; } from '@hyperlane-xyz/core';
import type { types } from '@hyperlane-xyz/utils'; import type { types } from '@hyperlane-xyz/utils';
@ -79,6 +80,20 @@ export class HyperlaneCoreDeployer<
return mailbox; return mailbox;
} }
async deployValidatorAnnounce<LocalChain extends Chain>(
chain: LocalChain,
mailboxAddress: string,
deployOpts?: DeployOptions,
): Promise<ValidatorAnnounce> {
const validatorAnnounce = await this.deployContract(
chain,
'validatorAnnounce',
[mailboxAddress],
deployOpts,
);
return validatorAnnounce;
}
async deployMultisigIsm<LocalChain extends Chain>( async deployMultisigIsm<LocalChain extends Chain>(
chain: LocalChain, chain: LocalChain,
): Promise<MultisigIsm> { ): Promise<MultisigIsm> {
@ -173,11 +188,16 @@ export class HyperlaneCoreDeployer<
multisigIsm.address, multisigIsm.address,
proxyAdmin, proxyAdmin,
); );
const validatorAnnounce = await this.deployValidatorAnnounce(
chain,
mailbox.address,
);
// Mailbox ownership is transferred upon initialization. // Mailbox ownership is transferred upon initialization.
const ownables: Ownable[] = [multisigIsm, proxyAdmin]; const ownables: Ownable[] = [multisigIsm, proxyAdmin];
await this.transferOwnershipOfContracts(chain, ownables); await this.transferOwnershipOfContracts(chain, ownables);
return { return {
validatorAnnounce,
proxyAdmin, proxyAdmin,
interchainGasPaymaster, interchainGasPaymaster,
mailbox, mailbox,

Loading…
Cancel
Save