Skip to content

Commit

Permalink
mirror to both 5ff1252 and 77ef3c5 (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
mm-zk committed Sep 5, 2023
1 parent fa37065 commit 67f38da
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 44 deletions.
4 changes: 4 additions & 0 deletions ethereum/contracts/zksync/Config.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,7 @@ uint256 constant MAX_NEW_FACTORY_DEPS = $(MAX_NEW_FACTORY_DEPS);

/// @dev The L2 gasPricePerPubdata required to be used in bridges.
uint256 constant REQUIRED_L2_GAS_PRICE_PER_PUBDATA = $(REQUIRED_L2_GAS_PRICE_PER_PUBDATA);

/// @dev The mask which should be applied to the packed batch and L2 block timestamp in order
/// to obtain the L2 block timestamp. Applying this mask is equivalent to calculating modulo 2**128
uint256 constant PACKED_L2_BLOCK_TIMESTAMP_MASK = 0xffffffffffffffffffffffffffffffff;
63 changes: 42 additions & 21 deletions ethereum/contracts/zksync/facets/Executor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

pragma solidity ^0.8.13;

import "./Base.sol";
import "../Config.sol";
import "../interfaces/IExecutor.sol";
import "../libraries/PairingsBn254.sol";
import "../libraries/PriorityQueue.sol";
import "../../common/libraries/UncheckedMath.sol";
import "../../common/libraries/UnsafeBytes.sol";
import "../../common/libraries/L2ContractHelper.sol";
import {Base} from "./Base.sol";
import {COMMIT_TIMESTAMP_NOT_OLDER, COMMIT_TIMESTAMP_APPROXIMATION_DELTA, EMPTY_STRING_KECCAK, L2_TO_L1_LOG_SERIALIZE_SIZE, INPUT_MASK, MAX_INITIAL_STORAGE_CHANGES_COMMITMENT_BYTES, MAX_REPEATED_STORAGE_CHANGES_COMMITMENT_BYTES, MAX_L2_TO_L1_LOGS_COMMITMENT_BYTES, PACKED_L2_BLOCK_TIMESTAMP_MASK} from "../Config.sol";
import {IExecutor} from "../interfaces/IExecutor.sol";
import {PairingsBn254} from "../libraries/PairingsBn254.sol";
import {PriorityQueue, PriorityOperation} from "../libraries/PriorityQueue.sol";
import {UncheckedMath} from "../../common/libraries/UncheckedMath.sol";
import {UnsafeBytes} from "../../common/libraries/UnsafeBytes.sol";
import {L2ContractHelper} from "../../common/libraries/L2ContractHelper.sol";
import {VerifierParams} from "../Storage.sol";
import {L2_BOOTLOADER_ADDRESS, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, L2_KNOWN_CODE_STORAGE_SYSTEM_CONTRACT_ADDR} from "../../common/L2ContractAddresses.sol";

/// @title zkSync Executor contract capable of processing events emitted in the zkSync protocol.
Expand All @@ -36,34 +37,27 @@ contract ExecutorFacet is Base, IExecutor {
uint256 expectedNumberOfLayer1Txs,
bytes32 expectedPriorityOperationsHash,
bytes32 previousBlockHash,
uint256 l2BlockTimestamp
uint256 packedBatchAndL2BlockTimestamp
) = _processL2Logs(_newBlock, _expectedSystemContractUpgradeTxHash);

require(_previousBlock.blockHash == previousBlockHash, "l");
// Check that the priority operation hash in the L2 logs is as expected
require(expectedPriorityOperationsHash == _newBlock.priorityOperationsHash, "t");
// Check that the number of processed priority operations is as expected
require(expectedNumberOfLayer1Txs == _newBlock.numberOfLayer1Txs, "ta");
// Check that the timestamp that came from the Bootloader is expected
require(l2BlockTimestamp == _newBlock.timestamp, "tb");

// Check the timestamp of the new block
_verifyBlockTimestamp(packedBatchAndL2BlockTimestamp, _newBlock.timestamp, _previousBlock.timestamp);

// Preventing "stack too deep error"
{
// Check the timestamp of the new block
bool timestampNotTooSmall = block.timestamp - COMMIT_TIMESTAMP_NOT_OLDER <= l2BlockTimestamp;
bool timestampNotTooBig = l2BlockTimestamp <= block.timestamp + COMMIT_TIMESTAMP_APPROXIMATION_DELTA;
require(timestampNotTooSmall, "h"); // New block timestamp is too small
require(timestampNotTooBig, "h1"); // New block timestamp is too big

// Check the index of repeated storage writes
uint256 newStorageChangesIndexes = uint256(uint32(bytes4(_newBlock.initialStorageChanges[:4])));
require(
_previousBlock.indexRepeatedStorageChanges + newStorageChangesIndexes ==
_newBlock.indexRepeatedStorageChanges,
"yq"
);

// NOTE: We don't check that _newBlock.timestamp > _previousBlock.timestamp, it is checked inside the L2
}

// Create block commitment for the proof verification
Expand All @@ -82,6 +76,33 @@ contract ExecutorFacet is Base, IExecutor {
);
}

/// @notice checks that the timestamps of both the new batch and the new L2 block are correct.
/// @param _packedBatchAndL2BlockTimestamp - packed batch and L2 block timestamp in a foramt of batchTimestamp * 2**128 + l2BlockTimestamp
/// @param _expectedBatchTimestamp - expected batch timestamp
/// @param _previousBatchTimestamp - the timestamp of the previous batch
function _verifyBlockTimestamp(
uint256 _packedBatchAndL2BlockTimestamp,
uint256 _expectedBatchTimestamp,
uint256 _previousBatchTimestamp
) internal view {
// Check that the timestamp that came from the system context is expected
uint256 batchTimestamp = _packedBatchAndL2BlockTimestamp >> 128;
require(batchTimestamp == _expectedBatchTimestamp, "tb");

// While the fact that _previousBatchTimestamp < batchTimestamp is already checked on L2,
// we double check it here for clarity
require(_previousBatchTimestamp < batchTimestamp, "h");

uint256 lastL2BlockTimestamp = _packedBatchAndL2BlockTimestamp & PACKED_L2_BLOCK_TIMESTAMP_MASK;

// On L2, all blocks have timestamps within the range of [batchTimestamp, lastL2BlockTimestamp].
// So here we need to only double check that:
// - The timestamp of the batch is not too small.
// - The timestamp of the last L2 block is not too big.
require(block.timestamp - COMMIT_TIMESTAMP_NOT_OLDER <= batchTimestamp, "h1"); // New batch timestamp is too small
require(lastL2BlockTimestamp <= block.timestamp + COMMIT_TIMESTAMP_APPROXIMATION_DELTA, "h2"); // The last L2 block timestamp is too big
}

/// @dev Check that L2 logs are proper and block contain all meta information for them
function _processL2Logs(CommitBlockInfo calldata _newBlock, bytes32 _expectedSystemContractUpgradeTxHash)
internal
Expand All @@ -90,7 +111,7 @@ contract ExecutorFacet is Base, IExecutor {
uint256 numberOfLayer1Txs,
bytes32 chainedPriorityTxsHash,
bytes32 previousBlockHash,
uint256 blockTimestamp
uint256 packedBatchAndL2BlockTimestamp
)
{
// Copy L2 to L1 logs into memory.
Expand Down Expand Up @@ -128,7 +149,7 @@ contract ExecutorFacet is Base, IExecutor {
// Make sure that the system context log wasn't processed yet, to
// avoid accident double reading `blockTimestamp` and `previousBlockHash`
require(!isSystemContextLogProcessed, "fx");
(blockTimestamp, ) = UnsafeBytes.readUint256(emittedL2Logs, i + 24);
(packedBatchAndL2BlockTimestamp, ) = UnsafeBytes.readUint256(emittedL2Logs, i + 24);
(previousBlockHash, ) = UnsafeBytes.readBytes32(emittedL2Logs, i + 56);
// Mark system context log as processed
isSystemContextLogProcessed = true;
Expand Down
1 change: 1 addition & 0 deletions ethereum/scripts/deploy-erc20.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ async function deployToken(token: TokenDescription, wallet: Wallet): Promise<Tok
await erc20.mint(testWallet.address, parseEther('3000000000'));
}
}

token.address = erc20.address;

// Remove the unneeded field
Expand Down
2 changes: 1 addition & 1 deletion ethereum/scripts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export function applyL1ToL2Alias(address: string): string {

export function readBlockBootloaderBytecode() {
const bootloaderPath = path.join(process.env.ZKSYNC_HOME as string, `etc/system-contracts/bootloader`);
return fs.readFileSync(`${bootloaderPath}/build/artifacts/proved_block.yul/proved_block.yul.zbin`);
return fs.readFileSync(`${bootloaderPath}/build/artifacts/proved_batch.yul/proved_batch.yul.zbin`);
}

export function readSystemContractsBytecode(fileName: string) {
Expand Down
37 changes: 19 additions & 18 deletions ethereum/test/unit_tests/executor_test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
L2_TO_L1_MESSENGER,
genesisStoredBlockInfo,
getCallRevertReason,
packBatchTimestampAndBlockTimestamp,
requestExecute
} from './utils';

Expand Down Expand Up @@ -166,7 +167,7 @@ describe(`Executor tests`, function () {

describe(`Commiting functionality`, async function () {
before(async () => {
currentTimestamp = (await ethers.providers.getDefaultProvider().getBlock(`latest`)).timestamp;
currentTimestamp = (await hardhat.ethers.providers.getDefaultProvider().getBlock(`latest`)).timestamp;
newCommitBlockInfo = {
blockNumber: 1,
timestamp: currentTimestamp,
Expand Down Expand Up @@ -227,38 +228,38 @@ describe(`Executor tests`, function () {
`0x00000001`,
`0x00000000`,
L2_SYSTEM_CONTEXT_ADDRESS,
ethers.constants.HashZero,
packBatchTimestampAndBlockTimestamp(1, 1),
ethers.constants.HashZero
]);

const wrongNewCommitBlockInfo = Object.assign({}, newCommitBlockInfo);
wrongNewCommitBlockInfo.l2Logs = wrongL2Logs;
wrongNewCommitBlockInfo.timestamp = 0; // too small
wrongNewCommitBlockInfo.timestamp = 1; // too small

const revertReason = await getCallRevertReason(
executor.connect(validator).commitBlocks(genesisStoredBlockInfo(), [wrongNewCommitBlockInfo])
);
expect(revertReason).equal(`h`);
expect(revertReason).equal(`h1`);
});

it(`Should revert on committing with too big new block timestamp`, async () => {
const wrongNewBlockTimestamp = `0xffffffff`; // too big
it(`Should revert on committing with too big last L2 block timestamp`, async () => {
const wrongL2BlockTimestamp = parseInt('0xffffffff');
const wrongL2Logs = ethers.utils.hexConcat([
`0x00000001`,
`0x00000000`,
L2_SYSTEM_CONTEXT_ADDRESS,
ethers.utils.hexZeroPad(wrongNewBlockTimestamp, 32),
packBatchTimestampAndBlockTimestamp(wrongL2BlockTimestamp, wrongL2BlockTimestamp),
ethers.constants.HashZero
]);

const wrongNewCommitBlockInfo = Object.assign({}, newCommitBlockInfo);
wrongNewCommitBlockInfo.l2Logs = wrongL2Logs;
wrongNewCommitBlockInfo.timestamp = parseInt(wrongNewBlockTimestamp);
wrongNewCommitBlockInfo.timestamp = wrongL2BlockTimestamp;

const revertReason = await getCallRevertReason(
executor.connect(validator).commitBlocks(genesisStoredBlockInfo(), [wrongNewCommitBlockInfo])
);
expect(revertReason).equal(`h1`);
expect(revertReason).equal(`h2`);
});

it(`Should revert on committing with wrong previous blockhash`, async () => {
Expand Down Expand Up @@ -535,7 +536,7 @@ describe(`Executor tests`, function () {
`0x00000001`,
`0x00000000`,
L2_SYSTEM_CONTEXT_ADDRESS,
ethers.utils.hexZeroPad(ethers.utils.hexlify(currentTimestamp), 32),
packBatchTimestampAndBlockTimestamp(currentTimestamp, currentTimestamp),
ethers.constants.HashZero
]);

Expand All @@ -560,7 +561,7 @@ describe(`Executor tests`, function () {
`0x00000001`,
`0x00000000`,
L2_SYSTEM_CONTEXT_ADDRESS,
ethers.utils.hexZeroPad(ethers.utils.hexlify(currentTimestamp), 32),
packBatchTimestampAndBlockTimestamp(currentTimestamp, currentTimestamp),
ethers.constants.HashZero
].concat(arr1);

Expand All @@ -581,7 +582,7 @@ describe(`Executor tests`, function () {
`0x00000001`,
`0x00000000`,
L2_SYSTEM_CONTEXT_ADDRESS,
ethers.utils.hexZeroPad(ethers.utils.hexlify(currentTimestamp), 32),
packBatchTimestampAndBlockTimestamp(currentTimestamp, currentTimestamp),
ethers.constants.HashZero
]);

Expand All @@ -605,7 +606,7 @@ describe(`Executor tests`, function () {
`0x00000001`,
`0x00000000`,
L2_SYSTEM_CONTEXT_ADDRESS,
ethers.utils.hexZeroPad(ethers.utils.hexlify(currentTimestamp), 32),
packBatchTimestampAndBlockTimestamp(currentTimestamp, currentTimestamp),
ethers.constants.HashZero
]);

Expand All @@ -629,7 +630,7 @@ describe(`Executor tests`, function () {
`0x00000001`,
`0x00000000`,
L2_SYSTEM_CONTEXT_ADDRESS,
ethers.utils.hexZeroPad(ethers.utils.hexlify(currentTimestamp), 32),
packBatchTimestampAndBlockTimestamp(currentTimestamp, currentTimestamp),
ethers.constants.HashZero
]);

Expand Down Expand Up @@ -697,7 +698,7 @@ describe(`Executor tests`, function () {
`0x00000001`,
`0x00000000`,
L2_SYSTEM_CONTEXT_ADDRESS,
ethers.utils.hexZeroPad(ethers.utils.hexlify(currentTimestamp), 32),
packBatchTimestampAndBlockTimestamp(currentTimestamp, currentTimestamp),
ethers.constants.HashZero
]);

Expand Down Expand Up @@ -758,7 +759,7 @@ describe(`Executor tests`, function () {
`0x00000002`,
`0x00000000`,
L2_SYSTEM_CONTEXT_ADDRESS,
ethers.utils.hexZeroPad(ethers.utils.hexlify(currentTimestamp), 32),
packBatchTimestampAndBlockTimestamp(currentTimestamp, currentTimestamp),
ethers.constants.HashZero,
`0x00010000`,
L2_BOOTLOADER_ADDRESS,
Expand Down Expand Up @@ -805,7 +806,7 @@ describe(`Executor tests`, function () {
`0x00000002`,
`0x00000000`,
L2_SYSTEM_CONTEXT_ADDRESS,
ethers.utils.hexZeroPad(ethers.utils.hexlify(currentTimestamp), 32),
packBatchTimestampAndBlockTimestamp(currentTimestamp, currentTimestamp),
ethers.constants.HashZero,
`0x00010000`,
L2_BOOTLOADER_ADDRESS,
Expand Down Expand Up @@ -878,7 +879,7 @@ describe(`Executor tests`, function () {
`0x00000001`,
`0x00000000`,
L2_SYSTEM_CONTEXT_ADDRESS,
ethers.utils.hexZeroPad(ethers.utils.hexlify(currentTimestamp), 32),
packBatchTimestampAndBlockTimestamp(currentTimestamp, currentTimestamp),
ethers.constants.HashZero
]);

Expand Down
7 changes: 4 additions & 3 deletions ethereum/test/unit_tests/l2-upgrade.test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import {
StoredBlockInfo,
CommitBlockInfo,
L2_SYSTEM_CONTEXT_ADDRESS,
L2_BOOTLOADER_ADDRESS
L2_BOOTLOADER_ADDRESS,
packBatchTimestampAndBlockTimestamp
} from './utils';
import * as ethers from 'ethers';
import { BigNumber, BigNumberish, BytesLike } from 'ethers';
Expand Down Expand Up @@ -640,10 +641,10 @@ interface L2ToL1Log {
value: string;
}

function contextLog(timestamp: BigNumberish, prevBlockHash: BytesLike): L2ToL1Log {
function contextLog(timestamp: number, prevBlockHash: BytesLike): L2ToL1Log {
return {
sender: L2_SYSTEM_CONTEXT_ADDRESS,
key: ethers.utils.hexlify(timestamp),
key: packBatchTimestampAndBlockTimestamp(timestamp, timestamp),
value: ethers.utils.hexlify(prevBlockHash)
};
}
Expand Down
9 changes: 8 additions & 1 deletion ethereum/test/unit_tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ export function genesisStoredBlockInfo(): StoredBlockInfo {
};
}

// Packs the batch timestamp and block timestamp and returns the 32-byte hex string
// which should be used for the "key" field of the L2->L1 system context log.
export function packBatchTimestampAndBlockTimestamp(batchTimestamp: number, blockTimestamp: number): string {
const packedNum = BigNumber.from(batchTimestamp).shl(128).or(BigNumber.from(blockTimestamp));
return ethers.utils.hexZeroPad(ethers.utils.hexlify(packedNum), 32);
}

export interface StoredBlockInfo {
blockNumber: BigNumberish;
blockHash: BytesLike;
Expand All @@ -100,7 +107,7 @@ export interface StoredBlockInfo {

export interface CommitBlockInfo {
blockNumber: BigNumberish;
timestamp: BigNumberish;
timestamp: number;
indexRepeatedStorageChanges: BigNumberish;
newStateRoot: BytesLike;
numberOfLayer1Txs: BigNumberish;
Expand Down

0 comments on commit 67f38da

Please sign in to comment.