@@ -57,13 +57,17 @@ abstract contract LCPClientBase is ILightClient, ILCPClientErrors {
57
57
58
58
// --------------------- Storage fields ---------------------
59
59
60
+ /// @dev clientId => client storage
60
61
mapping (string => ClientStorage) internal clientStorages;
61
62
62
- // rootCA 's public key parameters
63
+ /// @dev RootCA 's public key parameters
63
64
AVRValidator.RSAParams internal verifiedRootCAParams;
64
- // keccak256(signingCert) => RSAParams of signing public key
65
+ /// @dev keccak256(signingCert) => RSAParams of signing public key
65
66
mapping (bytes32 => AVRValidator.RSAParams) internal verifiedSigningRSAParams;
66
67
68
+ /// @dev Reserved storage space to allow for layout changes in the future
69
+ uint256 [50 ] private __gap;
70
+
67
71
// --------------------- Constructor ---------------------
68
72
69
73
/// @custom:oz-upgrades-unsafe-allow constructor
@@ -100,7 +104,8 @@ abstract contract LCPClientBase is ILightClient, ILCPClientErrors {
100
104
/**
101
105
* @dev initializeClient initializes a new client with the given state.
102
106
* If succeeded, it returns heights at which the consensus state are stored.
103
- * The function must be only called by IBCHandler.
107
+ * This function is guaranteed by the IBC contract to be called only once for each `clientId`.
108
+ * @param clientId the client identifier which is unique within the IBC handler
104
109
*/
105
110
function initializeClient (
106
111
string calldata clientId ,
@@ -164,12 +169,18 @@ abstract contract LCPClientBase is ILightClient, ILCPClientErrors {
164
169
165
170
// set allowed quote status and advisories
166
171
for (uint256 i = 0 ; i < clientState.allowed_quote_statuses.length ; i++ ) {
167
- clientStorage.allowedStatuses.allowedQuoteStatuses[clientState.allowed_quote_statuses[i]] =
168
- AVRValidator.FLAG_ALLOWED;
172
+ string memory allowedQuoteStatus = clientState.allowed_quote_statuses[i];
173
+ if (bytes (allowedQuoteStatus).length == 0 ) {
174
+ revert LCPClientClientStateInvalidAllowedQuoteStatus ();
175
+ }
176
+ clientStorage.allowedStatuses.allowedQuoteStatuses[allowedQuoteStatus] = AVRValidator.FLAG_ALLOWED;
169
177
}
170
178
for (uint256 i = 0 ; i < clientState.allowed_advisory_ids.length ; i++ ) {
171
- clientStorage.allowedStatuses.allowedAdvisories[clientState.allowed_advisory_ids[i]] =
172
- AVRValidator.FLAG_ALLOWED;
179
+ string memory allowedAdvisoryId = clientState.allowed_advisory_ids[i];
180
+ if (bytes (allowedAdvisoryId).length == 0 ) {
181
+ revert LCPClientClientStateInvalidAllowedAdvisoryId ();
182
+ }
183
+ clientStorage.allowedStatuses.allowedAdvisories[allowedAdvisoryId] = AVRValidator.FLAG_ALLOWED;
173
184
}
174
185
175
186
return clientState.latest_height;
@@ -433,16 +444,22 @@ abstract contract LCPClientBase is ILightClient, ILCPClientErrors {
433
444
434
445
LCPCommitment.validationContextEval (pmsg.context, block .timestamp * 1e9 );
435
446
436
- uint128 latestHeight = clientState.latest_height.toUint128 ();
437
447
uint128 postHeight = pmsg.postHeight.toUint128 ();
438
- if (latestHeight < postHeight) {
439
- clientState.latest_height = pmsg.postHeight;
440
- }
441
-
442
448
consensusState = clientStorage.consensusStates[postHeight];
449
+ if (consensusState.stateId != bytes32 (0 )) {
450
+ if (consensusState.stateId != pmsg.postStateId || consensusState.timestamp != uint64 (pmsg.timestamp)) {
451
+ revert LCPClientUpdateStateInconsistentConsensusState ();
452
+ }
453
+ // return empty heights if the consensus state is already stored
454
+ return heights;
455
+ }
443
456
consensusState.stateId = pmsg.postStateId;
444
457
consensusState.timestamp = uint64 (pmsg.timestamp);
445
458
459
+ uint128 latestHeight = clientState.latest_height.toUint128 ();
460
+ if (latestHeight < postHeight) {
461
+ clientState.latest_height = pmsg.postHeight;
462
+ }
446
463
heights = new Height.Data [](1 );
447
464
heights[0 ] = pmsg.postHeight;
448
465
return heights;
@@ -639,14 +656,6 @@ abstract contract LCPClientBase is ILightClient, ILCPClientErrors {
639
656
}
640
657
}
641
658
642
- function verifyECDSASignature (bytes32 commitment , bytes memory signature , address signer )
643
- internal
644
- pure
645
- returns (bool )
646
- {
647
- return verifyECDSASignature (commitment, signature) == signer;
648
- }
649
-
650
659
function verifyECDSASignature (bytes32 commitment , bytes memory signature ) internal pure returns (address ) {
651
660
if (uint8 (signature[64 ]) < 27 ) {
652
661
signature[64 ] = bytes1 (uint8 (signature[64 ]) + 27 );
0 commit comments