Skip to content

Commit 422e7b3

Browse files
authored
fix(lib/grandpa): Duplicate votes is GRANDPA are counted as equivocatory votes (GSR-11) (#2624)
1 parent 2bb2609 commit 422e7b3

File tree

3 files changed

+217
-57
lines changed

3 files changed

+217
-57
lines changed

lib/grandpa/errors.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,5 +99,4 @@ var (
9999
errVoteToSignatureMismatch = errors.New("votes and authority count mismatch")
100100
errVoteBlockMismatch = errors.New("block in vote is not descendant of previously finalised block")
101101
errVoteFromSelf = errors.New("got vote from ourselves")
102-
errInvalidMultiplicity = errors.New("more than two equivocatory votes for a voter")
103102
)

lib/grandpa/message_handler.go

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -284,22 +284,20 @@ func (h *MessageHandler) verifyCatchUpResponseCompletability(prevote, precommit
284284
return nil
285285
}
286286

287-
func getEquivocatoryVoters(votes []AuthData) (map[ed25519.PublicKeyBytes]struct{}, error) {
287+
func getEquivocatoryVoters(votes []AuthData) map[ed25519.PublicKeyBytes]struct{} {
288288
eqvVoters := make(map[ed25519.PublicKeyBytes]struct{})
289-
voters := make(map[ed25519.PublicKeyBytes]int, len(votes))
289+
voters := make(map[ed25519.PublicKeyBytes][64]byte, len(votes))
290290

291291
for _, v := range votes {
292-
voters[v.AuthorityID]++
293-
switch voters[v.AuthorityID] {
294-
case 1:
295-
case 2:
292+
signature, present := voters[v.AuthorityID]
293+
if present && !bytes.Equal(signature[:], v.Signature[:]) {
296294
eqvVoters[v.AuthorityID] = struct{}{}
297-
default:
298-
return nil, fmt.Errorf("%w: authority id %x has %d votes",
299-
errInvalidMultiplicity, v.AuthorityID, voters[v.AuthorityID])
295+
} else {
296+
voters[v.AuthorityID] = v.Signature
300297
}
301298
}
302-
return eqvVoters, nil
299+
300+
return eqvVoters
303301
}
304302

305303
func isDescendantOfHighestFinalisedBlock(blockState BlockState, hash common.Hash) (bool, error) {
@@ -329,10 +327,7 @@ func (h *MessageHandler) verifyCommitMessageJustification(fm *CommitMessage) err
329327
return errVoteBlockMismatch
330328
}
331329

332-
eqvVoters, err := getEquivocatoryVoters(fm.AuthData)
333-
if err != nil {
334-
return fmt.Errorf("could not get valid equivocatory voters: %w", err)
335-
}
330+
eqvVoters := getEquivocatoryVoters(fm.AuthData)
336331

337332
var count int
338333
for i, pc := range fm.Precommits {
@@ -465,10 +460,7 @@ func (h *MessageHandler) verifyPreCommitJustification(msg *CatchUpResponse) erro
465460
return errVoteBlockMismatch
466461
}
467462

468-
eqvVoters, err := getEquivocatoryVoters(auths)
469-
if err != nil {
470-
return fmt.Errorf("could not get valid equivocatory voters: %w", err)
471-
}
463+
eqvVoters := getEquivocatoryVoters(auths)
472464

473465
// verify pre-commit justification
474466
var count uint64
@@ -608,10 +600,7 @@ func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byt
608600
authPubKeys[i] = AuthData{AuthorityID: pcj.AuthorityID}
609601
}
610602

611-
equivocatoryVoters, err := getEquivocatoryVoters(authPubKeys)
612-
if err != nil {
613-
return nil, fmt.Errorf("could not get valid equivocatory voters: %w", err)
614-
}
603+
equivocatoryVoters := getEquivocatoryVoters(authPubKeys)
615604

616605
var count int
617606

lib/grandpa/message_handler_test.go

Lines changed: 206 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -807,44 +807,216 @@ func TestMessageHandler_VerifyBlockJustification_invalid(t *testing.T) {
807807
}
808808

809809
func Test_getEquivocatoryVoters(t *testing.T) {
810-
// many of equivocatory votes
810+
t.Parallel()
811+
811812
ed25519Keyring, err := keystore.NewEd25519Keyring()
812813
require.NoError(t, err)
813-
fakeAuthorities := []*ed25519.Keypair{
814-
ed25519Keyring.Alice().(*ed25519.Keypair),
815-
ed25519Keyring.Alice().(*ed25519.Keypair),
816-
ed25519Keyring.Bob().(*ed25519.Keypair),
817-
ed25519Keyring.Charlie().(*ed25519.Keypair),
818-
ed25519Keyring.Charlie().(*ed25519.Keypair),
819-
ed25519Keyring.Dave().(*ed25519.Keypair),
820-
ed25519Keyring.Dave().(*ed25519.Keypair),
821-
ed25519Keyring.Eve().(*ed25519.Keypair),
822-
ed25519Keyring.Ferdie().(*ed25519.Keypair),
823-
ed25519Keyring.Heather().(*ed25519.Keypair),
824-
ed25519Keyring.Heather().(*ed25519.Keypair),
825-
ed25519Keyring.Ian().(*ed25519.Keypair),
826-
ed25519Keyring.Ian().(*ed25519.Keypair),
814+
tests := map[string]struct {
815+
votes []AuthData
816+
want map[ed25519.PublicKeyBytes]struct{}
817+
}{
818+
"no votes": {
819+
votes: []AuthData{},
820+
want: map[ed25519.PublicKeyBytes]struct{}{},
821+
},
822+
"one vote": {
823+
votes: []AuthData{
824+
{
825+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
826+
Signature: [64]byte{1, 2, 3, 4},
827+
},
828+
},
829+
want: map[ed25519.PublicKeyBytes]struct{}{},
830+
},
831+
"two votes different authorities": {
832+
votes: []AuthData{
833+
{
834+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
835+
Signature: [64]byte{1, 2, 3, 4},
836+
},
837+
{
838+
AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(),
839+
Signature: [64]byte{1, 2, 3, 4},
840+
},
841+
},
842+
want: map[ed25519.PublicKeyBytes]struct{}{},
843+
},
844+
"duplicate votes": {
845+
votes: []AuthData{
846+
{
847+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
848+
Signature: [64]byte{1, 2, 3, 4},
849+
},
850+
{
851+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
852+
Signature: [64]byte{1, 2, 3, 4},
853+
},
854+
},
855+
want: map[ed25519.PublicKeyBytes]struct{}{},
856+
},
857+
"equivocatory vote": {
858+
votes: []AuthData{
859+
{
860+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
861+
Signature: [64]byte{1, 2, 3, 4},
862+
},
863+
{
864+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
865+
Signature: [64]byte{5, 6, 7, 8},
866+
},
867+
},
868+
want: map[ed25519.PublicKeyBytes]struct{}{
869+
ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(): {},
870+
},
871+
},
872+
"equivocatory vote with duplicate": {
873+
votes: []AuthData{
874+
{
875+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
876+
Signature: [64]byte{1, 2, 3, 4},
877+
},
878+
{
879+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
880+
Signature: [64]byte{5, 6, 7, 8},
881+
},
882+
{
883+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
884+
Signature: [64]byte{1, 2, 3, 4},
885+
},
886+
},
887+
want: map[ed25519.PublicKeyBytes]struct{}{
888+
ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(): {},
889+
},
890+
},
891+
"three voters one equivocatory": {
892+
votes: []AuthData{
893+
{
894+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
895+
Signature: [64]byte{1, 2, 3, 4},
896+
},
897+
{
898+
AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(),
899+
Signature: [64]byte{1, 2, 3, 4},
900+
},
901+
{
902+
AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(),
903+
Signature: [64]byte{5, 6, 7, 8},
904+
},
905+
{
906+
AuthorityID: ed25519Keyring.Charlie().Public().(*ed25519.PublicKey).AsBytes(),
907+
Signature: [64]byte{5, 6, 7, 8},
908+
},
909+
},
910+
want: map[ed25519.PublicKeyBytes]struct{}{
911+
ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(): {},
912+
},
913+
},
914+
"three voters one equivocatory one duplicate": {
915+
votes: []AuthData{
916+
{
917+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
918+
Signature: [64]byte{1, 2, 3, 4},
919+
},
920+
{
921+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
922+
Signature: [64]byte{5, 6, 7, 8},
923+
},
924+
{
925+
AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(),
926+
Signature: [64]byte{5, 6, 7, 8},
927+
},
928+
{
929+
AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(),
930+
Signature: [64]byte{5, 6, 7, 8},
931+
},
932+
{
933+
AuthorityID: ed25519Keyring.Charlie().Public().(*ed25519.PublicKey).AsBytes(),
934+
Signature: [64]byte{5, 6, 7, 8},
935+
},
936+
},
937+
want: map[ed25519.PublicKeyBytes]struct{}{
938+
ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(): {},
939+
},
940+
},
941+
"three voters two equivocatory": {
942+
votes: []AuthData{
943+
{
944+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
945+
Signature: [64]byte{1, 2, 3, 4},
946+
},
947+
{
948+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
949+
Signature: [64]byte{5, 6, 7, 8},
950+
},
951+
{
952+
AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(),
953+
Signature: [64]byte{1, 2, 3, 4},
954+
},
955+
{
956+
AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(),
957+
Signature: [64]byte{5, 6, 7, 8},
958+
},
959+
{
960+
AuthorityID: ed25519Keyring.Charlie().Public().(*ed25519.PublicKey).AsBytes(),
961+
Signature: [64]byte{5, 6, 7, 8},
962+
},
963+
},
964+
want: map[ed25519.PublicKeyBytes]struct{}{
965+
ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(): {},
966+
ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(): {},
967+
},
968+
},
969+
"three voters two duplicate": {
970+
votes: []AuthData{
971+
{
972+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
973+
Signature: [64]byte{1, 2, 3, 4},
974+
},
975+
{
976+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
977+
Signature: [64]byte{1, 2, 3, 4},
978+
},
979+
{
980+
AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(),
981+
Signature: [64]byte{1, 2, 3, 4},
982+
},
983+
{
984+
AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(),
985+
Signature: [64]byte{1, 2, 3, 4},
986+
},
987+
{
988+
AuthorityID: ed25519Keyring.Charlie().Public().(*ed25519.PublicKey).AsBytes(),
989+
Signature: [64]byte{5, 6, 7, 8},
990+
},
991+
},
992+
want: map[ed25519.PublicKeyBytes]struct{}{},
993+
},
994+
"three voters": {
995+
votes: []AuthData{
996+
{
997+
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
998+
Signature: [64]byte{1, 2, 3, 4},
999+
},
1000+
{
1001+
AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(),
1002+
Signature: [64]byte{1, 2, 3, 4},
1003+
},
1004+
{
1005+
AuthorityID: ed25519Keyring.Charlie().Public().(*ed25519.PublicKey).AsBytes(),
1006+
Signature: [64]byte{5, 6, 7, 8},
1007+
},
1008+
},
1009+
want: map[ed25519.PublicKeyBytes]struct{}{},
1010+
},
8271011
}
828-
829-
authData := make([]AuthData, len(fakeAuthorities))
830-
831-
for i, auth := range fakeAuthorities {
832-
authData[i] = AuthData{
833-
AuthorityID: auth.Public().(*ed25519.PublicKey).AsBytes(),
834-
}
1012+
for name, tt := range tests {
1013+
tt := tt
1014+
t.Run(name, func(t *testing.T) {
1015+
t.Parallel()
1016+
got := getEquivocatoryVoters(tt.votes)
1017+
assert.Equalf(t, tt.want, got, "getEquivocatoryVoters(%v)", tt.votes)
1018+
})
8351019
}
836-
837-
eqv, err := getEquivocatoryVoters(authData)
838-
require.NoError(t, err)
839-
require.Len(t, eqv, 5)
840-
841-
// test that getEquivocatoryVoters returns an error if a voter has more than two equivocatory votes
842-
authData = append(authData, AuthData{
843-
AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(),
844-
})
845-
846-
_, err = getEquivocatoryVoters(authData)
847-
require.ErrorIs(t, err, errInvalidMultiplicity)
8481020
}
8491021

8501022
func Test_VerifyCommitMessageJustification_ShouldRemoveEquivocatoryVotes(t *testing.T) {

0 commit comments

Comments
 (0)