From 16d87362cb3759904ba43a9aa27daef91047d7ea Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 12 Dec 2024 22:57:49 +0200 Subject: [PATCH] feat: migration and noNetwork fix --- .../1733443598_configurate_and_ens.ts | 4 +- hardhat.config.ts | 2 +- plugins/deployment_manager/Spider.ts | 31 +---------- plugins/scenario/Runner.ts | 55 +++++++++++++++---- plugins/scenario/World.ts | 10 ++-- plugins/scenario/utils/hreForBase.ts | 17 ++++-- tasks/deployment_manager/task.ts | 14 ++--- tasks/scenario/task.ts | 2 +- 8 files changed, 74 insertions(+), 61 deletions(-) diff --git a/deployments/scroll/weth/migrations/1733443598_configurate_and_ens.ts b/deployments/scroll/weth/migrations/1733443598_configurate_and_ens.ts index 470075147..df74b1192 100644 --- a/deployments/scroll/weth/migrations/1733443598_configurate_and_ens.ts +++ b/deployments/scroll/weth/migrations/1733443598_configurate_and_ens.ts @@ -194,9 +194,7 @@ export default migration('1733443598_configurate_and_ens', { }, PufETH: { supplyCap: exp(1_000, 18) - }, - baseTrackingSupplySpeed: 0, - baseTrackingBorrowSpeed: 0, + } }); // 3. diff --git a/hardhat.config.ts b/hardhat.config.ts index 77d47d842..da26b520f 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -119,7 +119,7 @@ export const networkConfigs: NetworkConfig[] = [ { network: 'mainnet', chainId: 1, - url: `http://normally-up-yeti.n0des.xyz` + url: `https://rpc.ankr.com/eth/${ANKR_KEY}`, }, { network: 'sepolia', diff --git a/plugins/deployment_manager/Spider.ts b/plugins/deployment_manager/Spider.ts index 126f2f689..9e712aa3c 100644 --- a/plugins/deployment_manager/Spider.ts +++ b/plugins/deployment_manager/Spider.ts @@ -50,33 +50,6 @@ function maybeStore(alias: Alias, address: Address, into: Aliases): boolean { return true; } } -async function retry(fn: () => Promise, retries: number = 10, timeLimit?: number, wait: number = 500) { - try { - return await asyncCallWithTimeout(fn(), timeLimit); - } catch (e) { - if (retries === 0) throw e; - - console.warn(`Retrying in ${wait}ms...`); - - await new Promise(ok => setTimeout(ok, wait)); - return retry(fn, retries - 1, timeLimit, wait >= 10000 ? 10000 : wait * 2); - } -} -async function asyncCallWithTimeout(asyncPromise: Promise, timeLimit: number = 120_000) { - let timeoutHandle: string | number | NodeJS.Timeout; - - const timeoutPromise = new Promise((_resolve, reject) => { - timeoutHandle = setTimeout( - () => reject(new Error('Async call timeout limit reached')), - timeLimit - ); - }); - - return Promise.race([asyncPromise, timeoutPromise]).then(result => { - clearTimeout(timeoutHandle); - return result; - }); -} async function discoverNodes( path: Contract[], @@ -85,9 +58,7 @@ async function discoverNodes( config: RelationInnerConfig, defaultKeyAndTemplate: string ): Promise { - const addresses = await retry(() => { - return readField(contract, getFieldKey(config, defaultKeyAndTemplate), context); - }); + const addresses = await readField(contract, getFieldKey(config, defaultKeyAndTemplate), context); const templates = config.alias ? asArray(config.alias) : [defaultKeyAndTemplate]; return addresses.map((address, i) => ({ address, diff --git a/plugins/scenario/Runner.ts b/plugins/scenario/Runner.ts index da19c4ebc..1791e3198 100644 --- a/plugins/scenario/Runner.ts +++ b/plugins/scenario/Runner.ts @@ -153,6 +153,37 @@ export class Runner { } } + +async function retry(fn: () => Promise, retries: number = 10, timeLimit?: number, wait: number = 100) { + try { + return await asyncCallWithTimeout(fn(), timeLimit); + } catch (e) { + if (retries === 0) throw e; + if(e.reason !== 'could not detect network') + throw e; + + console.warn(`Retrying in ${wait}ms...`); + + await new Promise(ok => setTimeout(ok, wait)); + return retry(fn, retries - 1, timeLimit, wait >= 10000 ? 10000 : wait * 2); + } +} +async function asyncCallWithTimeout(asyncPromise: Promise, timeLimit: number = 5000_000) { + let timeoutHandle: string | number | NodeJS.Timeout; + + const timeoutPromise = new Promise((_resolve, reject) => { + timeoutHandle = setTimeout( + () => reject(new Error('Async call timeout limit reached')), + timeLimit + ); + }); + + return Promise.race([asyncPromise, timeoutPromise]).then(result => { + clearTimeout(timeoutHandle); + return result; + }); +} + export async function runScenarios(bases: ForkSpec[]) { const loader = await Loader.load(); const [runningScenarios, skippedScenarios] = loader.splitScenarios(); @@ -161,16 +192,20 @@ export async function runScenarios(bases: ForkSpec[]) { const results: Result[] = []; for (const base of bases) { - const world = new World(base), dm = world.deploymentManager; - const delta = await dm.runDeployScript({ allMissing: true }); - console.log(`[${base.name}] Deployed ${dm.counter} contracts, spent ${dm.spent} to initialize world 🗺`); - console.log(`[${base.name}]\n${dm.diffDelta(delta)}`); - - if (world.auxiliaryDeploymentManager) { - await world.auxiliaryDeploymentManager.spider(); - } - - const runner = new Runner(base, world); + let runner: Runner; + await retry(async () => { + const world = new World(base); + await world.initialize(base); + const dm = world.deploymentManager; + const delta = await dm.runDeployScript({ allMissing: true }); + console.log(`[${base.name}] Deployed ${dm.counter} contracts, spent ${dm.spent} to initialize world 🗺`); + console.log(`[${base.name}]\n${dm.diffDelta(delta)}`); + + if (world.auxiliaryDeploymentManager) { + await world.auxiliaryDeploymentManager.spider(); + } + runner = new Runner(base, world); + }); // NB: contexts are (still) a bit awkward // they prob dont even really need to get passed through here currently diff --git a/plugins/scenario/World.ts b/plugins/scenario/World.ts index ffc8bdb10..35c0b53c6 100644 --- a/plugins/scenario/World.ts +++ b/plugins/scenario/World.ts @@ -28,15 +28,17 @@ export class World { snapshotAuxiliaryDeploymentManager?: DeploymentManager; constructor(base: ForkSpec) { - // Q: should we really need to fork/snapshot the deployment manager? - const hre = hreForBase(base); this.base = base; + } + + async initialize(base: ForkSpec) { + const hre = await hreForBase(base); this.deploymentManager = new DeploymentManager(base.network, base.deployment, hre); + // Q: should we really need to fork/snapshot the deployment manager? this.snapshotDeploymentManager = this.deploymentManager; - if (this.base.auxiliaryBase) { const auxiliaryBase = hre.config.scenario.bases.find(b => b.name === this.base.auxiliaryBase); - this.auxiliaryDeploymentManager = new DeploymentManager(auxiliaryBase.network, auxiliaryBase.deployment, hreForBase(auxiliaryBase)); + this.auxiliaryDeploymentManager = new DeploymentManager(auxiliaryBase.network, auxiliaryBase.deployment, await hreForBase(auxiliaryBase)); this.snapshotAuxiliaryDeploymentManager = this.auxiliaryDeploymentManager; } } diff --git a/plugins/scenario/utils/hreForBase.ts b/plugins/scenario/utils/hreForBase.ts index 5609d9572..7ef5e5a3c 100644 --- a/plugins/scenario/utils/hreForBase.ts +++ b/plugins/scenario/utils/hreForBase.ts @@ -1,4 +1,4 @@ -import type { ethers } from 'ethers'; +import { ethers } from 'ethers'; import type { HardhatEthersHelpers } from '@nomiclabs/hardhat-ethers/types'; import { HardhatRuntimeEnvironment } from 'hardhat/types'; import { HardhatContext } from 'hardhat/internal/context'; @@ -36,7 +36,7 @@ declare module 'hardhat/internal/core/runtime-environment' { } } -export function nonForkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { +export async function nonForkedHreForBase(base: ForkSpec): Promise { const ctx: HardhatContext = HardhatContext.getHardhatContext(); const hardhatArguments = getEnvHardhatArguments( @@ -61,7 +61,7 @@ export function nonForkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { ); } -export function forkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { +export async function forkedHreForBase(base: ForkSpec): Promise { const ctx: HardhatContext = HardhatContext.getHardhatContext(); const hardhatArguments = getEnvHardhatArguments(HARDHAT_PARAM_DEFINITIONS, process.env); @@ -73,6 +73,13 @@ export function forkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { const baseNetwork = networks[base.network] as HttpNetworkUserConfig; + const provider = new ethers.providers.JsonRpcProvider(baseNetwork.url); + + // noNetwork otherwise + if(!base.blockNumber) + // base.blockNumber = 17480000; + base.blockNumber = await provider.getBlockNumber() - 210; + if (!baseNetwork) { throw new Error(`cannot find network config for network: ${base.network}`); } @@ -96,7 +103,7 @@ export function forkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { defaultNetwork: 'hardhat', networks: { hardhat: forkedNetwork, - localhost + localhost: localhost }, }, }; @@ -111,7 +118,7 @@ export function forkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { ); } -export default function hreForBase(base: ForkSpec, fork = true): HardhatRuntimeEnvironment { +export default async function hreForBase(base: ForkSpec, fork = true): Promise { if (fork) { return forkedHreForBase(base); } else { diff --git a/tasks/deployment_manager/task.ts b/tasks/deployment_manager/task.ts index 5e08b7e37..1a7d84997 100644 --- a/tasks/deployment_manager/task.ts +++ b/tasks/deployment_manager/task.ts @@ -7,12 +7,12 @@ import { impersonateAddress } from '../../plugins/scenario/utils'; import hreForBase from '../../plugins/scenario/utils/hreForBase'; // TODO: Don't depend on scenario's hreForBase -function getForkEnv(env: HardhatRuntimeEnvironment, deployment: string): HardhatRuntimeEnvironment { +async function getForkEnv(env: HardhatRuntimeEnvironment, deployment: string): Promise { const base = env.config.scenario.bases.find(b => b.network == env.network.name && b.deployment == deployment); if (!base) { throw new Error(`No fork spec for ${env.network.name}`); } - return hreForBase(base); + return await hreForBase(base); } function getDefaultDeployment(config: HardhatConfig, network: string): string { @@ -65,7 +65,7 @@ task('deploy', 'Deploys market') .addFlag('overwrite', 'overwrites cache') .addParam('deployment', 'The deployment to deploy') .setAction(async ({ simulate, noDeploy, noVerify, noVerifyImpl, overwrite, deployment }, env) => { - const maybeForkEnv = simulate ? getForkEnv(env, deployment) : env; + const maybeForkEnv = simulate ? await getForkEnv(env, deployment) : env; const network = env.network.name; const tag = `${network}/${deployment}`; const dm = new DeploymentManager( @@ -174,7 +174,7 @@ task('migrate', 'Runs migration') .addFlag('overwrite', 'overwrites artifact if exists, fails otherwise') .setAction( async ({ migration: migrationName, prepare, enact, noEnacted, simulate, overwrite, deployment, impersonate }, env) => { - const maybeForkEnv = simulate ? getForkEnv(env, deployment) : env; + const maybeForkEnv = simulate ? await getForkEnv(env, deployment) : env; const network = env.network.name; const dm = new DeploymentManager( network, @@ -193,7 +193,7 @@ task('migrate', 'Runs migration') const governanceBase = isBridgedDeployment ? env.config.scenario.bases.find(b => b.name === base.auxiliaryBase) : undefined; if (governanceBase) { - const governanceEnv = hreForBase(governanceBase, simulate); + const governanceEnv = await hreForBase(governanceBase, simulate); governanceDm = new DeploymentManager( governanceBase.network, governanceBase.deployment, @@ -246,7 +246,7 @@ task('deploy_and_migrate', 'Runs deploy and migration') .addParam('deployment', 'The deployment to deploy') .setAction( async ({ migration: migrationName, prepare, enact, noEnacted, simulate, overwrite, deployment, impersonate, noDeploy, noVerify, noVerifyImpl }, env) => { - const maybeForkEnv = simulate ? getForkEnv(env, deployment) : env; + const maybeForkEnv = simulate ? await getForkEnv(env, deployment) : env; const network = env.network.name; const tag = `${network}/${deployment}`; const dm = new DeploymentManager( @@ -314,7 +314,7 @@ task('deploy_and_migrate', 'Runs deploy and migration') const governanceBase = isBridgedDeployment ? env.config.scenario.bases.find(b => b.name === base.auxiliaryBase) : undefined; if (governanceBase) { - const governanceEnv = hreForBase(governanceBase, simulate); + const governanceEnv = await hreForBase(governanceBase, simulate); governanceDm = new DeploymentManager( governanceBase.network, governanceBase.deployment, diff --git a/tasks/scenario/task.ts b/tasks/scenario/task.ts index 658623144..36ddc1c1b 100644 --- a/tasks/scenario/task.ts +++ b/tasks/scenario/task.ts @@ -39,7 +39,7 @@ task('scenario:spider', 'Runs spider in preparation for scenarios') const bases: ForkSpec[] = getBasesFromTaskArgs(taskArgs.bases, env); await Promise.all(bases.map(async (base) => { if (base.network !== 'hardhat') { - let hre = hreForBase(base); + let hre = await hreForBase(base); let dm = new DeploymentManager( base.name, base.deployment,