Commit d667bbb8 authored by Maurelian's avatar Maurelian Committed by GitHub

Merge pull request #1753 from ethereum-optimism/maurelian/check-moar-things

parents 5bacd4c0 bbd42e03
---
'@eth-optimism/contracts': patch
---
Add config checks to validation script
......@@ -30,9 +30,9 @@ export const color = Object.fromEntries(
])
)
export const getArtifact = (name: string) => {
// Paths to artifacts relative to artifacts/contracts
const locations = {
// helper for finding the right artifact from the deployed name
const locateArtifact = (name: string) => {
return {
'ChainStorageContainer-CTC-batches':
'L1/rollup/ChainStorageContainer.sol/ChainStorageContainer.json',
'ChainStorageContainer-SCC-batches':
......@@ -48,9 +48,12 @@ export const getArtifact = (name: string) => {
'libraries/resolver/Lib_ResolvedDelegateProxy.sol/Lib_ResolvedDelegateProxy.json',
Proxy__OVM_L1StandardBridge:
'chugsplash/L1ChugSplashProxy.sol/L1ChugSplashProxy.json',
}
}[name]
}
export const getArtifactFromManagedName = (name: string) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
return require(`../artifacts/contracts/${locations[name]}`)
return require(`../artifacts/contracts/${locateArtifact(name)}`)
}
export const getEtherscanUrl = (network, address: string) => {
......@@ -63,26 +66,32 @@ const truncateLongString = (value: string): string => {
return value.length > 66 ? `${value.slice(0, 66)}...` : value
}
export const printSectionHead = (msg: string) => {
console.log(color.cyan(msg))
console.log(
color.cyan('='.repeat(Math.max(...msg.split('\n').map((s) => s.length))))
)
}
export const printComparison = (
action: string,
description: string,
expected: { name: string; value: string },
deployed: { name: string; value: string }
expected: { name: string; value: any },
deployed: { name: string; value: any }
) => {
console.log(action + ':')
console.log(`\n${action}:`)
if (hexStringEquals(expected.value, deployed.value)) {
console.log(
color.green(
`${expected.name}: ${truncateLongString(expected.value)}
matches
${deployed.name}: ${truncateLongString(deployed.value)}`
)
color.green(`${expected.name}: ${truncateLongString(expected.value)}`)
)
console.log('matches')
console.log(
color.green(`${deployed.name}: ${truncateLongString(deployed.value)}`)
)
console.log(color.green(`${description} looks good! 😎`))
} else {
throw new Error(`${description} looks wrong.
${expected.value}\ndoes not match\n${deployed.value}.
`)
throw new Error(
`${description} looks wrong. ${expected.value}\ndoes not match\n${deployed.value}.`
)
}
console.log() // Add some whitespace
}
......@@ -4,13 +4,15 @@ import { ethers } from 'ethers'
import { task } from 'hardhat/config'
import * as types from 'hardhat/internal/core/params/argumentTypes'
import { hexStringEquals } from '@eth-optimism/core-utils'
import { getContractFactory } from '../src/contract-defs'
import { getContractFactory, getContractDefinition } from '../src/contract-defs'
import { names } from '../src/address-names'
import {
getInput,
color as c,
getArtifact,
getArtifactFromManagedName,
getEtherscanUrl,
printSectionHead,
printComparison,
} from '../src/validation-utils'
......@@ -49,7 +51,7 @@ task('validate:address-dictator')
const network = await provider.getNetwork()
console.log()
console.log(c.cyan("First make sure you're on the right chain:"))
printSectionHead("First make sure you're on the right chain:")
console.log(
`Reading from the ${c.red(network.name)} network (Chain ID: ${c.red(
'' + network.chainId
......@@ -57,16 +59,14 @@ task('validate:address-dictator')
)
await getInput(c.yellow('OK? Hit enter to continue.'))
// eslint-disable-next-line @typescript-eslint/no-var-requires
const dictatorArtifact = require('../artifacts/contracts/L1/deployment/AddressDictator.sol/AddressDictator.json')
const dictatorArtifact = getContractDefinition('AddressDictator')
const dictatorCode = await provider.getCode(args.dictator)
console.log(
c.cyan(`
Now validating the Address Dictator deployment at\n${getEtherscanUrl(
network,
args.dictator
)}`)
)
printSectionHead(`
Validate the Address Dictator deployment at\n${getEtherscanUrl(
network,
args.dictator
)}`)
printComparison(
'Comparing deployed AddressDictator bytecode against local build artifacts',
'Deployed AddressDictator code',
......@@ -87,12 +87,12 @@ Now validating the Address Dictator deployment at\n${getEtherscanUrl(
{ name: 'finalOwner ', value: finalOwner }
)
const manager = await dictatorContract.manager()
const deployedManager = await dictatorContract.manager()
printComparison(
'Validating the AddressManager address in the AddressDictator',
'addressManager',
{ name: 'manager', value: args.manager },
{ name: 'Address Manager', value: manager }
{ name: 'manager ', value: args.manager },
{ name: 'Address Manager', value: deployedManager }
)
await getInput(c.yellow('OK? Hit enter to continue.'))
......@@ -107,15 +107,20 @@ Now validating the Address Dictator deployment at\n${getEtherscanUrl(
// Now we loop over those and compare the addresses/deployedBytecode to deployment artifacts.
for (const pair of namedAddresses) {
if (pair.name === 'L2CrossDomainMessenger') {
console.log('L2CrossDomainMessenger is set to:', pair.addr)
await getInput(c.yellow('OK? Hit enter to continue.'))
// This is an L2 predeploy, so we skip bytecode and config validation.
continue
}
const currentAddress = await managerContract.getAddress(pair.name)
const artifact = getArtifact(pair.name)
const artifact = getArtifactFromManagedName(pair.name)
const addressChanged = !hexStringEquals(currentAddress, pair.addr)
if (addressChanged) {
console.log(
c.cyan(`
Now validating the ${pair.name} deployment.
printSectionHead(
`Validate the ${pair.name} deployment.
Current address: ${getEtherscanUrl(network, currentAddress)}
Upgraded address ${getEtherscanUrl(network, pair.addr)}`)
Upgraded address ${getEtherscanUrl(network, pair.addr)}`
)
const code = await provider.getCode(pair.addr)
......@@ -144,12 +149,138 @@ Upgraded address ${getEtherscanUrl(network, pair.addr)}`)
`Verifying ${pair.name} has the correct AddressManager address`,
`The AddressManager address in ${pair.name}`,
{ name: 'Deployed value', value: libAddressManager },
{ name: 'Expected value', value: manager }
{ name: 'Expected value', value: deployedManager }
)
await getInput(c.yellow('OK? Hit enter to continue.'))
}
}
}
await getInput(c.yellow('OK? Hit enter to continue.'))
await validateDeployedConfig(provider, network, args.manager, pair)
}
console.log(c.green('AddressManager Validation complete!'))
console.log(c.green('\nAddressManager Validation complete!'))
})
/**
* Validates that the deployed contracts have the expected storage variables.
*
* @param {*} provider
* @param {{ name: string; addr: string }} pair The contract name and address
*/
const validateDeployedConfig = async (
provider,
network,
manager,
pair: { name: string; addr: string }
) => {
printSectionHead(`
Ensure that the ${pair.name} at\n${getEtherscanUrl(
network,
pair.addr
)} is configured correctly`)
if (pair.name === names.managed.contracts.StateCommitmentChain) {
const scc = getContractFactory(pair.name)
.attach(pair.addr)
.connect(provider)
// --scc-fraud-proof-window 604800 \
const fraudProofWindow = await scc.FRAUD_PROOF_WINDOW()
printComparison(
'Checking the fraudProofWindow of the StateCommitmentChain',
'StateCommitmentChain.fraudProofWindow',
{
name: 'Configured fraudProofWindow',
value: ethers.BigNumber.from(604_800).toHexString(),
},
{
name: 'Deployed fraudProofWindow ',
value: ethers.BigNumber.from(fraudProofWindow).toHexString(),
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
// --scc-sequencer-publish-window 12592000 \
const sequencerPublishWindow = await scc.SEQUENCER_PUBLISH_WINDOW()
printComparison(
'Checking the sequencerPublishWindow of the StateCommitmentChain',
'StateCommitmentChain.sequencerPublishWindow',
{
name: 'Configured sequencerPublishWindow ',
value: ethers.BigNumber.from(12592000).toHexString(),
},
{
name: 'Deployed sequencerPublishWindow',
value: ethers.BigNumber.from(sequencerPublishWindow).toHexString(),
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
} else if (pair.name === names.managed.contracts.CanonicalTransactionChain) {
const ctc = getContractFactory(pair.name)
.attach(pair.addr)
.connect(provider)
// --ctc-max-transaction-gas-limit 15000000 \
const maxTransactionGasLimit = await ctc.maxTransactionGasLimit()
printComparison(
'Checking the maxTransactionGasLimit of the CanonicalTransactionChain',
'CanonicalTransactionChain.maxTransactionGasLimit',
{
name: 'Configured maxTransactionGasLimit',
value: ethers.BigNumber.from(15_000_000).toHexString(),
},
{
name: 'Deployed maxTransactionGasLimit ',
value: ethers.BigNumber.from(maxTransactionGasLimit).toHexString(),
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
// --ctc-l2-gas-discount-divisor 32 \
const l2GasDiscountDivisor = await ctc.l2GasDiscountDivisor()
printComparison(
'Checking the l2GasDiscountDivisor of the CanonicalTransactionChain',
'CanonicalTransactionChain.l2GasDiscountDivisor',
{
name: 'Configured l2GasDiscountDivisor',
value: ethers.BigNumber.from(32).toHexString(),
},
{
name: 'Deployed l2GasDiscountDivisor ',
value: ethers.BigNumber.from(l2GasDiscountDivisor).toHexString(),
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
// --ctc-enqueue-gas-cost 60000 \
const enqueueGasCost = await ctc.enqueueGasCost()
printComparison(
'Checking the enqueueGasCost of the CanonicalTransactionChain',
'CanonicalTransactionChain.enqueueGasCost',
{
name: 'Configured enqueueGasCost',
value: ethers.BigNumber.from(60000).toHexString(),
},
{
name: 'Deployed enqueueGasCost ',
value: ethers.BigNumber.from(enqueueGasCost).toHexString(),
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
} else if (pair.name === names.managed.contracts.OVM_L1CrossDomainMessenger) {
const messengerManager = await getContractFactory('L1CrossDomainMessenger')
.attach(pair.addr)
.connect(provider)
.libAddressManager()
printComparison(
'Ensure that the L1CrossDomainMessenger (implementation) is initialized with a non-zero Address Manager variable',
"L1CrossDomainMessenger's Lib_AddressManager",
{
name: 'Configured Lib_AddressManager',
value: messengerManager,
},
{
name: 'Deployed Lib_AddressManager ',
value: manager,
}
)
} else {
console.log(c.green(`${pair.name} has no config to check`))
await getInput(c.yellow('OK? Hit enter to continue.'))
}
}
......@@ -3,13 +3,14 @@
import { ethers } from 'ethers'
import { task } from 'hardhat/config'
import * as types from 'hardhat/internal/core/params/argumentTypes'
import { getContractFactory } from '../src/contract-defs'
import { getContractFactory, getContractDefinition } from '../src/contract-defs'
import {
getInput,
color as c,
getEtherscanUrl,
printComparison,
printSectionHead,
} from '../src/validation-utils'
task('validate:chugsplash-dictator')
......@@ -54,24 +55,24 @@ task('validate:chugsplash-dictator')
)})`
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
// eslint-disable-next-line @typescript-eslint/no-var-requires
const dictatorArtifact = require('../artifacts/contracts/L1/deployment/ChugSplashDictator.sol/ChugSplashDictator.json')
const dictatorArtifact = getContractDefinition('ChugSplashDictator')
const dictatorCode = await provider.getCode(args.dictator)
console.log(
c.cyan(`
Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
printSectionHead(
`Validate the Chugsplash Dictator deployment at\n${getEtherscanUrl(
network,
args.dictator
)}`)
)}`
)
printComparison(
'Comparing deployed ChugSplashDictator bytecode against local build artifacts',
'Compare the deployed ChugSplashDictator bytecode against local build artifacts',
'Deployed ChugSplashDictator code',
{ name: 'Compiled bytecode', value: dictatorArtifact.deployedBytecode },
{ name: 'Deployed bytecode', value: dictatorCode }
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
console.log(
c.cyan("The next 4 checks will validate the ChugSplashDictator's config")
......@@ -82,12 +83,13 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
.connect(provider)
const finalOwner = await dictatorContract.finalOwner()
printComparison(
'1. Comparing the finalOwner address in the ChugSplashDictator to the multisig address',
'Compare the finalOwner address in the ChugSplashDictator to the multisig address',
'finalOwner',
{ name: 'multisig address', value: args.multisig },
{ name: 'finalOwner ', value: finalOwner }
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
const dictatorMessengerSlotKey = await dictatorContract.messengerSlotKey()
const dictatorMessengerSlotVal = await dictatorContract.messengerSlotVal()
......@@ -96,7 +98,7 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
dictatorMessengerSlotKey
)
printComparison(
'2. Comparing the messenger slot key/value to be set, with the current values in the proxy',
'Compare the Messenger slot key/value to be set, with the current values in the proxy',
`Storage slot key ${dictatorMessengerSlotKey}`,
{
name: `Value in the proxy at slot key\n${dictatorMessengerSlotKey}`,
......@@ -108,6 +110,7 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
const dictatorBridgeSlotKey = await dictatorContract.bridgeSlotKey()
const dictatorBridgeSlotVal = await dictatorContract.bridgeSlotVal()
......@@ -116,7 +119,7 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
dictatorBridgeSlotKey
)
printComparison(
'3. Comparing the _Bridge_ slot key/value to be set, with the current values in the proxy',
'Compare the Bridge slot key/value to be set, with the current values in the proxy',
`Storage slot key ${dictatorBridgeSlotKey}`,
{
name: `Value currently in the proxy at slot key\n${dictatorBridgeSlotKey}`,
......@@ -128,15 +131,15 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
// eslint-disable-next-line @typescript-eslint/no-var-requires
const bridgeArtifact = require('../artifacts/contracts/L1/messaging/L1StandardBridge.sol/L1StandardBridge.json')
const bridgeArtifact = getContractDefinition('L1StandardBridge')
const expectedCodeHash = ethers.utils.keccak256(
bridgeArtifact.deployedBytecode
)
const actualCodeHash = await dictatorContract.codeHash()
printComparison(
"4. Comparing the Dictator's codeHash against hash of the local L1StandardBridge build artifacts",
"Compare the Dictator's codeHash against hash of the local L1StandardBridge build artifacts",
"Dictator's codeHash",
{
name: 'Expected codeHash',
......@@ -148,5 +151,6 @@ Now validating the Chugsplash Dictator deployment at\n${getEtherscanUrl(
}
)
await getInput(c.yellow('OK? Hit enter to continue.'))
console.log()
console.log(c.green('Chugsplash Dictator Validation complete!'))
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment