-
Notifications
You must be signed in to change notification settings - Fork 211
/
notifytracker.go
118 lines (103 loc) · 3.48 KB
/
notifytracker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package hare
import (
"context"
"encoding/binary"
"github.com/spacemeshos/go-spacemesh/common/types"
"github.com/spacemeshos/go-spacemesh/hash"
"github.com/spacemeshos/go-spacemesh/log"
)
// notifyTracker tracks notify messages.
// It also provides the number of notifications tracked for a given set.
type notifyTracker struct {
logger log.Log
round uint32
malCh chan<- *types.MalfeasanceGossip
notifies map[types.NodeID]*types.HareProofMsg // tracks PubKey->Notification
tracker *RefCountTracker // tracks ref count to each seen set
eTracker *EligibilityTracker
certificates map[types.Hash32]struct{} // tracks Set->certificate
}
func newNotifyTracker(
logger log.Log,
round uint32,
mch chan<- *types.MalfeasanceGossip,
et *EligibilityTracker,
expectedSize int,
) *notifyTracker {
return ¬ifyTracker{
logger: logger,
round: round,
malCh: mch,
notifies: make(map[types.NodeID]*types.HareProofMsg, expectedSize),
tracker: NewRefCountTracker(round, et, expectedSize),
eTracker: et,
certificates: make(map[types.Hash32]struct{}, expectedSize),
}
}
// OnNotify tracks the provided notification message.
// Returns true if the InnerMsg didn't affect the state, false otherwise.
func (nt *notifyTracker) OnNotify(ctx context.Context, msg *Message) bool {
metadata := types.HareMetadata{
Layer: msg.Layer,
Round: msg.Round,
MsgHash: msg.signedHash,
}
if prev, exist := nt.notifies[msg.SmesherID]; exist { // already seenSenders
if !prev.InnerMsg.Equivocation(&metadata) {
return true // ignored
}
nt.logger.WithContext(ctx).With().Warning("equivocation detected in notify round",
log.Stringer("smesher", msg.SmesherID),
log.Object("prev", &prev.InnerMsg),
log.Object("curr", &metadata),
)
nt.eTracker.Track(msg.SmesherID, msg.Round, msg.Eligibility.Count, false)
this := &types.HareProofMsg{
InnerMsg: metadata,
SmesherID: msg.SmesherID,
Signature: msg.Signature,
}
if err := reportEquivocation(ctx, msg.SmesherID, prev, this, &msg.Eligibility, nt.malCh); err != nil {
nt.logger.WithContext(ctx).With().Warning("failed to report equivocation in notify round",
log.Stringer("smesher", msg.SmesherID),
log.Err(err),
)
}
return true // ignored
}
// keep msg for pub
nt.notifies[msg.SmesherID] = &types.HareProofMsg{
InnerMsg: metadata,
SmesherID: msg.SmesherID,
Signature: msg.Signature,
}
// track that set
s := NewSet(msg.Values)
nt.onCertificate(msg.Cert.AggMsgs.Messages[0].Round, s)
nt.tracker.Track(s.ID(), msg.SmesherID)
return false
}
// NotificationsCount returns the number of notifications tracked for the provided set.
func (nt *notifyTracker) NotificationsCount(s *Set) *CountInfo {
return nt.tracker.CountStatus(s.ID())
}
// calculates a unique id for the provided k and set.
func calcID(k uint32, set *Set) types.Hash32 {
h := hash.New()
// write K
buff := make([]byte, 4)
binary.LittleEndian.PutUint32(buff, k) // K>=0 because this not pre-round
h.Write(buff)
// write set ObjectID
h.Write(set.ID().Bytes())
return types.BytesToHash(h.Sum([]byte{}))
}
// tracks certificates.
func (nt *notifyTracker) onCertificate(k uint32, set *Set) {
nt.certificates[calcID(k, set)] = struct{}{}
}
// HasCertificate returns true if a certificate exist for the provided set in the provided round, false otherwise.
func (nt *notifyTracker) HasCertificate(k uint32, set *Set) bool {
_, exist := nt.certificates[calcID(k, set)]
return exist
}