Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: 06-solomachine rename update to UpdateState #1110

Merged
merged 14 commits into from
Mar 16, 2022
Merged
Show file tree
Hide file tree
Changes from 6 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
6 changes: 6 additions & 0 deletions modules/light-clients/06-solomachine/types/misbehaviour.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ func (misbehaviour Misbehaviour) Type() string {
return exported.TypeClientMisbehaviour
}

// TODO: Remove GetHeight() when new interface type ClientMessage is introduced
// GetHeight implements the exported.Header interface
func (misbehaviour Misbehaviour) GetHeight() exported.Height {
return nil
}

// ValidateBasic implements Misbehaviour interface.
func (misbehaviour Misbehaviour) ValidateBasic() error {
if err := host.ClientIdentifierValidator(misbehaviour.ClientId); err != nil {
Expand Down
116 changes: 64 additions & 52 deletions modules/light-clients/06-solomachine/types/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,74 +17,86 @@ import (
// - the currently registered public key did not provide the update signature
func (cs ClientState) CheckHeaderAndUpdateState(
ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore,
header exported.Header,
msg exported.Header, // TODO: Update to exported.ClientMessage
) (exported.ClientState, exported.ConsensusState, error) {
smHeader, ok := header.(*Header)
if !ok {
return nil, nil, sdkerrors.Wrapf(
clienttypes.ErrInvalidHeader, "header type %T, expected %T", header, &Header{},
)
}

if err := checkHeader(cdc, &cs, smHeader); err != nil {
if err := cs.VerifyClientMessage(cdc, msg); err != nil {
return nil, nil, err
}

clientState, consensusState := update(&cs, smHeader)
return clientState, consensusState, nil
return cs.UpdateState(ctx, cdc, clientStore, msg)
}

// checkHeader checks if the Solo Machine update signature is valid.
func checkHeader(cdc codec.BinaryCodec, clientState *ClientState, header *Header) error {
// assert update sequence is current sequence
if header.Sequence != clientState.Sequence {
return sdkerrors.Wrapf(
clienttypes.ErrInvalidHeader,
"header sequence does not match the client state sequence (%d != %d)", header.Sequence, clientState.Sequence,
)
}
// VerifyClientMessage checks if the Solo Machine update signature(s) is valid.
Copy link
Contributor

Choose a reason for hiding this comment

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

godoc should be updated

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure! Any suggestions? What about something like:

// VerifyClientMessage introspects the provided ClientMessage and checks its validity
// A Solomachine Header is considered valid if the currently registered public key has signed over the new public key with the correct sequence
// A Solomachine Misbehaviour is considered valid if duplicate signatures of the current public key are found on two different messages at a given sequence

func (cs ClientState) VerifyClientMessage(cdc codec.BinaryCodec, clientMsg exported.Header) error {
switch msg := clientMsg.(type) {
case *Header:
// assert update sequence is current sequence
if msg.Sequence != cs.Sequence {
return sdkerrors.Wrapf(
clienttypes.ErrInvalidHeader,
"header sequence does not match the client state sequence (%d != %d)", msg.Sequence, cs.Sequence,
)
}

// assert update timestamp is not less than current consensus state timestamp
if header.Timestamp < clientState.ConsensusState.Timestamp {
return sdkerrors.Wrapf(
clienttypes.ErrInvalidHeader,
"header timestamp is less than to the consensus state timestamp (%d < %d)", header.Timestamp, clientState.ConsensusState.Timestamp,
)
}
// assert update timestamp is not less than current consensus state timestamp
if msg.Timestamp < cs.ConsensusState.Timestamp {
return sdkerrors.Wrapf(
clienttypes.ErrInvalidHeader,
"header timestamp is less than to the consensus state timestamp (%d < %d)", msg.Timestamp, cs.ConsensusState.Timestamp,
)
}

// assert currently registered public key signed over the new public key with correct sequence
data, err := HeaderSignBytes(cdc, header)
if err != nil {
return err
}
// assert currently registered public key signed over the new public key with correct sequence
data, err := HeaderSignBytes(cdc, msg)
if err != nil {
return err
}

sigData, err := UnmarshalSignatureData(cdc, header.Signature)
if err != nil {
return err
}
sigData, err := UnmarshalSignatureData(cdc, msg.Signature)
if err != nil {
return err
}

publicKey, err := clientState.ConsensusState.GetPubKey()
if err != nil {
return err
}
publicKey, err := cs.ConsensusState.GetPubKey()
if err != nil {
return err
}

if err := VerifySignature(publicKey, data, sigData); err != nil {
return sdkerrors.Wrap(ErrInvalidHeader, err.Error())
}
if err := VerifySignature(publicKey, data, sigData); err != nil {
return sdkerrors.Wrap(ErrInvalidHeader, err.Error())
}
case *Misbehaviour:
// NOTE: a check that the misbehaviour message data are not equal is done by
// misbehaviour.ValidateBasic which is called by the 02-client keeper.
// verify first signature
if err := verifySignatureAndData(cdc, cs, msg, msg.SignatureOne); err != nil {
return sdkerrors.Wrap(err, "failed to verify signature one")
}

// verify second signature
if err := verifySignatureAndData(cdc, cs, msg, msg.SignatureTwo); err != nil {
return sdkerrors.Wrap(err, "failed to verify signature two")
}

default:
return sdkerrors.Wrapf(clienttypes.ErrInvalidClientType, "expected type of %T or %T, got type %T", Header{}, Misbehaviour{}, msg)
}
return nil
}

// update the consensus state to the new public key and an incremented sequence
func update(clientState *ClientState, header *Header) (*ClientState, *ConsensusState) {
// UpdateState updates the consensus state to the new public key and an incremented sequence.
func (cs ClientState) UpdateState(
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore,
header exported.Header,
) (exported.ClientState, exported.ConsensusState, error) {
smHeader := header.(*Header)
consensusState := &ConsensusState{
PublicKey: header.NewPublicKey,
Diversifier: header.NewDiversifier,
Timestamp: header.Timestamp,
PublicKey: smHeader.NewPublicKey,
Diversifier: smHeader.NewDiversifier,
Timestamp: smHeader.Timestamp,
}

// increment sequence number
clientState.Sequence++
clientState.ConsensusState = consensusState
return clientState, consensusState
cs.Sequence++
cs.ConsensusState = consensusState
return &cs, consensusState, nil
}
Loading