Skip to content

Commit c04d185

Browse files
authored
fix(lib/grandpa): various finality fixes, improves cross-client finality (#2368)
1 parent c5389bd commit c04d185

File tree

4 files changed

+98
-18
lines changed

4 files changed

+98
-18
lines changed

lib/grandpa/errors.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ var (
9393
// ErrAuthorityNotInSet is returned when a precommit within a justification is signed by a key not in the authority set
9494
ErrAuthorityNotInSet = errors.New("authority is not in set")
9595

96-
errVoteExists = errors.New("already have vote")
9796
errVoteToSignatureMismatch = errors.New("votes and authority count mismatch")
9897
errInvalidVoteBlock = errors.New("block in vote is not descendant of previously finalised block")
98+
errVoteFromSelf = errors.New("got vote from ourselves")
9999
)

lib/grandpa/message_tracker.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package grandpa
55

66
import (
77
"sync"
8+
"time"
89

910
"github.com/ChainSafe/gossamer/dot/types"
1011
"github.com/ChainSafe/gossamer/lib/common"
@@ -82,6 +83,10 @@ func (t *tracker) addCatchUpResponse(cr *CatchUpResponse) {
8283
}
8384

8485
func (t *tracker) handleBlocks() {
86+
const timeout = time.Second
87+
ticker := time.NewTicker(timeout)
88+
defer ticker.Stop()
89+
8590
for {
8691
select {
8792
case b := <-t.in:
@@ -90,6 +95,8 @@ func (t *tracker) handleBlocks() {
9095
}
9196

9297
t.handleBlock(b)
98+
case <-ticker.C:
99+
t.handleTick()
93100
case <-t.stopped:
94101
return
95102
}
@@ -122,3 +129,32 @@ func (t *tracker) handleBlock(b *types.Block) {
122129
delete(t.commitMessages, h)
123130
}
124131
}
132+
133+
func (t *tracker) handleTick() {
134+
t.mapLock.Lock()
135+
defer t.mapLock.Unlock()
136+
137+
for _, vms := range t.voteMessages {
138+
for _, v := range vms {
139+
// handleMessage would never error for vote message
140+
_, err := t.handler.handleMessage(v.from, v.msg)
141+
if err != nil {
142+
logger.Debugf("failed to handle vote message %v: %s", v, err)
143+
}
144+
145+
if v.msg.Round < t.handler.grandpa.state.round && v.msg.SetID == t.handler.grandpa.state.setID {
146+
delete(t.voteMessages, v.msg.Message.Hash)
147+
}
148+
}
149+
}
150+
151+
for _, cm := range t.commitMessages {
152+
_, err := t.handler.handleMessage("", cm)
153+
if err != nil {
154+
logger.Debugf("failed to handle commit message %v: %s", cm, err)
155+
continue
156+
}
157+
158+
delete(t.commitMessages, cm.Vote.Hash)
159+
}
160+
}

lib/grandpa/message_tracker_test.go

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/ChainSafe/gossamer/dot/state"
1111
"github.com/ChainSafe/gossamer/dot/types"
12+
"github.com/ChainSafe/gossamer/lib/common"
1213
"github.com/ChainSafe/gossamer/lib/crypto/ed25519"
1314
"github.com/ChainSafe/gossamer/lib/keystore"
1415

@@ -85,11 +86,12 @@ func TestMessageTracker_SendMessage(t *testing.T) {
8586
})
8687
require.NoError(t, err)
8788

89+
const testTimeout = time.Second
8890
select {
8991
case v := <-in:
9092
require.Equal(t, msg, v.msg)
9193
case <-time.After(testTimeout):
92-
t.Errorf("did not receive vote message")
94+
t.Errorf("did not receive vote message %v", msg)
9395
}
9496
}
9597

@@ -180,3 +182,58 @@ func TestMessageTracker_MapInsideMap(t *testing.T) {
180182
_, ok = voteMsgs[authorityID]
181183
require.True(t, ok)
182184
}
185+
186+
func TestMessageTracker_handleTick(t *testing.T) {
187+
kr, err := keystore.NewEd25519Keyring()
188+
require.NoError(t, err)
189+
190+
gs, in, _, _ := setupGrandpa(t, kr.Bob().(*ed25519.Keypair))
191+
gs.tracker = newTracker(gs.blockState, gs.messageHandler)
192+
193+
testHash := common.Hash{1, 2, 3}
194+
msg := &VoteMessage{
195+
Round: 100,
196+
Message: SignedMessage{
197+
Hash: testHash,
198+
},
199+
}
200+
gs.tracker.addVote(&networkVoteMessage{
201+
msg: msg,
202+
})
203+
204+
gs.tracker.handleTick()
205+
206+
const testTimeout = time.Second
207+
select {
208+
case v := <-in:
209+
require.Equal(t, msg, v.msg)
210+
case <-time.After(testTimeout):
211+
t.Errorf("did not receive vote message %v", msg)
212+
}
213+
214+
// shouldn't be deleted as round in message >= grandpa round
215+
require.Equal(t, 1, len(gs.tracker.voteMessages[testHash]))
216+
217+
gs.state.round = 1
218+
msg = &VoteMessage{
219+
Round: 0,
220+
Message: SignedMessage{
221+
Hash: testHash,
222+
},
223+
}
224+
gs.tracker.addVote(&networkVoteMessage{
225+
msg: msg,
226+
})
227+
228+
gs.tracker.handleTick()
229+
230+
select {
231+
case v := <-in:
232+
require.Equal(t, msg, v.msg)
233+
case <-time.After(testTimeout):
234+
t.Errorf("did not receive vote message %v", msg)
235+
}
236+
237+
// should be deleted as round in message < grandpa round
238+
require.Empty(t, len(gs.tracker.voteMessages[testHash]))
239+
}

lib/grandpa/vote_message.go

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func (s *Service) receiveVoteMessages(ctx context.Context) {
3535
continue
3636
}
3737

38-
logger.Tracef("received vote message %v from %s", msg.msg, msg.from)
38+
logger.Debugf("received vote message %v from %s", msg.msg, msg.from)
3939
vm := msg.msg
4040

4141
switch vm.Message.Stage {
@@ -129,19 +129,6 @@ func (s *Service) validateVoteMessage(from peer.ID, m *VoteMessage) (*Vote, erro
129129
return nil, err
130130
}
131131

132-
switch m.Message.Stage {
133-
case prevote, primaryProposal:
134-
pv, has := s.loadVote(pk.AsBytes(), prevote)
135-
if has && pv.Vote.Hash.Equal(m.Message.Hash) {
136-
return nil, errVoteExists
137-
}
138-
case precommit:
139-
pc, has := s.loadVote(pk.AsBytes(), precommit)
140-
if has && pc.Vote.Hash.Equal(m.Message.Hash) {
141-
return nil, errVoteExists
142-
}
143-
}
144-
145132
err = validateMessageSignature(pk, m)
146133
if err != nil {
147134
return nil, err
@@ -194,10 +181,10 @@ func (s *Service) validateVoteMessage(from peer.ID, m *VoteMessage) (*Vote, erro
194181

195182
vote := NewVote(m.Message.Hash, m.Message.Number)
196183

197-
// if the vote is from ourselves, ignore
184+
// if the vote is from ourselves, return an error
198185
kb := [32]byte(s.publicKeyBytes())
199186
if bytes.Equal(m.Message.AuthorityID[:], kb[:]) {
200-
return vote, nil
187+
return nil, errVoteFromSelf
201188
}
202189

203190
err = s.validateVote(vote)

0 commit comments

Comments
 (0)