forked from scroll-tech/scroll
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMultipleVersionRollupVerifier.sol
165 lines (133 loc) · 5.94 KB
/
MultipleVersionRollupVerifier.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// SPDX-License-Identifier: MIT
pragma solidity =0.8.24;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IRollupVerifier} from "../../libraries/verifier/IRollupVerifier.sol";
import {IZkEvmVerifier} from "../../libraries/verifier/IZkEvmVerifier.sol";
/// @title MultipleVersionRollupVerifier
/// @notice Verifies aggregate zk proofs using the appropriate verifier.
contract MultipleVersionRollupVerifier is IRollupVerifier, Ownable {
/**********
* Events *
**********/
/// @notice Emitted when the address of verifier is updated.
/// @param version The version of the verifier.
/// @param startBatchIndex The start batch index when the verifier will be used.
/// @param verifier The address of new verifier.
event UpdateVerifier(uint256 version, uint256 startBatchIndex, address verifier);
/**********
* Errors *
**********/
/// @dev Thrown when the given address is `address(0)`.
error ErrorZeroAddress();
/// @dev Thrown when the given start batch index is smaller than `latestVerifier.startBatchIndex`.
error ErrorStartBatchIndexTooSmall();
/***********
* Structs *
***********/
struct Verifier {
// The start batch index for the verifier.
uint64 startBatchIndex;
// The address of zkevm verifier.
address verifier;
}
/*************
* Variables *
*************/
/// @notice Mapping from verifier version to the list of legacy zkevm verifiers.
/// The verifiers are sorted by batchIndex in increasing order.
mapping(uint256 => Verifier[]) public legacyVerifiers;
/// @notice Mapping from verifier version to the latest used zkevm verifier.
mapping(uint256 => Verifier) public latestVerifier;
/***************
* Constructor *
***************/
constructor(uint256[] memory _versions, address[] memory _verifiers) {
for (uint256 i = 0; i < _versions.length; i++) {
if (_verifiers[i] == address(0)) revert ErrorZeroAddress();
latestVerifier[_versions[i]].verifier = _verifiers[i];
emit UpdateVerifier(_versions[i], 0, _verifiers[i]);
}
}
/*************************
* Public View Functions *
*************************/
/// @notice Return the number of legacy verifiers.
/// @param _version The version of legacy verifiers.
/// @return The number of legacy verifiers.
function legacyVerifiersLength(uint256 _version) external view returns (uint256) {
return legacyVerifiers[_version].length;
}
/// @notice Compute the verifier should be used for specific batch.
/// @param _version The version of verifier to query.
/// @param _batchIndex The batch index to query.
/// @return The address of verifier.
function getVerifier(uint256 _version, uint256 _batchIndex) public view returns (address) {
// Normally, we will use the latest verifier.
Verifier memory _verifier = latestVerifier[_version];
if (_verifier.startBatchIndex > _batchIndex) {
uint256 _length = legacyVerifiers[_version].length;
// In most case, only last few verifier will be used by `ScrollChain`.
// So, we use linear search instead of binary search.
unchecked {
for (uint256 i = _length; i > 0; --i) {
_verifier = legacyVerifiers[_version][i - 1];
if (_verifier.startBatchIndex <= _batchIndex) break;
}
}
}
return _verifier.verifier;
}
/*****************************
* Public Mutating Functions *
*****************************/
/// @inheritdoc IRollupVerifier
function verifyAggregateProof(
uint256 _batchIndex,
bytes calldata _aggrProof,
bytes32 _publicInputHash
) external view override {
address _verifier = getVerifier(0, _batchIndex);
IZkEvmVerifier(_verifier).verify(_aggrProof, _publicInputHash);
}
/// @inheritdoc IRollupVerifier
function verifyAggregateProof(
uint256 _version,
uint256 _batchIndex,
bytes calldata _aggrProof,
bytes32 _publicInputHash
) external view override {
address _verifier = getVerifier(_version, _batchIndex);
IZkEvmVerifier(_verifier).verify(_aggrProof, _publicInputHash);
}
/************************
* Restricted Functions *
************************/
/// @notice Update the address of zkevm verifier.
/// @param _version The version of the verifier.
/// @param _startBatchIndex The start batch index when the verifier will be used.
/// @param _verifier The address of new verifier.
function updateVerifier(
uint256 _version,
uint64 _startBatchIndex,
address _verifier
) external onlyOwner {
// We are using version to decide the verifier to use and also this function is
// controlled by 7 days TimeLock. It is hard to predict `lastFinalizedBatchIndex` after 7 days.
// So we decide to remove this check to make verifier updating more easier.
// if (_startBatchIndex <= IScrollChain(scrollChain).lastFinalizedBatchIndex())
// revert ErrorStartBatchIndexFinalized();
Verifier memory _latestVerifier = latestVerifier[_version];
if (_startBatchIndex < _latestVerifier.startBatchIndex) revert ErrorStartBatchIndexTooSmall();
if (_verifier == address(0)) revert ErrorZeroAddress();
if (_latestVerifier.startBatchIndex < _startBatchIndex) {
// don't push when it is the first update of the version.
if (_latestVerifier.verifier != address(0)) {
legacyVerifiers[_version].push(_latestVerifier);
}
_latestVerifier.startBatchIndex = _startBatchIndex;
}
_latestVerifier.verifier = _verifier;
latestVerifier[_version] = _latestVerifier;
emit UpdateVerifier(_version, _startBatchIndex, _verifier);
}
}