From 40d13f47c0fac6f8d084623ea457d20011f7b870 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Tue, 28 Jun 2022 16:49:32 -0400 Subject: [PATCH 1/4] implement fix for duplicate votes is GRANDPA --- lib/grandpa/errors.go | 1 - lib/grandpa/message_handler.go | 81 ++++------ lib/grandpa/message_handler_test.go | 240 ++++++++++++++++++++++++---- 3 files changed, 241 insertions(+), 81 deletions(-) diff --git a/lib/grandpa/errors.go b/lib/grandpa/errors.go index 1908f785cf..9b2ce98b72 100644 --- a/lib/grandpa/errors.go +++ b/lib/grandpa/errors.go @@ -98,5 +98,4 @@ var ( errVoteToSignatureMismatch = errors.New("votes and authority count mismatch") errVoteBlockMismatch = errors.New("block in vote is not descendant of previously finalised block") errVoteFromSelf = errors.New("got vote from ourselves") - errInvalidMultiplicity = errors.New("more than two equivocatory votes for a voter") ) diff --git a/lib/grandpa/message_handler.go b/lib/grandpa/message_handler.go index 766ca26b29..5fa6a0a87f 100644 --- a/lib/grandpa/message_handler.go +++ b/lib/grandpa/message_handler.go @@ -284,22 +284,21 @@ func (h *MessageHandler) verifyCatchUpResponseCompletability(prevote, precommit return nil } -func getEquivocatoryVoters(votes []AuthData) (map[ed25519.PublicKeyBytes]struct{}, error) { +func getEquivocatoryVoters(votes []AuthData) map[ed25519.PublicKeyBytes]struct{} { eqvVoters := make(map[ed25519.PublicKeyBytes]struct{}) - voters := make(map[ed25519.PublicKeyBytes]int, len(votes)) + voters := make(map[ed25519.PublicKeyBytes][64]byte, len(votes)) for _, v := range votes { - voters[v.AuthorityID]++ - switch voters[v.AuthorityID] { - case 1: - case 2: - eqvVoters[v.AuthorityID] = struct{}{} - default: - return nil, fmt.Errorf("%w: authority id %x has %d votes", - errInvalidMultiplicity, v.AuthorityID, voters[v.AuthorityID]) + signature, present := voters[v.AuthorityID] + if present { + if !bytes.Equal(signature[:], v.Signature[:]) { + eqvVoters[v.AuthorityID] = struct{}{} + } + } else { + voters[v.AuthorityID] = v.Signature } } - return eqvVoters, nil + return eqvVoters } func isDescendantOfHighestFinalisedBlock(blockState BlockState, hash common.Hash) (bool, error) { @@ -329,10 +328,7 @@ func (h *MessageHandler) verifyCommitMessageJustification(fm *CommitMessage) err return errVoteBlockMismatch } - eqvVoters, err := getEquivocatoryVoters(fm.AuthData) - if err != nil { - return fmt.Errorf("could not get valid equivocatory voters: %w", err) - } + eqvVoters := getEquivocatoryVoters(fm.AuthData) var count int for i, pc := range fm.Precommits { @@ -465,10 +461,7 @@ func (h *MessageHandler) verifyPreCommitJustification(msg *CatchUpResponse) erro return errVoteBlockMismatch } - eqvVoters, err := getEquivocatoryVoters(auths) - if err != nil { - return fmt.Errorf("could not get valid equivocatory voters: %w", err) - } + eqvVoters := getEquivocatoryVoters(auths) // verify pre-commit justification var count uint64 @@ -553,41 +546,40 @@ func (h *MessageHandler) verifyJustification(just *SignedVote, round, setID uint return nil } -// VerifyBlockJustification verifies the finality justification for a block, returns scale encoded justification with -// any extra bytes removed. -func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byte) ([]byte, error) { +// VerifyBlockJustification verifies the finality justification for a block +func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byte) error { fj := Justification{} err := scale.Unmarshal(justification, &fj) if err != nil { - return nil, err + return err } setID, err := s.grandpaState.GetSetIDByBlockNumber(uint(fj.Commit.Number)) if err != nil { - return nil, fmt.Errorf("cannot get set ID from block number: %w", err) + return fmt.Errorf("cannot get set ID from block number: %w", err) } has, err := s.blockState.HasFinalisedBlock(fj.Round, setID) if err != nil { - return nil, err + return err } if has { - return nil, fmt.Errorf("already have finalised block with setID=%d and round=%d", setID, fj.Round) + return fmt.Errorf("already have finalised block with setID=%d and round=%d", setID, fj.Round) } isDescendant, err := isDescendantOfHighestFinalisedBlock(s.blockState, fj.Commit.Hash) if err != nil { - return nil, err + return err } if !isDescendant { - return nil, errVoteBlockMismatch + return errVoteBlockMismatch } auths, err := s.grandpaState.GetAuthorities(setID) if err != nil { - return nil, fmt.Errorf("cannot get authorities for set ID: %w", err) + return fmt.Errorf("cannot get authorities for set ID: %w", err) } // threshold is two-thirds the number of authorities, @@ -595,7 +587,7 @@ func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byt threshold := (2 * len(auths) / 3) if len(fj.Commit.Precommits) < threshold { - return nil, ErrMinVotesNotMet + return ErrMinVotesNotMet } authPubKeys := make([]AuthData, len(fj.Commit.Precommits)) @@ -603,10 +595,7 @@ func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byt authPubKeys[i] = AuthData{AuthorityID: pcj.AuthorityID} } - equivocatoryVoters, err := getEquivocatoryVoters(authPubKeys) - if err != nil { - return nil, fmt.Errorf("could not get valid equivocatory voters: %w", err) - } + equivocatoryVoters := getEquivocatoryVoters(authPubKeys) var count int @@ -618,20 +607,20 @@ func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byt // check if vote was for descendant of committed block isDescendant, err := s.blockState.IsDescendantOf(hash, just.Vote.Hash) if err != nil { - return nil, err + return err } if !isDescendant { - return nil, ErrPrecommitBlockMismatch + return ErrPrecommitBlockMismatch } pk, err := ed25519.NewPublicKey(just.AuthorityID[:]) if err != nil { - return nil, err + return err } if !isInAuthSet(pk, auths) { - return nil, ErrAuthorityNotInSet + return ErrAuthorityNotInSet } // verify signature for each precommit @@ -642,16 +631,16 @@ func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byt SetID: setID, }) if err != nil { - return nil, err + return err } ok, err := pk.Verify(msg, just.Signature[:]) if err != nil { - return nil, err + return err } if !ok { - return nil, ErrInvalidSignature + return ErrInvalidSignature } if _, ok := equivocatoryVoters[just.AuthorityID]; ok { @@ -662,30 +651,30 @@ func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byt } if count+len(equivocatoryVoters) < threshold { - return nil, ErrMinVotesNotMet + return ErrMinVotesNotMet } err = verifyBlockHashAgainstBlockNumber(s.blockState, fj.Commit.Hash, uint(fj.Commit.Number)) if err != nil { - return nil, err + return err } for _, preCommit := range fj.Commit.Precommits { err := verifyBlockHashAgainstBlockNumber(s.blockState, preCommit.Vote.Hash, uint(preCommit.Vote.Number)) if err != nil { - return nil, err + return err } } err = s.blockState.SetFinalisedHash(hash, fj.Round, setID) if err != nil { - return nil, err + return err } logger.Debugf( "set finalised block with hash %s, round %d and set id %d", hash, fj.Round, setID) - return scale.Marshal(fj) + return nil } func verifyBlockHashAgainstBlockNumber(bs BlockState, hash common.Hash, number uint) error { diff --git a/lib/grandpa/message_handler_test.go b/lib/grandpa/message_handler_test.go index 2f43675ed0..73ebe16bee 100644 --- a/lib/grandpa/message_handler_test.go +++ b/lib/grandpa/message_handler_test.go @@ -792,44 +792,216 @@ func TestMessageHandler_VerifyBlockJustification_invalid(t *testing.T) { } func Test_getEquivocatoryVoters(t *testing.T) { - // many of equivocatory votes + t.Parallel() + ed25519Keyring, err := keystore.NewEd25519Keyring() require.NoError(t, err) - fakeAuthorities := []*ed25519.Keypair{ - ed25519Keyring.Alice().(*ed25519.Keypair), - ed25519Keyring.Alice().(*ed25519.Keypair), - ed25519Keyring.Bob().(*ed25519.Keypair), - ed25519Keyring.Charlie().(*ed25519.Keypair), - ed25519Keyring.Charlie().(*ed25519.Keypair), - ed25519Keyring.Dave().(*ed25519.Keypair), - ed25519Keyring.Dave().(*ed25519.Keypair), - ed25519Keyring.Eve().(*ed25519.Keypair), - ed25519Keyring.Ferdie().(*ed25519.Keypair), - ed25519Keyring.Heather().(*ed25519.Keypair), - ed25519Keyring.Heather().(*ed25519.Keypair), - ed25519Keyring.Ian().(*ed25519.Keypair), - ed25519Keyring.Ian().(*ed25519.Keypair), + tests := map[string]struct { + votes []AuthData + want map[ed25519.PublicKeyBytes]struct{} + }{ + "no votes": { + votes: []AuthData{}, + want: map[ed25519.PublicKeyBytes]struct{}{}, + }, + "one vote": { + votes: []AuthData{ + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + }, + want: map[ed25519.PublicKeyBytes]struct{}{}, + }, + "two votes different authorities": { + votes: []AuthData{ + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + }, + want: map[ed25519.PublicKeyBytes]struct{}{}, + }, + "duplicate votes": { + votes: []AuthData{ + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + }, + want: map[ed25519.PublicKeyBytes]struct{}{}, + }, + "equivocatory vote": { + votes: []AuthData{ + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + }, + want: map[ed25519.PublicKeyBytes]struct{}{ + ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(): {}, + }, + }, + "equivocatory vote with duplicate": { + votes: []AuthData{ + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + }, + want: map[ed25519.PublicKeyBytes]struct{}{ + ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(): {}, + }, + }, + "three voters one equivocatory": { + votes: []AuthData{ + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + { + AuthorityID: ed25519Keyring.Charlie().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + }, + want: map[ed25519.PublicKeyBytes]struct{}{ + ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(): {}, + }, + }, + "three voters one equivocatory one duplicate": { + votes: []AuthData{ + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + { + AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + { + AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + { + AuthorityID: ed25519Keyring.Charlie().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + }, + want: map[ed25519.PublicKeyBytes]struct{}{ + ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(): {}, + }, + }, + "three voters two equivocatory": { + votes: []AuthData{ + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + { + AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + { + AuthorityID: ed25519Keyring.Charlie().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + }, + want: map[ed25519.PublicKeyBytes]struct{}{ + ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(): {}, + ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(): {}, + }, + }, + "three voters two duplicate": { + votes: []AuthData{ + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Charlie().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + }, + want: map[ed25519.PublicKeyBytes]struct{}{}, + }, + "three voters": { + votes: []AuthData{ + { + AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Bob().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{1, 2, 3, 4}, + }, + { + AuthorityID: ed25519Keyring.Charlie().Public().(*ed25519.PublicKey).AsBytes(), + Signature: [64]byte{5, 6, 7, 8}, + }, + }, + want: map[ed25519.PublicKeyBytes]struct{}{}, + }, } - - authData := make([]AuthData, len(fakeAuthorities)) - - for i, auth := range fakeAuthorities { - authData[i] = AuthData{ - AuthorityID: auth.Public().(*ed25519.PublicKey).AsBytes(), - } + for name, tt := range tests { + tt := tt + t.Run(name, func(t *testing.T) { + t.Parallel() + got := getEquivocatoryVoters(tt.votes) + assert.Equalf(t, tt.want, got, "getEquivocatoryVoters(%v)", tt.votes) + }) } - - eqv, err := getEquivocatoryVoters(authData) - require.NoError(t, err) - require.Len(t, eqv, 5) - - // test that getEquivocatoryVoters returns an error if a voter has more than two equivocatory votes - authData = append(authData, AuthData{ - AuthorityID: ed25519Keyring.Alice().Public().(*ed25519.PublicKey).AsBytes(), - }) - - _, err = getEquivocatoryVoters(authData) - require.ErrorIs(t, err, errInvalidMultiplicity) } func Test_VerifyCommitMessageJustification_ShouldRemoveEquivocatoryVotes(t *testing.T) { From e06fdda66a464068fbbf61239716b7385f3df045 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Fri, 1 Jul 2022 15:23:17 -0400 Subject: [PATCH 2/4] fix merge conflicts --- lib/grandpa/message_handler.go | 45 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/lib/grandpa/message_handler.go b/lib/grandpa/message_handler.go index 5fa6a0a87f..3c6b63fa90 100644 --- a/lib/grandpa/message_handler.go +++ b/lib/grandpa/message_handler.go @@ -546,40 +546,41 @@ func (h *MessageHandler) verifyJustification(just *SignedVote, round, setID uint return nil } -// VerifyBlockJustification verifies the finality justification for a block -func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byte) error { +// VerifyBlockJustification verifies the finality justification for a block, returns scale encoded justification with +// any extra bytes removed. +func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byte) ([]byte, error) { fj := Justification{} err := scale.Unmarshal(justification, &fj) if err != nil { - return err + return nil, err } setID, err := s.grandpaState.GetSetIDByBlockNumber(uint(fj.Commit.Number)) if err != nil { - return fmt.Errorf("cannot get set ID from block number: %w", err) + return nil, fmt.Errorf("cannot get set ID from block number: %w", err) } has, err := s.blockState.HasFinalisedBlock(fj.Round, setID) if err != nil { - return err + return nil, err } if has { - return fmt.Errorf("already have finalised block with setID=%d and round=%d", setID, fj.Round) + return nil, fmt.Errorf("already have finalised block with setID=%d and round=%d", setID, fj.Round) } isDescendant, err := isDescendantOfHighestFinalisedBlock(s.blockState, fj.Commit.Hash) if err != nil { - return err + return nil, err } if !isDescendant { - return errVoteBlockMismatch + return nil, errVoteBlockMismatch } auths, err := s.grandpaState.GetAuthorities(setID) if err != nil { - return fmt.Errorf("cannot get authorities for set ID: %w", err) + return nil, fmt.Errorf("cannot get authorities for set ID: %w", err) } // threshold is two-thirds the number of authorities, @@ -587,7 +588,7 @@ func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byt threshold := (2 * len(auths) / 3) if len(fj.Commit.Precommits) < threshold { - return ErrMinVotesNotMet + return nil, ErrMinVotesNotMet } authPubKeys := make([]AuthData, len(fj.Commit.Precommits)) @@ -607,20 +608,20 @@ func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byt // check if vote was for descendant of committed block isDescendant, err := s.blockState.IsDescendantOf(hash, just.Vote.Hash) if err != nil { - return err + return nil, err } if !isDescendant { - return ErrPrecommitBlockMismatch + return nil, ErrPrecommitBlockMismatch } pk, err := ed25519.NewPublicKey(just.AuthorityID[:]) if err != nil { - return err + return nil, err } if !isInAuthSet(pk, auths) { - return ErrAuthorityNotInSet + return nil, ErrAuthorityNotInSet } // verify signature for each precommit @@ -631,16 +632,16 @@ func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byt SetID: setID, }) if err != nil { - return err + return nil, err } ok, err := pk.Verify(msg, just.Signature[:]) if err != nil { - return err + return nil, err } if !ok { - return ErrInvalidSignature + return nil, ErrInvalidSignature } if _, ok := equivocatoryVoters[just.AuthorityID]; ok { @@ -651,30 +652,30 @@ func (s *Service) VerifyBlockJustification(hash common.Hash, justification []byt } if count+len(equivocatoryVoters) < threshold { - return ErrMinVotesNotMet + return nil, ErrMinVotesNotMet } err = verifyBlockHashAgainstBlockNumber(s.blockState, fj.Commit.Hash, uint(fj.Commit.Number)) if err != nil { - return err + return nil, err } for _, preCommit := range fj.Commit.Precommits { err := verifyBlockHashAgainstBlockNumber(s.blockState, preCommit.Vote.Hash, uint(preCommit.Vote.Number)) if err != nil { - return err + return nil, err } } err = s.blockState.SetFinalisedHash(hash, fj.Round, setID) if err != nil { - return err + return nil, err } logger.Debugf( "set finalised block with hash %s, round %d and set id %d", hash, fj.Round, setID) - return nil + return scale.Marshal(fj) } func verifyBlockHashAgainstBlockNumber(bs BlockState, hash common.Hash, number uint) error { From 653d730ceb3f213e9e111c1a9581ec5a6aa9f7ca Mon Sep 17 00:00:00 2001 From: edwardmack Date: Wed, 6 Jul 2022 10:24:19 -0400 Subject: [PATCH 3/4] re-commit to trigger CI tests --- lib/grandpa/message_handler.go | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/grandpa/message_handler.go b/lib/grandpa/message_handler.go index 3c6b63fa90..7c829d85ac 100644 --- a/lib/grandpa/message_handler.go +++ b/lib/grandpa/message_handler.go @@ -298,6 +298,7 @@ func getEquivocatoryVoters(votes []AuthData) map[ed25519.PublicKeyBytes]struct{} voters[v.AuthorityID] = v.Signature } } + return eqvVoters } From a73d3c9ce75dec43786fe740fb8e4155d3e4f1f6 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Fri, 8 Jul 2022 10:40:16 -0400 Subject: [PATCH 4/4] simplify condition check --- lib/grandpa/message_handler.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/grandpa/message_handler.go b/lib/grandpa/message_handler.go index 7c829d85ac..1afd5dbf7d 100644 --- a/lib/grandpa/message_handler.go +++ b/lib/grandpa/message_handler.go @@ -290,10 +290,8 @@ func getEquivocatoryVoters(votes []AuthData) map[ed25519.PublicKeyBytes]struct{} for _, v := range votes { signature, present := voters[v.AuthorityID] - if present { - if !bytes.Equal(signature[:], v.Signature[:]) { - eqvVoters[v.AuthorityID] = struct{}{} - } + if present && !bytes.Equal(signature[:], v.Signature[:]) { + eqvVoters[v.AuthorityID] = struct{}{} } else { voters[v.AuthorityID] = v.Signature }