Skip to content

Commit 03752d0

Browse files
committed
fix to allow only client state upgrade
Signed-off-by: Jun Kimura <jun.kimura@datachain.jp>
1 parent 1071b8f commit 03752d0

File tree

2 files changed

+154
-76
lines changed

2 files changed

+154
-76
lines changed

contracts/toki/TokiLCPClientZKDCAP.sol

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -66,28 +66,13 @@ contract TokiLCPClientZKDCAP is LCPClientZKDCAPOwnableUpgradeable {
6666
revert LCPClientClientStateFrozen();
6767
}
6868

69-
Height.Data memory latestHeight =
70-
Height.Data(clientState.latest_height.revision_number, clientState.latest_height.revision_height);
71-
if (IBCHeight.isZero(latestHeight) || IBCHeight.gte(latestHeight, newConsensusState.height)) {
72-
revert LCPClientClientStateInvalidLatestHeight();
73-
}
69+
// ------- Upgrade ClientState ------- //
7470

7571
// Validate ClientState
7672
if (newClientState.mrenclave.length != 32) {
7773
revert LCPClientClientStateInvalidMrenclaveLength();
7874
}
7975

80-
// Validate ConsensusState
81-
if (newConsensusState.consensusState.timestamp == 0) {
82-
revert LCPClientConsensusStateInvalidTimestamp();
83-
}
84-
85-
// A stateId with zero length or zero value is invalid.
86-
if (newConsensusState.consensusState.stateId == bytes32(0)) {
87-
revert LCPClientConsensusStateInvalidStateId();
88-
}
89-
90-
// Upgrade ClientState
9176
clientState.mrenclave = newClientState.mrenclave;
9277
clientState.key_expiration = newClientState.keyExpiration;
9378

@@ -119,15 +104,38 @@ contract TokiLCPClientZKDCAP is LCPClientZKDCAPOwnableUpgradeable {
119104
clientState.zkdcap_verifier_infos[0] = newClientState.zkdcapVerifierInfos[0];
120105
clientStorage.zkDCAPRisc0ImageId = parseRiscZeroVerifierInfo(newClientState.zkdcapVerifierInfos[0]);
121106

122-
// Upgrade ConsensusState and latestHeight of ClientState
123-
clientState.latest_height.revision_number = newConsensusState.height.revision_number;
124-
clientState.latest_height.revision_height = newConsensusState.height.revision_height;
125-
uint128 height = IBCHeight.toUint128(newConsensusState.height);
126-
clientStorage.consensusStates[height] = newConsensusState.consensusState;
107+
// ------- Upgrade ConsensusState ------- //
127108

109+
Height.Data memory latestHeight =
110+
Height.Data(clientState.latest_height.revision_number, clientState.latest_height.revision_height);
111+
Height.Data[] memory heights;
112+
// If the new consensus state is zero, do not upgrade the consensus state
113+
if (!IBCHeight.isZero(newConsensusState.height)) {
114+
// Validate ConsensusState
115+
if (newConsensusState.consensusState.timestamp == 0) {
116+
revert LCPClientConsensusStateInvalidTimestamp();
117+
}
118+
119+
// A stateId with zero length or zero value is invalid.
120+
if (newConsensusState.consensusState.stateId == bytes32(0)) {
121+
revert LCPClientConsensusStateInvalidStateId();
122+
}
123+
124+
// NOTE: If the latest height is zero, do not upgrade the consensus state
125+
if (IBCHeight.isZero(latestHeight) || IBCHeight.gte(latestHeight, newConsensusState.height)) {
126+
revert LCPClientClientStateInvalidLatestHeight();
127+
}
128+
129+
// Upgrade ConsensusState and latestHeight of ClientState
130+
clientState.latest_height.revision_number = newConsensusState.height.revision_number;
131+
clientState.latest_height.revision_height = newConsensusState.height.revision_height;
132+
uint128 height = IBCHeight.toUint128(newConsensusState.height);
133+
clientStorage.consensusStates[height] = newConsensusState.consensusState;
134+
135+
heights = new Height.Data[](1);
136+
heights[0] = newConsensusState.height;
137+
}
128138
// Update commitments
129-
Height.Data[] memory heights = new Height.Data[](1);
130-
heights[0] = newConsensusState.height;
131139
IIBCClient(ibcHandler).updateClientCommitments(newClientState.clientId, heights);
132140
}
133141

test/toki/TokiLCPClientTest.t.sol

Lines changed: 123 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -78,56 +78,7 @@ contract TokiLCPClientTest is BasicTest {
7878
return;
7979
}
8080
string memory clientId = "lcp-zkdcap";
81-
Options memory opts;
82-
opts.constructorData = abi.encode(
83-
address(this), false, ZKDCAPTestHelper.dummyIntelRootCACert(), address(new NopRiscZeroVerifier())
84-
);
85-
address proxy = Upgrades.deployUUPSProxy(
86-
"LCPClientZKDCAPOwnableUpgradeable.sol",
87-
abi.encodePacked(LCPClientZKDCAPOwnableUpgradeable.initialize.selector),
88-
opts
89-
);
90-
LCPClientZKDCAPOwnableUpgradeable lc = LCPClientZKDCAPOwnableUpgradeable(proxy);
91-
IbcLightclientsLcpV1ClientState.Data memory clientState = defaultClientState();
92-
clientState.allowed_quote_statuses = new string[](2);
93-
clientState.allowed_quote_statuses[0] = DCAPValidator.TCB_STATUS_CONFIGURATION_NEEDED_STRING;
94-
clientState.allowed_quote_statuses[1] = DCAPValidator.TCB_STATUS_OUT_OF_DATE_STRING;
95-
clientState.allowed_advisory_ids = new string[](2);
96-
clientState.allowed_advisory_ids[0] = "INTEL-SA-0001";
97-
clientState.allowed_advisory_ids[1] = "INTEL-SA-0003";
98-
lc.initializeClient(
99-
clientId, LCPProtoMarshaler.marshal(clientState), LCPProtoMarshaler.marshal(defaultConsensusState())
100-
);
101-
DCAPValidator.Output memory output = ZKDCAPTestHelper.qvOutput();
102-
output.advisoryIDs = clientState.allowed_advisory_ids;
103-
Vm.Wallet memory ek0 = vm.createWallet("ek0");
104-
output.enclaveKey = ek0.addr;
105-
// warp to the time of `output.validityNotBefore`
106-
vm.warp(output.validityNotBefore);
107-
lc.zkDCAPRegisterEnclaveKey(clientId, registerEnclaveKeyMessage(output));
108-
{
109-
LCPCommitment.UpdateStateProxyMessage memory updateStateMessage;
110-
updateStateMessage.prevHeight = Height.Data(0, 0);
111-
updateStateMessage.prevStateId = bytes32(0);
112-
updateStateMessage.postHeight = Height.Data(0, 1);
113-
updateStateMessage.postStateId = keccak256("state-1");
114-
updateStateMessage.timestamp = 1;
115-
LCPCommitment.ValidationContext memory vc;
116-
updateStateMessage.context = abi.encode(vc);
117-
updateStateMessage.emittedStates = new LCPCommitment.EmittedState[](1);
118-
119-
LCPCommitment.HeaderedProxyMessage memory headeredMessage;
120-
headeredMessage.header = LCPCommitment.LCP_MESSAGE_HEADER_UPDATE_STATE;
121-
headeredMessage.message = abi.encode(updateStateMessage);
122-
123-
IbcLightclientsLcpV1UpdateClientMessage.Data memory message;
124-
message.proxy_message = abi.encode(headeredMessage);
125-
126-
(uint8 v, bytes32 r, bytes32 s) = vm.sign(ek0, keccak256(message.proxy_message));
127-
message.signatures = new bytes[](1);
128-
message.signatures[0] = abi.encodePacked(r, s, v);
129-
lc.updateClient(clientId, message);
130-
}
81+
LCPClientZKDCAPOwnableUpgradeable lc = contractUpgradeCommon(clientId);
13182

13283
TokiLCPClientZKDCAP.NewClientState memory newClientState;
13384
newClientState.clientId = clientId;
@@ -143,8 +94,12 @@ contract TokiLCPClientTest is BasicTest {
14394
bytes31(0), // reserved
14495
bytes32(keccak256("new verifier"))
14596
);
146-
assertNotEq(newClientState.zkdcapVerifierInfos[0], clientState.zkdcap_verifier_infos[0]);
147-
assertNotEq(newClientState.allowedQuoteStatuses.length, clientState.allowed_quote_statuses.length);
97+
{
98+
(bytes memory bz,) = lc.getClientState(clientId);
99+
IbcLightclientsLcpV1ClientState.Data memory clientState = LCPProtoMarshaler.unmarshalClientState(bz);
100+
assertNotEq(newClientState.zkdcapVerifierInfos[0], clientState.zkdcap_verifier_infos[0]);
101+
assertNotEq(newClientState.allowedQuoteStatuses.length, clientState.allowed_quote_statuses.length);
102+
}
148103

149104
TokiLCPClientZKDCAP.NewConsensusState memory newConsensusState;
150105
newConsensusState.height = Height.Data(0, 2);
@@ -157,7 +112,7 @@ contract TokiLCPClientTest is BasicTest {
157112
address(this), false, ZKDCAPTestHelper.dummyIntelRootCACert(), address(new NopRiscZeroVerifier()), 2
158113
);
159114
Upgrades.upgradeProxy(
160-
proxy,
115+
address(lc),
161116
"TokiLCPClientZKDCAP.sol",
162117
abi.encodeCall(TokiLCPClientZKDCAP.upgrade, (newClientState, newConsensusState)),
163118
opts2
@@ -184,6 +139,121 @@ contract TokiLCPClientTest is BasicTest {
184139
}
185140
}
186141

142+
function testContractUpgradeWithEmptyConsensusState() public {
143+
if (!vm.envOr("TEST_UPGRADEABLE", false)) {
144+
return;
145+
}
146+
string memory clientId = "lcp-zkdcap";
147+
LCPClientZKDCAPOwnableUpgradeable lc = contractUpgradeCommon(clientId);
148+
149+
TokiLCPClientZKDCAP.NewClientState memory newClientState;
150+
newClientState.clientId = clientId;
151+
newClientState.mrenclave = abi.encodePacked(keccak256("new mrenclave"));
152+
newClientState.keyExpiration = 60 * 60;
153+
newClientState.allowedQuoteStatuses = new string[](1);
154+
newClientState.allowedQuoteStatuses[0] = DCAPValidator.TCB_STATUS_SW_HARDENING_NEEDED_STRING;
155+
newClientState.allowedAdvisoryIds = new string[](1);
156+
newClientState.allowedAdvisoryIds[0] = "INTEL-SA-0002";
157+
newClientState.zkdcapVerifierInfos = new bytes[](1);
158+
newClientState.zkdcapVerifierInfos[0] = abi.encodePacked(
159+
bytes1(uint8(1)), // zkvmType
160+
bytes31(0), // reserved
161+
bytes32(keccak256("new verifier"))
162+
);
163+
164+
{
165+
(bytes memory bz,) = lc.getClientState(clientId);
166+
IbcLightclientsLcpV1ClientState.Data memory clientState = LCPProtoMarshaler.unmarshalClientState(bz);
167+
assertNotEq(newClientState.zkdcapVerifierInfos[0], clientState.zkdcap_verifier_infos[0]);
168+
assertNotEq(newClientState.allowedQuoteStatuses.length, clientState.allowed_quote_statuses.length);
169+
}
170+
171+
TokiLCPClientZKDCAP.NewConsensusState memory newConsensusState;
172+
// NOTE: The new consensus state is empty
173+
newConsensusState.height = Height.Data(0, 0);
174+
175+
Options memory opts2;
176+
opts2.referenceContract = "LCPClientZKDCAPOwnableUpgradeable.sol";
177+
opts2.constructorData = abi.encode(
178+
address(this), false, ZKDCAPTestHelper.dummyIntelRootCACert(), address(new NopRiscZeroVerifier()), 2
179+
);
180+
Upgrades.upgradeProxy(
181+
address(lc),
182+
"TokiLCPClientZKDCAP.sol",
183+
abi.encodeCall(TokiLCPClientZKDCAP.upgrade, (newClientState, newConsensusState)),
184+
opts2
185+
);
186+
187+
{
188+
(bytes memory bz,) = lc.getClientState(clientId);
189+
IbcLightclientsLcpV1ClientState.Data memory clientState = LCPProtoMarshaler.unmarshalClientState(bz);
190+
assertEq(clientState.latest_height.revision_number, 0);
191+
assertEq(clientState.latest_height.revision_height, 1);
192+
assertEq(clientState.mrenclave, newClientState.mrenclave);
193+
assertEq(clientState.key_expiration, newClientState.keyExpiration);
194+
assertEq(clientState.allowed_quote_statuses.length, 1);
195+
assertEq(clientState.allowed_quote_statuses[0], newClientState.allowedQuoteStatuses[0]);
196+
assertEq(clientState.allowed_advisory_ids.length, 1);
197+
assertEq(clientState.allowed_advisory_ids[0], newClientState.allowedAdvisoryIds[0]);
198+
assertEq(clientState.zkdcap_verifier_infos[0], newClientState.zkdcapVerifierInfos[0]);
199+
}
200+
}
201+
202+
function contractUpgradeCommon(string memory clientId) internal returns (LCPClientZKDCAPOwnableUpgradeable) {
203+
Options memory opts;
204+
opts.constructorData = abi.encode(
205+
address(this), false, ZKDCAPTestHelper.dummyIntelRootCACert(), address(new NopRiscZeroVerifier())
206+
);
207+
LCPClientZKDCAPOwnableUpgradeable lc = LCPClientZKDCAPOwnableUpgradeable(
208+
Upgrades.deployUUPSProxy(
209+
"LCPClientZKDCAPOwnableUpgradeable.sol",
210+
abi.encodePacked(LCPClientZKDCAPOwnableUpgradeable.initialize.selector),
211+
opts
212+
)
213+
);
214+
IbcLightclientsLcpV1ClientState.Data memory clientState = defaultClientState();
215+
clientState.allowed_quote_statuses = new string[](2);
216+
clientState.allowed_quote_statuses[0] = DCAPValidator.TCB_STATUS_CONFIGURATION_NEEDED_STRING;
217+
clientState.allowed_quote_statuses[1] = DCAPValidator.TCB_STATUS_OUT_OF_DATE_STRING;
218+
clientState.allowed_advisory_ids = new string[](2);
219+
clientState.allowed_advisory_ids[0] = "INTEL-SA-0001";
220+
clientState.allowed_advisory_ids[1] = "INTEL-SA-0003";
221+
lc.initializeClient(
222+
clientId, LCPProtoMarshaler.marshal(clientState), LCPProtoMarshaler.marshal(defaultConsensusState())
223+
);
224+
DCAPValidator.Output memory output = ZKDCAPTestHelper.qvOutput();
225+
output.advisoryIDs = clientState.allowed_advisory_ids;
226+
Vm.Wallet memory ek0 = vm.createWallet("ek0");
227+
output.enclaveKey = ek0.addr;
228+
// warp to the time of `output.validityNotBefore`
229+
vm.warp(output.validityNotBefore);
230+
lc.zkDCAPRegisterEnclaveKey(clientId, registerEnclaveKeyMessage(output));
231+
{
232+
LCPCommitment.UpdateStateProxyMessage memory updateStateMessage;
233+
updateStateMessage.prevHeight = Height.Data(0, 0);
234+
updateStateMessage.prevStateId = bytes32(0);
235+
updateStateMessage.postHeight = Height.Data(0, 1);
236+
updateStateMessage.postStateId = keccak256("state-1");
237+
updateStateMessage.timestamp = 1;
238+
LCPCommitment.ValidationContext memory vc;
239+
updateStateMessage.context = abi.encode(vc);
240+
updateStateMessage.emittedStates = new LCPCommitment.EmittedState[](1);
241+
242+
LCPCommitment.HeaderedProxyMessage memory headeredMessage;
243+
headeredMessage.header = LCPCommitment.LCP_MESSAGE_HEADER_UPDATE_STATE;
244+
headeredMessage.message = abi.encode(updateStateMessage);
245+
246+
IbcLightclientsLcpV1UpdateClientMessage.Data memory message;
247+
message.proxy_message = abi.encode(headeredMessage);
248+
249+
(uint8 v, bytes32 r, bytes32 s) = vm.sign(ek0, keccak256(message.proxy_message));
250+
message.signatures = new bytes[](1);
251+
message.signatures[0] = abi.encodePacked(r, s, v);
252+
lc.updateClient(clientId, message);
253+
}
254+
return lc;
255+
}
256+
187257
function testRecoveredLCPClientUpgradeable() public {
188258
string memory clientId = "lcp-zkdcap";
189259
TestTokiLCPClientZKDCAP lc = new TestTokiLCPClientZKDCAP(

0 commit comments

Comments
 (0)