Skip to content

Commit

Permalink
Add test for instant upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
vladbochok committed Jan 5, 2022
1 parent c90c6a4 commit a34aa3a
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.7.0;

pragma experimental ABIEncoderV2;

import "../AdditionalZkSync.sol";

contract AdditionalZkSyncCutNoticePeriodUnitTest is AdditionalZkSync {
function enableUpgradeFromScratch() external {
upgradePreparationActive = false;
upgradePreparationActivationTime = 0;
approvedUpgradeNoticePeriod = UPGRADE_NOTICE_PERIOD;
upgradeStartTimestamp = block.timestamp;
for (uint256 i = 0; i < SECURITY_COUNCIL_MEMBERS_NUMBER; ++i) {
securityCouncilApproves[i] = false;
}
numberOfApprovalsFromSecurityCouncil = 0;
}

function disableUpgrade() external {
upgradeStartTimestamp = 0;
}

function getApprovedUpgradeNoticePeriod() external view returns (uint256) {
return approvedUpgradeNoticePeriod;
}
}
11 changes: 11 additions & 0 deletions contracts/contracts/dev-contracts/DummyUpgradeGatekeeper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.7.0;

contract DummyUpgradeGatekeeper {
address[] public nextTargets;

function setNextTargets(address[] calldata _targets) external {
nextTargets = _targets;
}
}
16 changes: 7 additions & 9 deletions contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@ const prodConfig = {
DUMMY_VERIFIER: false,
NEW_ADDITIONAL_ZKSYNC_ADDRESS: process.env.CONTRACTS_ADDITIONAL_ZKSYNC_ADDR,
UPGRADE_GATEKEEPER_ADDRESS: process.env.CONTRACTS_UPGRADE_GATEKEEPER_ADDR,
REGENESIS_MULTISIG_ADDRESS: process.env.MISC_REGENESIS_MULTISIG_ADDRESS,

SECURITY_COUNCIL_MEMBERS_NUMBER: process.env.MISC_SECURITY_COUNCIL_MEMBERS_NUMBER,
SECURITY_COUNCIL_MEMBERS: process.env.MISC_SECURITY_COUNCIL_MEMBERS,
SECURITY_COUNCIL_THRESHOLD: process.env.MISC_SECURITY_COUNCIL_THRESHOLD
};

const testnetConfig = {
UPGRADE_NOTICE_PERIOD: 0,
MAX_AMOUNT_OF_REGISTERED_TOKENS: 1023,
// PRIORITY_EXPIRATION: 101,
DUMMY_VERIFIER: false,
REGENESIS_MULTISIG_ADDRESS: process.env.MISC_REGENESIS_MULTISIG_ADDRESS,
NEW_ADDITIONAL_ZKSYNC_ADDRESS: process.env.CONTRACTS_ADDITIONAL_ZKSYNC_ADDR,
UPGRADE_GATEKEEPER_ADDRESS: process.env.CONTRACTS_UPGRADE_GATEKEEPER_ADDR,

Expand All @@ -32,26 +31,25 @@ const testnetConfig = {
};

const testConfig = {
UPGRADE_NOTICE_PERIOD: 0,
// UPGRADE_NOTICE_PERIOD: 0,
MAX_AMOUNT_OF_REGISTERED_TOKENS: 5,
PRIORITY_EXPIRATION: 101,
DUMMY_VERIFIER: true,
REGENESIS_MULTISIG_ADDRESS: '0xAA7113B9de498556dC76eDFEFc57681083c861C1',
NEW_ADDITIONAL_ZKSYNC_ADDRESS: process.env.CONTRACTS_ADDITIONAL_ZKSYNC_ADDR,
UPGRADE_GATEKEEPER_ADDRESS: process.env.CONTRACTS_UPGRADE_GATEKEEPER_ADDR,

SECURITY_COUNCIL_MEMBERS_NUMBER: process.env.MISC_SECURITY_COUNCIL_MEMBERS_NUMBER,
SECURITY_COUNCIL_MEMBERS: process.env.MISC_SECURITY_COUNCIL_MEMBERS,
SECURITY_COUNCIL_THRESHOLD: process.env.MISC_SECURITY_COUNCIL_THRESHOLD
SECURITY_COUNCIL_MEMBERS_NUMBER: '3',
// First 3 accounts obtained from `$ZKSYNC_HOME/etc/test_config/constant/test_mnemonic.json` mnemonic
SECURITY_COUNCIL_MEMBERS:
'0x36615Cf349d7F6344891B1e7CA7C72883F5dc049,0xa61464658AfeAf65CccaaFD3a512b69A83B77618,0x0D43eB5B8a47bA8900d84AA36656c92024e9772e',
SECURITY_COUNCIL_THRESHOLD: '2'
};

const localConfig = Object.assign({}, prodConfig);
// @ts-ignore
localConfig.UPGRADE_NOTICE_PERIOD = 0;
localConfig.DUMMY_VERIFIER = process.env.CONTRACTS_TEST_DUMMY_VERIFIER === 'true';
// @ts-ignore
localConfig.REGENESIS_MULTISIG_ADDRESS = process.env.MISC_REGENESIS_MULTISIG_ADDRESS;
// @ts-ignore
localConfig.NEW_ADDITIONAL_ZKSYNC_ADDRESS = process.env.CONTRACTS_ADDITIONAL_ZKSYNC_ADDR;

localConfig.SECURITY_COUNCIL_MEMBERS_NUMBER = process.env.MISC_SECURITY_COUNCIL_MEMBERS_NUMBER;
Expand Down
144 changes: 144 additions & 0 deletions contracts/test/instant_upgrade.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import * as hardhat from 'hardhat';
import { expect } from 'chai';
import { getCallRevertReason } from './common';
import {
AdditionalZkSyncCutNoticePeriodUnitTestFactory,
AdditionalZkSyncCutNoticePeriodUnitTest,
DummyUpgradeGatekeeper,
DummyUpgradeGatekeeperFactory
} from '../typechain';
import * as fs from 'fs';
import * as path from 'path';
import { ethers } from 'hardhat';

const testConfigPath = path.join(process.env.ZKSYNC_HOME as string, `etc/test_config/constant`);
const ethTestConfig = JSON.parse(fs.readFileSync(`${testConfigPath}/eth.json`, { encoding: 'utf-8' }));

const SECURITY_COUNCIL_MEMBERS_NUMBER = parseInt(hardhat.config.solpp.defs.SECURITY_COUNCIL_MEMBERS_NUMBER);
const SECURITY_COUNCIL_MEMBERS = hardhat.config.solpp.defs.SECURITY_COUNCIL_MEMBERS.split(',');
const SECURITY_COUNCIL_THRESHOLD = parseInt(hardhat.config.solpp.defs.SECURITY_COUNCIL_THRESHOLD);
const UPGRADE_GATEKEEPER_ADDRESS = hardhat.config.solpp.defs.UPGRADE_GATEKEEPER_ADDRESS;

async function signApproveCutUpgradeNoticePeriod(gatekeeper, signer): Promise<string> {
const targets = await Promise.all([
gatekeeper.nextTargets(0),
gatekeeper.nextTargets(1),
gatekeeper.nextTargets(2)
]);
const targetsHash = ethers.utils.solidityKeccak256(['address', 'address', 'address'], targets);
const signature = await signer.signMessage(`Approved new ZkSync's target contracts hash\n${targetsHash}`);

return signature;
}

describe('Instant upgrade with security council members', function () {
let securityCouncilMembers;
let zkSyncTarget: AdditionalZkSyncCutNoticePeriodUnitTest;
let upgradeGatekeeper: DummyUpgradeGatekeeper;

before(async () => {
// Address values of security council are hardcoded in contracts.
// Get accounts that can sign messages and check that they correspond to addresses that are hardcoded in the tests contract.
securityCouncilMembers = [];
for (let i = 0; i < SECURITY_COUNCIL_MEMBERS_NUMBER; ++i) {
const account = await hardhat.ethers.Wallet.fromMnemonic(
ethTestConfig.test_mnemonic,
"m/44'/60'/0'/0/" + i
).connect(hardhat.ethers.provider);
securityCouncilMembers.push(account);
await hardhat.network.provider.send('hardhat_setBalance', [account.address, '0xfffffffffffffffff']);

expect(account.address).to.eq(SECURITY_COUNCIL_MEMBERS[i]);
}

const zkSyncFactory = await hardhat.ethers.getContractFactory('AdditionalZkSyncCutNoticePeriodUnitTest');
const zkSyncContract = await zkSyncFactory.deploy();
zkSyncTarget = AdditionalZkSyncCutNoticePeriodUnitTestFactory.connect(
zkSyncContract.address,
zkSyncContract.signer
);
await zkSyncTarget.disableUpgrade();

// The address of `upgradeGatekeeper` is hardcoded as well, so we can't deploy a new contract
// so we set the bytecode to the address that is already hardcoded in the `additionalZkSync`
const upgradeGatekeeperArtifacts = await hardhat.artifacts.readArtifact('DummyUpgradeGatekeeper');
await hardhat.network.provider.send('hardhat_setCode', [
UPGRADE_GATEKEEPER_ADDRESS,
upgradeGatekeeperArtifacts.deployedBytecode
]);
upgradeGatekeeper = DummyUpgradeGatekeeperFactory.connect(UPGRADE_GATEKEEPER_ADDRESS, zkSyncContract.signer);
});

it('should fail to speed up upgrade before upgrade started', async () => {
const { revertReason } = await getCallRevertReason(() => zkSyncTarget.cutUpgradeNoticePeriod());
expect(revertReason).to.eq('p1');
});

it('should fail to speed up upgrade with signatures before upgrade started', async () => {
const { revertReason } = await getCallRevertReason(() => zkSyncTarget.cutUpgradeNoticePeriodBySignature([]));
expect(revertReason).to.eq('p2');
});

context('cut upgrade notice period through `cutUpgradeNoticePeriod`', function () {
beforeEach(async () => {
await zkSyncTarget.enableUpgradeFromScratch();
});

it('should NOT cut upgrade notice period without permission', async () => {
const tx = await zkSyncTarget.cutUpgradeNoticePeriod();
expect(tx).to.not.emit(zkSyncTarget, 'NoticePeriodChange');
expect(tx).to.not.emit(zkSyncTarget, 'approveCutUpgradeNoticePeriod');
});

it('cut upgrade notice period', async () => {
const noticePeriodBefore = await zkSyncTarget.getApprovedUpgradeNoticePeriod();
for (let i = 0; i < SECURITY_COUNCIL_MEMBERS_NUMBER; ++i) {
const tx = await zkSyncTarget.connect(securityCouncilMembers[i]).cutUpgradeNoticePeriod();
expect(tx).to.emit(zkSyncTarget, 'approveCutUpgradeNoticePeriod');
if (i == SECURITY_COUNCIL_THRESHOLD - 1) {
expect(tx).to.emit(zkSyncTarget, 'NoticePeriodChange');
} else {
expect(tx).to.not.emit(zkSyncTarget, 'NoticePeriodChange');
}
}
const noticePeriodAfter = await zkSyncTarget.getApprovedUpgradeNoticePeriod();

expect(noticePeriodBefore).to.not.eq(0);
expect(noticePeriodAfter).to.eq(0);
});
});

context('cut upgrade notice period through `cutUpgradeNoticePeriodBySignature`', function () {
before(async () => {
const targets = [ethers.constants.AddressZero, ethers.constants.AddressZero, zkSyncTarget.address];
await upgradeGatekeeper.setNextTargets(targets);
});

beforeEach(async () => {
await zkSyncTarget.enableUpgradeFromScratch();
});

it('should NOT cut upgrade notice period without permission', async () => {
const signature = await signApproveCutUpgradeNoticePeriod(upgradeGatekeeper, zkSyncTarget.signer);
const tx = await zkSyncTarget.cutUpgradeNoticePeriodBySignature([signature]);
expect(tx).to.not.emit(zkSyncTarget, 'NoticePeriodChange');
expect(tx).to.not.emit(zkSyncTarget, 'approveCutUpgradeNoticePeriod');
});

it('cut upgrade notice period', async () => {
const noticePeriodBefore = await zkSyncTarget.getApprovedUpgradeNoticePeriod();
const signatures = [];
for (let i = 0; i < SECURITY_COUNCIL_THRESHOLD; ++i) {
const signature = await signApproveCutUpgradeNoticePeriod(upgradeGatekeeper, securityCouncilMembers[i]);
signatures.push(signature);
}
const tx = await zkSyncTarget.cutUpgradeNoticePeriodBySignature(signatures);
expect(tx).to.emit(zkSyncTarget, 'approveCutUpgradeNoticePeriod');
expect(tx).to.emit(zkSyncTarget, 'NoticePeriodChange');
const noticePeriodAfter = await zkSyncTarget.getApprovedUpgradeNoticePeriod();

expect(noticePeriodBefore).to.not.eq(0);
expect(noticePeriodAfter).to.eq(0);
});
});
});
4 changes: 0 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10670,10 +10670,6 @@ yocto-queue@^0.1.0:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==

"zksync-config@link:contracts/https:/github.com/matter-labs/configs":
version "0.0.0"
uid ""

"zksync@link:sdk/zksync.js":
version "0.11.6"
dependencies:
Expand Down

0 comments on commit a34aa3a

Please sign in to comment.