Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions light-clients/lcp/types/client_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,6 @@ func (cs ClientState) VerifyMembership(
if err != nil {
return err
}
hashedValue := crypto.Keccak256Hash(value)

if !height.EQ(msg.Height) {
return errorsmod.Wrapf(ErrInvalidStateCommitment, "invalid height: expected=%v got=%v", height, msg.Height)
Expand All @@ -232,8 +231,12 @@ func (cs ClientState) VerifyMembership(
if !bytes.Equal(commitmentPath, msg.Path) {
return errorsmod.Wrapf(ErrInvalidStateCommitment, "invalid path: expected=%v got=%v", string(commitmentPath), string(msg.Path))
}
if hashedValue != msg.Value {
return errorsmod.Wrapf(ErrInvalidStateCommitment, "invalid value: expected=%X got=%X", hashedValue[:], msg.Value)
// Note that this function is used for verify NonMembership proof and NonMembership proof has no hashed value in its proof.
if len(value) > 0 {
hashedValue := crypto.Keccak256Hash(value)
if hashedValue != msg.Value {
return errorsmod.Wrapf(ErrInvalidStateCommitment, "invalid value: expected=%X got=%X", hashedValue[:], msg.Value)
}
}
if !msg.StateID.EqualBytes(consensusState.StateId) {
return errorsmod.Wrapf(ErrInvalidStateCommitment, "invalid state ID: expected=%v got=%v", consensusState.StateId, msg.StateID)
Expand Down
58 changes: 38 additions & 20 deletions relay/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,35 +337,53 @@ func (pr *Prover) ProveState(ctx core.QueryContext, path string, value []byte) (
if err != nil {
return nil, clienttypes.Height{}, fmt.Errorf("failed originProver.ProveState: path=%v value=%x %w", path, value, err)
}
m := elc.MsgVerifyMembership{
ClientId: pr.config.ElcClientId,
Prefix: []byte(exported.StoreKey),
Path: path,
Value: value,
ProofHeight: proofHeight,
Proof: proof,
Signer: pr.activeEnclaveKey.GetEnclaveKeyAddress().Bytes(),
}
res, err := pr.lcpServiceClient.VerifyMembership(ctx.Context(), &m)
if err != nil {
return nil, clienttypes.Height{}, fmt.Errorf("failed ELC's VerifyMembership: elc_client_id=%v msg=%v %w", pr.config.ElcClientId, m, err)

var cp lcptypes.CommitmentProofs
if len(value) == 0 {
m := elc.MsgVerifyNonMembership{
ClientId: pr.config.ElcClientId,
Prefix: []byte(exported.StoreKey),
Path: path,
ProofHeight: proofHeight,
Proof: proof,
Signer: pr.activeEnclaveKey.GetEnclaveKeyAddress().Bytes(),
}
res, err := pr.lcpServiceClient.VerifyNonMembership(ctx.Context(), &m)
if err != nil {
return nil, clienttypes.Height{}, fmt.Errorf("failed ELC's VerifyNonMembership: elc_client_id=%v msg=%v %w", pr.config.ElcClientId, m, err)
}
cp.Message = res.Message
cp.Signatures = [][]byte{res.Signature}
Comment on lines +351 to +356
Copy link

Copilot AI May 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Both the NonMembership and Membership branches assign cp.Message and cp.Signatures in an identical manner. Consider refactoring to reduce code duplication by extracting these assignments outside the conditional branches.

Suggested change
res, err := pr.lcpServiceClient.VerifyNonMembership(ctx.Context(), &m)
if err != nil {
return nil, clienttypes.Height{}, fmt.Errorf("failed ELC's VerifyNonMembership: elc_client_id=%v msg=%v %w", pr.config.ElcClientId, m, err)
}
cp.Message = res.Message
cp.Signatures = [][]byte{res.Signature}
var err error
res, err = pr.lcpServiceClient.VerifyNonMembership(ctx.Context(), &m)
if err != nil {
return nil, clienttypes.Height{}, fmt.Errorf("failed ELC's VerifyNonMembership: elc_client_id=%v msg=%v %w", pr.config.ElcClientId, m, err)
}

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type of VerifyMembership and VerifyMembership is not compatible.
I think generics is needed to commonalize these code, it is a bit over spec at this situation.

} else {
m := elc.MsgVerifyMembership{
ClientId: pr.config.ElcClientId,
Prefix: []byte(exported.StoreKey),
Path: path,
Value: value,
ProofHeight: proofHeight,
Proof: proof,
Signer: pr.activeEnclaveKey.GetEnclaveKeyAddress().Bytes(),
}
res, err := pr.lcpServiceClient.VerifyMembership(ctx.Context(), &m)
if err != nil {
return nil, clienttypes.Height{}, fmt.Errorf("failed ELC's VerifyMembership: elc_client_id=%v msg=%v %w", pr.config.ElcClientId, m, err)
}
cp.Message = res.Message
cp.Signatures = [][]byte{res.Signature}
}
message, err := lcptypes.EthABIDecodeHeaderedProxyMessage(res.Message)
message, err := lcptypes.EthABIDecodeHeaderedProxyMessage(cp.Message)
if err != nil {
return nil, clienttypes.Height{}, fmt.Errorf("failed to decode headered proxy message: message=%x %w", res.Message, err)
return nil, clienttypes.Height{}, fmt.Errorf("failed to decode headered proxy message: message=%x %w", cp.Message, err)
}
sc, err := message.GetVerifyMembershipProxyMessage()
if err != nil {
return nil, clienttypes.Height{}, fmt.Errorf("failed GetVerifyMembershipProxyMessage: message=%x %w", res.Message, err)
return nil, clienttypes.Height{}, fmt.Errorf("failed GetVerifyMembershipProxyMessage: message=%x %w", cp.Message, err)
}
cp, err := lcptypes.EthABIEncodeCommitmentProofs(&lcptypes.CommitmentProofs{
Message: res.Message,
Signatures: [][]byte{res.Signature},
})
cpEnc, err := lcptypes.EthABIEncodeCommitmentProofs(&cp)
if err != nil {
return nil, clienttypes.Height{}, fmt.Errorf("failed to encode commitment proof: %w", err)
}
return cp, sc.Height, nil
return cpEnc, sc.Height, nil
}

// ProveHostConsensusState returns an existence proof of the consensus state at `height`
Expand Down
Loading