Skip to content

Commit

Permalink
Review update
Browse files Browse the repository at this point in the history
  • Loading branch information
ignasirv committed Oct 21, 2024
1 parent 0225d15 commit a649b0f
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 108 deletions.
37 changes: 26 additions & 11 deletions deployment/v2/4_createRollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,35 @@ async function main() {
throw new Error(`Consensus contract not supported, supported contracts are: ${supportedConsensus}`);
}

// Check consensus compatibility
if (isVanillaClient) {
if (consensusContract !== "PolygonPessimisticConsensus") {
throw new Error(`Vanilla client only supports PolygonPessimisticConsensus`);
}
// Check sovereign params
const mandatorySovereignParams = [
"bridgeManager",
"sovereignWETHAddress",
"sovereignWETHAddressIsNotMintable",
"globalExitRootUpdater",
];
for (const parameterName of mandatorySovereignParams) {
if (typeof sovereignParams[parameterName] === undefined || sovereignParams[parameterName] === "") {
throw new Error(`Missing sovereign parameter: ${parameterName}`);
}
}
}

const dataAvailabilityProtocol = createRollupParameters.dataAvailabilityProtocol || "PolygonDataCommittee";

const supporteDataAvailabilityProtocols = ["PolygonDataCommittee"];
const supportedDataAvailabilityProtocols = ["PolygonDataCommittee"];

if (
consensusContract.includes("PolygonValidiumEtrog") &&
!supporteDataAvailabilityProtocols.includes(dataAvailabilityProtocol)
!supportedDataAvailabilityProtocols.includes(dataAvailabilityProtocol)
) {
throw new Error(
`Data availability protocol not supported, supported data availability protocols are: ${supporteDataAvailabilityProtocols}`
`Data availability protocol not supported, supported data availability protocols are: ${supportedDataAvailabilityProtocols}`
);
}

Expand Down Expand Up @@ -342,13 +361,6 @@ async function main() {
let batchData = "";
// If is vanilla client, replace genesis by sovereign contracts, else, inject initialization batch
if (isVanillaClient) {
// Check sovereign params
const mandatorySovereignParams = ["bridgeManager", "sovereignWETHAddress", "sovereignWETHAddressIsNotMintable", "globalExitRootUpdater"];
for (const parameterName of mandatorySovereignParams) {
if (sovereignParams[parameterName] === undefined || sovereignParams[parameterName] === "") {
throw new Error(`Missing sovereign parameter: ${parameterName}`);
}
}
const initializeParams = {
rollupID: rollupID,
gasTokenAddress,
Expand All @@ -362,7 +374,6 @@ async function main() {
globalExitRootUpdater: sovereignParams.globalExitRootUpdater,
};
genesis = await updateVanillaGenesis(genesis, chainID, initializeParams);
fs.writeFileSync(pathGenesis, JSON.stringify(genesis, null, 1));
} else {
if (consensusContract === "PolygonPessimisticConsensus") {
// Add the first batch of the created rollup
Expand Down Expand Up @@ -440,6 +451,10 @@ async function main() {
outputJson.verifierAddress = verifierContract.target;
outputJson.consensusContract = consensusContract;

// Rewrite updated genesis in case of vanilla client
if (isVanillaClient) {
fs.writeFileSync(pathGenesis, JSON.stringify(genesis, null, 1));
}
fs.writeFileSync(pathOutputJson, JSON.stringify(outputJson, null, 1));
}

Expand Down
170 changes: 73 additions & 97 deletions deployment/v2/utils/updateVanillaGenesis.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import {MemDB, ZkEVMDB, getPoseidon, smtUtils, processorUtils} from "@0xpolygonhermez/zkevm-commonjs";
const {Address} = require("ethereumjs-util");
import {ethers} from "hardhat";
const {getContractAddress} = require("@ethersproject/address");
import fs from "fs";
const bridgeContractName = "BridgeL2SovereignChain";
import {expect} from "chai";

async function updateVanillaGenesis(genesis, chainID, initializeParams) {
// Load genesis on a zkEVMDB
Expand All @@ -25,13 +24,11 @@ async function updateVanillaGenesis(genesis, chainID, initializeParams) {
const batch = await zkEVMDB.buildBatch(
1000, //limitTimestamp
ethers.ZeroAddress, //trustedSequencer
smtUtils.stringToH4(ethers.ZeroHash),
undefined,
{} //options
smtUtils.stringToH4(ethers.ZeroHash), // l1InfoRoot
);
// Add changeL2Block tx
const txChangeL2Block = {
type: 11,
type: 11,
deltaTimestamp: 3,
l1Info: {
globalExitRoot: "0x090bcaf734c4f06c93954a827b45a6e8c67b8e0fd1e0a35a1c5982d6961828f9",
Expand All @@ -47,52 +44,53 @@ async function updateVanillaGenesis(genesis, chainID, initializeParams) {
const sovereignBridgeFactory = await ethers.getContractFactory("BridgeL2SovereignChain");
// Get deploy transaction for bridge
const deployBridgeData = await sovereignBridgeFactory.getDeployTransaction();
const deployer = genesis.genesis.find((o: {accountName: string}) => o.accountName === "deployer");
let deployerNonce = Number(deployer.nonce);
const txDeploy = ethers.Transaction.from({
const injectedTx = {
type: 0, // force ethers to parse it as a legacy transaction
chainId: 0, // force ethers to parse it as a pre-EIP155 transaction
to: null,
nonce: deployerNonce,
value: 0,
gasLimit: 10000000,
gasPrice: 0,
gasLimit: 30000000,
nonce: 0,
data: deployBridgeData.data,
chainId: chainID,
type: 0, // legacy transaction
});
await addTxToBatch(batch, txDeploy);
const sovereignBridgeAddress = getContractAddress({from: deployer.address, nonce: deployerNonce++}); // Increase nonce
signature: {
v: "0x1b",
r: "0x00000000000000000000000000000000000000000000000000000005ca1ab1e0",
s: "0x000000000000000000000000000000000000000000000000000000005ca1ab1e",
},
};
let txObject = ethers.Transaction.from(injectedTx);
const txDeployBridge = processorUtils.rawTxToCustomRawTx(txObject.serialized);
// Check ecrecover
expect(txObject.from).to.equal(ethers.recoverAddress(txObject.unsignedHash, txObject.signature))
batch.addRawTx(txDeployBridge);
const sovereignBridgeAddress = getContractAddress({from: txObject.from, nonce: injectedTx.nonce});

// Create deploy GER transaction
const gerContractName = "GlobalExitRootManagerL2SovereignChain";
const gerFactory = await ethers.getContractFactory(gerContractName);
const deployGERData = await gerFactory.getDeployTransaction(sovereignBridgeAddress);
txDeploy.nonce = deployerNonce;
txDeploy.data = deployGERData.data;
await addTxToBatch(batch, txDeploy);
const GERAddress = getContractAddress({from: deployer.address, nonce: deployerNonce++});
injectedTx.data = deployGERData.data;
txObject = ethers.Transaction.from(injectedTx);
const txDeployGER = processorUtils.rawTxToCustomRawTx(txObject.serialized);
batch.addRawTx(txDeployGER);
const GERAddress = getContractAddress({from: txObject.from, nonce: injectedTx.nonce});

await batch.executeTxs();
await zkEVMDB.consolidate(batch);

// Get values of bridge and ger for genesis
const gerGenesis = await getDataFromBatch(GERAddress, batch);
const bridgeGenesis = await getDataFromBatch(sovereignBridgeAddress, batch);

// replace old bridge and ger manager by sovereign contracts bytecode
const oldBridge = genesis.genesis.find(function (obj) {
return obj.contractName == "PolygonZkEVMBridgeV2";
});
oldBridge.contractName = bridgeContractName;
oldBridge.bytecode = bridgeGenesis.bytecode;
// oldBridge.storage = bridgeGenesis.storage;
oldBridge.bytecode = `0x${await zkEVMDB.getBytecode(sovereignBridgeAddress)}`;

const oldGer = genesis.genesis.find(function (obj) {
return obj.contractName == "PolygonZkEVMGlobalExitRootL2";
});
oldGer.contractName = gerContractName;
oldGer.bytecode = gerGenesis.bytecode;
// oldGer.storage = gerGenesis.storage;
// Update genesis with new contracts bytecode and storage
oldGer.bytecode = `0x${await zkEVMDB.getBytecode(GERAddress)}`;

// Setup a second zkEVM to initialize both contracts
const zkEVMDB2 = await ZkEVMDB.newZkEVM(
Expand Down Expand Up @@ -145,22 +143,9 @@ async function updateVanillaGenesis(genesis, chainID, initializeParams) {
const bridgeProxy = genesis.genesis.find(function (obj) {
return obj.contractName == "PolygonZkEVMBridgeV2 proxy";
});
const injectedTx = {
type: 0, // force ethers to parse it as a legacy transaction
chainId: 0, // force ethers to parse it as a pre-EIP155 transaction
to: bridgeProxy.address,
value: 0,
gasPrice: 0,
gasLimit: 30000000,
nonce: 0,
data: initializeData,
signature: {
v: "0x1b",
r: "0x00000000000000000000000000000000000000000000000000000005ca1ab1e0",
s: "0x000000000000000000000000000000000000000000000000000000005ca1ab1e",
},
};
const txObject = ethers.Transaction.from(injectedTx);
injectedTx.to = bridgeProxy.address;
injectedTx.data = initializeData;
txObject = ethers.Transaction.from(injectedTx);
const txInitializeBridge = processorUtils.rawTxToCustomRawTx(txObject.serialized);
batch2.addRawTx(txInitializeBridge);

Expand All @@ -181,63 +166,54 @@ async function updateVanillaGenesis(genesis, chainID, initializeParams) {
await batch2.executeTxs();
await zkEVMDB2.consolidate(batch2);

const proxyBridgeInitializedGenesis = await getDataFromBatch(bridgeProxy.address, batch2);

// Update bridgeProxy genesis
// Update bridgeProxy storage
bridgeProxy.contractName = bridgeContractName + " proxy";
bridgeProxy.storage = proxyBridgeInitializedGenesis.storage;

const proxyGERInitializedGenesis = await getDataFromBatch(gerProxy.address, batch2);
bridgeProxy.storage = await zkEVMDB2.dumpStorage(bridgeProxy.address);
// Pad storage values with zeros
const padTo32Bytes = (value) => {
const hexValue = value.startsWith("0x") ? value.slice(2) : value; // Remove '0x'
return "0x" + hexValue.padStart(64, "0"); // Pad to 64 hex digits
};
bridgeProxy.storage = Object.entries(bridgeProxy.storage).reduce((acc, [key, value]) => {
acc[key] = padTo32Bytes(value);
return acc;
}, {});

// Sanity check bridge storage
if (rollupID !== 0) {
expect(
ethers.toBigInt(bridgeProxy.storage["0x0000000000000000000000000000000000000000000000000000000000000000"])
).to.equal(ethers.toBigInt(ethers.toBeHex(rollupID)));
}
if (gasTokenAddress !== ethers.ZeroAddress) {
expect(
ethers.toBigInt(bridgeProxy.storage["0x000000000000000000000000000000000000000000000000000000000000006d"])
).to.equal(
ethers.toBigInt(`${ethers.toBeHex(gasTokenNetwork)}${gasTokenAddress.replace(/^0x/, "")}`.toLowerCase())
);
}
expect(bridgeProxy.storage["0x0000000000000000000000000000000000000000000000000000000000000068"]).to.include(
globalExitRootManager.toLowerCase().slice(2)
);
expect(bridgeProxy.storage["0x00000000000000000000000000000000000000000000000000000000000000a3"]).to.include(
bridgeManager.toLowerCase().slice(2)
);

// Update bridgeProxy genesis
// Update bridgeProxy storage
gerProxy.contractName = gerContractName + " proxy";
gerProxy.storage = proxyGERInitializedGenesis.storage;
gerProxy.storage = await zkEVMDB2.dumpStorage(gerProxy.address);
gerProxy.storage = Object.entries(gerProxy.storage).reduce((acc, [key, value]) => {
acc[key] = padTo32Bytes(value);
return acc;
}, {});

// Sanity check ger storage
expect(gerProxy.storage["0x0000000000000000000000000000000000000000000000000000000000000034"]).to.include(
globalExitRootUpdater.toLowerCase().slice(2)
);
// update genesis root
genesis.root = smtUtils.h4toString(zkEVMDB2.stateRoot);
// fs.writeFileSync("genesis-vanilla.json", JSON.stringify(genesis, null, 2));
genesis.root = smtUtils.h4toString(zkEVMDB2.getCurrentStateRoot());
return genesis;
}

/**
* Adds a deploy transaction to the batch, it is signer by deployer address
* @param batch Batch to add the transaction
* @param tx tx to add to the batch
*/
async function addTxToBatch(batch, tx) {
const signer = ethers.HDNodeWallet.fromMnemonic(
ethers.Mnemonic.fromPhrase("test test test test test test test test test test test junk"),
"m/44'/60'/0'/0/0"
);
const signedTx = await signer.signTransaction(tx);
const rawTx = processorUtils.rawTxToCustomRawTx(signedTx);
batch.addRawTx(rawTx);
}

/**
* Creates a contract object with the current state of the contract
* @param contractAddress to retrieve the data
* @param batch to obtain the vm
* @returns the current state of the contract
*/
async function getDataFromBatch(contractAddress, batch) {
const addressInstance = Address.fromString(contractAddress);
const account = await batch.vm.stateManager.getAccount(addressInstance);
const code = await batch.vm.stateManager.getContractCode(addressInstance);
const sto = await batch.vm.stateManager.dumpStorage(addressInstance);
const keys = Object.keys(sto).map((k) => `0x${k}`);
const values = Object.values(sto).map((k) => `0x${k}`);
const contractObject = {
balance: account.balance.toString(),
nonce: account.nonce.toString(),
address: contractAddress,
bytecode: `0x${code.toString("hex")}`,
storage: {},
};
for (let k = 0; k < keys.length; k++) {
const value = ethers.decodeRlp(values[k]);
contractObject.storage[keys[k]] = `0x${value.replace(/^0x/, "").padStart(64, "0")}`;
}
return contractObject;
}

export default updateVanillaGenesis;

0 comments on commit a649b0f

Please sign in to comment.