Skip to content
Closed
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
237 changes: 142 additions & 95 deletions integration-tests/test/ovm-self-upgrades.spec.ts
Original file line number Diff line number Diff line change
@@ -1,104 +1,84 @@
import { expect } from 'chai'
import { Wallet, utils, BigNumber, Contract } from 'ethers'
import { Direction } from './shared/watcher-utils'

import { OptimismEnv } from './shared/env'

import { getContractInterface } from '@eth-optimism/contracts'
import { l2Provider, OVM_ETH_ADDRESS } from './shared/utils'
/* Imports: External */
import { ethers } from 'hardhat'
import { Wallet, Contract } from 'ethers'
import {
getContractInterface,
getChugSplashActionBundle,
ChugSplashAction,
isSetStorageAction,
predeploys,
} from '@eth-optimism/contracts'

/* Imports: Internal */
import { OptimismEnv } from './shared/env'


// TODO: use actual imported Chugsplash type

interface SetCodeInstruction {
target: string // address
code: string // bytes memory
}

interface SetStorageInstruction {
target: string // address
key: string // bytes32
value: string // bytes32
}

type ChugsplashInstruction = SetCodeInstruction | SetStorageInstruction

// Just an array of the above two instruction types.
type ChugSplashInstructions = Array<ChugsplashInstruction>

const isSetStorageInstruction = (instr: ChugsplashInstruction): instr is SetStorageInstruction => {
return !instr["code"]
}

describe('OVM Self-Upgrades', async () => {
let env: OptimismEnv
let l2Wallet: Wallet
let OVM_UpgradeExecutor: Contract

const applyChugsplashInstructions = async (instructions: ChugSplashInstructions) => {
for (const instruction of instructions) {
let res
if (isSetStorageInstruction(instruction)) {
res = await OVM_UpgradeExecutor.setStorage(
instruction.target,
instruction.key,
instruction.value
)
} else {
res = await OVM_UpgradeExecutor.setCode(
instruction.target,
instruction.code
)
}
await res.wait() // TODO: promise.all
const executeAndVerifyChugSplashBundle = async (
ChugSplashDeployer: Contract,
actions: ChugSplashAction[]
): Promise<void> => {
const bundle = getChugSplashActionBundle(actions)

const res1 = await ChugSplashDeployer.approveTransactionBundle(
bundle.root,
bundle.actions.length,
{
gasLimit: 8000000,
gasPrice: 0,
}
}

const checkChugsplashInstructionsApplied = async (instructions: ChugSplashInstructions) => {
for (const instruction of instructions) {
// TODO: promise.all this for with a map for efficiency
if (isSetStorageInstruction(instruction)) {
const actualStorage = await l2Provider.getStorageAt(
instruction.target,
instruction.key
)
expect(actualStorage).to.deep.eq(instruction.value)
} else {
const actualCode = await l2Provider.getCode(
instruction.target
)
expect(actualCode).to.deep.eq(instruction.code)
)
await res1.wait()

for (const rawAction of bundle.actions) {
const res2 = await ChugSplashDeployer.executeAction(
rawAction.action,
rawAction.proof,
{
gasPrice: 0,
}
)
await res2.wait()

const action = actions[rawAction.proof.actionIndex]
if (isSetStorageAction(action)) {
expect(
await ChugSplashDeployer.provider.getStorageAt(
action.target,
action.key
)
).to.deep.equal(action.value)
} else {
expect(
await ChugSplashDeployer.provider.getCode(action.target)
).to.deep.equal(action.code)
}
}
}

const applyAndVerifyUpgrade = async (instructions: ChugSplashInstructions) => {
await applyChugsplashInstructions(instructions)
await checkChugsplashInstructionsApplied(instructions)
}

describe.only('OVM Self-Upgrades', async () => {
let env: OptimismEnv
let l2Wallet: Wallet
let ChugSplashDeployer: Contract
before(async () => {
env = await OptimismEnv.new()
l2Wallet = env.l2Wallet

OVM_UpgradeExecutor = new Contract(
'0x420000000000000000000000000000000000000a',
getContractInterface('OVM_UpgradeExecutor', true),
ChugSplashDeployer = new Contract(
predeploys.ChugSplashDeployer,
getContractInterface('ChugSplashDeployer', true),
l2Wallet
)
})

describe('setStorage and setCode are correctly applied', () => {
it('Should execute a basic storage upgrade', async () => {
const basicStorageUpgrade: ChugSplashInstructions = [
await executeAndVerifyChugSplashBundle(ChugSplashDeployer, [
{
target: OVM_ETH_ADDRESS,
key: '0x1234123412341234123412341234123412341234123412341234123412341234',
value: '0x6789123412341234123412341234123412341234123412341234678967896789',
}
]
await applyAndVerifyUpgrade(basicStorageUpgrade)
target: predeploys.OVM_ETH,
key: `0x${'12'.repeat(32)}`,
value: `0x${'32'.repeat(32)}`,
},
])
})

it('Should execute a basic upgrade overwriting existing deployed code', async () => {
Expand All @@ -107,25 +87,92 @@ describe('OVM Self-Upgrades', async () => {
).deploy()
await DummyContract.deployTransaction.wait()

const basicCodeUpgrade: ChugSplashInstructions = [
await executeAndVerifyChugSplashBundle(ChugSplashDeployer, [
{
target: DummyContract.address,
code: '0x1234123412341234123412341234123412341234123412341234123412341234',
}
]
await applyAndVerifyUpgrade(basicCodeUpgrade)
code: `0x${'12'.repeat(32)}`,
},
])
})

it('Should execute a basic code upgrade which is not overwriting an existing account', async () => {
// TODO: fix me? Currently breaks due to nil pointer dereference; triggerd by evm.StateDB.SetCode(...) in ovm_state_manager.go ?
// More recent update: I cannot get this to error out any more.
const emptyAccountCodeUpgrade: ChugSplashInstructions = [
await executeAndVerifyChugSplashBundle(ChugSplashDeployer, [
{
target: `0x${'56'.repeat(20)}`,
code: `0x${'12'.repeat(32)}`,
},
])
})

it('should set code and set storage in the same bundle', async () => {
await executeAndVerifyChugSplashBundle(ChugSplashDeployer, [
{
target: `0x${'56'.repeat(20)}`,
code: `0x${'12'.repeat(32)}`,
},
{
target: `0x${'56'.repeat(20)}`,
key: `0x${'12'.repeat(32)}`,
value: `0x${'12'.repeat(32)}`,
},
])
})

it('should set code multiple times in the same bundle', async () => {
await executeAndVerifyChugSplashBundle(ChugSplashDeployer, [
{
target: `0x${'56'.repeat(20)}`,
code: `0x${'12'.repeat(32)}`,
},
{
target: `0x${'56'.repeat(20)}`,
code: `0x${'34'.repeat(32)}`,
},
{
target: `0x${'56'.repeat(20)}`,
code: `0x${'56'.repeat(32)}`,
},
])
})

it('should set storage multiple times in the same bundle', async () => {
await executeAndVerifyChugSplashBundle(ChugSplashDeployer, [
{
target: `0x${'56'.repeat(20)}`,
key: `0x${'12'.repeat(32)}`,
value: `0x${'12'.repeat(32)}`,
},
{
target: `0x${'56'.repeat(20)}`,
key: `0x${'34'.repeat(32)}`,
value: `0x${'12'.repeat(32)}`,
},
{
target: `0x${'56'.repeat(20)}`,
key: `0x${'56'.repeat(32)}`,
value: `0x${'12'.repeat(32)}`,
},
])
})

it.skip('should set storage multiple times with different addresses in the same bundle', async () => {
await executeAndVerifyChugSplashBundle(ChugSplashDeployer, [
{
target: `0x${'57'.repeat(20)}`,
key: `0x${'12'.repeat(32)}`,
value: `0x${'12'.repeat(32)}`,
},
{
target: `0x${'58'.repeat(20)}`,
key: `0x${'34'.repeat(32)}`,
value: `0x${'12'.repeat(32)}`,
},
{
target: '0x5678657856785678567856785678567856785678',
code: '0x1234123412341234123412341234123412341234123412341234123412341234',
}
]
await applyAndVerifyUpgrade(emptyAccountCodeUpgrade)
target: `0x${'59'.repeat(20)}`,
key: `0x${'56'.repeat(32)}`,
value: `0x${'12'.repeat(32)}`,
},
])
})
})
})
21 changes: 13 additions & 8 deletions integration-tests/test/ovmcontext.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,21 @@ describe('OVM Context: Layer 2 EVM Context', () => {

for (let i = start; i < tip.number; i++) {
const block = await L2Provider.getBlockWithTransactions(i)
const [, returnData] = await OVMMulticall.callStatic.aggregate([
const [, returnData] = await OVMMulticall.callStatic.aggregate(
[
OVMMulticall.address,
OVMMulticall.interface.encodeFunctionData('getCurrentBlockTimestamp'),
[
OVMMulticall.address,
OVMMulticall.interface.encodeFunctionData(
'getCurrentBlockTimestamp'
),
],
[
OVMMulticall.address,
OVMMulticall.interface.encodeFunctionData('getCurrentBlockNumber'),
],
],
[
OVMMulticall.address,
OVMMulticall.interface.encodeFunctionData('getCurrentBlockNumber'),
],
], {blockTag: i})
{ blockTag: i }
)

const timestamp = BigNumber.from(returnData[0])
const blockNumber = BigNumber.from(returnData[1])
Expand Down
59 changes: 59 additions & 0 deletions packages/contracts/chugsplash-deploy/deploy-l2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"contracts": {
"OVM_L2ToL1MessagePasser": {
"address": "0x4200000000000000000000000000000000000000",
"source": "OVM_L2ToL1MessagePasser"
},
"OVM_L1MessageSender": {
"address": "0x4200000000000000000000000000000000000001",
"source": "OVM_L1MessageSender"
},
"OVM_DeployerWhitelist": {
"address": "0x4200000000000000000000000000000000000002",
"source": "OVM_DeployerWhitelist",
"variables": {
"owner": "{{ env.DEPLOYER_WHITELIST_OWNER }}"
}
},
"OVM_ECDSAContractAccount": {
"address": "0x4200000000000000000000000000000000000003",
"source": "OVM_ECDSAContractAccount"
},
"OVM_SequencerEntrypoint": {
"address": "0x4200000000000000000000000000000000000005",
"source": "OVM_SequencerEntrypoint"
},
"OVM_ETH": {
"address": "0x4200000000000000000000000000000000000006",
"source": "OVM_ETH",
"variables": {
"l1TokenGateway": "{{ env.L1_ETH_GATEWAY_ADDRESS }}",
"messenger": "{{ contracts.OVM_L2CrossDomainMessenger }}",
"name": "Ether",
"symbol": "ETH"
}
},
"OVM_L2CrossDomainMessenger": {
"address": "0x4200000000000000000000000000000000000007",
"source": "OVM_L2CrossDomainMessenger",
"variables": {
"libAddressManager": "{{ contracts.Lib_AddressManager }}"
}
},
"OVM_ProxyEOA": {
"address": "0x4200000000000000000000000000000000000009",
"source": "OVM_ProxyEOA"
},
"Lib_AddressManager": {
"address": "0x4200000000000000000000000000000000000008",
"source": "Lib_AddressManager",
"variables": {
"_owner": "0x1212121212121212121212121212121212121212"
}
},
"ERC1820Registry": {
"address": "0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24",
"source": "ERC1820Registry"
}
}
}
Loading