Commit b8a3c25f authored by Kelvin Fichter's avatar Kelvin Fichter

Ported exports from contracts v1

parent 0541e0cd
/* External Imports */
import * as fs from 'fs'
import * as path from 'path'
import * as mkdirp from 'mkdirp'
/* Internal Imports */
import { makeStateDump } from '../src'
;(async () => {
const outdir = path.resolve(__dirname, '../build/dumps')
const outfile = path.join(outdir, 'state-dump.latest.json')
mkdirp.sync(outdir)
const dump = await makeStateDump()
fs.writeFileSync(outfile, JSON.stringify(dump))
})()
......@@ -4,6 +4,7 @@ pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_EthUtils } from "../../libraries/utils/Lib_EthUtils.sol";
/* Interface Imports */
......@@ -20,7 +21,7 @@ import { console } from "@nomiclabs/buidler/console.sol";
/**
* @title OVM_ExecutionManager
*/
contract OVM_ExecutionManager is iOVM_ExecutionManager {
contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
/********************************
* External Contract References *
......@@ -59,12 +60,14 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
***************/
/**
* @param _ovmSafetyChecker Address of the iOVM_SafetyChecker implementation.
* @param _libAddressManager Address of the Address Manager.
*/
constructor(
address _ovmSafetyChecker
) {
ovmSafetyChecker = iOVM_SafetyChecker(_ovmSafetyChecker);
address _libAddressManager
)
Lib_AddressResolver(_libAddressManager)
{
ovmSafetyChecker = iOVM_SafetyChecker(resolve("OVM_SafetyChecker"));
}
......
......@@ -2,18 +2,38 @@
pragma solidity ^0.7.0;
contract Helper_SimpleProxy {
address private owner;
address private target;
constructor(
address _target
) {
target = _target;
constructor() {
owner = msg.sender;
}
fallback()
external
{
(bool success, bytes memory returndata) = target.call(msg.data);
makeExternalCall(target, msg.data);
}
function setTarget(
address _target
)
public
{
if (msg.sender == owner) {
target = _target;
} else {
makeExternalCall(target, msg.data);
}
}
function makeExternalCall(
address _target,
bytes memory _calldata
)
private
{
(bool success, bytes memory returndata) = _target.call(_calldata);
if (success) {
assembly {
......
......@@ -7,11 +7,14 @@
"build": "yarn run build:contracts && yarn run build:typescript && yarn run build:copy",
"build:typescript": "tsc -p .",
"build:contracts": "buidler compile",
"build:dump": "ts-node \"bin/take-dump.ts\"",
"build:copy": "copyfiles -u 2 \"contracts/optimistic-ethereum/**/*.sol\" \"build/contracts\"",
"test": "yarn run test:contracts",
"test:contracts": "buidler test --show-stack-traces",
"lint": "tslint --format stylish --project .",
"fix": "prettier --config prettier-config.json --write \"buidler.config.ts\" \"{src,test}/**/*.ts\"",
"lint": "yarn run lint:typescript",
"lint:typescript": "tslint --format stylish --project .",
"lint:fix": "yarn run lint:fix:typescript",
"lint:fix:typescript": "prettier --config prettier-config.json --write \"buidler.config.ts\" \"{src,test}/**/*.ts\"",
"clean": "rm -rf ./artifacts ./build ./cache"
},
"devDependencies": {
......@@ -30,6 +33,7 @@
"ethereum-waffle": "3.0.0",
"ethers": "5.0.0",
"fs-extra": "^9.0.1",
"ganache-core": "^2.12.1",
"lodash": "^4.17.20",
"mocha": "^8.1.1",
"prettier": "^2.1.2",
......
import * as path from 'path'
import { ethers, ContractFactory, Signer } from 'ethers'
import { Interface } from 'ethers/lib/utils'
export const getContractDefinition = (name: string): any => {
return require(path.join(__dirname, '../artifacts', `${name}.json`))
}
export const getContractInterface = (name: string): Interface => {
const definition = getContractDefinition(name)
return new ethers.utils.Interface(definition.abi)
}
export const getContractFactory = (
name: string,
signer?: Signer
): ContractFactory => {
const definition = getContractDefinition(name)
const contractInterface = getContractInterface(name)
return new ContractFactory(contractInterface, definition.bytecode, signer)
}
/* External Imports */
import { Signer, ContractFactory, Contract } from 'ethers'
/* Internal Imports */
import { getContractFactory } from '../contract-defs'
export interface RollupDeployConfig {
deploymentSigner: Signer
ovmGasMeteringConfig: {
minTransactionGasLimit: number
maxTransactionGasLimit: number
maxGasPerQueuePerEpoch: number
secondsPerEpoch: number
}
transactionChainConfig: {
sequencer: string | Signer
forceInclusionPeriodSeconds: number
}
whitelistConfig: {
owner: string | Signer
allowArbitraryContractDeployment: boolean
}
}
export interface ContractDeployParameters {
factory: ContractFactory
params?: any[]
afterDeploy?: (contracts?: { [name: string]: Contract }) => Promise<void>
}
export interface ContractDeployConfig {
[name: string]: ContractDeployParameters
}
export const makeContractDeployConfig = async (
config: RollupDeployConfig,
AddressManager: Contract
): Promise<ContractDeployConfig> => {
return {
OVM_L1CrossDomainMessenger: {
factory: getContractFactory('OVM_L1CrossDomainMessenger'),
params: [AddressManager.address],
},
OVM_L2CrossDomainMessenger: {
factory: getContractFactory('OVM_L2CrossDomainMessenger'),
params: [AddressManager.address],
},
OVM_CanonicalTransactionChain: {
factory: getContractFactory('OVM_CanonicalTransactionChain'),
params: [
AddressManager.address,
config.transactionChainConfig.forceInclusionPeriodSeconds,
],
afterDeploy: async (): Promise<void> => {
const sequencer = config.transactionChainConfig.sequencer
const sequencerAddress =
typeof sequencer === 'string'
? sequencer
: await sequencer.getAddress()
await AddressManager.setAddress('Sequencer', sequencerAddress)
},
},
OVM_StateCommitmentChain: {
factory: getContractFactory('OVM_StateCommitmentChain'),
params: [AddressManager.address],
},
OVM_ExecutionManager: {
factory: getContractFactory('OVM_ExecutionManager'),
params: [AddressManager.address],
},
OVM_StateManager: {
factory: getContractFactory('OVM_StateManager'),
params: [await config.deploymentSigner.getAddress()],
afterDeploy: async (contracts): Promise<void> => {
await contracts.OVM_StateManager.setExecutionManager(
contracts.OVM_ExecutionManager.address
)
},
},
OVM_StateManagerFactory: {
factory: getContractFactory('OVM_StateManagerFactory'),
},
OVM_L1ToL2TransactionQueue: {
factory: getContractFactory('OVM_L1ToL2TransactionQueue'),
params: [AddressManager.address],
},
OVM_FraudVerifier: {
factory: getContractFactory('OVM_FraudVerifier'),
params: [AddressManager.address],
},
OVM_StateTransitionerFactory: {
factory: getContractFactory('OVM_StateTransitionerFactory'),
},
}
}
/* External Imports */
import { Signer, Contract, ContractFactory } from 'ethers'
/* Internal Imports */
import { RollupDeployConfig, makeContractDeployConfig } from './config'
import { getContractFactory } from '../contract-defs'
export interface DeployResult {
AddressManager: Contract
failedDeployments: string[]
contracts: {
[name: string]: Contract
}
}
export const deploy = async (
config: RollupDeployConfig
): Promise<DeployResult> => {
const Factory__SimpleProxy: ContractFactory = getContractFactory(
'Helper_SimpleProxy',
config.deploymentSigner
)
const AddressManager: Contract = await getContractFactory(
'Lib_AddressManager',
config.deploymentSigner
).deploy()
const contractDeployConfig = await makeContractDeployConfig(
config,
AddressManager
)
const failedDeployments: string[] = []
const contracts: {
[name: string]: Contract
} = {}
for (const [name, contractDeployParameters] of Object.entries(
contractDeployConfig
)) {
const SimpleProxy = await Factory__SimpleProxy.deploy()
await AddressManager.setAddress(name, SimpleProxy.address)
try {
contracts[name] = await contractDeployParameters.factory
.connect(config.deploymentSigner)
.deploy(...contractDeployParameters.params)
await SimpleProxy.setTarget(contracts[name].address)
} catch (err) {
failedDeployments.push(name)
}
}
for (const contractDeployParameters of Object.values(contractDeployConfig)) {
if (contractDeployParameters.afterDeploy) {
await contractDeployParameters.afterDeploy(contracts)
}
}
return {
AddressManager,
failedDeployments,
contracts,
}
}
export { RollupDeployConfig } from './config'
export { deploy } from './deploy'
/* External Imports */
import * as path from 'path'
import { ethers } from 'ethers'
import * as Ganache from 'ganache-core'
/* Internal Imports */
import { deploy, RollupDeployConfig } from './contract-deployment'
import { getContractDefinition } from './contract-defs'
import { keccak256 } from 'ethers/lib/utils'
type Accounts = Array<{
originalAddress: string
address: string
code: string
}>
interface StorageDump {
[key: string]: string
}
export interface StateDump {
contracts: {
ovmExecutionManager: string
ovmStateManager: string
}
accounts: {
[address: string]: {
balance: number
nonce: number
code: string
storage: StorageDump
}
}
}
/**
* Finds the addresses of all accounts changed in the state.
* @param cStateManager Instance of the callback-based internal vm StateManager.
* @returns Array of changed addresses.
*/
const getChangedAccounts = async (cStateManager: any): Promise<string[]> => {
return new Promise<string[]>((resolve, reject) => {
const accounts: string[] = []
const stream = cStateManager._trie.createReadStream()
stream.on('data', (val: any) => {
accounts.push(val.key.toString('hex'))
})
stream.on('end', () => {
resolve(accounts)
})
})
}
/**
* Generates a storage dump for a given address.
* @param cStateManager Instance of the callback-based internal vm StateManager.
* @param address Address to generate a state dump for.
*/
const getStorageDump = async (
cStateManager: any,
address: string
): Promise<StorageDump> => {
return new Promise<StorageDump>((resolve, reject) => {
cStateManager._getStorageTrie(address, (err: any, trie: any) => {
if (err) {
reject(err)
}
const storage: StorageDump = {}
const stream = trie.createReadStream()
stream.on('data', (val: any) => {
storage[val.key.toString('hex')] = val.value.toString('hex')
})
stream.on('end', () => {
resolve(storage)
})
})
})
}
/**
* Replaces old addresses found in a storage dump with new ones.
* @param storageDump Storage dump to sanitize.
* @param accounts Set of accounts to sanitize with.
* @returns Sanitized storage dump.
*/
const sanitizeStorageDump = (
storageDump: StorageDump,
accounts: Accounts
): StorageDump => {
for (const [key, value] of Object.entries(storageDump)) {
let parsedKey = key
let parsedValue = value
for (const account of accounts) {
const re = new RegExp(`${account.originalAddress}`, 'g')
parsedValue = parsedValue.replace(re, account.address)
parsedKey = parsedKey.replace(re, account.address)
}
if (parsedKey !== key) {
delete storageDump[key]
}
storageDump[parsedKey] = parsedValue
}
return storageDump
}
export const makeStateDump = async (): Promise<any> => {
const ganache = (Ganache as any).provider({
gasLimit: 100_000_000,
allowUnlimitedContractSize: true,
accounts: [
{
secretKey:
'0x29f3edee0ad3abf8e2699402e0e28cd6492c9be7eaab00d732a791c33552f797',
balance: 10000000000000000000000000000000000,
},
],
})
const provider = new ethers.providers.Web3Provider(ganache)
const signer = provider.getSigner(0)
const config: RollupDeployConfig = {
deploymentSigner: signer,
ovmGasMeteringConfig: {
minTransactionGasLimit: 0,
maxTransactionGasLimit: 1_000_000_000,
maxGasPerQueuePerEpoch: 1_000_000_000_000,
secondsPerEpoch: 600,
},
transactionChainConfig: {
sequencer: signer,
forceInclusionPeriodSeconds: 600,
},
whitelistConfig: {
owner: signer,
allowArbitraryContractDeployment: true,
},
}
const deploymentResult = await deploy(config)
const pStateManager = ganache.engine.manager.state.blockchain.vm.pStateManager
const cStateManager = pStateManager._wrapped
const ovmExecutionManagerOriginalAddress = deploymentResult.contracts.OVM_ExecutionManager.address
.slice(2)
.toLowerCase()
const ovmExecutionManagerAddress = 'c0dec0dec0dec0dec0dec0dec0dec0dec0de0000'
const ovmStateManagerOriginalAddress = deploymentResult.contracts.OVM_StateManager.address
.slice(2)
.toLowerCase()
const ovmStateManagerAddress = 'c0dec0dec0dec0dec0dec0dec0dec0dec0de0001'
const l2ToL1MessagePasserDef = getContractDefinition(
'OVM_L2ToL1MessagePasser'
)
const l2ToL1MessagePasserHash = keccak256(
l2ToL1MessagePasserDef.deployedBytecode
)
const l2ToL1MessagePasserAddress = '4200000000000000000000000000000000000000'
const l1MessageSenderDef = getContractDefinition('OVM_L1MessageSender')
const l1MessageSenderHash = keccak256(l1MessageSenderDef.deployedBytecode)
const l1MessageSenderAddress = '4200000000000000000000000000000000000001'
const changedAccounts = await getChangedAccounts(cStateManager)
let deadAddressIndex = 0
let accounts: Accounts = []
for (const originalAddress of changedAccounts) {
const code = (
await pStateManager.getContractCode(originalAddress)
).toString('hex')
const codeHash = keccak256('0x' + code)
if (code.length === 0) {
continue
}
// Sorry for this one!
let address = originalAddress
if (codeHash === l2ToL1MessagePasserHash) {
address = l2ToL1MessagePasserAddress
} else if (codeHash === l1MessageSenderHash) {
address = l1MessageSenderAddress
} else if (originalAddress === ovmExecutionManagerOriginalAddress) {
address = ovmExecutionManagerAddress
} else if (originalAddress === ovmStateManagerOriginalAddress) {
address = ovmStateManagerAddress
} else {
address = `deaddeaddeaddeaddeaddeaddeaddeaddead${deadAddressIndex
.toString(16)
.padStart(4, '0')}`
deadAddressIndex++
}
accounts.push({
originalAddress,
address,
code: code,
})
}
const dump: StateDump = {
contracts: {
ovmExecutionManager: '0x' + ovmExecutionManagerAddress,
ovmStateManager: '0x' + ovmStateManagerAddress,
},
accounts: {},
}
for (const account of accounts) {
const storageDump = sanitizeStorageDump(
await getStorageDump(cStateManager, account.originalAddress),
accounts
)
dump.accounts[account.address] = {
balance: 0,
nonce: 0,
code: account.code,
storage: storageDump,
}
}
return dump
}
export const getLatestStateDump = (): StateDump => {
return require(path.join(__dirname, '../dumps', `state-dump.latest.json`))
}
export * from './contract-defs'
export * from './contract-dumps'
export * from './contract-deployment'
......@@ -7,10 +7,11 @@ export const setProxyTarget = async (
name: string,
target: Contract
): Promise<void> => {
const SimpleProxy = await (
const SimpleProxy: Contract = await (
await ethers.getContractFactory('Helper_SimpleProxy')
).deploy(target.address)
).deploy()
await SimpleProxy.setTarget(target.address)
await AddressManager.setAddress(name, SimpleProxy.address)
}
......
......@@ -144,18 +144,31 @@ export class ExecutionManagerTestRunner {
return
}
const AddressManager = await (
await ethers.getContractFactory('Lib_AddressManager')
).deploy()
this.contracts.OVM_SafetyChecker = await (
await ethers.getContractFactory('OVM_SafetyChecker')
).deploy()
await AddressManager.setAddress(
'OVM_SafetyChecker',
this.contracts.OVM_SafetyChecker.address
)
this.contracts.OVM_ExecutionManager = await (
await smoddit('OVM_ExecutionManager')
).deploy(this.contracts.OVM_SafetyChecker.address)
).deploy(AddressManager.address)
this.contracts.OVM_StateManager = await (
await smoddit('OVM_StateManager')
).deploy(this.contracts.OVM_ExecutionManager.address)
this.contracts.Helper_TestRunner = await (
await ethers.getContractFactory('Helper_TestRunner')
).deploy()
this.contracts.Factory__Helper_TestRunner_CREATE = await ethers.getContractFactory(
'Helper_TestRunner_CREATE'
)
......
......@@ -39,7 +39,16 @@
resolved "https://registry.yarnpkg.com/@ensdomains/resolver/-/resolver-0.2.4.tgz#c10fe28bf5efbf49bff4666d909aed0265efbc89"
integrity sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==
"@ethereum-waffle/chai@^3.0.0":
"@eth-optimism/smock@^0.1.0":
version "0.0.1"
resolved "https://registry.yarnpkg.com/@eth-optimism/smock/-/smock-0.0.1.tgz#8ea7379072eccfe5cac327e7eb78384f0e38b18c"
integrity sha512-lJmdXaDkAQ7Y2T9GfEzrhF6lrJ3WiEb8HJyDBjr2r3Cd4/0b2RAQj4kqkKLFZyGDMnAZ0O+XnTTyaKhBXkDSXw==
dependencies:
ethereum-waffle "^3"
ethers "^5"
fs-extra "^9.0.1"
"@ethereum-waffle/chai@^3.0.0", "@ethereum-waffle/chai@^3.1.1":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-3.1.1.tgz#2d2594e19613cdee0eaa1a38fc8dac31f66460e6"
integrity sha512-gbpjfIz+XhM9sH8BtBiRmK+eU6WuAWPK5TqIMR7QwzcGQ4XkIoFzACRNc/kxnV5f9Townpgr7yp0yzbzJJCWiw==
......@@ -47,7 +56,7 @@
"@ethereum-waffle/provider" "^3.1.1"
ethers "^5.0.0"
"@ethereum-waffle/compiler@^3.0.0":
"@ethereum-waffle/compiler@^3.0.0", "@ethereum-waffle/compiler@^3.1.1":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@ethereum-waffle/compiler/-/compiler-3.1.1.tgz#df3dba3c5dc556afe04f259e0789c16bc34333f5"
integrity sha512-vneBsbR7VaqZ0cDJRc+pr7aU6ZB8uO2h4ScKsn3GQIXE1GYB4i9eUxvRkdi5t/cS7YufnmUyKQU/IyAjivDcWw==
......@@ -70,7 +79,7 @@
"@ensdomains/resolver" "^0.2.4"
ethers "^5.0.1"
"@ethereum-waffle/mock-contract@^3.0.0":
"@ethereum-waffle/mock-contract@^3.0.0", "@ethereum-waffle/mock-contract@^3.1.1":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@ethereum-waffle/mock-contract/-/mock-contract-3.1.1.tgz#ae0fe5bcdb7a0ba64069098394ea4e54a02ed293"
integrity sha512-by4eUeL7FGQzczi4nM94YcnYWV9EPsjx9WI9A66LzLHHPdEyIvAUZyyBQ+9hLYwUqJ78ppLoVx+xYWEagHx/jg==
......@@ -3072,6 +3081,17 @@ ethereum-waffle@3.0.0:
"@ethereum-waffle/provider" "^3.0.0"
ethers "^5.0.1"
ethereum-waffle@^3:
version "3.1.1"
resolved "https://registry.yarnpkg.com/ethereum-waffle/-/ethereum-waffle-3.1.1.tgz#2a63475104281dca1fd2ffed12ab8f6605219d51"
integrity sha512-kiJo7PPGKsRfNiQOB8Z/ogLTHrU7Cj7VOZrdU3nyx9xXobkTFN9F9FcwdYZRg3gw3C1XnuOd18Jk2hPfuQbORA==
dependencies:
"@ethereum-waffle/chai" "^3.1.1"
"@ethereum-waffle/compiler" "^3.1.1"
"@ethereum-waffle/mock-contract" "^3.1.1"
"@ethereum-waffle/provider" "^3.1.1"
ethers "^5.0.1"
ethereumjs-abi@0.6.5:
version "0.6.5"
resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz#5a637ef16ab43473fa72a29ad90871405b3f5241"
......@@ -3088,15 +3108,7 @@ ethereumjs-abi@0.6.7:
bn.js "^4.11.8"
ethereumjs-util "^6.0.0"
ethereumjs-abi@^0.6.8:
version "0.6.8"
resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz#71bc152db099f70e62f108b7cdfca1b362c6fcae"
integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==
dependencies:
bn.js "^4.11.8"
ethereumjs-util "^6.0.0"
"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git":
ethereumjs-abi@^0.6.8, "ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git":
version "0.6.8"
resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#1ce6a1d64235fabe2aaf827fd606def55693508f"
dependencies:
......@@ -3322,7 +3334,7 @@ ethers@5.0.0:
"@ethersproject/web" "^5.0.0"
"@ethersproject/wordlists" "^5.0.0"
ethers@^5.0.0, ethers@^5.0.1:
ethers@^5, ethers@^5.0.0, ethers@^5.0.1:
version "5.0.14"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.0.14.tgz#fc33613ff3c1eb04c481f32083f2be315079e2a2"
integrity sha512-6WkoYwAURTr/4JiSZlrMJ9mm3pBv/bWrOu7sVXdLGw9QU4cp/GDZVrKKnh5GafMTzanuNBJoaEanPCjsbe4Mig==
......@@ -3821,7 +3833,7 @@ functional-red-black-tree@^1.0.1, functional-red-black-tree@~1.0.1:
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
ganache-core@^2.10.2:
ganache-core@^2.10.2, ganache-core@^2.12.1:
version "2.12.1"
resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.12.1.tgz#c21e8f7eca6e15f13756a353928357e0b8960d9e"
integrity sha512-gycoVl3TChAbL6ZZQrK1gS2cNMheX+JXVBKTpMAzuLHwb5gE1CB1s6YYN3F7rB86opaEuldCSuTJK1dv4xYRAw==
......
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