-
Notifications
You must be signed in to change notification settings - Fork 211
/
builder.go
197 lines (167 loc) · 6 KB
/
builder.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package hare
import (
"fmt"
"github.com/spacemeshos/go-spacemesh/codec"
"github.com/spacemeshos/go-spacemesh/common/types"
"github.com/spacemeshos/go-spacemesh/hash"
"github.com/spacemeshos/go-spacemesh/log"
"github.com/spacemeshos/go-spacemesh/signing"
)
//go:generate scalegen -types Message,Certificate,AggregatedMessages,InnerMessage
type Message struct {
*InnerMessage
SmesherID types.NodeID
Signature types.EdSignature
Eligibility types.HareEligibility
// capture the message hash signed by smesher.
// some redundant data were removed before signing to reduce network traffic.
// after the receiver verified the signature, the inner messages may be altered
// to add back redundant data. for example, Values in the nested messages
// of a Certificate are trimmed before gossipping and added back after signature is
// verified. we want to capture the original hash signed by the smesher.
signedHash types.Hash32
}
// MessageFromBuffer builds an Hare message from the provided bytes buffer.
// It returns an error if unmarshal of the provided byte slice failed.
func MessageFromBuffer(buf []byte) (*Message, error) {
msg := &Message{}
if err := codec.Decode(buf, msg); err != nil {
return msg, fmt.Errorf("serialize: %w", err)
}
return msg, nil
}
func (m *Message) MarshalLogObject(encoder log.ObjectEncoder) error {
encoder.AddObject("inner_msg", m.InnerMessage)
encoder.AddUint32("layer_id", m.Layer.Uint32())
encoder.AddUint32("round", m.Round)
encoder.AddString("signature", m.Signature.String())
encoder.AddObject("eligibility", &m.Eligibility)
return nil
}
// Field returns a log field. Implements the LoggableField interface.
func (m *Message) Field() log.Field {
return log.Object("hare_msg", m)
}
// Bytes returns the message as bytes.
// It panics if the message errored on unmarshal.
func (m *Message) Bytes() []byte {
buf, err := codec.Encode(m)
if err != nil {
log.With().Fatal("failed to encode Message", log.Err(err))
}
return buf
}
// SignedBytes returns the signed data for hare message.
func (m *Message) SignedBytes() []byte {
buf, err := codec.Encode(&types.HareMetadata{
Layer: m.Layer,
Round: m.Round,
MsgHash: types.BytesToHash(m.InnerMessage.HashBytes()),
})
if err != nil {
log.With().Fatal("failed to encode HareMetadata", log.Err(err))
}
return buf
}
// Certificate is a collection of messages and the set of values.
// Typically used as a collection of commit messages.
type Certificate struct {
Values []types.ProposalID `scale:"max=500"` // the committed set S - expected are 50 proposals per layer + safety margin
AggMsgs *AggregatedMessages
}
// AggregatedMessages is a collection of messages.
type AggregatedMessages struct {
Messages []Message `scale:"max=1000"` // limited by hare config parameter N with safety margin
}
// InnerMessage is the actual set of fields that describe a message in the Hare protocol.
type InnerMessage struct {
Layer types.LayerID
Round uint32 // the round counter (K)
Type MessageType
CommittedRound uint32 // the round Values (S) is committed (Ki)
Values []types.ProposalID `scale:"max=500"` // the set S. optional for commit InnerMsg in a certificate - expected are 50 proposals per layer + safety margin
Svp *AggregatedMessages // optional. only for proposal Messages
Cert *Certificate // optional
}
// HashBytes returns the message as bytes.
func (im *InnerMessage) HashBytes() []byte {
h := hash.New()
_, err := codec.EncodeTo(h, im)
if err != nil {
log.With().Fatal("failed to encode InnerMsg for hashing", log.Err(err))
}
return h.Sum(nil)
}
func (im *InnerMessage) MarshalLogObject(encoder log.ObjectEncoder) error {
encoder.AddString("msg_type", im.Type.String())
encoder.AddUint32("committed_round", im.CommittedRound)
return nil
}
// messageBuilder is the impl of the builder DP.
// It allows the user to set the different fields of the builder and eventually Build the message.
type messageBuilder struct {
msg *Message
inner *InnerMessage
}
// newMessageBuilder returns a new, empty message builder.
// One should not assume any values are pre-set.
func newMessageBuilder() *messageBuilder {
m := &messageBuilder{&Message{}, &InnerMessage{}}
m.msg.InnerMessage = m.inner
return m
}
// Build returns the protocol message as type Msg.
func (mb *messageBuilder) Build() *Message {
return mb.msg
}
// SetCertificate sets certificate.
func (mb *messageBuilder) SetCertificate(certificate *Certificate) *messageBuilder {
mb.inner.Cert = certificate
return mb
}
// Sign calls the provided signer to calculate the signature and then set it accordingly.
func (mb *messageBuilder) Sign(signer *signing.EdSigner) *messageBuilder {
mb.msg.Signature = signer.Sign(signing.HARE, mb.msg.SignedBytes())
mb.msg.SmesherID = signer.NodeID()
return mb
}
// SetType sets message type.
func (mb *messageBuilder) SetType(msgType MessageType) *messageBuilder {
mb.inner.Type = msgType
return mb
}
// SetLayer sets the layer.
func (mb *messageBuilder) SetLayer(id types.LayerID) *messageBuilder {
mb.msg.Layer = id
return mb
}
// SetRoundCounter sets the round counter.
func (mb *messageBuilder) SetRoundCounter(round uint32) *messageBuilder {
mb.msg.Round = round
return mb
}
// SetCommittedRound sets the committed round of the set values.
func (mb *messageBuilder) SetCommittedRound(round uint32) *messageBuilder {
mb.inner.CommittedRound = round
return mb
}
// SetValues sets values.
func (mb *messageBuilder) SetValues(set *Set) *messageBuilder {
mb.inner.Values = set.ToSlice()
return mb
}
// SetRoleProof sets role proof.
func (mb *messageBuilder) SetRoleProof(sig types.VrfSignature) *messageBuilder {
mb.msg.Eligibility.Proof = sig
return mb
}
// SetEligibilityCount sets eligibility count.
func (mb *messageBuilder) SetEligibilityCount(eligibilityCount uint16) *messageBuilder {
mb.msg.Eligibility.Count = eligibilityCount
return mb
}
// SetSVP sets svp.
func (mb *messageBuilder) SetSVP(svp *AggregatedMessages) *messageBuilder {
mb.inner.Svp = svp
return mb
}