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

lib/grandpa: verify block justification when handling FinalizationMessage #1084

Merged
merged 12 commits into from
Aug 18, 2020

Conversation

edwardmack
Copy link
Member

Changes

  • added function verifyJustification which check given FinalizationMessage and confirms:

    • Verifies signature is valid for singed FullVote.
    • Authority was in the set indicated by setID
    • The total number of signatures is >= 2/3 the number of voters is the list.

Tests

go test ./lib/grandpa/...

Checklist

  • I have read CODE_OF_CONDUCT and CONTRIBUTING
  • I have provided as much information as possible and necessary
  • I have reviewed my own pull request before requesting a review
  • All integration tests and required coverage checks are passing

Issues

@@ -72,5 +72,8 @@ var ErrNotFinalizationMessage = errors.New("cannot get finalized hash from VoteM
// ErrNoJustification is returned when no justification can be found for a block, ie. it has not been finalized
var ErrNoJustification = errors.New("no justification found for block")

// ErrMinVotesNotMet is returned when the number of votes is less than the required minimum
Copy link
Contributor

Choose a reason for hiding this comment

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

could you add in a Justification?

}

// confirm total # signatures >= 2/3 of number of voters
if !(sigCount >= (2/3)*len(h.grandpa.state.voters)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

you could use h.grandpa.state.threshold() instead of (2/3)*len(h.grandpa.state.voters)

Copy link
Member Author

Choose a reason for hiding this comment

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

good idea, this also fixes the issue you pointed out with the test.

@@ -177,6 +177,57 @@ func TestMessageHandler_FinalizationMessage_NoCatchUpRequest(t *testing.T) {
cm, err := fm.ToConsensusMessage()
require.NoError(t, err)

h := NewMessageHandler(gs, st.Block)
out, err := h.HandleMessage(cm)
require.EqualError(t, err, "signature is not valid")
Copy link
Contributor

Choose a reason for hiding this comment

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

change to require.Equal(t, err, ErrInvalidSignature)?


func TestMessageHandler_FinalizationMessage_NoCatchUpRequest_ValidSig(t *testing.T) {
st := newTestState(t)
voters := newTestVoters(t)
Copy link
Contributor

Choose a reason for hiding this comment

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

hm, something in this test seems off, newTestVoters should return 9 votes, so a finalization message with only 1 signature shouldn't meet the threshold, maybe I am missing something?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, I fixed verify so this test fails, going to add tests...

Copy link
Contributor

@noot noot left a comment

Choose a reason for hiding this comment

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

overall looking good!! could you add a unit test for only the verifyJustification method?

Comment on lines 106 to 141
// verify signature
msg, err := scale.Encode(&FullVote{
Stage: precommit,
Vote: NewVote(j.Vote.hash, j.Vote.number),
Round: fm.Round,
SetID: h.grandpa.state.setID,
})
if err != nil {
return err
}

pk, err := ed25519.NewPublicKey(j.AuthorityID[:])
if err != nil {
return err
}

ok, err := pk.Verify(msg, j.Signature[:])
if err != nil {
return err
}

if !ok {
return ErrInvalidSignature
}

// verify authority in justification set
authFound := false
for _, auth := range h.grandpa.Authorities() {
if reflect.DeepEqual(auth.Key.AsBytes(), j.AuthorityID) {
authFound = true
break
}
}
if !authFound {
return ErrVoterNotFound
}
Copy link
Contributor

Choose a reason for hiding this comment

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

it might also be nice to break this into a separate function that accepts *Justification, stage, vote, round, and setID, since it'll be used for catch up response handling as well

Copy link
Member Author

Choose a reason for hiding this comment

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

All set.

Copy link
Contributor

@noot noot left a comment

Choose a reason for hiding this comment

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

great work!

@edwardmack edwardmack merged commit 5dbc019 into development Aug 18, 2020
@edwardmack edwardmack deleted the ed/verify_block_justification branch August 18, 2020 00:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

verify block justification when handling FinalizationMessage
2 participants