Skip to content

Commit accd67a

Browse files
committed
feat: add referenceBlockNumber (#1472)
**Motivation:** For the aggregator, we need to provide a block.number that is associated with a reference timestamp to easily index stake weights. **Modifications:** Add a `referenceBlockNumber` to `confirmGlobalTableRoot` along with the following functions: - `getLatestReferenceBlockNumber` - `getReferenceBlockNumber(timestamp)` **Result:** Easier offchain usage
1 parent c4a292a commit accd67a

File tree

10 files changed

+547
-97
lines changed

10 files changed

+547
-97
lines changed

pkg/bindings/BN254CertificateVerifier/binding.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/bindings/ECDSACertificateVerifier/binding.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/bindings/IOperatorTableUpdater/binding.go

Lines changed: 87 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/bindings/OperatorTableUpdater/binding.go

Lines changed: 88 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/bindings/OperatorTableUpdaterStorage/binding.go

Lines changed: 87 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/contracts/interfaces/IOperatorTableUpdater.sol

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,15 @@ interface IOperatorTableUpdater is
6565
* @param globalTableRootCert certificate of the root
6666
* @param globalTableRoot merkle root of all operatorSet tables
6767
* @param referenceTimestamp timestamp of the root
68+
* @param referenceBlockNumber block number of the root
6869
* @dev Any entity can submit with a valid certificate signed off by the `globalRootConfirmerSet`
6970
* @dev The `msgHash` in the `globalOperatorTableRootCert` is the hash of the `globalOperatorTableRoot`
7071
*/
7172
function confirmGlobalTableRoot(
7273
BN254Certificate calldata globalTableRootCert,
7374
bytes32 globalTableRoot,
74-
uint32 referenceTimestamp
75+
uint32 referenceTimestamp,
76+
uint32 referenceBlockNumber
7577
) external;
7678

7779
/**
@@ -145,15 +147,41 @@ interface IOperatorTableUpdater is
145147
*/
146148
function getLatestReferenceTimestamp() external view returns (uint32);
147149

150+
/**
151+
* @notice Get the latest reference block number
152+
* @return The latest reference block number
153+
*/
154+
function getLatestReferenceBlockNumber() external view returns (uint32);
155+
156+
/**
157+
* @notice Get the reference block number for a given reference timestamp
158+
* @param referenceTimestamp the reference timestamp
159+
* @return The reference block number for the given reference timestamp
160+
*/
161+
function getReferenceBlockNumberByTimestamp(
162+
uint32 referenceTimestamp
163+
) external view returns (uint32);
164+
165+
/**
166+
* @notice Get the reference timestamp for a given reference block number
167+
* @param referenceBlockNumber the reference block number
168+
* @return The reference timestamp for the given reference block number
169+
*/
170+
function getReferenceTimestampByBlockNumber(
171+
uint32 referenceBlockNumber
172+
) external view returns (uint32);
173+
148174
/**
149175
* @notice Get the message hash for the certificate of a global table root update
150176
* @param globalTableRoot the global table root
151177
* @param referenceTimestamp the reference timestamp
178+
* @param referenceBlockNumber the reference block number
152179
* @return The message hash for a global table root
153180
*/
154181
function getGlobalTableUpdateMessageHash(
155182
bytes32 globalTableRoot,
156-
uint32 referenceTimestamp
183+
uint32 referenceTimestamp,
184+
uint32 referenceBlockNumber
157185
) external view returns (bytes32);
158186

159187
/**

src/contracts/multichain/OperatorTableUpdater.sol

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,15 @@ contract OperatorTableUpdater is Initializable, OwnableUpgradeable, OperatorTabl
6363
function confirmGlobalTableRoot(
6464
BN254Certificate calldata globalTableRootCert,
6565
bytes32 globalTableRoot,
66-
uint32 referenceTimestamp
66+
uint32 referenceTimestamp,
67+
uint32 referenceBlockNumber
6768
) external {
6869
// Table roots can only be updated for current or past timestamps and after the latest reference timestamp
6970
require(referenceTimestamp <= block.timestamp, GlobalTableRootInFuture());
7071
require(referenceTimestamp > _latestReferenceTimestamp, GlobalTableRootStale());
7172
require(
72-
globalTableRootCert.messageHash == getGlobalTableUpdateMessageHash(globalTableRoot, referenceTimestamp),
73+
globalTableRootCert.messageHash
74+
== getGlobalTableUpdateMessageHash(globalTableRoot, referenceTimestamp, referenceBlockNumber),
7375
InvalidMessageHash()
7476
);
7577

@@ -82,8 +84,10 @@ contract OperatorTableUpdater is Initializable, OwnableUpgradeable, OperatorTabl
8284

8385
require(isValid, CertificateInvalid());
8486

85-
// Update the global table root
87+
// Update the global table root & reference timestamps
8688
_latestReferenceTimestamp = referenceTimestamp;
89+
_referenceBlockNumbers[referenceTimestamp] = referenceBlockNumber;
90+
_referenceTimestamps[referenceBlockNumber] = referenceTimestamp;
8791
_globalTableRoots[referenceTimestamp] = globalTableRoot;
8892

8993
emit NewGlobalTableRoot(referenceTimestamp, globalTableRoot);
@@ -195,12 +199,34 @@ contract OperatorTableUpdater is Initializable, OwnableUpgradeable, OperatorTabl
195199
return _latestReferenceTimestamp;
196200
}
197201

202+
/// @inheritdoc IOperatorTableUpdater
203+
function getLatestReferenceBlockNumber() external view returns (uint32) {
204+
return _referenceBlockNumbers[_latestReferenceTimestamp];
205+
}
206+
207+
/// @inheritdoc IOperatorTableUpdater
208+
function getReferenceBlockNumberByTimestamp(
209+
uint32 referenceTimestamp
210+
) external view returns (uint32) {
211+
return _referenceBlockNumbers[referenceTimestamp];
212+
}
213+
214+
/// @inheritdoc IOperatorTableUpdater
215+
function getReferenceTimestampByBlockNumber(
216+
uint32 referenceBlockNumber
217+
) external view returns (uint32) {
218+
return _referenceTimestamps[referenceBlockNumber];
219+
}
220+
198221
/// @inheritdoc IOperatorTableUpdater
199222
function getGlobalTableUpdateMessageHash(
200223
bytes32 globalTableRoot,
201-
uint32 referenceTimestamp
224+
uint32 referenceTimestamp,
225+
uint32 referenceBlockNumber
202226
) public pure returns (bytes32) {
203-
return keccak256(abi.encode(GLOBAL_TABLE_ROOT_CERT_TYPEHASH, globalTableRoot, referenceTimestamp));
227+
return keccak256(
228+
abi.encode(GLOBAL_TABLE_ROOT_CERT_TYPEHASH, globalTableRoot, referenceTimestamp, referenceBlockNumber)
229+
);
204230
}
205231

206232
/// @inheritdoc IOperatorTableUpdater

src/contracts/multichain/OperatorTableUpdaterStorage.sol

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ abstract contract OperatorTableUpdaterStorage is IOperatorTableUpdater {
3636
/// @notice The global table roots by timestamp
3737
mapping(uint32 timestamp => bytes32 globalTableRoot) internal _globalTableRoots;
3838

39+
/// @notice Mapping from latest reference timestamp to reference block number
40+
mapping(uint32 referenceTimestamp => uint32 referenceBlockNumber) internal _referenceBlockNumbers;
41+
42+
/// @notice Mapping from reference block number to reference timestamp
43+
mapping(uint32 referenceBlockNumber => uint32 referenceTimestamp) internal _referenceTimestamps;
44+
3945
// Constructor
4046
constructor(
4147
IBN254CertificateVerifier _bn254CertificateVerifier,
@@ -50,5 +56,5 @@ abstract contract OperatorTableUpdaterStorage is IOperatorTableUpdater {
5056
* variables without shifting down storage in the inheritance chain.
5157
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
5258
*/
53-
uint256[45] private __gap;
59+
uint256[44] private __gap;
5460
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
.
2+
└── OperatorTableUpdater (**** denotes that integration tests are needed to fully validate path)
3+
├── when initialize is called
4+
│ ├── given that the contract is already initialized
5+
│ │ └── it should revert
6+
│ └── given that the contract is not initialized
7+
│ └── it should set the owner, global root confirmer set, threshold, and update operator table & emit events
8+
├── when confirmGlobalTableRoot is called
9+
│ ├── given that the reference timestamp is in the future
10+
│ │ └── it should revert with GlobalTableRootInFuture
11+
│ ├── given that the reference timestamp is not greater than latest
12+
│ │ └── it should revert with GlobalTableRootStale
13+
│ ├── given that the message hash is invalid
14+
│ │ └── it should revert with InvalidMessageHash
15+
│ ├── given that the certificate is invalid
16+
│ │ └── it should revert with CertificateInvalid
17+
│ └── given that all parameters are valid
18+
│ └── it should update global table root, reference timestamp, block number mappings (both directions) & emit NewGlobalTableRoot event
19+
├── when updateOperatorTable is called
20+
│ ├── given that the reference timestamp is not greater than operator set's latest
21+
│ │ └── it should revert with TableUpdateForPastTimestamp
22+
│ ├── given that the global table root does not match the reference timestamp
23+
│ │ └── it should revert with InvalidGlobalTableRoot
24+
│ ├── given that the merkle proof is invalid
25+
│ │ └── it should revert with InvalidOperatorSetProof
26+
│ ├── given that the curve type is invalid
27+
│ │ └── it should revert with InvalidCurveType
28+
│ ├── given that the curve type is BN254
29+
│ │ └── it should call bn254CertificateVerifier.updateOperatorTable with decoded info
30+
│ └── given that the curve type is ECDSA
31+
│ └── it should call ecdsaCertificateVerifier.updateOperatorTable with decoded info
32+
├── when setGlobalRootConfirmerSet is called
33+
│ ├── given that the caller is not the owner
34+
│ │ └── it should revert
35+
│ └── given that the caller is the owner
36+
│ └── it should update the global root confirmer set & emit GlobalRootConfirmerSetUpdated event
37+
├── when setGlobalRootConfirmationThreshold is called
38+
│ ├── given that the caller is not the owner
39+
│ │ └── it should revert
40+
│ ├── given that the threshold exceeds MAX_BPS
41+
│ │ └── it should revert with InvalidConfirmationThreshold
42+
│ └── given that the caller is owner and threshold is valid
43+
│ └── it should update the threshold & emit GlobalRootConfirmationThresholdUpdated event
44+
├── when getGlobalTableRootByTimestamp is called
45+
│ └── it should return the global table root for the given timestamp
46+
├── when getCurrentGlobalTableRoot is called
47+
│ └── it should return the global table root for the latest reference timestamp
48+
├── when getGlobalRootConfirmerSet is called
49+
│ └── it should return the current global root confirmer set
50+
├── when getCertificateVerifier is called
51+
│ ├── given that the curve type is BN254
52+
│ │ └── it should return the bn254CertificateVerifier address
53+
│ ├── given that the curve type is ECDSA
54+
│ │ └── it should return the ecdsaCertificateVerifier address
55+
│ └── given that the curve type is invalid
56+
│ └── it should revert with InvalidCurveType
57+
├── when getLatestReferenceTimestamp is called
58+
│ └── it should return the latest reference timestamp
59+
├── when getLatestReferenceBlockNumber is called
60+
│ └── it should return the reference block number for the latest reference timestamp
61+
├── when getReferenceBlockNumberByTimestamp is called
62+
│ └── it should return the reference block number for the given timestamp
63+
├── when getReferenceTimestampByBlockNumber is called
64+
│ └── it should return the reference timestamp for the given block number
65+
├── when getGlobalTableUpdateMessageHash is called
66+
│ └── it should return the keccak256 hash of encoded typehash, root, timestamp, and block number
67+
└── when getGlobalConfirmerSetReferenceTimestamp is called
68+
└── it should return the latest reference timestamp for the global root confirmer set

0 commit comments

Comments
 (0)