-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathverifier.go
83 lines (72 loc) · 1.8 KB
/
verifier.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
package don
import (
"fmt"
"github.com/amirylm/p2pmq/proto"
)
var (
skipThreshold int64 = 5
invalidThreshold int64 = 25
)
// reportVerifier is doing the actual validation on incoming messages
type reportVerifier struct {
reports *ReportBuffer
dons map[string]map[OracleID]OnchainPublicKey
}
func NewReportVerifier(reports *ReportBuffer) *reportVerifier {
return &reportVerifier{
reports: reports,
dons: make(map[string]map[OracleID]OnchainPublicKey),
}
}
func (rv *reportVerifier) Process(msg *proto.Message) ([]byte, proto.ValidationResult) {
raw := msg.GetData()
r, err := UnmarshalReport(raw)
if err != nil || r == nil {
// bad encoding
return raw, proto.ValidationResult_REJECT
}
pubkeys, ok := rv.dons[r.Src]
if !ok {
return raw, proto.ValidationResult_IGNORE
}
s := NewSigner(0)
valid := 0
for oid, pk := range pubkeys {
sig, ok := r.Sigs[oid]
if !ok {
continue
}
if err := s.Verify(pk, r.Ctx, r.GetReportData(), sig); err != nil {
fmt.Printf("failed to verify report: %v\n", err)
return raw, proto.ValidationResult_REJECT
}
valid++
}
// n = 3f + 1
// n-1 = 3f
// f = (n-1)/3
n := len(pubkeys)
f := (n - 1) / 3
threshold := n - f
if valid < threshold {
return raw, proto.ValidationResult_REJECT
}
return raw, rv.validateSequence(r)
}
func (rv *reportVerifier) validateSequence(r *MockedSignedReport) proto.ValidationResult {
latest := rv.reports.GetLatest(r.Src)
if latest != nil {
diff := r.SeqNumber - latest.SeqNumber
switch {
case diff > invalidThreshold:
return proto.ValidationResult_REJECT
case diff > skipThreshold:
return proto.ValidationResult_IGNORE
default: // less than skipThreshold, accept
}
}
if rv.reports.Get(r.Src, r.SeqNumber) != nil {
return proto.ValidationResult_IGNORE
}
return proto.ValidationResult_ACCEPT
}