Skip to content

Commit

Permalink
It compiles
Browse files Browse the repository at this point in the history
  • Loading branch information
ly0va committed Jun 12, 2024
1 parent 2d68877 commit ca4ec9b
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 15 deletions.
16 changes: 16 additions & 0 deletions l1-contracts/contracts/dev-contracts/test/DummyExecutor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pragma solidity 0.8.24;

import {IExecutor} from "../../state-transition/chain-interfaces/IExecutor.sol";
import {PriorityOpsBatchInfo} from "../../state-transition/libraries/PriorityTree.sol";

/// @title DummyExecutor
/// @notice A test smart contract implementing the IExecutor interface to simulate Executor behavior for testing purposes.
Expand Down Expand Up @@ -125,10 +126,25 @@ contract DummyExecutor is IExecutor {
);
}

function executeBatches(
StoredBatchInfo[] calldata _batchesData,
PriorityOpsBatchInfo[] calldata
) external {
executeBatches(_batchesData);
}

function executeBatchesSharedBridge(uint256, StoredBatchInfo[] calldata _batchesData) external {
executeBatches(_batchesData);
}

function executeBatchesSharedBridge(
uint256,
StoredBatchInfo[] calldata _batchesData,
PriorityOpsBatchInfo[] calldata
) external {
executeBatches(_batchesData);
}

function revertBatches(uint256 _newLastBatch) public {
require(
getTotalBatchesCommitted > _newLastBatch,
Expand Down
32 changes: 26 additions & 6 deletions l1-contracts/contracts/state-transition/ValidatorTimelock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {LibMap} from "./libraries/LibMap.sol";
import {IExecutor} from "./chain-interfaces/IExecutor.sol";
import {IStateTransitionManager} from "./IStateTransitionManager.sol";
import {PriorityOpsBatchInfo} from "./libraries/PriorityTree.sol";

/// @author Matter Labs
/// @custom:security-contact [email protected]
Expand Down Expand Up @@ -180,20 +181,39 @@ contract ValidatorTimelock is IExecutor, Ownable2Step {

/// @dev Check that batches were committed at least X time ago and
/// make a call to the hyperchain diamond contract with the same calldata.
function executeBatches(StoredBatchInfo[] calldata _newBatchesData) external onlyValidator(ERA_CHAIN_ID) {
_executeBatchesInner(ERA_CHAIN_ID, _newBatchesData);
}
// function executeBatches(StoredBatchInfo[] calldata _newBatchesData) external onlyValidator(ERA_CHAIN_ID) {
// _executeBatchesInner(ERA_CHAIN_ID, _newBatchesData, emptyPriorityOpsData());
// }

/// @dev Check that batches were committed at least X time ago and
/// make a call to the hyperchain diamond contract with the same calldata.
// function executeBatchesSharedBridge(
// uint256 _chainId,
// StoredBatchInfo[] calldata _newBatchesData
// ) external onlyValidator(_chainId) {
// _executeBatchesInner(_chainId, _newBatchesData, emptyPriorityOpsData());
// }

function executeBatches(
StoredBatchInfo[] calldata _batchesData,
PriorityOpsBatchInfo[] calldata _priorityOpsData
) external onlyValidator(ERA_CHAIN_ID) {
_executeBatchesInner(ERA_CHAIN_ID, _batchesData, _priorityOpsData);
}

function executeBatchesSharedBridge(
uint256 _chainId,
StoredBatchInfo[] calldata _newBatchesData
StoredBatchInfo[] calldata _newBatchesData,
PriorityOpsBatchInfo[] calldata _priorityOpsData
) external onlyValidator(_chainId) {
_executeBatchesInner(_chainId, _newBatchesData);
_executeBatchesInner(ERA_CHAIN_ID, _newBatchesData, _priorityOpsData);
}

function _executeBatchesInner(uint256 _chainId, StoredBatchInfo[] calldata _newBatchesData) internal {
function _executeBatchesInner(
uint256 _chainId,
StoredBatchInfo[] calldata _newBatchesData,
PriorityOpsBatchInfo[] calldata
) internal {
uint256 delay = executionDelay; // uint32
unchecked {
// solhint-disable-next-line gas-length-in-loops
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ import {Diamond} from "../libraries/Diamond.sol";
import {ZkSyncHyperchainBase} from "./facets/ZkSyncHyperchainBase.sol";
import {L2_TO_L1_LOG_SERIALIZE_SIZE, MAX_GAS_PER_TRANSACTION} from "../../common/Config.sol";
import {InitializeData, IDiamondInit} from "../chain-interfaces/IDiamondInit.sol";
import {PriorityQueue} from "../libraries/PriorityQueue.sol";
import {PriorityTree} from "../libraries/PriorityTree.sol";

/// @author Matter Labs
/// @dev The contract is used only once to initialize the diamond proxy.
/// @dev The deployment process takes care of this contract's initialization.
contract DiamondInit is ZkSyncHyperchainBase, IDiamondInit {
using PriorityQueue for PriorityQueue.Queue;
using PriorityTree for PriorityTree.Tree;

/// @dev Initialize the implementation to prevent any possibility of a Parity hack.
constructor() reentrancyGuardInitializer {}

Expand Down Expand Up @@ -48,6 +53,8 @@ contract DiamondInit is ZkSyncHyperchainBase, IDiamondInit {
s.priorityTxMaxGasLimit = _initializeData.priorityTxMaxGasLimit;
s.feeParams = _initializeData.feeParams;
s.blobVersionedHashRetriever = _initializeData.blobVersionedHashRetriever;
// TODO - how to do this during the upgrade?
s.priorityTree.setup(keccak256(''), s.priorityQueue.getTotalPriorityTxs());

// While this does not provide a protection in the production, it is needed for local testing
// Length of the L2Log encoding should not be equal to the length of other L2Logs' tree nodes preimages
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity 0.8.24;

import {IVerifier, VerifierParams} from "../chain-interfaces/IVerifier.sol";
import {PriorityQueue} from "../../state-transition/libraries/PriorityQueue.sol";
import {PriorityTree} from "../../state-transition/libraries/PriorityTree.sol";

/// @notice Indicates whether an upgrade is initiated and if yes what type
/// @param None Upgrade is NOT initiated
Expand Down Expand Up @@ -151,4 +152,6 @@ struct ZkSyncHyperchainStorage {
uint128 baseTokenGasPriceMultiplierDenominator;
/// @dev The optional address of the contract that has to be used for transaction filtering/whitelisting
address transactionFilterer;
/// @dev TODO
PriorityTree.Tree priorityTree;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {UnsafeBytes} from "../../../common/libraries/UnsafeBytes.sol";
import {L2_BOOTLOADER_ADDRESS, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, L2_PUBDATA_CHUNK_PUBLISHER_ADDR} from "../../../common/L2ContractAddresses.sol";
import {PubdataPricingMode} from "../ZkSyncHyperchainStorage.sol";
import {IStateTransitionManager} from "../../IStateTransitionManager.sol";
import {PriorityTree, PriorityOpsBatchInfo} from "../../libraries/PriorityTree.sol";

// While formally the following import is not used, it is needed to inherit documentation from it
import {IZkSyncHyperchainBase} from "../../chain-interfaces/IZkSyncHyperchainBase.sol";
Expand All @@ -23,6 +24,7 @@ import {IZkSyncHyperchainBase} from "../../chain-interfaces/IZkSyncHyperchainBas
contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor {
using UncheckedMath for uint256;
using PriorityQueue for PriorityQueue.Queue;
using PriorityTree for PriorityTree.Tree;

/// @inheritdoc IZkSyncHyperchainBase
string public constant override getName = "ExecutorFacet";
Expand Down Expand Up @@ -334,6 +336,14 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor {
}
}

function _rollingHash(bytes32[] calldata _hashes) internal pure returns (bytes32) {
bytes32 hash = EMPTY_STRING_KECCAK;
for (uint256 i = 0; i < _hashes.length; i = i.uncheckedInc()) {
hash = keccak256(abi.encode(hash, _hashes[i]));
}
return hash;
}

/// @dev Executes one batch
/// @dev 1. Processes all pending operations (Complete priority requests)
/// @dev 2. Finalizes batch on Ethereum
Expand All @@ -353,23 +363,70 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor {
s.l2LogsRootHashes[currentBatchNumber] = _storedBatch.l2LogsTreeRoot;
}

// TODO: once we use this method, the normal priorityQueue becomes unusable since we didn't pop the elements
function _executeOneBatch(
StoredBatchInfo memory _storedBatch,
PriorityOpsBatchInfo calldata _priorityOpsData,
uint256 _executedBatchIdx
) internal {
uint256 currentBatchNumber = _storedBatch.batchNumber;
require(currentBatchNumber == s.totalBatchesExecuted + _executedBatchIdx + 1, "k"); // Execute batches in order
require(
_hashStoredBatchInfo(_storedBatch) == s.storedBatchHashes[currentBatchNumber],
"exe10" // executing batch should be committed
);

bytes32 priorityOperationsRollingHash = _rollingHash(_priorityOpsData.itemHashes);
require(priorityOperationsRollingHash == _storedBatch.priorityOperationsHash, "x");
// TODO: pop the elements from the queue?
s.priorityTree.processBatch(_priorityOpsData);

// Save root hash of L2 -> L1 logs tree
s.l2LogsRootHashes[currentBatchNumber] = _storedBatch.l2LogsTreeRoot;
}

/// @inheritdoc IExecutor
// function executeBatchesSharedBridge(
// uint256,
// StoredBatchInfo[] calldata _batchesData
// ) external nonReentrant onlyValidator {
// _executeBatches(_batchesData, emptyPriorityOpsData());
// }

/// @inheritdoc IExecutor
// function executeBatches(StoredBatchInfo[] calldata _batchesData) external nonReentrant onlyValidator {
// _executeBatches(_batchesData, emptyPriorityOpsData());
// }

function executeBatchesSharedBridge(
uint256,
StoredBatchInfo[] calldata _batchesData
StoredBatchInfo[] calldata _batchesData,
PriorityOpsBatchInfo[] calldata _priorityOpsData
) external nonReentrant onlyValidator {
_executeBatches(_batchesData);
_executeBatches(_batchesData, _priorityOpsData);
}

/// @inheritdoc IExecutor
function executeBatches(StoredBatchInfo[] calldata _batchesData) external nonReentrant onlyValidator {
_executeBatches(_batchesData);
function executeBatches(
StoredBatchInfo[] calldata _batchesData,
PriorityOpsBatchInfo[] calldata _priorityOpsData
) external nonReentrant onlyValidator {
_executeBatches(_batchesData, _priorityOpsData);
}

function _executeBatches(StoredBatchInfo[] calldata _batchesData) internal {
function _executeBatches(StoredBatchInfo[] calldata _batchesData, PriorityOpsBatchInfo[] calldata _priorityOpsData) internal {
uint256 nBatches = _batchesData.length;
uint256 nPriorityOpsDatas = _priorityOpsData.length;
if (nPriorityOpsDatas != 0) {
require(nBatches == nPriorityOpsDatas, "");
require(s.priorityTree.startIndex <= s.priorityQueue.getFirstUnprocessedPriorityTx(), "");
}

for (uint256 i = 0; i < nBatches; i = i.uncheckedInc()) {
_executeOneBatch(_batchesData[i], i);
if (nPriorityOpsDatas != 0) {
_executeOneBatch(_batchesData[i], _priorityOpsData[i], i);
} else {
_executeOneBatch(_batchesData[i], i);
}
emit BlockExecution(_batchesData[i].batchNumber, _batchesData[i].batchHash, _batchesData[i].commitment);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {IMailbox} from "../../chain-interfaces/IMailbox.sol";
import {ITransactionFilterer} from "../../chain-interfaces/ITransactionFilterer.sol";
import {Merkle} from "../../libraries/Merkle.sol";
import {PriorityQueue, PriorityOperation} from "../../libraries/PriorityQueue.sol";
import {PriorityTree} from "../../libraries/PriorityTree.sol";
import {TransactionValidator} from "../../libraries/TransactionValidator.sol";
import {WritePriorityOpParams, L2CanonicalTransaction, L2Message, L2Log, TxStatus, BridgehubL2TransactionRequest} from "../../../common/Messaging.sol";
import {FeeParams, PubdataPricingMode} from "../ZkSyncHyperchainStorage.sol";
Expand All @@ -31,6 +32,7 @@ import {IZkSyncHyperchainBase} from "../../chain-interfaces/IZkSyncHyperchainBas
contract MailboxFacet is ZkSyncHyperchainBase, IMailbox {
using UncheckedMath for uint256;
using PriorityQueue for PriorityQueue.Queue;
using PriorityTree for PriorityTree.Tree;

/// @inheritdoc IZkSyncHyperchainBase
string public constant override getName = "MailboxFacet";
Expand Down Expand Up @@ -342,6 +344,7 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox {
layer2Tip: uint192(0) // TODO: Restore after fee modeling will be stable. (SMA-1230)
})
);
s.priorityTree.push(canonicalTxHash);

// Data that is needed for the operator to simulate priority queue offchain
// solhint-disable-next-line func-named-parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pragma solidity 0.8.24;

import {IZkSyncHyperchainBase} from "./IZkSyncHyperchainBase.sol";
import {PriorityOpsBatchInfo} from "../libraries/PriorityTree.sol";

/// @dev Enum used by L2 System Contracts to differentiate logs.
enum SystemLogKey {
Expand Down Expand Up @@ -178,10 +179,18 @@ interface IExecutor is IZkSyncHyperchainBase {
/// - Processing all pending operations (commpleting priority requests).
/// - Finalizing this batch (i.e. allowing to withdraw funds from the system)
/// @param _batchesData Data of the batches to be executed.
function executeBatches(StoredBatchInfo[] calldata _batchesData) external;
// function executeBatches(StoredBatchInfo[] calldata _batchesData) external;

function executeBatches(StoredBatchInfo[] calldata _batchesData, PriorityOpsBatchInfo[] calldata _priorityOpsData) external;

/// @notice same as `executeBatches` but with the chainId so ValidatorTimelock can sort the inputs.
function executeBatchesSharedBridge(uint256 _chainId, StoredBatchInfo[] calldata _batchesData) external;
// function executeBatchesSharedBridge(uint256 _chainId, StoredBatchInfo[] calldata _batchesData) external;

function executeBatchesSharedBridge(
uint256 _chainId,
StoredBatchInfo[] calldata _batchesData,
PriorityOpsBatchInfo[] calldata _priorityOpsData
) external;

/// @notice Reverts unexecuted batches
/// @param _newLastBatch batch number after which batches should be reverted
Expand Down
62 changes: 62 additions & 0 deletions l1-contracts/contracts/state-transition/libraries/PriorityTree.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

import {DynamicIncrementalMerkle} from "../../common/libraries/openzeppelin/IncrementalMerkle.sol";
import {Merkle} from "./Merkle.sol";

struct PriorityOpsBatchInfo {
bytes32[] leftPath;
bytes32[] rightPath;
bytes32[] itemHashes;
}

library PriorityTree {
using PriorityTree for Tree;
using DynamicIncrementalMerkle for DynamicIncrementalMerkle.Bytes32PushTree;

struct Tree {
uint256 startIndex;
uint256 unprocessedIndex; // relative to `startIndex`
DynamicIncrementalMerkle.Bytes32PushTree tree;
}

/// @notice Returns zero if and only if no operations were processed from the queue
/// @return Index of the oldest priority operation that wasn't processed yet
function getFirstUnprocessedPriorityTx(Tree storage _tree) internal view returns (uint256) {
return _tree.startIndex + _tree.unprocessedIndex;
}

/// @return The total number of priority operations that were added to the priority queue, including all processed ones
function getTotalPriorityTxs(Tree storage _tree) internal view returns (uint256) {
return _tree.startIndex + _tree.tree._nextLeafIndex;
}

/// @return The total number of unprocessed priority operations in a priority queue
function getSize(Tree storage _tree) internal view returns (uint256) {
return uint256(_tree.tree._nextLeafIndex - _tree.unprocessedIndex);
}

/// @notice Add the priority operation to the end of the priority queue
function push(Tree storage _tree, bytes32 _hash) internal {
_tree.tree.push(_hash);
}

function setup(Tree storage _tree, bytes32 _zero, uint256 _startIndex) internal {
_tree.tree.setup(_zero);
_tree.startIndex = _startIndex;
}

function processBatch(
Tree storage _tree,
PriorityOpsBatchInfo calldata _priorityOpsData
) internal {
bytes32 expectedRoot = Merkle.calculateRoot(
_priorityOpsData.leftPath,
_priorityOpsData.rightPath,
_tree.unprocessedIndex,
_priorityOpsData.itemHashes
);
require(expectedRoot == _tree.tree.root(), "");
_tree.unprocessedIndex += _priorityOpsData.itemHashes.length;
}
}


0 comments on commit ca4ec9b

Please sign in to comment.