-
Notifications
You must be signed in to change notification settings - Fork 986
/
Copy pathSCPDriver.h
262 lines (217 loc) · 8.66 KB
/
SCPDriver.h
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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#pragma once
// Copyright 2014 Stellar Development Foundation and contributors. Licensed
// under the Apache License, Version 2.0. See the COPYING file at the root
// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0
#include "util/NonCopyable.h"
#include <chrono>
#include <functional>
#include <map>
#include <memory>
#include <set>
#include "xdr/Stellar-SCP.h"
namespace stellar
{
class ValueWrapper : public NonMovableOrCopyable
{
Value const mValue;
public:
explicit ValueWrapper(Value const& value);
virtual ~ValueWrapper();
Value const&
getValue() const
{
return mValue;
}
};
typedef std::shared_ptr<SCPQuorumSet> SCPQuorumSetPtr;
typedef std::shared_ptr<ValueWrapper> ValueWrapperPtr;
class WrappedValuePtrComparator
{
public:
bool operator()(ValueWrapperPtr const& l, ValueWrapperPtr const& r) const;
};
typedef std::set<ValueWrapperPtr, WrappedValuePtrComparator> ValueWrapperPtrSet;
class SCPEnvelopeWrapper : public NonMovableOrCopyable
{
SCPEnvelope const mEnvelope;
public:
explicit SCPEnvelopeWrapper(SCPEnvelope const& e);
virtual ~SCPEnvelopeWrapper();
SCPEnvelope const&
getEnvelope() const
{
return mEnvelope;
}
SCPStatement const&
getStatement() const
{
return mEnvelope.statement;
}
};
typedef std::shared_ptr<SCPEnvelopeWrapper> SCPEnvelopeWrapperPtr;
class SCPDriver
{
public:
virtual ~SCPDriver()
{
}
// Envelope signature
virtual void signEnvelope(SCPEnvelope& envelope) = 0;
// SCPEnvelopeWrapper factory
virtual SCPEnvelopeWrapperPtr wrapEnvelope(SCPEnvelope const& envelope);
// ValueWrapperPtr factory
virtual ValueWrapperPtr wrapValue(Value const& value);
// Retrieves a quorum set from its hash
//
// All SCP statement (see `SCPNomination` and `SCPStatement`) include
// a quorum set hash.
// SCP does not define how quorum sets are exchanged between nodes,
// hence their retrieval is delegated to the user of SCP.
// The return value is not cached by SCP, as quorum sets are transient.
//
// `nullptr` is a valid return value which cause the statement to be
// considered invalid.
virtual SCPQuorumSetPtr getQSet(Hash const& qSetHash) = 0;
// Users of the SCP library should inherit from SCPDriver and implement the
// virtual methods which are called by the SCP implementation to
// abstract the transport layer used from the implementation of the SCP
// protocol.
// Delegates the emission of an SCPEnvelope to the user of SCP. Envelopes
// should be flooded to the network.
virtual void emitEnvelope(SCPEnvelope const& envelope) = 0;
// methods to hand over the validation and ordering of values and ballots.
// `validateValue` is called on each message received before any processing
// is done. It should be used to filter out values that are not compatible
// with the current state of that node. Invalid values can never
// externalize.
// If the value cannot be validated (node is missing some context) but
// passes
// the validity checks, kMaybeValidValue can be returned. This will cause
// the current slot to be marked as a non validating slot: the local node
// will abstain from emitting its position.
// validation can be *more* restrictive during nomination as needed
// NB: validation levels are ordered
enum ValidationLevel
{
kInvalidValue = 0, // value is invalid for sure
kMaybeValidValue = 1, // value may be valid
kFullyValidatedValue = 2 // value is valid for sure
};
virtual ValidationLevel
validateValue(uint64 slotIndex, Value const& value, bool nomination)
{
return kMaybeValidValue;
}
// `extractValidValue` transforms the value, if possible to a different
// value that the local node would agree to (fully validated).
// This is used during nomination when encountering an invalid value (ie
// validateValue did not return `kFullyValidatedValue` for this value).
// returning nullptr means no valid value could be extracted
virtual ValueWrapperPtr
extractValidValue(uint64 slotIndex, Value const& value)
{
return nullptr;
}
// `getValueString` is used for debugging
// default implementation is the hash of the value
virtual std::string getValueString(Value const& v) const;
// `toStrKey` returns StrKey encoded string representation
virtual std::string toStrKey(NodeID const& pk, bool fullKey = true) const;
// `toShortString` converts to the common name of a key if found
virtual std::string toShortString(NodeID const& pk) const;
// `getHashOf` computes the hash for the given vector of byte vector
virtual Hash
getHashOf(std::vector<xdr::opaque_vec<>> const& vals) const = 0;
// `computeHashNode` is used by the nomination protocol to
// randomize the order of messages between nodes.
virtual uint64 computeHashNode(uint64 slotIndex, Value const& prev,
bool isPriority, int32_t roundNumber,
NodeID const& nodeID);
// `computeValueHash` is used by the nomination protocol to
// randomize the relative order between values.
virtual uint64 computeValueHash(uint64 slotIndex, Value const& prev,
int32_t roundNumber, Value const& value);
// `combineCandidates` computes the composite value based off a list
// of candidate values.
virtual ValueWrapperPtr
combineCandidates(uint64 slotIndex,
ValueWrapperPtrSet const& candidates) = 0;
// `setupTimer`: requests to trigger 'cb' after timeout
// if cb is nullptr, the timer is cancelled
virtual void setupTimer(uint64 slotIndex, int timerID,
std::chrono::milliseconds timeout,
std::function<void()> cb) = 0;
virtual void stopTimer(uint64 slotIndex, int timerID) = 0;
// `computeTimeout` computes a timeout given a round number
// it should be sufficiently large such that nodes in a
// quorum can exchange 4 messages
virtual std::chrono::milliseconds computeTimeout(uint32 roundNumber);
// returns the weight of the node within the qset normalized between
// 0-UINT64_MAX. If `nodeID` is the local node, then set `isLocalNode` to
// `true`.
virtual uint64 getNodeWeight(NodeID const& nodeID, SCPQuorumSet const& qset,
bool isLocalNode) const;
// Inform about events happening within the consensus algorithm.
// `valueExternalized` is called at most once per slot when the slot
// externalize its value.
virtual void
valueExternalized(uint64 slotIndex, Value const& value)
{
}
// ``nominatingValue`` is called every time the local instance nominates
// a new value.
virtual void
nominatingValue(uint64 slotIndex, Value const& value)
{
}
// the following methods are used for monitoring of the SCP subsystem
// most implementation don't really need to do anything with these
// `updatedCandidateValue` is called every time a new candidate value
// is included in the candidate set, the value passed in is
// a composite value
virtual void
updatedCandidateValue(uint64 slotIndex, Value const& value)
{
}
// `startedBallotProtocol` is called when the ballot protocol is started
// (ie attempts to prepare a new ballot)
virtual void
startedBallotProtocol(uint64 slotIndex, SCPBallot const& ballot)
{
}
// `acceptedBallotPrepared` every time a ballot is accepted as prepared
virtual void
acceptedBallotPrepared(uint64 slotIndex, SCPBallot const& ballot)
{
}
// `confirmedBallotPrepared` every time a ballot is confirmed prepared
virtual void
confirmedBallotPrepared(uint64 slotIndex, SCPBallot const& ballot)
{
}
// `acceptedCommit` every time a ballot is accepted commit
virtual void
acceptedCommit(uint64 slotIndex, SCPBallot const& ballot)
{
}
// `ballotDidHearFromQuorum` is called when we received messages related to
// the current `mBallot` from a set of node that is a transitive quorum for
// the local node.
virtual void
ballotDidHearFromQuorum(uint64 slotIndex, SCPBallot const& ballot)
{
}
#ifdef BUILD_TESTS
std::function<uint64(NodeID const&)> mPriorityLookupForTesting;
void
setPriorityLookup(std::function<uint64(NodeID const&)> const& f)
{
mPriorityLookupForTesting = f;
}
#endif
private:
uint64
hashHelper(uint64 slotIndex, Value const& prev,
std::function<void(std::vector<xdr::opaque_vec<>>&)> extra);
};
}