Skip to content

fix: ensure GRE handles multiple chains with same chainId gracefully #695

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 52 additions & 16 deletions gre/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import GraphNetwork from './helpers/network'
import { createProvider } from 'hardhat/internal/core/providers/construction'
import { EthersProviderWrapper } from '@nomiclabs/hardhat-ethers/internal/ethers-provider-wrapper'

import { logDebug } from './logger'
import { logDebug, logWarn } from './logger'
import { HARDHAT_NETWORK_NAME } from 'hardhat/plugins'

interface GREChains {
l1ChainId: number
Expand Down Expand Up @@ -99,19 +100,25 @@ export function getProviders(
const getProvider = (
networks: NetworksConfig,
chainId: number,
mainNetworkName: string,
isMainProvider: boolean,
chainLabel: string,
): EthersProviderWrapper | undefined => {
const network = getNetworkConfig(networks, chainId) as HttpNetworkConfig
const networkName = getNetworkName(networks, chainId)
const network = getNetworkConfig(networks, chainId, mainNetworkName) as HttpNetworkConfig
const networkName = getNetworkName(networks, chainId, mainNetworkName)

logDebug(`Provider url for ${chainLabel}(${networkName}): ${network?.url}`)

// Ensure at least main provider is configured
if (isMainProvider && network === undefined) {
// For Hardhat network we don't need url to create a provider
if (
isMainProvider &&
(network === undefined || network.url === undefined) &&
networkName !== HARDHAT_NETWORK_NAME
) {
throw new GREPluginError(`Must set a provider url for chain: ${chainId}!`)
}

logDebug(`Provider url for ${chainLabel}: ${network?.url}`)

if (network === undefined || networkName === undefined) {
return undefined
}
Expand All @@ -123,8 +130,8 @@ export function getProviders(
return ethersProviderWrapper
}

const l1Provider = getProvider(hre.config.networks, l1ChainId, isHHL1, 'L1')
const l2Provider = getProvider(hre.config.networks, l2ChainId, !isHHL1, 'L2')
const l1Provider = getProvider(hre.config.networks, l1ChainId, hre.network.name, isHHL1, 'L1')
const l2Provider = getProvider(hre.config.networks, l2ChainId, hre.network.name, !isHHL1, 'L2')

return {
l1Provider,
Expand All @@ -142,8 +149,8 @@ export function getGraphConfigPaths(
logDebug('== Getting graph config paths')
logDebug(`Graph base dir: ${hre.config.paths.graph}`)

const l1Network = getNetworkConfig(hre.config.networks, l1ChainId)
const l2Network = getNetworkConfig(hre.config.networks, l2ChainId)
const l1Network = getNetworkConfig(hre.config.networks, l1ChainId, hre.network.name)
const l2Network = getNetworkConfig(hre.config.networks, l2ChainId, hre.network.name)

// Priority is as follows:
// - hre.graph() init parameter l1GraphConfigPath/l2GraphConfigPath
Expand Down Expand Up @@ -205,14 +212,43 @@ export function getGraphConfigPaths(
}
}

function getNetworkConfig(networks: NetworksConfig, chainId: number): NetworkConfig | undefined {
return Object.keys(networks)
.map((n) => networks[n])
.find((n) => n.chainId === chainId)
function getNetworkConfig(
networks: NetworksConfig,
chainId: number,
mainNetworkName: string,
): (NetworkConfig & { name: string }) | undefined {
let candidateNetworks = Object.keys(networks)
.map((n) => ({ ...networks[n], name: n }))
.filter((n) => n.chainId === chainId)

if (candidateNetworks.length > 1) {
logWarn(
`Found multiple networks with chainId ${chainId}, trying to use main network name to desambiguate`,
)

candidateNetworks = candidateNetworks.filter((n) => n.name === mainNetworkName)

if (candidateNetworks.length === 1) {
return candidateNetworks[0]
} else {
throw new GREPluginError(
`Found multiple networks with chainID ${chainId}. This is not supported!`,
)
}
} else if (candidateNetworks.length === 1) {
return candidateNetworks[0]
} else {
return undefined
}
}

function getNetworkName(networks: NetworksConfig, chainId: number): string | undefined {
return Object.keys(networks).find((n) => networks[n].chainId === chainId)
function getNetworkName(
networks: NetworksConfig,
chainId: number,
mainNetworkName: string,
): string | undefined {
const network = getNetworkConfig(networks, chainId, mainNetworkName)
return network?.name
}

function normalizePath(_path: string, graphPath: string) {
Expand Down
3 changes: 3 additions & 0 deletions gre/gre.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ extendConfig((config: HardhatConfig, userConfig: Readonly<HardhatUserConfig>) =>

extendEnvironment((hre: HardhatRuntimeEnvironment) => {
hre.graph = (opts: GraphRuntimeEnvironmentOptions = {}) => {
logDebug('*** Initializing Graph Runtime Environment (GRE) ***')
logDebug(`Main network: ${hre.network.name}`)

const { l1ChainId, l2ChainId, isHHL1 } = getChains(hre.network.config.chainId)
const { l1Provider, l2Provider } = getProviders(hre, l1ChainId, l2ChainId, isHHL1)
const addressBookPath = getAddressBookPath(hre, opts)
Expand Down
16 changes: 15 additions & 1 deletion gre/test/gre.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('GRE usage', function () {
describe('graph-config project setting --network to an L2', function () {
useEnvironment('graph-config', 'arbitrum-goerli')

it('should return L1 and L2 configured objects ', function () {
it('should return L1 and L2 configured objects', function () {
const g = this.hre.graph()

expect(g).to.be.an('object')
Expand All @@ -32,6 +32,20 @@ describe('GRE usage', function () {
})
})

describe('graph-config project setting --network to hardhat network', function () {
useEnvironment('graph-config', 'hardhat')

it('should return L1 configured object and L2 unconfigured', function () {
const g = this.hre.graph()

expect(g).to.be.an('object')
expect(g.l1).to.be.an('object')
expect(g.l2).to.be.null
expect(g.l1.chainId).to.equal(1337)
expect(g.chainId).to.equal(1337)
})
})

describe('graph-config project setting --network to an L1 with no configured counterpart', function () {
useEnvironment('graph-config', 'localhost')

Expand Down