-
Notifications
You must be signed in to change notification settings - Fork 662
/
sender.go
219 lines (195 loc) · 8.31 KB
/
sender.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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package common
import (
"context"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow"
"github.com/ava-labs/avalanchego/utils/set"
)
// Sender defines how a consensus engine sends messages and requests to other
// validators.
//
// Messages can be categorized as either: requests, responses, or gossip. Gossip
// messages do not include requestIDs, because no response is expected from the
// peer. However, both requests and responses include requestIDs.
//
// It is expected that each [nodeID + requestID + expected response type] that
// is outstanding at any given time is unique.
//
// As an example, it is valid to send `Get(nodeA, request0)` and
// `PullQuery(nodeA, request0)` because they have different expected response
// types, `Put` and `Chits`.
//
// Additionally, after having sent `Get(nodeA, request0)` and receiving either
// `Put(nodeA, request0)` or `GetFailed(nodeA, request0)`, it is valid to resend
// `Get(nodeA, request0)`. Because the initial `Get` request is no longer
// outstanding.
//
// This means that requestIDs can be reused. In practice, requests always have a
// reasonable maximum timeout, so it is generally safe to assume that by the
// time the requestID space has been exhausted, the beginning of the requestID
// space is free of conflicts.
type Sender interface {
snow.Acceptor
StateSummarySender
AcceptedStateSummarySender
FrontierSender
AcceptedSender
FetchSender
QuerySender
Gossiper
AppSender
}
// StateSummarySender defines how a consensus engine sends state sync messages to
// other nodes.
type StateSummarySender interface {
// SendGetStateSummaryFrontier requests that every node in [nodeIDs] sends a
// StateSummaryFrontier message.
SendGetStateSummaryFrontier(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32)
// SendStateSummaryFrontier responds to a StateSummaryFrontier message with this
// engine's current state summary frontier.
SendStateSummaryFrontier(ctx context.Context, nodeID ids.NodeID, requestID uint32, summary []byte)
}
type AcceptedStateSummarySender interface {
// SendGetAcceptedStateSummary requests that every node in [nodeIDs] sends an
// AcceptedStateSummary message with all the state summary IDs referenced by [heights]
// that the node thinks are accepted.
SendGetAcceptedStateSummary(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, heights []uint64)
// SendAcceptedStateSummary responds to a AcceptedStateSummary message with a
// set of summary ids that are accepted.
SendAcceptedStateSummary(ctx context.Context, nodeID ids.NodeID, requestID uint32, summaryIDs []ids.ID)
}
// FrontierSender defines how a consensus engine sends frontier messages to
// other nodes.
type FrontierSender interface {
// SendGetAcceptedFrontier requests that every node in [nodeIDs] sends an
// AcceptedFrontier message.
SendGetAcceptedFrontier(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32)
// SendAcceptedFrontier responds to a AcceptedFrontier message with this
// engine's current accepted frontier.
SendAcceptedFrontier(
ctx context.Context,
nodeID ids.NodeID,
requestID uint32,
containerID ids.ID,
)
}
// AcceptedSender defines how a consensus engine sends messages pertaining to
// accepted containers
type AcceptedSender interface {
// SendGetAccepted requests that every node in [nodeIDs] sends an Accepted
// message with all the IDs in [containerIDs] that the node thinks are
// accepted.
SendGetAccepted(
ctx context.Context,
nodeIDs set.Set[ids.NodeID],
requestID uint32,
containerIDs []ids.ID,
)
// SendAccepted responds to a GetAccepted message with a set of IDs of
// containers that are accepted.
SendAccepted(ctx context.Context, nodeID ids.NodeID, requestID uint32, containerIDs []ids.ID)
}
// FetchSender defines how a consensus engine sends retrieval messages to other
// nodes.
type FetchSender interface {
// Request that the specified node send the specified container to this
// node.
SendGet(ctx context.Context, nodeID ids.NodeID, requestID uint32, containerID ids.ID)
// SendGetAncestors requests that node [nodeID] send container [containerID]
// and its ancestors.
SendGetAncestors(ctx context.Context, nodeID ids.NodeID, requestID uint32, containerID ids.ID)
// Tell the specified node about [container].
SendPut(ctx context.Context, nodeID ids.NodeID, requestID uint32, container []byte)
// Give the specified node several containers at once. Should be in response
// to a GetAncestors message with request ID [requestID] from the node.
SendAncestors(ctx context.Context, nodeID ids.NodeID, requestID uint32, containers [][]byte)
}
// QuerySender defines how a consensus engine sends query messages to other
// nodes.
type QuerySender interface {
// Request from the specified nodes their preferred frontier, given the
// existence of the specified container.
// This is the same as PullQuery, except that this message includes the body
// of the container rather than its ID.
SendPushQuery(
ctx context.Context,
nodeIDs set.Set[ids.NodeID],
requestID uint32,
container []byte,
requestedHeight uint64,
)
// Request from the specified nodes their preferred frontier, given the
// existence of the specified container.
SendPullQuery(
ctx context.Context,
nodeIDs set.Set[ids.NodeID],
requestID uint32,
containerID ids.ID,
requestedHeight uint64,
)
// Send chits to the specified node
SendChits(
ctx context.Context,
nodeID ids.NodeID,
requestID uint32,
preferredID ids.ID,
preferredIDAtHeight ids.ID,
acceptedID ids.ID,
)
}
// Gossiper defines how a consensus engine gossips a container on the accepted
// frontier to other nodes
type Gossiper interface {
// Gossip the provided container throughout the network
SendGossip(ctx context.Context, container []byte)
}
// NetworkAppSender sends VM-level messages to nodes in the network.
type NetworkAppSender interface {
// Send an application-level request.
// A nil return value guarantees that for each nodeID in [nodeIDs],
// the VM corresponding to this AppSender eventually receives either:
// * An AppResponse from nodeID with ID [requestID]
// * An AppRequestFailed from nodeID with ID [requestID]
// Exactly one of the above messages will eventually be received per nodeID.
// A non-nil error should be considered fatal.
SendAppRequest(ctx context.Context, nodeIDs set.Set[ids.NodeID], requestID uint32, appRequestBytes []byte) error
// Send an application-level response to a request.
// This response must be in response to an AppRequest that the VM corresponding
// to this AppSender received from [nodeID] with ID [requestID].
// A non-nil error should be considered fatal.
SendAppResponse(ctx context.Context, nodeID ids.NodeID, requestID uint32, appResponseBytes []byte) error
// Gossip an application-level message.
// A non-nil error should be considered fatal.
SendAppGossip(ctx context.Context, appGossipBytes []byte) error
SendAppGossipSpecific(ctx context.Context, nodeIDs set.Set[ids.NodeID], appGossipBytes []byte) error
}
// CrossChainAppSender sends local VM-level messages to another VM.
type CrossChainAppSender interface {
// SendCrossChainAppRequest sends an application-level request to a
// specific chain.
//
// A nil return value guarantees that the VM corresponding to this
// CrossChainAppSender eventually receives either:
// * A CrossChainAppResponse from [chainID] with ID [requestID]
// * A CrossChainAppRequestFailed from [chainID] with ID [requestID]
// Exactly one of the above messages will eventually be received from
// [chainID].
// A non-nil error should be considered fatal.
SendCrossChainAppRequest(ctx context.Context, chainID ids.ID, requestID uint32, appRequestBytes []byte) error
// SendCrossChainAppResponse sends an application-level response to a
// specific chain
//
// This response must be in response to a CrossChainAppRequest that the VM
// corresponding to this CrossChainAppSender received from [chainID] with ID
// [requestID].
// A non-nil error should be considered fatal.
SendCrossChainAppResponse(ctx context.Context, chainID ids.ID, requestID uint32, appResponseBytes []byte) error
}
// AppSender sends application (VM) level messages.
// See also common.AppHandler.
type AppSender interface {
NetworkAppSender
CrossChainAppSender
}