Skip to content

Commit

Permalink
add sync range batch root
Browse files Browse the repository at this point in the history
  • Loading branch information
zkbenny committed Apr 1, 2024
1 parent e6f96ba commit 5b53e20
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 47 deletions.
55 changes: 36 additions & 19 deletions contracts/Arbitrator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -147,36 +147,52 @@ contract Arbitrator is IArbitrator, OwnableUpgradeable, UUPSUpgradeable, Reentra
/// @dev This function is called within the `claimMessageCallback` of L1 gateway
function receiveMessage(uint256 _value, bytes calldata _callData) external payable {
require(msg.value == _value, "Invalid msg value");
IL1Gateway gateway = IL1Gateway(msg.sender);
IL1Gateway sourceGateway = IL1Gateway(msg.sender);
// `forwardParams` is set in `claimMessage`
bytes memory _forwardParams;
assembly {
_forwardParams := tload(forwardParams.slot)
}
// Ensure the caller is L1 gateway
if (gateway == primaryChainGateway) {
if (sourceGateway == primaryChainGateway) {
// Unpack destination chain and final callData
bytes[] memory gatewayCallDataLists = abi.decode(_callData, (bytes[]));
// `forwardParams` is set in `claimMessage`
bytes[] memory gatewayForwardParams = abi.decode(forwardParams, (bytes[]));
uint256 gatewayLength = gatewayCallDataLists.length;
require(gatewayLength == gatewayForwardParams.length, "Invalid forward params length");
bytes[] memory gatewayDataList = abi.decode(_callData, (bytes[]));
bytes[] memory gatewayForwardParamsList = abi.decode(_forwardParams, (bytes[]));
uint256 gatewayLength = gatewayDataList.length;
require(gatewayLength == gatewayForwardParamsList.length, "Invalid forward params length");
unchecked {
for (uint256 i = 0; i < gatewayLength; ++i) {
bytes memory gatewayCallData = gatewayCallDataLists[i];
bytes memory gatewayForwardParam = gatewayForwardParams[i];
(IL1Gateway secondaryChainGateway, uint256 callValue, bytes memory callData) = abi.decode(gatewayCallData, (IL1Gateway, uint256, bytes));
require(secondaryChainGateways[secondaryChainGateway], "Invalid secondary chain gateway");
(uint256 sendMsgFee, bytes memory adapterParams) = abi.decode(gatewayForwardParam, (uint256, bytes));
bytes memory gatewayData = gatewayDataList[i];
bytes memory gatewayForwardParams = gatewayForwardParamsList[i];
(IL1Gateway targetGateway, uint256 targetCallValue, bytes memory targetCallData) = abi.decode(
gatewayData,
(IL1Gateway, uint256, bytes)
);
require(secondaryChainGateways[targetGateway], "Invalid secondary chain gateway");
(uint256 sendMsgFee, bytes memory adapterParams) = abi.decode(
gatewayForwardParams,
(uint256, bytes)
);
// Forward fee to send message
secondaryChainGateway.sendMessage{value: sendMsgFee + callValue}(callValue, callData, adapterParams);
targetGateway.sendMessage{value: sendMsgFee + targetCallValue}(
targetCallValue,
targetCallData,
adapterParams
);
emit MessageForwarded(targetGateway, targetCallValue, targetCallData);
}
}
} else {
require(secondaryChainGateways[gateway], "Not secondary chain gateway");
// `forwardParams` is set in `claimMessage`
(uint256 sendMsgFee, bytes memory adapterParams) = abi.decode(forwardParams, (uint256, bytes));
require(secondaryChainGateways[sourceGateway], "Not secondary chain gateway");
(uint256 sendMsgFee, bytes memory adapterParams) = abi.decode(_forwardParams, (uint256, bytes));
// Forward fee to send message
primaryChainGateway.sendMessage{value: sendMsgFee + _value}(_value, _callData, adapterParams);
IL1Gateway targetGateway = primaryChainGateway;
targetGateway.sendMessage{value: sendMsgFee + _value}(_value, _callData, adapterParams);
emit MessageForwarded(targetGateway, _value, _callData);
}
emit MessageForwarded(gateway, _value, _callData);
}

/// @dev Deprecated after dencun upgrade
function forwardMessage(
IL1Gateway _gateway,
uint256 _value,
Expand Down Expand Up @@ -213,7 +229,8 @@ contract Arbitrator is IArbitrator, OwnableUpgradeable, UUPSUpgradeable, Reentra
tstore(forwardParams.slot, _forwardParams)
}
// Call the claim interface of source chain message service
// And it will inner call the `claimCallback` interface of source chain L1Gateway
// And it will inner call the `claimMessageCallback` interface of source chain L1Gateway
// In the `claimMessageCallback` of L1Gateway, it will inner call `receiveMessage` of Arbitrator
// No use of return value
Address.functionCall(_sourceChainCanonicalMessageService, _sourceChainClaimCallData);
}
Expand Down
60 changes: 38 additions & 22 deletions contracts/ZkLink.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ contract ZkLink is
public isEthWithdrawalFinalized;
/// @dev The forward fee allocator
address public forwardFeeAllocator;
/// @dev The range root hash of [fromBatchNumber, toBatchNumber]
/// The range = keccak256(abi.encodePacked(fromBatchNumber, toBatchNumber))
mapping(bytes32 range => bytes32 rangeRootHash) public rangRootHashMap;
/// @dev The range batch root hash of [fromBatchNumber, toBatchNumber]
/// The key is keccak256(abi.encodePacked(fromBatchNumber, toBatchNumber))
mapping(bytes32 range => bytes32 rangeBatchRootHash) public rangBatchRootHashes;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
Expand All @@ -110,8 +110,13 @@ contract ZkLink is
event SyncL2Requests(uint256 totalSyncedPriorityTxs, bytes32 syncHash, uint256 forwardEthAmount);
/// @notice Emitted when receive batch root from primary chain.
event SyncBatchRoot(uint256 batchNumber, bytes32 l2LogsRootHash, uint256 forwardEthAmount);
/// @notice Emitted when receive range batch root from primary chain.
event SyncRangeBatchRoot(uint256 fromBatchNumber, uint256 toBatchNumber, bytes32 rangeRootHash, uint256 forwardEthAmount);
/// @notice Emitted when receive range batch root hash from primary chain.
event SyncRangeBatchRoot(
uint256 fromBatchNumber,
uint256 toBatchNumber,
bytes32 rangeBatchRootHash,
uint256 forwardEthAmount
);
/// @notice Emitted when receive l2 tx hash from primary chain.
event SyncL2TxHash(bytes32 l2TxHash, bytes32 primaryChainL2TxHash);
/// @notice Emitted when validator withdraw forward fee
Expand Down Expand Up @@ -464,32 +469,43 @@ contract ZkLink is
}

function syncRangeBatchRoot(
uint256 _fromBatchNumber, uint256 _toBatchNumber, bytes32 _rangeRootHash, uint256 _forwardEthAmount
uint256 _fromBatchNumber,
uint256 _toBatchNumber,
bytes32 _rangeBatchRootHash,
uint256 _forwardEthAmount
) external payable onlyGateway {
require(_toBatchNumber >= _fromBatchNumber, "Invalid range");
require(msg.value == _forwardEthAmount, "Invalid forward amount");
bytes32 range = keccak256(abi.encodePacked(_fromBatchNumber, _toBatchNumber));
rangRootHashMap[range] = _rangeRootHash;
emit SyncRangeBatchRoot(_fromBatchNumber, _toBatchNumber, _rangeRootHash, _forwardEthAmount);
}

function openRangeBatchRoot(uint256 _fromBatchNumber, uint256 _toBatchNumber, bytes32[] memory _l2LogsRootHashes) external onlyValidator {
rangBatchRootHashes[range] = _rangeBatchRootHash;
emit SyncRangeBatchRoot(_fromBatchNumber, _toBatchNumber, _rangeBatchRootHash, _forwardEthAmount);
}

/// @dev Unzip the root hashes in the range
/// @param _fromBatchNumber The batch number from
/// @param _toBatchNumber The batch number to
/// @param _l2LogsRootHashes The l2LogsRootHash list in the range [`_fromBatchNumber`, `_toBatchNumber`]
function openRangeBatchRootHash(
uint256 _fromBatchNumber,
uint256 _toBatchNumber,
bytes32[] memory _l2LogsRootHashes
) external onlyValidator {
require(_toBatchNumber >= _fromBatchNumber, "Invalid range");
bytes32 range = keccak256(abi.encodePacked(_fromBatchNumber, _toBatchNumber));
bytes32 rangeRootHash = rangRootHashMap[range];
require(rangeRootHash != bytes32(0), "Rang root hash not exist");
uint256 rootHashLength = _l2LogsRootHashes.length;
require(rootHashLength == _toBatchNumber - _fromBatchNumber + 1, "Invalid root hashes length");
bytes32 openRangeRootHash = _l2LogsRootHashes[0];
l2LogsRootHashes[_fromBatchNumber] = openRangeRootHash;
bytes32 rangeBatchRootHash = rangBatchRootHashes[range];
require(rangeBatchRootHash != bytes32(0), "Rang batch root hash not exist");
uint256 rootHashesLength = _l2LogsRootHashes.length;
require(rootHashesLength == _toBatchNumber - _fromBatchNumber + 1, "Invalid root hashes length");
bytes32 _rangeBatchRootHash = _l2LogsRootHashes[0];
l2LogsRootHashes[_fromBatchNumber] = _rangeBatchRootHash;
unchecked {
for (uint256 i = 1; i < rootHashLength; ++i) {
bytes32 l2LogsRootHash = _l2LogsRootHashes[i];
l2LogsRootHashes[_fromBatchNumber + i] = l2LogsRootHash;
openRangeRootHash = Merkle._efficientHash(openRangeRootHash, l2LogsRootHash);
for (uint256 i = 1; i < rootHashesLength; ++i) {
bytes32 _l2LogsRootHash = _l2LogsRootHashes[i];
l2LogsRootHashes[_fromBatchNumber + i] = _l2LogsRootHash;
_rangeBatchRootHash = Merkle._efficientHash(_rangeBatchRootHash, _l2LogsRootHash);
}
}
require(openRangeRootHash == rangeRootHash, "Incorrect range root hash");
require(_rangeBatchRootHash == rangeBatchRootHash, "Incorrect root hash");
if (_toBatchNumber > totalBatchesExecuted) {
totalBatchesExecuted = _toBatchNumber;
}
Expand Down
15 changes: 15 additions & 0 deletions contracts/dev-contracts/DummyZkLink.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ contract DummyZkLink is IZkLink, OwnableUpgradeable, UUPSUpgradeable, Reentrancy
IL2Gateway public gateway;

event ReceiveBatchRoot(uint256 batchNumber, bytes32 l2LogsRootHash, uint256 forwardEthAmount);
event ReceiveRangeBatchRoot(
uint256 fromBatchNumber,
uint256 toBatchNumber,
bytes32 rangeBatchRootHash,
uint256 forwardEthAmount
);
event ReceiveL2TxHash(bytes32 l2TxHash, bytes32 primaryChainL2TxHash);

modifier onlyGateway() {
Expand Down Expand Up @@ -55,6 +61,15 @@ contract DummyZkLink is IZkLink, OwnableUpgradeable, UUPSUpgradeable, Reentrancy
emit ReceiveBatchRoot(_batchNumber, _l2LogsRootHash, _forwardEthAmount);
}

function syncRangeBatchRoot(
uint256 _fromBatchNumber,
uint256 _toBatchNumber,
bytes32 _rangeBatchRootHash,
uint256 _forwardEthAmount
) external payable {
emit ReceiveRangeBatchRoot(_fromBatchNumber, _toBatchNumber, _rangeBatchRootHash, _forwardEthAmount);
}

function syncL2TxHash(bytes32 _l2TxHash, bytes32 _primaryChainL2TxHash) external onlyGateway {
emit ReceiveL2TxHash(_l2TxHash, _primaryChainL2TxHash);
}
Expand Down
4 changes: 2 additions & 2 deletions contracts/interfaces/IArbitrator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ interface IArbitrator {
/// @notice Claim a message of source chain and deliver it to the target chain
/// @param _sourceChainCanonicalMessageService The message service to claim message
/// @param _sourceChainClaimCallData The call data that need to claim message from source chain
/// @param _targetChainAdapterParams Some params need to call canonical message service of target chain
/// @param _forwardParams Some params need to call canonical message service of target chain
function claimMessage(
address _sourceChainCanonicalMessageService,
bytes calldata _sourceChainClaimCallData,
bytes memory _targetChainAdapterParams
bytes memory _forwardParams
) external payable;
}
12 changes: 9 additions & 3 deletions contracts/interfaces/IZkLink.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,17 @@ interface IZkLink {
/// @param _forwardEthAmount The forward eth amount
function syncBatchRoot(uint256 _batchNumber, bytes32 _l2LogsRootHash, uint256 _forwardEthAmount) external payable;

/// @notice Receive range batch root from primary chain
/// @notice Receive range batch root hash from primary chain
/// @param _fromBatchNumber The batch number from
/// @param _toBatchNumber The batch number to
/// @param _rangeRootHash The range root hash
function syncRangeBatchRoot(uint256 _fromBatchNumber, uint256 _toBatchNumber, bytes32 _rangeRootHash) external;
/// @param _rangeBatchRootHash The accumulation hash of l2LogsRootHash in the range [`_fromBatchNumber`, `_toBatchNumber`]
/// @param _forwardEthAmount The forward eth amount
function syncRangeBatchRoot(
uint256 _fromBatchNumber,
uint256 _toBatchNumber,
bytes32 _rangeBatchRootHash,
uint256 _forwardEthAmount
) external payable;

/// @notice Receive l2 tx hash from primary chain
/// @param _l2TxHash The l2 tx hash on local chain
Expand Down
2 changes: 1 addition & 1 deletion contracts/zksync/l1-contracts/zksync/libraries/Merkle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ library Merkle {
}

/// @dev Keccak hash of the concatenation of two 32-byte words
function _efficientHash(bytes32 _lhs, bytes32 _rhs) private pure returns (bytes32 result) {
function _efficientHash(bytes32 _lhs, bytes32 _rhs) public pure returns (bytes32 result) {
assembly {
mstore(0x00, _lhs)
mstore(0x20, _rhs)
Expand Down

0 comments on commit 5b53e20

Please sign in to comment.