forked from matter-labs/zksync
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c90c6a4
commit a34aa3a
Showing
5 changed files
with
190 additions
and
13 deletions.
There are no files selected for viewing
28 changes: 28 additions & 0 deletions
28
contracts/contracts/dev-contracts/AdditionalZkSyncCutNoticePeriodUnitTest.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
11
contracts/contracts/dev-contracts/DummyUpgradeGatekeeper.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters