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

implement solo machine client #6267

Merged
merged 101 commits into from
Aug 24, 2020
Merged

implement solo machine client #6267

merged 101 commits into from
Aug 24, 2020

Conversation

colin-axner
Copy link
Contributor

@colin-axner colin-axner commented May 21, 2020

Description

closes: #5382

old-pr: #6115


Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why.

  • Targeted PR against correct branch (see CONTRIBUTING.md)
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the module structure standards.
  • Wrote unit and integration tests
  • Updated relevant documentation (docs/) or specification (x/<module>/spec/)
  • Added relevant godoc comments.
  • Added a relevant changelog entry to the Unreleased section in CHANGELOG.md
  • Re-reviewed Files changed in the Github PR explorer

@colin-axner colin-axner added x/ibc S:blocked Status: Blocked labels May 21, 2020
@colin-axner colin-axner marked this pull request as ready for review August 21, 2020 14:53
@colin-axner
Copy link
Contributor Author

I think a spec directory should still be added, but I don't think they need to block merge of this pr. I probably won't get to it until after finishing proto migration in 07-tendermint + removing some more amino

// current sequence of the consensus state
uint64 sequence = 1;
// public key of the solo machine
cosmos.base.crypto.v1beta1.PublicKey public_key = 2
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this will likely become Any in the near future, but I didn't want to block this pr on the sdk supporting that functionality

}

// Signature contains the signature and the timestamp of the signature.
message Signature {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

would SignatureAndTimestamp be more clear? Other suggestions?

Copy link
Member

Choose a reason for hiding this comment

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

TimestampedSignature?

if len(sd.Signature) == 0 {
return sdkerrors.Wrap(ErrInvalidSignatureAndData, "signature cannot be empty")
}
if len(sd.Data) == 0 {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

what happens if the solo machine signs over just the sequence @cwgoes ? should I remove this check?

Copy link
Contributor

Choose a reason for hiding this comment

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

At the moment that would be invalid, so this check is fine


// VerifyClientState verifies a proof of the client state of the running chain
// stored on the solo machine.
func (cs ClientState) VerifyClientState(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cwgoes @AdityaSripal please verify this is correct, it hasn't been updated in the ICS spec yet

Copy link
Contributor

Choose a reason for hiding this comment

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

At first glance this seems fine. I'll update the spec.

consensusState := &ConsensusState{
// increment sequence number
Sequence: clientState.ConsensusState.Sequence + 1,
PublicKey: header.NewPublicKey,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Timestamp is missing here. Do I need to add timestamp to the header? This is missing on the ICS spec as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it'd make sense to address this in a followup. Would prefer to have this pr merged so all future changes are easier to review and so merge conflicts don't stack up

Copy link
Contributor

Choose a reason for hiding this comment

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

It won't really be up to date since a header update is only used to change the public key

Copy link
Member

@AdityaSripal AdityaSripal left a comment

Choose a reason for hiding this comment

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

Nice work!! One main issue regarding VerifyClientConsensusState

}

// Signature contains the signature and the timestamp of the signature.
message Signature {
Copy link
Member

Choose a reason for hiding this comment

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

TimestampedSignature?

message MsgCreateClient {
option (gogoproto.goproto_getters) = false;
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
string chain_id = 2 [(gogoproto.moretags) = "yaml:\"chain_id\""];
Copy link
Member

Choose a reason for hiding this comment

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

Why would a solo-machine have a chain-id?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#6267 (comment)

I'm not too convinced of its usefulness which is why I have left off any validation of it (it can be blank)

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, my response was just because it seemed we needed to have that function, I don't think it needs to be in the message - where is that function used anyways? There shouldn't need to be client-external reference to a chain ID

@@ -169,14 +176,16 @@ type ClientType byte

// available client types
const (
Tendermint ClientType = iota + 1 // 1
Localhost
SoloMachine ClientType = 6
Copy link
Member

Choose a reason for hiding this comment

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

I like this change 👍

func NewClientState(chainID string, consensusState *ConsensusState) *ClientState {
return &ClientState{
ChainId: chainID,
FrozenHeight: 0,
Copy link
Member

Choose a reason for hiding this comment

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

Easier to understand if this is FrozenSequence

}
}

// GetChainID returns an empty string.
Copy link
Member

Choose a reason for hiding this comment

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

doc says it should return empty string and I agree. ClientState shouldn't have ChainID and this should return ""

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed (also see above). Sorry for my confusing comment before. Why do we have this interface function in the first place?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems there is partial consensus on removing ChainID. cc/ @fedekunze

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good question. I don't think it is being used outside of tendermint (but it can remain a tm client state specific func). I think we can just remove it in another pr

Copy link
Contributor Author

Choose a reason for hiding this comment

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

opened #7143

return err
}

data, err := ConsensusStateSignBytes(cdc, sequence, signature.Timestamp, path, cs.ConsensusState)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
data, err := ConsensusStateSignBytes(cdc, sequence, signature.Timestamp, path, cs.ConsensusState)
data, err := ConsensusStateSignBytes(cdc, sequence, signature.Timestamp, path, consState)

)
}

if cs.ConsensusState.GetTimestamp() > signature.Timestamp {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if cs.ConsensusState.GetTimestamp() > signature.Timestamp {
if cs.ConsensusState.GetTimestamp() >= signature.Timestamp {

Copy link
Contributor Author

@colin-axner colin-axner Aug 24, 2020

Choose a reason for hiding this comment

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

this is currently correct based on ICS spec

abortTransactionUnless(proof.timestamp >= clientState.consensusState.timestamp)

cc/ @cwgoes

Copy link
Contributor

Choose a reason for hiding this comment

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

The timestamp needs to be non-decreasing; it does not need to be increasing technically (though usually it will be)


// sets the client state to the store
func setClientState(store sdk.KVStore, cdc codec.BinaryMarshaler, clientState clientexported.ClientState) {
bz, err := codec.MarshalAny(cdc, clientState)
Copy link
Member

Choose a reason for hiding this comment

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

nit: You can use clienttypes.MustMarshalClientState

pubKey := clientState.ConsensusState.GetPubKey()

// assert that provided signature data are different
if bytes.Equal(evidence.SignatureOne.Data, evidence.SignatureTwo.Data) {
Copy link
Member

Choose a reason for hiding this comment

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

Hasn't this check happened in ValidateBasic?

// EvidenceSignBytes returns the sign bytes for verification of misbehaviour.
//
// Format: {sequence}{data}
func EvidenceSignBytes(sequence uint64, data []byte) []byte {
Copy link
Member

Choose a reason for hiding this comment

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

nit: This function can be renamed to be more general

Copy link
Contributor Author

Choose a reason for hiding this comment

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

agreed. But I'm not sure what a good replacement would be. I guess I could do SignBytes? but that feels a little too vague. Going to leave for now since it is only used by evidence

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

Mostly LGTM; see comments. Agreed that most can be addressed in a follow-up.

message MsgCreateClient {
option (gogoproto.goproto_getters) = false;
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
string chain_id = 2 [(gogoproto.moretags) = "yaml:\"chain_id\""];
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, my response was just because it seemed we needed to have that function, I don't think it needs to be in the message - where is that function used anyways? There shouldn't need to be client-external reference to a chain ID

}
}

// GetChainID returns an empty string.
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed (also see above). Sorry for my confusing comment before. Why do we have this interface function in the first place?

}

// Validate performs basic validation of the client state fields.
func (cs ClientState) Validate() error {
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed, see above comments.


// VerifyClientState verifies a proof of the client state of the running chain
// stored on the solo machine.
func (cs ClientState) VerifyClientState(
Copy link
Contributor

Choose a reason for hiding this comment

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

At first glance this seems fine. I'll update the spec.

return nil
}

// VerifyClientConsensusState verifies a proof of the consensus state of the
Copy link
Contributor

Choose a reason for hiding this comment

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

Aye. This is true of all of the verifyXYZ functions; they all verify some state stored by the solo machine.

if len(sd.Signature) == 0 {
return sdkerrors.Wrap(ErrInvalidSignatureAndData, "signature cannot be empty")
}
if len(sd.Data) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

At the moment that would be invalid, so this check is fine

@@ -0,0 +1,217 @@
package types
Copy link
Contributor

Choose a reason for hiding this comment

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

I should have thought about this earlier, but I wonder if we should make these all proto structs instead of this kinda-arbitrary bytestring concatenation encoding? cc @warner any thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

This can be deferred to a follow-up, though, since this file is nicely abstracted (thanks)

consensusState := &ConsensusState{
// increment sequence number
Sequence: clientState.ConsensusState.Sequence + 1,
PublicKey: header.NewPublicKey,
Copy link
Contributor

Choose a reason for hiding this comment

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

It won't really be up to date since a header update is only used to change the public key

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

ACK modulo follow-ups

@colin-axner colin-axner added the A:automerge Automatically merge PR once all prerequisites pass. label Aug 24, 2020
@mergify mergify bot merged commit 46927c3 into master Aug 24, 2020
@mergify mergify bot deleted the colin/5382-solo-machine-client branch August 24, 2020 10:06
@fedekunze
Copy link
Collaborator

Finally! this is awesome 🙌 So excited

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A:automerge Automatically merge PR once all prerequisites pass.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ICS 06: Solo machine client
5 participants