forked from ssvlabs/ssv-spec
/
messages.go
125 lines (102 loc) · 3.43 KB
/
messages.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
119
120
121
122
123
124
125
package types
import (
"bytes"
"encoding/binary"
"encoding/hex"
"encoding/json"
)
// ValidatorPK is an eth2 validator public key
type ValidatorPK []byte
const (
pubKeySize = 48
pubKeyStartPos = 0
roleTypeSize = 4
roleTypeStartPos = pubKeyStartPos + pubKeySize
)
type Validate interface {
// Validate returns error if msg validation doesn't pass.
// Msg validation checks the msg, it's variables for validity.
Validate() error
}
// MessageIDBelongs returns true if message ID belongs to validator
func (vid ValidatorPK) MessageIDBelongs(msgID MessageID) bool {
toMatch := msgID.GetPubKey()
return bytes.Equal(vid, toMatch)
}
// MessageID is used to identify and route messages to the right validator and Runner
type MessageID [52]byte
func (msg MessageID) GetPubKey() []byte {
return msg[pubKeyStartPos : pubKeyStartPos+pubKeySize]
}
func (msg MessageID) GetRoleType() BeaconRole {
roleByts := msg[roleTypeStartPos : roleTypeStartPos+roleTypeSize]
return BeaconRole(binary.LittleEndian.Uint32(roleByts))
}
func NewMsgID(pk []byte, role BeaconRole) MessageID {
roleByts := make([]byte, 4)
binary.LittleEndian.PutUint32(roleByts, uint32(role))
return newMessageID(pk, roleByts)
}
func (msgID MessageID) String() string {
return hex.EncodeToString(msgID[:])
}
func MessageIDFromBytes(mid []byte) MessageID {
if len(mid) < pubKeySize+roleTypeSize {
return MessageID{}
}
return newMessageID(mid[pubKeyStartPos:pubKeyStartPos+pubKeySize], mid[roleTypeStartPos:roleTypeStartPos+roleTypeSize])
}
func newMessageID(pk, roleByts []byte) MessageID {
mid := MessageID{}
copy(mid[pubKeyStartPos:pubKeyStartPos+pubKeySize], pk)
copy(mid[roleTypeStartPos:roleTypeStartPos+roleTypeSize], roleByts)
return mid
}
type MsgType uint64
const (
// SSVConsensusMsgType are all QBFT consensus related messages
SSVConsensusMsgType MsgType = iota
// SSVPartialSignatureMsgType are all partial signatures msgs over beacon chain specific signatures
SSVPartialSignatureMsgType
// DKGMsgType represent all DKG related messages
DKGMsgType
)
type Root interface {
// GetRoot returns the root used for signing and verification
GetRoot() ([]byte, error)
}
// MessageSignature includes all functions relevant for a signed message (QBFT message, post consensus msg, etc)
type MessageSignature interface {
Root
GetSignature() Signature
GetSigners() []OperatorID
// MatchedSigners returns true if the provided signer ids are equal to GetSignerIds() without order significance
MatchedSigners(ids []OperatorID) bool
// Aggregate will aggregate the signed message if possible (unique signers, same digest, valid)
Aggregate(signedMsg MessageSignature) error
}
// SSVMessage is the main message passed within the SSV network, it can contain different types of messages (QBTF, Sync, etc.)
type SSVMessage struct {
MsgType MsgType
MsgID MessageID
Data []byte
}
func (msg *SSVMessage) GetType() MsgType {
return msg.MsgType
}
// GetID returns a unique msg ID that is used to identify to which validator should the message be sent for processing
func (msg *SSVMessage) GetID() MessageID {
return msg.MsgID
}
// GetData returns message Data as byte slice
func (msg *SSVMessage) GetData() []byte {
return msg.Data
}
// Encode returns a msg encoded bytes or error
func (msg *SSVMessage) Encode() ([]byte, error) {
return json.Marshal(msg)
}
// Decode returns error if decoding failed
func (msg *SSVMessage) Decode(data []byte) error {
return json.Unmarshal(data, &msg)
}