Skip to content
This repository has been archived by the owner on Dec 5, 2021. It is now read-only.

Add regenesis #237

Open
wants to merge 27 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
62e72c5
Add regenesis
boyuan-chen Jul 27, 2021
9e64856
Merge branch 'develop' into add-regenesis
CAPtheorem Jul 28, 2021
ec3e1ae
Merge branch 'develop' into add-regenesis
CAPtheorem Jul 28, 2021
83340fd
Merge branch 'develop' into add-regenesis
CAPtheorem Jul 30, 2021
353b4c1
Add L1MessengerRegenesis contract
boyuan-chen Jul 30, 2021
bbd746f
In progress
boyuan-chen Jul 31, 2021
e90dcf9
Merge branch 'develop' into add-regenesis
CAPtheorem Aug 1, 2021
301c298
Merge branch 'develop' into add-regenesis
CAPtheorem Aug 1, 2021
65531fb
Merge branch 'develop' into add-regenesis
boyuan-chen Aug 2, 2021
28fdce1
Add regenesis
boyuan-chen Aug 2, 2021
1f6a6c8
Add message relayer regenesis
boyuan-chen Aug 2, 2021
9b0c8d0
Update package.json
boyuan-chen Aug 2, 2021
3c4b3ac
Update package.json
boyuan-chen Aug 2, 2021
9752d3c
Update README.md
boyuan-chen Aug 2, 2021
4e931fb
Update README.md
boyuan-chen Aug 3, 2021
33fcaa1
Remove OVM_L1CrossDomainMessenger
boyuan-chen Aug 3, 2021
34d9982
Merge branch 'develop' into add-regenesis
CAPtheorem Aug 5, 2021
05cd647
Fix regenesis contract
boyuan-chen Aug 5, 2021
baf9559
Merge branch 'develop' into add-regenesis
CAPtheorem Aug 5, 2021
cb66f83
regenesis v2
boyuan-chen Aug 5, 2021
41713ba
Finish Regenesis
boyuan-chen Aug 6, 2021
f0246d1
Merge branch 'develop' into add-regenesis
CAPtheorem Aug 9, 2021
217f5f8
Merge branch 'develop' into add-regenesis
CAPtheorem Aug 11, 2021
0239748
Merge branch 'develop' into add-regenesis
boyuan-chen Aug 25, 2021
9497c82
Add integration regenesis
boyuan-chen Aug 25, 2021
7c07797
Merge branch 'add-regenesis' of https://github.com/omgnetwork/optimis…
boyuan-chen Aug 25, 2021
198cb28
Merge branch 'develop' into add-regenesis
CAPtheorem Sep 12, 2021
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
28 changes: 12 additions & 16 deletions omgx_documention/Service_maintenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ We open the following the ports:
>
> `omgx/l2geth`: it's the most important service, so we should give as much memory as we can.
>
> `omgx/message-relayer-fast` and `omgx/message-relayer` : both message relayers can stop due the OOM issue. Giving it **4GB** memory can reduce the number of times that it needs to restart.
> `omgx/message-relayer-fast` and `omgx/message-relayer` : both message relayers can stop due the OOM issue. Giving it **4GB** memory can reduce the number of times that it needs to restart.
>
> [**IMPORTANT**] When `omgx/message-relayer-fast` and `omgx/message-relayer` restart, they scans all L2 blocks and check if there is a cross domain message and if the message is relayed to L1. It takes about 5 mins to sync 4K L2 blocks.

Expand Down Expand Up @@ -144,22 +144,18 @@ type Genesis struct {
}
```

### Bypass `GasPriceOracleOwnerAddress`
### Make regenesis

Modify `l2GasPriceOracleAddress` in [rollup/sync_service.go](https://github.com/omgnetwork/optimism/blob/9e07036f61a02ffb23eff405c3274f5f24950ad5/l2geth/rollup/sync_service.go#L49).
Download the l2geth data from the server first, then get the state dump via

```go
var (
// l2GasPriceSlot refers to the storage slot that the L2 gas price is stored
// in in the OVM_GasPriceOracle predeploy
l2GasPriceSlot = common.BigToHash(big.NewInt(1))
// l2GasPriceOracleOwnerSlot refers to the storage slot that the owner of
// the OVM_GasPriceOracle is stored in
l2GasPriceOracleOwnerSlot = common.BigToHash(big.NewInt(0))
// l2GasPriceOracleAddress is the address of the OVM_GasPriceOracle
// predeploy
// l2GasPriceOracleAddress = common.HexToAddress("0x420000000000000000000000000000000000000F")
l2GasPriceOracleAddress = common.HexToAddress("OVM_GasPriceOracleAddress")
)
```
geth dump LATEST_BLOCK_NUMBER --datadir DIR > state-dump.genesis.json
```

Move `state-dump.genesis.json` to `packages/contracts/dist/dump` and run

```
yarn build:dump
yarn build:regenesis
```

3 changes: 1 addition & 2 deletions ops/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: "3"

services:

# base service builder
builder:
image: omgx/builder:latest
Expand Down Expand Up @@ -314,7 +314,6 @@ services:
#GAS_PRICE_ORACLE_ETHEREUM_HTTP_URL: http://l2geth:8545 # Defined in the upstream ethereum-optimism .yml file
L1_NODE_WEB3_URL: http://l1_chain:8545
L2_NODE_WEB3_URL: http://l2geth:8545
GAS_PRICE_ORACLE_PRIVATE_KEY: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
GAS_PRICE_ORACLE_ADDRESS: "0x420000000000000000000000000000000000000F"
DEPLOYER_PRIVATE_KEY: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
SEQUENCER_PRIVATE_KEY: "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
Expand Down
17 changes: 17 additions & 0 deletions packages/contracts/bin/take-regenesis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* External Imports */
import * as fs from 'fs'
import * as path from 'path'

/* Internal Imports */
import { makeRegenesisDump } from '../src/regenesis/make-regenesis'
;(async () => {
const outdir = path.resolve(__dirname, '../dist/dumps')
const stateDumpLatestDir = path.join(outdir, 'state-dump.latest.json')
const stateDumpGenesisDir = path.join(outdir, 'state-dump.genesis.json')

const stateDumpLatest = JSON.parse(fs.readFileSync(stateDumpLatestDir, 'utf-8'))
const stateDumpGenesis = JSON.parse(fs.readFileSync(stateDumpGenesisDir, 'utf-8'))

const dump = makeRegenesisDump(stateDumpLatest, stateDumpGenesis)
fs.writeFileSync(stateDumpLatestDir, JSON.stringify(dump, null, 4))
})()
1 change: 1 addition & 0 deletions packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"build:contracts": "hardhat compile --show-stack-traces",
"build:contracts:ovm": "hardhat compile --network optimism",
"build:dump": "ts-node \"bin/take-dump.ts\"",
"build:regenesis": "ts-node \"bin/take-regenesis.ts\"",
"build:typechain": "hardhat typechain",
"build:typechain:ovm": "hardhat --network optimism typechain",
"test": "yarn run test:contracts",
Expand Down
36 changes: 36 additions & 0 deletions packages/contracts/src/regenesis/make-regenesis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export const makeRegenesisDump = (dump:any, genesis: any) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the script that we have used to make the regenesis: https://github.com/ethereum-optimism/scripts/blob/main/scripts/state-surgery.js. It currently includes some specific logic for the previous regenesis, so look at its history if you are interested in seeing a more pure form.

Whenever there is another regenesis, we will move it into the monorepo and be very thorough around using it and documenting it.

const stateDumpGeneis = genesis.accounts
const stateDumpLatest = dump.accounts

// We only update the data storage of OVM_ETH
// in state-dump.latest.json
const updatePredeployedContract = [
"OVM_ETH",
]
// get the predeployed contracts
// { CONTRACT_ADDRESS: CONTRACT_NAME }
const predeployedContract = Object.keys(stateDumpLatest)
.reduce((acc, cur) => {
acc[stateDumpLatest[cur].address] = cur
return acc
}, {})

predeployedContract["0x420000000000000000000000000000000000000b"] = "EXECUTION_MANAGER_WRAPPER"
predeployedContract["0x420000000000000000000000000000000000000f"] = "OVM_GasPriceOracle"

for (const eachAddress of Object.keys(stateDumpGeneis)) {
const contractName = predeployedContract[eachAddress]
// contracts that are not predeployed
if (typeof contractName === 'undefined') {
stateDumpLatest[eachAddress] = {
address: eachAddress,
...stateDumpGeneis[eachAddress]
}
// Update OVM_ETH
} else if (updatePredeployedContract.includes(contractName)) {
stateDumpLatest[contractName].storage = stateDumpGeneis[eachAddress].storage
}
}

return { accounts: stateDumpLatest }
}
11 changes: 11 additions & 0 deletions packages/omgx/regenesis/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
NODE_ENV=local
L1_NODE_WEB3_URL=http://localhost:9545
L2_NODE_WEB3_URL=http://localhost:8545
ADDRESS_MANAGER_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
L1_WALLET_KEY=0xde9be858da4a475276426320d5e9262ecfc3ba460bfac56360bfa6c4c28b4ee0
TEST_PRIVATE_KEY_1=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
TARGET_GAS_LIMIT=9000000000
CHAIN_ID=28
URL=http://localhost:8080/addresses.json
OMGX_URL=http://localhost:8078/addresses.json
78 changes: 78 additions & 0 deletions packages/omgx/regenesis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Regenesis

The regenesis means that we upgrade the OMGX network by regenerating the genesis block. During the regenesis, the state dump of the latest block is generated (including all user's nonces, token balances, contract code, and contract storage) and a new chain is spun up from this latest state sump. Since the new chain is started from the new genesis block, we have to remove all transaction history and logs. The transaction history and logs will be inaccessible from the new chain except under extreme circumstances.

## Upcoming

### 2.0.0 - L2 upgradeablity

* Rinkeby -- 08/04/2021

Upgrade the gas contract and add the fee vault contract

## What will happen on the Regenesis day?

The regenesis process takes up to 6 hours. All deposits will be halted and the L2 endpoint will become private! **DON'T** deposit your funds to **L1StandardTokenBridge** and **L1LiquidityPool** during the regenesis process! We will accept new transactions again once the regenesis is done.

## How does a Regenesis affect tooling?

Since we start from the block #0 after the regenesis, the Graph will have to re-sync their hosted service and users will have to redeploy all of their subgraphs. [blockexplorer](https://blockexplorer.rinkeby.omgx.network/?network=OmgX) won't maintain the transaction history before the regenesis.

## How do we make a Regenesis?

> This part is for someone who understands the optimism infrastructure.

### Step 0: make the L2 endpoint private

The L2 endpoint can only be accessed from specific ip addresses.

### Step 1: speed up the pending transactions from L2 to L1

The genesis redeploys all L1 contracts, so there is no way to relay those messages to L1 after the regenesis. Speeding up the transactions requires us to deploy a new **OVM_L1CrossDomainMessenger** to bypass the 7-day waiting period first.

Deploying a new **OVM_L1CrossDomainMessenger** via:

```bash
cd packages/omgx/regenesis
yarn build:contracts
yarn deploy
```

After deploying the **OVM_L1CrossDomainMessenger** contract, run the modified message relayer via:

```bash
yarn build
yarn start
```

The modified message relayer scans all the messages that are supposed to be relayed on L1 contract and makes sure that all messages are relayed to L1 contracts.

### Step 2: redeploy contracts

The regenesis means that we will redeploy the L1 contracts. However, we don't redeploy the following contracts: **Lib_AddressManager**, **Proxy__OVM_L1CrossDomainMessenger**, **Proxy__OVM_L1StandardBridge** and **Proxy__OVM_L1CrossDomainMessengerFast**. The address of **Lib_AddressManager** is stored in the proxy contracts, we have to keep both proxy contracts and address manager contract. Removing the rest `.json` files in `packages/contracts/deployments/..` and deploying the new contracts via:

```bash
yarn deploy
```

### Step 3: take a state dump of the latest block

The L2 chain data is stored in EC2 and ECS. Copy the L2 chain data to your local directory first, then run

```bash
geth dump LATEST_BLOCK_NUMBER --datadir DATADIRCTOTY > packages/contracts/dist/dump/state-dump.regenesis.json
```

Migrate the latest state dump data into our genesis block json file via:

```bash
yarn build:dump
yarn build:regenesis
```

### Step 4: fire up a new chain using the new `state-dump.latest.json`

## Note

The regenesis process is very **dangerous!** **DON'T touch it if you don't understand what you are doing.**

96 changes: 96 additions & 0 deletions packages/omgx/regenesis/bin/deploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Wallet, providers } from 'ethers'
import { getContractFactory } from '@eth-optimism/contracts'

require('dotenv').config()

import hre from 'hardhat'

const main = async () => {

console.log('Starting OMGX regenesis contracts deployment...')

//const config = parseEnv()
//not clear if the output is used anywhere?

const network = process.env.NETWORK || 'local'

const l1Provider = new providers.JsonRpcProvider(process.env.L1_NODE_WEB3_URL)
const l2Provider = new providers.JsonRpcProvider(process.env.L2_NODE_WEB3_URL)

const deployer_l1 = new Wallet(process.env.DEPLOYER_PRIVATE_KEY, l1Provider)
const deployer_l2 = new Wallet(process.env.DEPLOYER_PRIVATE_KEY, l2Provider)

const getAddressManager = (provider: any, addressManagerAddress: any) => {
return getContractFactory('Lib_AddressManager')
.connect(provider)
.attach(addressManagerAddress) as any
}

console.log(`ADDRESS_MANAGER_ADDRESS was set to ${process.env.ADDRESS_MANAGER_ADDRESS}`)
const addressManager = getAddressManager(deployer_l1, process.env.ADDRESS_MANAGER_ADDRESS);

const l1MessengerAddress = await addressManager.getAddress(
'Proxy__OVM_L1CrossDomainMessenger'
)

const OVM_L1CrossDomainMessengerAddress = await addressManager.getAddress(
'OVM_L1CrossDomainMessenger'
)

const l2MessengerAddress = await addressManager.getAddress(
'OVM_L2CrossDomainMessenger'
)

const L1StandardBridgeAddress = await addressManager.getAddress(
'Proxy__OVM_L1StandardBridge'
)
const L1StandardBridge = getContractFactory('OVM_L1StandardBridge')
.connect(deployer_l1)
.attach(L1StandardBridgeAddress)

const L2StandardBridgeAddress = await L1StandardBridge.l2TokenBridge()

await hre.run('deploy', {
l1MessengerAddress,
l2MessengerAddress,
OVM_L1CrossDomainMessengerAddress,
L1StandardBridgeAddress,
L2StandardBridgeAddress,
l1Provider,
l2Provider,
deployer_l1,
deployer_l2,
addressManager,
network,
//noCompile: process.env.NO_COMPILE ? true : false, //not clear how/where this is connected
})

}

main()
.then(() => process.exit(0))
.catch((error) => {
console.log(
JSON.stringify({ error: error.message, stack: error.stack }, null, 2)
)
process.exit(1)
})

//Based on the code, does not seem to be used?
// function parseEnv() {

// function ensure(env, type) {
// if (typeof process.env[env] === 'undefined')
// return undefined
// if (type === 'number')
// return parseInt(process.env[env], 10)
// return process.env[env]
// }

// return {
// l1provider: ensure('L1_NODE_WEB3_URL', 'string'),
// l2provider: ensure('L2_NODE_WEB3_URL', 'string'),
// deployer: ensure('DEPLOYER_PRIVATE_KEY', 'string'),
// emOvmChainId: ensure('CHAIN_ID', 'number'),
// }
// }
67 changes: 67 additions & 0 deletions packages/omgx/regenesis/contracts/L1Message.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0;

/* Library Imports */
import "@eth-optimism/contracts/contracts/optimistic-ethereum/libraries/bridge/OVM_CrossDomainEnabled.sol";
import { L2Message } from "./L2Message.sol";

contract L1Message is OVM_CrossDomainEnabled {

address L2MessageAddress;
string crossDomainMessage;
uint256 public crossDomainMessageCount;

event ReceiveL2Message (
string _message
);

/********************
* Constructor *
********************/
constructor (
address _l1CrossDomainMessenger
)
OVM_CrossDomainEnabled(_l1CrossDomainMessenger)
{}

function init (
address _L2MessageAddress
)
public
{
L2MessageAddress = _L2MessageAddress;
}

function sendMessageL1ToL2 () public {
bytes memory data = abi.encodeWithSelector(
L2Message.receiveL1Message.selector,
"messageFromL1"
);

// Send calldata into L1
sendCrossDomainMessage(
address(L2MessageAddress),
1200000,
data
);
}

/*************************
* Cross-chain Functions *
*************************/

/**
* Receive message from L2
* @param _message message
*/
function receiveL2Message(
string memory _message
)
external
onlyFromCrossDomainAccount(address(L2MessageAddress))
{
crossDomainMessage = _message;
crossDomainMessageCount = crossDomainMessageCount + 1;
emit ReceiveL2Message(_message);
}
}
Loading