Skip to content
This repository has been archived by the owner on Mar 25, 2024. It is now read-only.

feat: calculate-hashes command to detect contract changes #37

Merged
merged 26 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3621c4c
feat: calculate-hashes
benceharomi Oct 6, 2023
dacbeb3
fix: build-yul command updated
benceharomi Oct 6, 2023
d732a3e
chore: CI workflow renamed
benceharomi Oct 6, 2023
6355c20
feat(calculate-hashes): "--check-only" flag added
benceharomi Oct 8, 2023
62f8b9a
ci: calculate-hashes added to pipeline
benceharomi Oct 8, 2023
639650b
modifying hash to test calculate-hashes in CI
benceharomi Oct 8, 2023
30d5dd8
Revert "modifying hash to test calculate-hashes in CI"
benceharomi Oct 8, 2023
b4c7cd9
chore: bytecodeHash renamed
benceharomi Oct 9, 2023
adfd15e
chore: importing and typo
benceharomi Oct 9, 2023
f655642
feat: revert command renames
benceharomi Oct 11, 2023
4566798
chore: major calculate-hashes refactor
benceharomi Oct 11, 2023
1305230
Merge branch 'dev' into bh-evm-290-detect-when-bootloader-hash-has-ch…
benceharomi Oct 11, 2023
f9388f3
ci: check hashes into separate job
benceharomi Oct 11, 2023
6fb1383
ci: yarn cacheing
benceharomi Oct 11, 2023
dd1d9e7
fix: absolutePath
benceharomi Oct 11, 2023
cd5018b
fix: hash updated
benceharomi Oct 11, 2023
d5788c0
fix: SHA256 hash updated
benceharomi Oct 11, 2023
7d9770d
docs: readme updated
benceharomi Oct 12, 2023
4047088
chore: changed hashes to array
benceharomi Oct 12, 2023
59c390d
chore: SystemContractsHashes updated
benceharomi Oct 12, 2023
b8868f5
Merge branch 'dev' into bh-evm-290-detect-when-bootloader-hash-has-ch…
benceharomi Oct 16, 2023
e75c105
lint(calculate-hashes): format+lint
benceharomi Oct 16, 2023
494df9c
docs: command name typo
benceharomi Oct 16, 2023
247c90f
fix: calculate hashes updated
benceharomi Oct 16, 2023
0a9a14f
chore: automatic contracts details generation
benceharomi Oct 18, 2023
bfd2f28
chore: changed the order of json properties
benceharomi Oct 18, 2023
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
7 changes: 3 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: "Rust CI"
name: "CI"
on:
pull_request:

Expand All @@ -12,6 +12,5 @@ jobs:
node-version: 18.18.0
- run: yarn
- run: yarn build
- run: yarn preprocess
- run: yarn compile-yul

- run: yarn build-yul
- run: yarn calculate-hashes --check-only
16 changes: 7 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ To keep the zero-knowledge circuits as simple as possible and enable simple exte
These are privileged special-purpose contracts that instantiate some recurring actions on the protocol level. Some of the
most commonly used contracts:

`ContractDeployer` This contract is used to deploy new smart contracts. Its job is to make sure that the bytecode for each deployed
contract is known. This contract also defines the derivation address. Whenever a contract is deployed, a ContractDeployed
`ContractDeployer` This contract is used to deploy new smart contracts. Its job is to make sure that the bytecode for each deployed
contract is known. This contract also defines the derivation address. Whenever a contract is deployed, a ContractDeployed
event is emitted.

`L1Messenger` This contract is used to send messages from zkSync to Ethereum. For each message sent, the L1MessageSent event is emitted.
Expand All @@ -23,20 +23,18 @@ event is emitted.
the deployment nonce are stored in a single place) and also for the ease of the operator.

`Bootloader` For greater extensibility and to lower the overhead, some parts of the protocol (e.g. account abstraction rules) were
moved to an ephemeral contract called a bootloader.
moved to an ephemeral contract called a bootloader.

We call it ephemeral because it is not physically deployed and cannot be called, but it has a formal address that is used
We call it ephemeral because it is not physically deployed and cannot be called, but it has a formal address that is used
on msg.sender, when it calls other contracts.

## Building

This repository is used as a submodule of the [zksync-2-dev](https://github.com/matter-labs/zksync-2-dev).

Compile the solidity contracts: `yarn build`
Build the solidity contracts: `yarn build`

Run the bootloader preprocessor: `yarn preprocess`

Compile the yul contracts: `yarn hardhat run ./scripts/compile-yul.ts`
Build the yul contracts: `yarn build-yul`

## Update Process

Expand All @@ -48,7 +46,7 @@ Here is an overview of the release process of the system contracts which is aime

The `main` branch contains the latest code that is ready to be deployed into production. It reflects the most stable and audited version of the protocol.

### `dev` branch
### `dev` branch

The `dev` branch is for active development & the latest code changes. Whenever a new PR with system contract changes is created it should be based on the `dev` branch.

Expand Down
10 changes: 10 additions & 0 deletions SystemContractsHashes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
benceharomi marked this conversation as resolved.
Show resolved Hide resolved
"bootloader": {
"sourceCodeHash": "0x707be27f15eb14a7d15fd97a337f1226842ebc3f6239ecba2e67018753abe8b1",
"byteCodeHash": "0x010009416e909e0819593a9806bbc841d25c5cdfed3f4a1523497c6814e5194a"
},
"defaultAA": {
"sourceCodeHash": "0x0af09156a1485eb2f398a082027504281a8224f8d611662570d8a43efd967372",
"byteCodeHash": "0x0100065d134a862a777e50059f5e0fbe68b583f3617a67820f7edda0d7f253a0"
}
}
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@
"build": "hardhat compile",
"clean": "hardhat clean",
"fmt": "prettier --config prettier.js --write contracts/*.sol contracts/**/*.sol",
"preprocess": "rm -rf ./bootloader/build && yarn ts-node scripts/process.ts",
"preprocess-yul": "rm -rf ./bootloader/build && yarn ts-node scripts/process.ts",
"deploy-preimages": "ts-node scripts/deploy-preimages.ts",
"compile-yul": "ts-node scripts/compile-yul.ts"
"compile-yul": "ts-node scripts/compile-yul.ts",
"build-yul": "yarn preprocess-yul && yarn compile-yul",
"calculate-hashes" : "ts-node scripts/calculate-hashes.ts"
}
}
122 changes: 122 additions & 0 deletions scripts/calculate-hashes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { ethers } from "ethers";
import fs from "fs";
import { hashBytecode } from "zksync-web3/build/src/utils";

type Hashes = {
sourceCodeHash: string;
byteCodeHash: string;
};

type SystemContractsHashes = {
bootloader: Hashes;
defaultAA: Hashes;
};

const BOOTLOADER_SOURCE_CODE_PATH = "./bootloader/build/proved_batch.yul";
const BOOTLOADER_BYTECODE_PATH =
"./bootloader/build/artifacts/proved_batch.yul/proved_batch.yul.zbin";
const DEFAULT_ACCOUNT_SOURCE_CODE_PATH = "./contracts/DefaultAccount.sol";
const DEFAULT_ACCOUNT_JSON_PATH =
"./artifacts-zk/cache-zk/solpp-generated-contracts/DefaultAccount.sol/DefaultAccount.json";
const OUTPUT_FILE_PATH = "./SystemContractsHashes.json";

const readFileAsHexString = (path: string, errorMessage: string): string => {
try {
return "0x" + fs.readFileSync(path, "hex");
} catch {
throw new Error(errorMessage);
}
};

const loadBytecodeFromJson = (path: string, errorMessage: string): string => {
try {
const jsonFile = fs.readFileSync(path, "utf8");
return JSON.parse(jsonFile).bytecode;
} catch {
throw new Error(errorMessage);
}
};

const getHashes = (
sourceCode: string,
bytecode: string,
errorMessage: string
): Hashes => {
try {
return {
sourceCodeHash: ethers.utils.sha256(sourceCode),
benceharomi marked this conversation as resolved.
Show resolved Hide resolved
byteCodeHash: ethers.utils.hexlify(hashBytecode(bytecode)),
};
} catch {
throw new Error(errorMessage);
}
};

const main = async () => {
const checkOnly = process.argv.includes("--check-only");

const bootloaderSourceCode = readFileAsHexString(
BOOTLOADER_SOURCE_CODE_PATH,
"Failed to read Bootloader source code. Make sure to run `yarn build-yul` before you run this script!"
benceharomi marked this conversation as resolved.
Show resolved Hide resolved
);
const bootloaderBytecode = readFileAsHexString(
BOOTLOADER_BYTECODE_PATH,
"Failed to read Bootloader bytecode. Make sure to run `yarn build-yul` before you run this script!"
);
const defaultAASourceCode = readFileAsHexString(
DEFAULT_ACCOUNT_SOURCE_CODE_PATH,
"Failed to read DefaultAccount source code. Make sure to run `yarn build` before you run this script!"
);
const defaultAABytecode = loadBytecodeFromJson(
DEFAULT_ACCOUNT_JSON_PATH,
"Failed to read DefaultAccount bytecode. Make sure to run `yarn build` before you run this script!"
);

const systemContractsHashes: SystemContractsHashes = {
bootloader: getHashes(
bootloaderSourceCode,
bootloaderBytecode,
"Failed to calculate Bootloader hashes."
),
defaultAA: getHashes(
defaultAASourceCode,
defaultAABytecode,
"Failed to calculate DefaultAccount hashes."
),
};

const newSystemContractsHashes = JSON.stringify(
benceharomi marked this conversation as resolved.
Show resolved Hide resolved
systemContractsHashes,
null,
2
);

const oldSystemContractsHashes = fs.readFileSync(OUTPUT_FILE_PATH, "utf8");

if (oldSystemContractsHashes === newSystemContractsHashes) {
console.log(
"Calculated hashes match the hashes in the SystemContractsHashes.json file."
);
return;
} else if (checkOnly) {
console.error(
"Calculated hashes differ from the hashes in the SystemContractsHashes.json file. Exiting..."
benceharomi marked this conversation as resolved.
Show resolved Hide resolved
);
benceharomi marked this conversation as resolved.
Show resolved Hide resolved
process.exit(1);
} else {
console.log(
"Calculated hashes differ from the hashes in the SystemContractsHashes.json file. Updating..."
);

fs.writeFileSync(OUTPUT_FILE_PATH, newSystemContractsHashes);
console.log("Update finished. New hashes:");
console.log(newSystemContractsHashes);
}
};

main()
.then(() => process.exit(0))
.catch((err) => {
console.error("Error:", err.message || err);
process.exit(1);
});
Loading