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 (pkg/scale): Integrate scale into grandpa library #1694

Closed
Closed
Show file tree
Hide file tree
Changes from all 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
25 changes: 13 additions & 12 deletions lib/grandpa/grandpa.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/ChainSafe/gossamer/lib/blocktree"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/crypto/ed25519"
"github.com/ChainSafe/gossamer/pkg/scale"

log "github.com/ChainSafe/log15"
)
Expand Down Expand Up @@ -587,7 +588,7 @@ func (s *Service) playGrandpaRound() error {
return nil
}

func (s *Service) sendVoteMessage(stage subround, msg *VoteMessage, roundComplete <-chan struct{}) {
func (s *Service) sendVoteMessage(stage Subround, msg *VoteMessage, roundComplete <-chan struct{}) {
ticker := time.NewTicker(interval * 4)
defer ticker.Stop()

Expand Down Expand Up @@ -676,7 +677,7 @@ func (s *Service) attemptToFinalize() error {
}
}

func (s *Service) loadVote(key ed25519.PublicKeyBytes, stage subround) (*SignedVote, bool) {
func (s *Service) loadVote(key ed25519.PublicKeyBytes, stage Subround) (*SignedVote, bool) {
var (
v interface{}
has bool
Expand All @@ -696,7 +697,7 @@ func (s *Service) loadVote(key ed25519.PublicKeyBytes, stage subround) (*SignedV
return v.(*SignedVote), true
}

func (s *Service) deleteVote(key ed25519.PublicKeyBytes, stage subround) {
func (s *Service) deleteVote(key ed25519.PublicKeyBytes, stage Subround) {
switch stage {
case prevote, primaryProposal:
s.prevotes.Delete(key)
Expand Down Expand Up @@ -842,7 +843,7 @@ func (s *Service) finalise() error {
return err
}

pcj, err := newJustification(s.state.round, bfc.Hash, bfc.Number, pcs).Encode()
pcj, err := scale.Marshal(newJustification(s.state.round, bfc.Hash, bfc.Number, pcs))
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: create a local var for the justification on another line

if err != nil {
return err
}
Expand Down Expand Up @@ -880,7 +881,7 @@ func (s *Service) finalise() error {
// createJustification collects the signed precommits received for this round and turns them into
// a justification by adding all signed precommits that are for the best finalised candidate or
// a descendent of the bfc
func (s *Service) createJustification(bfc common.Hash, stage subround) ([]*SignedVote, error) {
func (s *Service) createJustification(bfc common.Hash, stage Subround) ([]*SignedVote, error) {
var (
spc *sync.Map
err error
Expand Down Expand Up @@ -1128,7 +1129,7 @@ func (s *Service) getGrandpaGHOST() (Vote, error) {
// thus, if there are no blocks with >=threshold total votes, but the sum of votes for blocks A and B is >=threshold, then this function returns
// the first common ancestor of A and B.
// in general, this function will return the highest block on each chain with >=threshold votes.
func (s *Service) getPossibleSelectedBlocks(stage subround, threshold uint64) (map[common.Hash]uint32, error) {
func (s *Service) getPossibleSelectedBlocks(stage Subround, threshold uint64) (map[common.Hash]uint32, error) {
// get blocks that were directly voted for
votes := s.getDirectVotes(stage)
blocks := make(map[common.Hash]uint32)
Expand Down Expand Up @@ -1167,7 +1168,7 @@ func (s *Service) getPossibleSelectedBlocks(stage subround, threshold uint64) (m

// getPossibleSelectedAncestors recursively searches for ancestors with >=2/3 votes
// it returns a map of block hash -> number, such that the blocks in the map have >=2/3 votes
func (s *Service) getPossibleSelectedAncestors(votes []Vote, curr common.Hash, selected map[common.Hash]uint32, stage subround, threshold uint64) (map[common.Hash]uint32, error) {
func (s *Service) getPossibleSelectedAncestors(votes []Vote, curr common.Hash, selected map[common.Hash]uint32, stage Subround, threshold uint64) (map[common.Hash]uint32, error) {
for _, v := range votes {
if v.Hash == curr {
continue
Expand Down Expand Up @@ -1211,7 +1212,7 @@ func (s *Service) getPossibleSelectedAncestors(votes []Vote, curr common.Hash, s

// getTotalVotesForBlock returns the total number of observed votes for a block B in a subround, which is equal
// to the direct votes for B and B's descendants plus the total number of equivocating voters
func (s *Service) getTotalVotesForBlock(hash common.Hash, stage subround) (uint64, error) {
func (s *Service) getTotalVotesForBlock(hash common.Hash, stage Subround) (uint64, error) {
// observed votes for block
dv, err := s.getVotesForBlock(hash, stage)
if err != nil {
Expand All @@ -1232,7 +1233,7 @@ func (s *Service) getTotalVotesForBlock(hash common.Hash, stage subround) (uint6
// getVotesForBlock returns the number of observed votes for a block B.
// The set of all observed votes by v in the sub-round stage of round r for block B is
// equal to all of the observed direct votes cast for block B and all of the B's descendants
func (s *Service) getVotesForBlock(hash common.Hash, stage subround) (uint64, error) {
func (s *Service) getVotesForBlock(hash common.Hash, stage Subround) (uint64, error) {
votes := s.getDirectVotes(stage)

// B will be counted as in it's own subchain, so don't need to start with B's vote count
Expand All @@ -1258,7 +1259,7 @@ func (s *Service) getVotesForBlock(hash common.Hash, stage subround) (uint64, er
}

// getDirectVotes returns a map of Votes to direct vote counts
func (s *Service) getDirectVotes(stage subround) map[Vote]uint64 {
func (s *Service) getDirectVotes(stage Subround) map[Vote]uint64 {
votes := make(map[Vote]uint64)

var src *sync.Map
Expand All @@ -1278,7 +1279,7 @@ func (s *Service) getDirectVotes(stage subround) map[Vote]uint64 {
}

// getVotes returns all the current votes as an array
func (s *Service) getVotes(stage subround) []Vote {
func (s *Service) getVotes(stage Subround) []Vote {
votes := s.getDirectVotes(stage)
va := make([]Vote, len(votes))
i := 0
Expand Down Expand Up @@ -1375,7 +1376,7 @@ func (s *Service) PreCommits() []ed25519.PublicKeyBytes {
return votes
}

func (s *Service) lenVotes(stage subround) int {
func (s *Service) lenVotes(stage Subround) int {
var count int

switch stage {
Expand Down
154 changes: 22 additions & 132 deletions lib/grandpa/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@ package grandpa

import (
"fmt"
"io"
"math/big"

"github.com/ChainSafe/gossamer/dot/network"
"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/crypto/ed25519"
"github.com/ChainSafe/gossamer/lib/scale"
"github.com/ChainSafe/gossamer/pkg/scale"
)

// GrandpaMessage is implemented by all GRANDPA network messages
Expand All @@ -46,15 +44,15 @@ var (
// FullVote represents a vote with additional information about the state
// this is encoded and signed and the signature is included in SignedMessage
type FullVote struct {
Stage subround
Stage Subround
Vote *Vote
Round uint64
SetID uint64
}

// SignedMessage represents a block hash and number signed by an authority
type SignedMessage struct {
Stage subround // 0 for pre-vote, 1 for pre-commit, 2 for primary proposal
Stage Subround // 0 for pre-vote, 1 for pre-commit, 2 for primary proposal
Hash common.Hash
Number uint32
Signature [64]byte // ed25519.SignatureLength
Expand All @@ -66,37 +64,6 @@ func (m *SignedMessage) String() string {
return fmt.Sprintf("stage=%s hash=%s number=%d authorityID=%s", m.Stage, m.Hash, m.Number, m.AuthorityID)
}

// Decode SCALE decodes the data into a SignedMessage
func (m *SignedMessage) Decode(r io.Reader) (err error) {
m.Stage, err = subround(0).Decode(r)
if err != nil {
return err
}

vote, err := new(Vote).Decode(r)
if err != nil {
return err
}

m.Hash = vote.Hash
m.Number = vote.Number

sig, err := common.Read64Bytes(r)
if err != nil {
return err
}

copy(m.Signature[:], sig[:])

id, err := common.Read32Bytes(r)
if err != nil {
return err
}

copy(m.AuthorityID[:], id[:])
return nil
}

// VoteMessage represents a network-level vote message
// https://github.com/paritytech/substrate/blob/master/client/finality-grandpa/src/communication/gossip.rs#L336
type VoteMessage struct {
Expand All @@ -105,31 +72,17 @@ type VoteMessage struct {
Message *SignedMessage
}

// Decode SCALE decodes the data into a VoteMessage
func (v *VoteMessage) Decode(r io.Reader) (err error) {
v.Round, err = common.ReadUint64(r)
if err != nil {
return err
}

v.SetID, err = common.ReadUint64(r)
if err != nil {
return err
}

v.Message = new(SignedMessage)
err = v.Message.Decode(r)
return err
}

// Type returns voteType
func (v *VoteMessage) Type() byte {
return voteType
}

// Index Returns VDT index
func (v *VoteMessage) Index() uint { return 0 }
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
func (v *VoteMessage) Index() uint { return 0 }
func (vm *VoteMessage) Index() uint { return 0 }

Update all the other receiver functions too.


// ToConsensusMessage converts the VoteMessage into a network-level consensus message
func (v *VoteMessage) ToConsensusMessage() (*ConsensusMessage, error) {
enc, err := scale.Encode(v)
enc, err := scale.Marshal(v)
if err != nil {
return nil, err
}
Expand All @@ -147,9 +100,12 @@ type NeighbourMessage struct {
Number uint32
}

// Index Returns VDT index
func (m *NeighbourMessage) Index() uint { return 2 }
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
func (m *NeighbourMessage) Index() uint { return 2 }
func (nm *NeighbourMessage) Index() uint { return 2 }


// ToConsensusMessage converts the NeighbourMessage into a network-level consensus message
func (m *NeighbourMessage) ToConsensusMessage() (*network.ConsensusMessage, error) {
enc, err := scale.Encode(m)
enc, err := scale.Marshal(m)
if err != nil {
return nil, err
}
Expand All @@ -170,29 +126,6 @@ type AuthData struct {
AuthorityID ed25519.PublicKeyBytes
}

// Encode SCALE encodes the AuthData
func (d *AuthData) Encode() ([]byte, error) {
return append(d.Signature[:], d.AuthorityID[:]...), nil
}

// Decode SCALE decodes the data into an AuthData
func (d *AuthData) Decode(r io.Reader) error {
sig, err := common.Read64Bytes(r)
if err != nil {
return err
}

copy(d.Signature[:], sig[:])

id, err := common.Read32Bytes(r)
if err != nil {
return err
}

copy(d.AuthorityID[:], id[:])
return nil
}

// CommitMessage represents a network finalisation message
type CommitMessage struct {
Round uint64
Expand All @@ -202,57 +135,8 @@ type CommitMessage struct {
AuthData []*AuthData
}

// Decode SCALE decodes the data into a CommitMessage
func (f *CommitMessage) Decode(r io.Reader) (err error) {
f.Round, err = common.ReadUint64(r)
if err != nil {
return err
}

f.SetID, err = common.ReadUint64(r)
if err != nil {
return err
}

f.Vote, err = new(Vote).Decode(r)
if err != nil {
return err
}

sd := &scale.Decoder{Reader: r}
numPrecommits, err := sd.Decode(new(big.Int))
if err != nil {
return err
}

f.Precommits = make([]*Vote, numPrecommits.(*big.Int).Int64())
for i := range f.Precommits {
f.Precommits[i], err = new(Vote).Decode(r)
if err != nil {
return err
}
}

numAuthData, err := sd.Decode(new(big.Int))
if err != nil {
return err
}

if numAuthData.(*big.Int).Cmp(numPrecommits.(*big.Int)) != 0 {
return ErrPrecommitSignatureMismatch
}

f.AuthData = make([]*AuthData, numAuthData.(*big.Int).Int64())
for i := range f.AuthData {
f.AuthData[i] = new(AuthData)
err = f.AuthData[i].Decode(r)
if err != nil {
return err
}
}

return nil
}
// Index Returns VDT index
func (f *CommitMessage) Index() uint { return 1 }
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
func (f *CommitMessage) Index() uint { return 1 }
func (cm *CommitMessage) Index() uint { return 1 }


// Type returns commitType
func (f *CommitMessage) Type() byte {
Expand All @@ -261,7 +145,7 @@ func (f *CommitMessage) Type() byte {

// ToConsensusMessage converts the CommitMessage into a network-level consensus message
func (f *CommitMessage) ToConsensusMessage() (*ConsensusMessage, error) {
enc, err := scale.Encode(f)
enc, err := scale.Marshal(f)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -323,6 +207,9 @@ type catchUpRequest struct {
SetID uint64
}

// Index Returns VDT index
func (r *catchUpRequest) Index() uint { return 3 }

func newCatchUpRequest(round, setID uint64) *catchUpRequest {
return &catchUpRequest{
Round: round,
Expand All @@ -337,7 +224,7 @@ func (r *catchUpRequest) Type() byte {

// ToConsensusMessage converts the catchUpRequest into a network-level consensus message
func (r *catchUpRequest) ToConsensusMessage() (*ConsensusMessage, error) {
enc, err := scale.Encode(r)
enc, err := scale.Marshal(r)
if err != nil {
return nil, err
}
Expand All @@ -356,6 +243,9 @@ type catchUpResponse struct {
Number uint32
}

// Index Returns VDT index
func (r *catchUpResponse) Index() uint { return 4 }

func (s *Service) newCatchUpResponse(round, setID uint64) (*catchUpResponse, error) {
header, err := s.blockState.GetFinalisedHeader(round, setID)
if err != nil {
Expand Down Expand Up @@ -389,7 +279,7 @@ func (r *catchUpResponse) Type() byte {

// ToConsensusMessage converts the catchUpResponse into a network-level consensus message
func (r *catchUpResponse) ToConsensusMessage() (*ConsensusMessage, error) {
enc, err := scale.Encode(r)
enc, err := scale.Marshal(r)
if err != nil {
return nil, err
}
Expand Down
Loading