From f04959a57b5e704f32e2f457ea275ae5cbdbc36d Mon Sep 17 00:00:00 2001 From: Nam Chu Hoai Date: Tue, 15 Mar 2022 16:09:16 -0400 Subject: [PATCH] Support local deploys for agent development (#234) * Support local deploys for agent development * Write out base db path * PR review --- rust/config/local/alfajores_config.json | 68 +++++++++++++++++++ rust/config/local/fuji_config.json | 68 +++++++++++++++++++ rust/config/local/kovan_config.json | 68 +++++++++++++++++++ rust/config/local/mumbai_config.json | 68 +++++++++++++++++++ .../config/environments/local/agent.ts | 17 +++++ .../abacus-deploy/config/networks/testnets.ts | 4 +- typescript/abacus-deploy/hardhat.config.ts | 1 + .../abacus-deploy/scripts/create-keys.ts | 14 ++++ .../abacus-deploy/scripts/delete-keys.ts | 14 ++++ .../abacus-deploy/scripts/dev/create-keys.ts | 12 ---- .../abacus-deploy/scripts/dev/delete-keys.ts | 12 ---- typescript/abacus-deploy/src/agents/index.ts | 59 ++++++++++++---- typescript/abacus-deploy/src/config/agent.ts | 8 ++- typescript/abacus-deploy/src/config/chain.ts | 2 + .../abacus-deploy/src/config/environment.ts | 1 + .../abacus-deploy/src/core/CoreDeploy.ts | 6 +- 16 files changed, 380 insertions(+), 42 deletions(-) create mode 100644 rust/config/local/alfajores_config.json create mode 100644 rust/config/local/fuji_config.json create mode 100644 rust/config/local/kovan_config.json create mode 100644 rust/config/local/mumbai_config.json create mode 100644 typescript/abacus-deploy/config/environments/local/agent.ts create mode 100644 typescript/abacus-deploy/scripts/create-keys.ts create mode 100644 typescript/abacus-deploy/scripts/delete-keys.ts delete mode 100644 typescript/abacus-deploy/scripts/dev/create-keys.ts delete mode 100644 typescript/abacus-deploy/scripts/dev/delete-keys.ts diff --git a/rust/config/local/alfajores_config.json b/rust/config/local/alfajores_config.json new file mode 100644 index 000000000..5a82b5903 --- /dev/null +++ b/rust/config/local/alfajores_config.json @@ -0,0 +1,68 @@ +{ + "environment": "local", + "signers": { + "alfajores": { + "key": "", + "type": "hexKey" + }, + "kovan": { + "key": "", + "type": "hexKey" + }, + "fuji": { + "key": "", + "type": "hexKey" + }, + "mumbai": { + "key": "", + "type": "hexKey" + } + }, + "replicas": { + "kovan": { + "address": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933", + "domain": "3000", + "name": "kovan", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "fuji": { + "address": "0x809d550fca64d94Bd9F66E60752A544199cfAC3D", + "domain": "43113", + "name": "fuji", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "mumbai": { + "address": "0xdbC43Ba45381e02825b14322cDdd15eC4B3164E6", + "domain": "80001", + "name": "mumbai", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + } + }, + "home": { + "address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707", + "domain": "1000", + "name": "alfajores", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "tracing": { + "level": "debug", + "fmt": "json" + }, + "db": "db_path" +} \ No newline at end of file diff --git a/rust/config/local/fuji_config.json b/rust/config/local/fuji_config.json new file mode 100644 index 000000000..69d309135 --- /dev/null +++ b/rust/config/local/fuji_config.json @@ -0,0 +1,68 @@ +{ + "environment": "local", + "signers": { + "fuji": { + "key": "", + "type": "hexKey" + }, + "alfajores": { + "key": "", + "type": "hexKey" + }, + "kovan": { + "key": "", + "type": "hexKey" + }, + "mumbai": { + "key": "", + "type": "hexKey" + } + }, + "replicas": { + "alfajores": { + "address": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82", + "domain": "1000", + "name": "alfajores", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "kovan": { + "address": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB", + "domain": "3000", + "name": "kovan", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "mumbai": { + "address": "0xDC11f7E700A4c898AE5CAddB1082cFfa76512aDD", + "domain": "80001", + "name": "mumbai", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + } + }, + "home": { + "address": "0x0E801D84Fa97b50751Dbf25036d067dCf18858bF", + "domain": "43113", + "name": "fuji", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "tracing": { + "level": "debug", + "fmt": "json" + }, + "db": "db_path" +} \ No newline at end of file diff --git a/rust/config/local/kovan_config.json b/rust/config/local/kovan_config.json new file mode 100644 index 000000000..75e1c589c --- /dev/null +++ b/rust/config/local/kovan_config.json @@ -0,0 +1,68 @@ +{ + "environment": "local", + "signers": { + "kovan": { + "key": "", + "type": "hexKey" + }, + "alfajores": { + "key": "", + "type": "hexKey" + }, + "fuji": { + "key": "", + "type": "hexKey" + }, + "mumbai": { + "key": "", + "type": "hexKey" + } + }, + "replicas": { + "alfajores": { + "address": "0x610178dA211FEF7D417bC0e6FeD39F05609AD788", + "domain": "1000", + "name": "alfajores", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "fuji": { + "address": "0x5f3f1dBD7B74C6B46e8c44f98792A1dAf8d69154", + "domain": "43113", + "name": "fuji", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "mumbai": { + "address": "0x21dF544947ba3E8b3c32561399E88B52Dc8b2823", + "domain": "80001", + "name": "mumbai", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + } + }, + "home": { + "address": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f", + "domain": "3000", + "name": "kovan", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "tracing": { + "level": "debug", + "fmt": "json" + }, + "db": "db_path" +} \ No newline at end of file diff --git a/rust/config/local/mumbai_config.json b/rust/config/local/mumbai_config.json new file mode 100644 index 000000000..7fee55c38 --- /dev/null +++ b/rust/config/local/mumbai_config.json @@ -0,0 +1,68 @@ +{ + "environment": "local", + "signers": { + "mumbai": { + "key": "", + "type": "hexKey" + }, + "alfajores": { + "key": "", + "type": "hexKey" + }, + "kovan": { + "key": "", + "type": "hexKey" + }, + "fuji": { + "key": "", + "type": "hexKey" + } + }, + "replicas": { + "alfajores": { + "address": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1", + "domain": "1000", + "name": "alfajores", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "kovan": { + "address": "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8", + "domain": "3000", + "name": "kovan", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "fuji": { + "address": "0x82e01223d51Eb87e16A03E24687EDF0F294da6f1", + "domain": "43113", + "name": "fuji", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + } + }, + "home": { + "address": "0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07", + "domain": "80001", + "name": "mumbai", + "rpcStyle": "ethereum", + "connection": { + "type": "http", + "url": "" + } + }, + "tracing": { + "level": "debug", + "fmt": "json" + }, + "db": "db_path" +} \ No newline at end of file diff --git a/typescript/abacus-deploy/config/environments/local/agent.ts b/typescript/abacus-deploy/config/environments/local/agent.ts new file mode 100644 index 000000000..cb562be8d --- /dev/null +++ b/typescript/abacus-deploy/config/environments/local/agent.ts @@ -0,0 +1,17 @@ +import { AgentConfig, DeployEnvironment } from '../../../src/config'; + +export const agentConfig: AgentConfig = { + environment: DeployEnvironment.local, + namespace: 'abacus-local', + runEnv: 'local', + docker: { + repo: 'gcr.io/abacus-labs/abacus-agent', + tag: 'e3c1b3bdcc8f92d506626785e4e7c058ba8d79be', + }, + validator: { + interval: 5, + }, + relayer: { + interval: 5, + }, +}; diff --git a/typescript/abacus-deploy/config/networks/testnets.ts b/typescript/abacus-deploy/config/networks/testnets.ts index bff15dbb5..f3edeafa1 100644 --- a/typescript/abacus-deploy/config/networks/testnets.ts +++ b/typescript/abacus-deploy/config/networks/testnets.ts @@ -11,7 +11,7 @@ export const alfajores: ChainConfigWithoutSigner = { export const fuji: ChainConfigWithoutSigner = { name: ChainName.FUJI, domain: 43113, - confirmations: 3, + confirmations: 1, overrides: {}, }; @@ -30,6 +30,7 @@ export const kovan: ChainConfigWithoutSigner = { overrides: { gasPrice: BigNumber.from(10_000_000_000), }, + confirmations: 3, }; export const mumbai: ChainConfigWithoutSigner = { @@ -46,6 +47,7 @@ export const rinkarby: ChainConfigWithoutSigner = { gasPrice: 0, gasLimit: 600_000_000, }, + confirmations: 2, }; export const rinkeby: ChainConfigWithoutSigner = { diff --git a/typescript/abacus-deploy/hardhat.config.ts b/typescript/abacus-deploy/hardhat.config.ts index 4c7b72a68..854d61f62 100644 --- a/typescript/abacus-deploy/hardhat.config.ts +++ b/typescript/abacus-deploy/hardhat.config.ts @@ -61,6 +61,7 @@ task('abacus', 'Deploys abacus on top of an already running Harthat Network') // Write configs deploy.writeOutput(getEnvironmentDirectory(environment)); + deploy.writeRustConfigs(environment, getEnvironmentDirectory(environment)); }); task('kathy', 'Dispatches random abacus messages') diff --git a/typescript/abacus-deploy/scripts/create-keys.ts b/typescript/abacus-deploy/scripts/create-keys.ts new file mode 100644 index 000000000..f99ac9f4c --- /dev/null +++ b/typescript/abacus-deploy/scripts/create-keys.ts @@ -0,0 +1,14 @@ +import { createAgentGCPKeys } from '../src/agents/gcp'; +import { getEnvironment, getChainConfigs } from './utils'; + +async function main() { + const environment = await getEnvironment(); + const chains = await getChainConfigs(environment); + + return createAgentGCPKeys( + environment, + Object.values(chains).map((c) => c.name), + ); +} + +main().then(console.log).catch(console.error); diff --git a/typescript/abacus-deploy/scripts/delete-keys.ts b/typescript/abacus-deploy/scripts/delete-keys.ts new file mode 100644 index 000000000..5e465a01d --- /dev/null +++ b/typescript/abacus-deploy/scripts/delete-keys.ts @@ -0,0 +1,14 @@ +import { deleteAgentGCPKeys } from '../src/agents/gcp'; +import { getEnvironment, getChainConfigsRecord } from './utils'; + +async function main() { + const environment = await getEnvironment(); + const chains = await getChainConfigsRecord(environment); + + return deleteAgentGCPKeys( + environment, + Object.values(chains).map((c) => c.name), + ); +} + +main().then(console.log).catch(console.error); diff --git a/typescript/abacus-deploy/scripts/dev/create-keys.ts b/typescript/abacus-deploy/scripts/dev/create-keys.ts deleted file mode 100644 index fcd1c3c3b..000000000 --- a/typescript/abacus-deploy/scripts/dev/create-keys.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { createAgentGCPKeys } from '../../src/agents/gcp'; -import { getChains } from '../../config/environments/dev/chains'; - -async function main() { - const chains = await getChains(); - return createAgentGCPKeys( - 'dev', - chains.map((c) => c.name), - ); -} - -main().then(console.log).catch(console.error); diff --git a/typescript/abacus-deploy/scripts/dev/delete-keys.ts b/typescript/abacus-deploy/scripts/dev/delete-keys.ts deleted file mode 100644 index 2bee4fbd5..000000000 --- a/typescript/abacus-deploy/scripts/dev/delete-keys.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { deleteAgentGCPKeys } from '../../src/agents/gcp'; -import { getChains } from '../../config/environments/dev/chains'; - -async function main() { - const chains = await getChains(); - return deleteAgentGCPKeys( - 'dev', - chains.map((c) => c.name), - ); -} - -main().then(console.log).catch(console.error); diff --git a/typescript/abacus-deploy/src/agents/index.ts b/typescript/abacus-deploy/src/agents/index.ts index 0cde0a8e6..19824935a 100644 --- a/typescript/abacus-deploy/src/agents/index.ts +++ b/typescript/abacus-deploy/src/agents/index.ts @@ -10,17 +10,18 @@ import { AgentAwsKey } from './aws'; export enum KEY_ROLE_ENUM { UpdaterAttestation = 'validator-attestation', UpdaterSigner = 'validator-signer', - ProcessorSigner = 'processor-signer', + CheckpointerSigner = 'checkpointer-signer', RelayerSigner = 'relayer-signer', WatcherAttestation = 'watcher-attestation', WatcherSigner = 'watcher-signer', Deployer = 'deployer', Bank = 'bank', } + export const KEY_ROLES = [ 'validator-attestation', 'validator-signer', - 'processor-signer', + 'checkpointer-signer', 'relayer-signer', 'watcher-attestation', 'watcher-signer', @@ -43,6 +44,8 @@ async function helmValuesForChain( return undefined; }; + const chain = chains.find((_) => _.name === chainName)!; + return { image: { repository: agentConfig.docker.repo, @@ -71,11 +74,12 @@ async function helmValuesForChain( attestationSigner: { ...credentials(KEY_ROLE_ENUM.UpdaterAttestation), }, - ...include(!!agentConfig.validator!.interval, { - pollingInterval: agentConfig.validator!.interval || '', + reorg_period: chain.confirmations, + ...include(!!agentConfig.validator?.interval, { + pollingInterval: agentConfig.validator?.interval || '', }), - ...include(!!agentConfig.validator!.pause, { - updatePause: agentConfig.validator!.pause || '', + ...include(!!agentConfig.validator?.pause, { + updatePause: agentConfig.validator?.pause || '', }), }, relayer: { @@ -84,12 +88,15 @@ async function helmValuesForChain( name: chain.name, ...credentials(KEY_ROLE_ENUM.RelayerSigner), })), + ...include(!!agentConfig.validator?.interval, { + pollingInterval: agentConfig.validator?.interval || '', + }), }, processor: { enabled: true, transactionSigners: chains.map((chain) => ({ name: chain.name, - ...credentials(KEY_ROLE_ENUM.ProcessorSigner), + ...credentials(KEY_ROLE_ENUM.CheckpointerSigner), })), indexonly: agentConfig.processor?.indexOnly || [], s3BucketName: agentConfig.processor?.s3Bucket || '', @@ -111,7 +118,7 @@ export async function getAgentEnvVars( chains, ); const envVars: string[] = []; - + const chain = chains.find((_) => _.name === homeChainName)!; const rpcEndpoints = await getSecretRpcEndpoints(agentConfig, chains); envVars.push(`OPT_BASE_HOME_CONNECTION_URL=${rpcEndpoints[homeChainName]}`); valueDict.optics.replicaChains.forEach((replicaChain: any) => { @@ -127,6 +134,9 @@ export async function getAgentEnvVars( envVars.push(`RUN_ENV=${agentConfig.runEnv}`); envVars.push(`OPT_BASE_METRICS=9090`); envVars.push(`OPT_BASE_TRACING_LEVEL=info`); + envVars.push( + `OPT_BASE_DB=/tmp/${agentConfig.environment}-${role}-${homeChainName}-db`, + ); try { const gcpKeys = await fetchAgentGCPKeys( @@ -145,13 +155,36 @@ export async function getAgentEnvVars( // Updater attestation key if (role.startsWith('validator')) { envVars.push( - `OPT_BASE_UPDATER_KEY=${strip0x( + `OPT_BASE_VALIDATOR_KEY=${strip0x( gcpKeys[homeChainName + '-' + KEY_ROLE_ENUM.UpdaterAttestation] .privateKey, )}`, + `OPT_BASE_VALIDATOR_TYPE=hexKey`, + ); + // Throw an error if the chain config did not specify the reorg period + if (valueDict.optics.validator.confirmations === undefined) { + throw new Error( + `Panic: Chain config for ${homeChainName} did not specify a reorg period`, + ); + } + + envVars.push( + `OPT_VALIDATOR_REORGPERIOD=${chain.confirmations! - 1}`, + `OPT_VALIDATOR_INTERVAL=${valueDict.optics.validator.pollingInterval}`, + ); + } + + if (role.startsWith('relayer')) { + envVars.push( + `OPT_RELAYER_INTERVAL=${valueDict.optics.relayer.pollingInterval}`, ); } } catch (error) { + // This happens if you don't have a result type + if ((error as any).toString().includes('Panic')) { + throw error; + } + // Keys are in AWS const awsKeys = await getSecretAwsCredentials(agentConfig); @@ -174,15 +207,15 @@ export async function getAgentEnvVars( ); }); - // Updater attestation key + // Validator attestation key if (role.startsWith('validator')) { const key = new AgentAwsKey(agentConfig, role, homeChainName); - envVars.push(`OPT_BASE_UPDATER_TYPE=aws`); + envVars.push(`OPT_BASE_VALIDATOR_TYPE=aws`); envVars.push( - `OPT_BASE_UPDATER_ID=${key.credentialsAsHelmValue.aws.keyId}`, + `OPT_BASE_VALIDATOR_ID=${key.credentialsAsHelmValue.aws.keyId}`, ); envVars.push( - `OPT_BASE_UPDATER_REGION=${key.credentialsAsHelmValue.aws.region}`, + `OPT_BASE_VALIDATOR_REGION=${key.credentialsAsHelmValue.aws.region}`, ); } } diff --git a/typescript/abacus-deploy/src/config/agent.ts b/typescript/abacus-deploy/src/config/agent.ts index 97e6c06a4..515895b9c 100644 --- a/typescript/abacus-deploy/src/config/agent.ts +++ b/typescript/abacus-deploy/src/config/agent.ts @@ -16,6 +16,11 @@ interface ProcessorConfig { s3Bucket: string; } +interface RelayerConfig { + // How often a relayer should check for new signed checkpoints + interval?: number; +} + interface ValidatorConfig { // How often an validator should check for new updates interval?: number; @@ -37,6 +42,7 @@ export interface AgentConfig { aws?: AwsConfig; processor?: ProcessorConfig; validator?: ValidatorConfig; + relayer?: RelayerConfig; } export type RustSigner = { @@ -51,7 +57,7 @@ export type RustConnection = { export type RustContractBlock = { address: types.Address; - domain: types.Domain; + domain: string; name: ChainName; rpcStyle: string; // TODO connection: RustConnection; diff --git a/typescript/abacus-deploy/src/config/chain.ts b/typescript/abacus-deploy/src/config/chain.ts index 7b549bdfc..5ef530eae 100644 --- a/typescript/abacus-deploy/src/config/chain.ts +++ b/typescript/abacus-deploy/src/config/chain.ts @@ -29,7 +29,9 @@ export type ChainConfig = { signer: ethers.Signer; overrides: ethers.Overrides; supports1559?: boolean; + // The number of confirmations considered reorg safe confirmations?: number; + poll_interval?: number; }; export type ChainConfigWithoutSigner = Omit; diff --git a/typescript/abacus-deploy/src/config/environment.ts b/typescript/abacus-deploy/src/config/environment.ts index 1e01e042f..f9ac08ffb 100644 --- a/typescript/abacus-deploy/src/config/environment.ts +++ b/typescript/abacus-deploy/src/config/environment.ts @@ -7,4 +7,5 @@ export enum DeployEnvironment { test = 'test', production = 'production', stagingCommunity = 'staging-community', + local = 'local', } diff --git a/typescript/abacus-deploy/src/core/CoreDeploy.ts b/typescript/abacus-deploy/src/core/CoreDeploy.ts index 85919a3fc..025b07d09 100644 --- a/typescript/abacus-deploy/src/core/CoreDeploy.ts +++ b/typescript/abacus-deploy/src/core/CoreDeploy.ts @@ -55,12 +55,12 @@ export class CoreDeploy extends CommonDeploy { const filepath = path.join( this.configDirectory(directory), 'rust', - `${this.name(domain)}.json`, + `${this.name(domain)}_config.json`, ); const outbox = { address: this.outbox(domain).address, - domain, + domain: domain.toString(), name: this.name(domain), rpcStyle: 'ethereum', connection: { @@ -86,7 +86,7 @@ export class CoreDeploy extends CommonDeploy { for (const remote of this.remotes(domain)) { const inbox = { address: this.inbox(remote, domain).address, - domain: remote, + domain: remote.toString(), name: this.name(remote), rpcStyle: 'ethereum', connection: {