Skip to content

Commit 210a1fb

Browse files
authored
Universal nonce (#119)
* Update contracts to use universal nonce. * Update tests. * Update Go wrapper.
1 parent c61578f commit 210a1fb

File tree

4 files changed

+93
-126
lines changed

4 files changed

+93
-126
lines changed

src/IDAOracle.sol

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import "./lib/tree/binary/BinaryMerkleProof.sol";
77
/// @notice Data Availability Oracle interface.
88
interface IDAOracle {
99
/// @notice Verify a Data Availability attestation.
10-
/// @param _tupleRootIndex Index of the tuple root to prove against.
10+
/// @param _tupleRootNonce Nonce of the tuple root to prove against.
1111
/// @param _tuple Data root tuple to prove inclusion of.
12-
/// @param _proof Binary Merkle tree proof that `tuple` is in the root at `tupleRootIndex`.
12+
/// @param _proof Binary Merkle tree proof that `tuple` is in the root at `_tupleRootNonce`.
1313
/// @return `true` is proof is valid, `false` otherwise.
1414
function verifyAttestation(
15-
uint256 _tupleRootIndex,
15+
uint256 _tupleRootNonce,
1616
DataRootTuple memory _tuple,
1717
BinaryMerkleProof memory _proof
1818
) external view returns (bool);

src/QuantumGravityBridge.sol

+31-33
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,8 @@ contract QuantumGravityBridge is IDAOracle {
5151
bytes32 public state_lastValidatorSetCheckpoint;
5252
/// @notice Voting power required to submit a new update.
5353
uint256 public state_powerThreshold;
54-
/// @notice Unique nonce of validator set updates.
55-
uint256 public state_lastValidatorSetNonce;
56-
/// @notice Unique nonce of data root tuple root updates.
57-
uint256 public state_lastDataRootTupleRootNonce;
54+
/// @notice Nonce for bridge events. Must be incremented sequentially.
55+
uint256 public state_eventNonce;
5856
/// @notice Mapping of data root tuple root nonces to data root tuple roots.
5957
mapping(uint256 => bytes32) public state_dataRootTupleRoots;
6058

@@ -63,13 +61,13 @@ contract QuantumGravityBridge is IDAOracle {
6361
////////////
6462

6563
/// @notice Emitted when a new root of data root tuples is relayed.
66-
/// @param nonce Nonce.
64+
/// @param nonce Event nonce.
6765
/// @param dataRootTupleRoot Merkle root of relayed data root tuples.
6866
/// See `submitDataRootTupleRoot`.
6967
event DataRootTupleRootEvent(uint256 indexed nonce, bytes32 dataRootTupleRoot);
7068

7169
/// @notice Emitted when the validator set is updated.
72-
/// @param nonce Nonce.
70+
/// @param nonce Event nonce.
7371
/// @param powerThreshold New voting power threshold.
7472
/// @param validatorSetHash Hash of new validator set.
7573
/// See `updateValidatorSet`.
@@ -103,7 +101,7 @@ contract QuantumGravityBridge is IDAOracle {
103101

104102
/// @param _bridge_id Identifier of the bridge, used in signatures for
105103
/// domain separation.
106-
/// @param _nonce Celestia block height at which bridge is initialized.
104+
/// @param _nonce Initial event nonce.
107105
/// @param _powerThreshold Initial voting power that is needed to approve
108106
/// operations.
109107
/// @param _validatorSetHash Initial validator set hash. This does not need
@@ -123,7 +121,7 @@ contract QuantumGravityBridge is IDAOracle {
123121

124122
// EFFECTS
125123

126-
state_lastValidatorSetNonce = _nonce;
124+
state_eventNonce = _nonce;
127125
state_lastValidatorSetCheckpoint = newCheckpoint;
128126
state_powerThreshold = _powerThreshold;
129127

@@ -180,19 +178,17 @@ contract QuantumGravityBridge is IDAOracle {
180178
/// @dev Make a domain-separated commitment to a data root tuple root.
181179
/// A hash of all relevant information about a data root tuple root.
182180
/// The format of the hash is:
183-
/// keccak256(bridge_id, DATA_ROOT_TUPLE_ROOT_DOMAIN_SEPARATOR, oldNonce, newNonce, dataRootTupleRoot)
181+
/// keccak256(bridge_id, DATA_ROOT_TUPLE_ROOT_DOMAIN_SEPARATOR, nonce, dataRootTupleRoot)
184182
/// @param _bridge_id Bridge ID.
185-
/// @param _oldNonce Celestia block height at which commitment begins.
186-
/// @param _newNonce Celestia block height at which commitment ends.
183+
/// @param _nonce Event nonce.
187184
/// @param _dataRootTupleRoot Data root tuple root.
188185
function domainSeparateDataRootTupleRoot(
189186
bytes32 _bridge_id,
190-
uint256 _oldNonce,
191-
uint256 _newNonce,
187+
uint256 _nonce,
192188
bytes32 _dataRootTupleRoot
193189
) private pure returns (bytes32) {
194190
bytes32 c = keccak256(
195-
abi.encode(_bridge_id, DATA_ROOT_TUPLE_ROOT_DOMAIN_SEPARATOR, _oldNonce, _newNonce, _dataRootTupleRoot)
191+
abi.encode(_bridge_id, DATA_ROOT_TUPLE_ROOT_DOMAIN_SEPARATOR, _nonce, _dataRootTupleRoot)
196192
);
197193

198194
return c;
@@ -248,7 +244,7 @@ contract QuantumGravityBridge is IDAOracle {
248244
/// The validator set hash that is signed over is domain separated as per
249245
/// `domainSeparateValidatorSetHash`.
250246
/// @param _newValidatorSetHash The hash of the new validator set.
251-
/// @param _newNonce The new Celestia block height.
247+
/// @param _newNonce The new event nonce.
252248
/// @param _currentValidatorSet The current validator set.
253249
/// @param _sigs Signatures.
254250
function updateValidatorSet(
@@ -260,11 +256,11 @@ contract QuantumGravityBridge is IDAOracle {
260256
) external {
261257
// CHECKS
262258

263-
uint256 currentNonce = state_lastValidatorSetNonce;
259+
uint256 currentNonce = state_eventNonce;
264260
uint256 currentPowerThreshold = state_powerThreshold;
265261

266-
// Check that the new validator set nonce is greater than the old one.
267-
if (_newNonce <= currentNonce) {
262+
// Check that the new nonce is one more than the current one.
263+
if (_newNonce != currentNonce + 1) {
268264
revert InvalidValidatorSetNonce();
269265
}
270266

@@ -295,7 +291,7 @@ contract QuantumGravityBridge is IDAOracle {
295291

296292
state_lastValidatorSetCheckpoint = newCheckpoint;
297293
state_powerThreshold = _newPowerThreshold;
298-
state_lastValidatorSetNonce = _newNonce;
294+
state_eventNonce = _newNonce;
299295

300296
// LOGS
301297

@@ -314,24 +310,26 @@ contract QuantumGravityBridge is IDAOracle {
314310
///
315311
/// The data tuple root that is signed over is domain separated as per
316312
/// `domainSeparateDataRootTupleRoot`.
317-
/// @param _nonce The Celestia block height up to which the data root tuple
318-
/// root commits to.
313+
/// @param _newNonce The new event nonce.
314+
/// @param _validatorSetNonce The nonce of the latest update to the
315+
/// validator set.
319316
/// @param _dataRootTupleRoot The Merkle root of data root tuples.
320317
/// @param _currentValidatorSet The current validator set.
321318
/// @param _sigs Signatures.
322319
function submitDataRootTupleRoot(
323-
uint256 _nonce,
320+
uint256 _newNonce,
321+
uint256 _validatorSetNonce,
324322
bytes32 _dataRootTupleRoot,
325323
Validator[] calldata _currentValidatorSet,
326324
Signature[] calldata _sigs
327325
) external {
328326
// CHECKS
329327

330-
uint256 currentNonce = state_lastDataRootTupleRootNonce;
328+
uint256 currentNonce = state_eventNonce;
331329
uint256 currentPowerThreshold = state_powerThreshold;
332330

333-
// Check that the data root tuple root nonce is higher than the last nonce.
334-
if (_nonce <= currentNonce) {
331+
// Check that the new nonce is one more than the current one.
332+
if (_newNonce != currentNonce + 1) {
335333
revert InvalidDataRootTupleRootNonce();
336334
}
337335

@@ -345,7 +343,7 @@ contract QuantumGravityBridge is IDAOracle {
345343
if (
346344
domainSeparateValidatorSetHash(
347345
BRIDGE_ID,
348-
state_lastValidatorSetNonce,
346+
_validatorSetNonce,
349347
currentPowerThreshold,
350348
currentValidatorSetHash
351349
) != state_lastValidatorSetCheckpoint
@@ -355,32 +353,32 @@ contract QuantumGravityBridge is IDAOracle {
355353

356354
// Check that enough current validators have signed off on the data
357355
// root tuple root and nonce.
358-
bytes32 c = domainSeparateDataRootTupleRoot(BRIDGE_ID, currentNonce, _nonce, _dataRootTupleRoot);
356+
bytes32 c = domainSeparateDataRootTupleRoot(BRIDGE_ID, _newNonce, _dataRootTupleRoot);
359357
checkValidatorSignatures(_currentValidatorSet, _sigs, c, currentPowerThreshold);
360358

361359
// EFFECTS
362360

363-
state_lastDataRootTupleRootNonce = _nonce;
364-
state_dataRootTupleRoots[_nonce] = _dataRootTupleRoot;
361+
state_eventNonce = _newNonce;
362+
state_dataRootTupleRoots[_newNonce] = _dataRootTupleRoot;
365363

366364
// LOGS
367365

368-
emit DataRootTupleRootEvent(_nonce, _dataRootTupleRoot);
366+
emit DataRootTupleRootEvent(_newNonce, _dataRootTupleRoot);
369367
}
370368

371369
/// @dev see "./IDAOracle.sol"
372370
function verifyAttestation(
373-
uint256 _tupleRootIndex,
371+
uint256 _tupleRootNonce,
374372
DataRootTuple memory _tuple,
375373
BinaryMerkleProof memory _proof
376374
) external view override returns (bool) {
377375
// Tuple must have been committed before.
378-
if (_tupleRootIndex > state_lastDataRootTupleRootNonce) {
376+
if (_tupleRootNonce > state_eventNonce) {
379377
return false;
380378
}
381379

382380
// Load the tuple root at the given index from storage.
383-
bytes32 root = state_dataRootTupleRoots[_tupleRootIndex];
381+
bytes32 root = state_dataRootTupleRoots[_tupleRootNonce];
384382

385383
// Verify the proof.
386384
bool isProofValid = BinaryMerkleTree.verify(root, _proof, abi.encode(_tuple));

src/test/QuantumGravityBridge.t.sol

+12-11
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,17 @@ contract RelayerTest is DSTest {
3333

3434
Validator[] private validators;
3535
uint256 private votingPower = 5000;
36-
uint256 private valsetNonce = 0;
3736
uint256 private dataTupleRootNonce = 0;
3837

3938
// Set up Foundry cheatcodes.
4039
CheatCodes cheats = CheatCodes(HEVM_ADDRESS);
4140

4241
function setUp() public {
42+
uint256 initialVelsetNonce = 0;
43+
4344
validators.push(Validator(cheats.addr(testPriv1), votingPower));
4445
bytes32 hash = computeValidatorSetHash(validators);
45-
bridge = new QuantumGravityBridge(BRIDGE_ID, valsetNonce, (2 * votingPower) / 3, hash);
46+
bridge = new QuantumGravityBridge(BRIDGE_ID, initialVelsetNonce, (2 * votingPower) / 3, hash);
4647
}
4748

4849
function testUpdateValidatorSet() public {
@@ -65,17 +66,18 @@ contract RelayerTest is DSTest {
6566

6667
bridge.updateValidatorSet(newNonce, newPowerThreshold, newVSHash, oldVS, sigs);
6768

68-
assertEq(bridge.state_lastValidatorSetNonce(), newNonce);
69+
assertEq(bridge.state_eventNonce(), newNonce);
6970
assertEq(bridge.state_powerThreshold(), newPowerThreshold);
7071
assertEq(bridge.state_lastValidatorSetCheckpoint(), newCheckpoint);
7172
}
7273

7374
function testSubmitDataRootTupleRoot() public {
74-
uint256 newNonce = 1;
75+
uint256 initialVelsetNonce = 0;
76+
uint256 nonce = 1;
7577
// 32 bytes, chosen at random.
7678
bytes32 newTupleRoot = 0x0de92bac0b356560d821f8e7b6f5c9fe4f3f88f6c822283efd7ab51ad56a640e;
7779

78-
bytes32 newDataRootTupleRoot = domainSeparateDataRootTupleRoot(BRIDGE_ID, valsetNonce, newNonce, newTupleRoot);
80+
bytes32 newDataRootTupleRoot = domainSeparateDataRootTupleRoot(BRIDGE_ID, nonce, newTupleRoot);
7981

8082
// Signature for the update.
8183
Signature[] memory sigs = new Signature[](1);
@@ -86,10 +88,10 @@ contract RelayerTest is DSTest {
8688
Validator[] memory valSet = new Validator[](1);
8789
valSet[0] = Validator(cheats.addr(testPriv1), votingPower);
8890

89-
bridge.submitDataRootTupleRoot(newNonce, newTupleRoot, valSet, sigs);
91+
bridge.submitDataRootTupleRoot(nonce, initialVelsetNonce, newTupleRoot, valSet, sigs);
9092

91-
assertEq(bridge.state_lastDataRootTupleRootNonce(), newNonce);
92-
assertEq(bridge.state_dataRootTupleRoots(newNonce), newTupleRoot);
93+
assertEq(bridge.state_eventNonce(), nonce);
94+
assertEq(bridge.state_dataRootTupleRoots(nonce), newTupleRoot);
9395
}
9496

9597
function computeValidatorSetHash(Validator[] memory _validators) private pure returns (bytes32) {
@@ -111,12 +113,11 @@ contract RelayerTest is DSTest {
111113

112114
function domainSeparateDataRootTupleRoot(
113115
bytes32 _bridge_id,
114-
uint256 _oldNonce,
115-
uint256 _newNonce,
116+
uint256 _nonce,
116117
bytes32 _dataRootTupleRoot
117118
) private pure returns (bytes32) {
118119
bytes32 c = keccak256(
119-
abi.encode(_bridge_id, DATA_ROOT_TUPLE_ROOT_DOMAIN_SEPARATOR, _oldNonce, _newNonce, _dataRootTupleRoot)
120+
abi.encode(_bridge_id, DATA_ROOT_TUPLE_ROOT_DOMAIN_SEPARATOR, _nonce, _dataRootTupleRoot)
120121
);
121122

122123
return c;

0 commit comments

Comments
 (0)