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

fix(lib/grandpa): clean up Grandpa tracked commit and vote messages #2478

Closed
wants to merge 2 commits into from
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
29 changes: 29 additions & 0 deletions internal/grandpa/clean/commits.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package clean

import (
"container/ring"

"github.com/ChainSafe/gossamer/lib/common"
)

type CommitsCleaner struct {
hashesRing *ring.Ring
cleanup func(hash common.Hash)
}

func NewCommitsCleaner(maxSize int,
cleanup func(hash common.Hash)) *CommitsCleaner {
return &CommitsCleaner{
hashesRing: ring.New(maxSize),
cleanup: cleanup,
}
}

func (cc *CommitsCleaner) TrackAndClean(hash common.Hash) {
if cc.hashesRing.Value != nil {
oldHash := cc.hashesRing.Value.(common.Hash)
cc.cleanup(oldHash)
}
cc.hashesRing.Value = hash
cc.hashesRing = cc.hashesRing.Next()
}
40 changes: 40 additions & 0 deletions internal/grandpa/clean/votes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package clean

import (
"container/ring"

"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/crypto/ed25519"
)

type VotesCleaner struct {
hashesRing *ring.Ring
cleanup func(hash common.Hash, authorityID ed25519.PublicKeyBytes)
}

func NewVotesCleaner(maxSize int,
cleanup func(hash common.Hash, authorityID ed25519.PublicKeyBytes)) *VotesCleaner {
return &VotesCleaner{
hashesRing: ring.New(maxSize),
cleanup: cleanup,
}
}

type hashAuthorityID struct {
hash common.Hash
authorityID ed25519.PublicKeyBytes
}

func (vc *VotesCleaner) TrackAndClean(hash common.Hash, authorityID ed25519.PublicKeyBytes) {
if vc.hashesRing.Value != nil {
oldHashAuthorityID := vc.hashesRing.Value.(hashAuthorityID)
oldHash := oldHashAuthorityID.hash
oldAuthorityID := oldHashAuthorityID.authorityID
vc.cleanup(oldHash, oldAuthorityID)
}
vc.hashesRing.Value = hashAuthorityID{
hash: hash,
authorityID: authorityID,
}
vc.hashesRing = vc.hashesRing.Next()
}
40 changes: 36 additions & 4 deletions lib/grandpa/message_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/internal/grandpa/clean"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/crypto/ed25519"
)
Expand All @@ -18,10 +19,12 @@ import (
type tracker struct {
blockState BlockState
handler *MessageHandler
// map of vote block hash -> array of VoteMessages for that hash
// map of vote block hash to authority ID (ed25519 public Key) to vote message
voteMessages map[common.Hash]map[ed25519.PublicKeyBytes]*networkVoteMessage
votesCleaner *clean.VotesCleaner
// map of commit block hash to commit message
commitMessages map[common.Hash]*CommitMessage
commitsCleaner *clean.CommitsCleaner
mapLock sync.Mutex
in chan *types.Block // receive imported block from BlockState
stopped chan struct{}
Expand All @@ -32,18 +35,44 @@ type tracker struct {
}

func newTracker(bs BlockState, handler *MessageHandler) *tracker {
commitMessages := make(map[common.Hash]*CommitMessage)
const maxCommitMessages = 1000
commitCleanup := func(hash common.Hash) { delete(commitMessages, hash) }
commitsCleaner := clean.NewCommitsCleaner(maxCommitMessages, commitCleanup)

voteMessages := make(map[common.Hash]map[ed25519.PublicKeyBytes]*networkVoteMessage)
const maxVoteMessages = 1000
voteCleanup := newVotesCleanup(voteMessages)
votesCleaner := clean.NewVotesCleaner(maxVoteMessages, voteCleanup)

return &tracker{
blockState: bs,
handler: handler,
voteMessages: make(map[common.Hash]map[ed25519.PublicKeyBytes]*networkVoteMessage),
voteMessages: voteMessages,
votesCleaner: votesCleaner,
commitMessages: make(map[common.Hash]*CommitMessage),
commitsCleaner: commitsCleaner,
mapLock: sync.Mutex{},
in: bs.GetImportedBlockNotifierChannel(),
stopped: make(chan struct{}),
catchUpResponseMessages: make(map[uint64]*CatchUpResponse),
}
}

func newVotesCleanup(voteMessages map[common.Hash]map[ed25519.PublicKeyBytes]*networkVoteMessage) (
cleanup func(hash common.Hash, authorityID ed25519.PublicKeyBytes)) {
return func(hash common.Hash, authorityID ed25519.PublicKeyBytes) {
messages, ok := voteMessages[hash]
if !ok {
return
}
delete(messages, authorityID)
if len(messages) == 0 {
delete(voteMessages, hash)
}
}
}

func (t *tracker) start() {
go t.handleBlocks()
}
Expand All @@ -68,18 +97,21 @@ func (t *tracker) addVote(v *networkVoteMessage) {
}

msgs[v.msg.Message.AuthorityID] = v
t.votesCleaner.TrackAndClean(v.msg.Message.Hash, v.msg.Message.AuthorityID)
}

func (t *tracker) addCommit(cm *CommitMessage) {
t.mapLock.Lock()
defer t.mapLock.Unlock()
t.commitMessages[cm.Vote.Hash] = cm
t.commitsCleaner.TrackAndClean(cm.Vote.Hash)
}

func (t *tracker) addCatchUpResponse(cr *CatchUpResponse) {
func (t *tracker) addCatchUpResponse(cr *CatchUpResponse) { //nolint:unparam
t.catchUpResponseMessageMutex.Lock()
defer t.catchUpResponseMessageMutex.Unlock()
t.catchUpResponseMessages[cr.Round] = cr
// uncomment when usage is setup properly, see #1531
// t.catchUpResponseMessages[cr.Round] = cr
}

func (t *tracker) handleBlocks() {
Expand Down