forked from stellar/stellar-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHerderSCPDriver.h
230 lines (184 loc) · 7.06 KB
/
HerderSCPDriver.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
#pragma once
// Copyright 2017 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 "herder/Herder.h"
#include "herder/TxSetFrame.h"
#include "scp/SCPDriver.h"
#include "xdr/Stellar-ledger.h"
namespace medida
{
class Counter;
class Meter;
class Timer;
class Histogram;
}
namespace stellar
{
class Application;
class HerderImpl;
class LedgerManager;
class PendingEnvelopes;
class SCP;
class Upgrades;
class VirtualTimer;
struct StellarValue;
struct SCPEnvelope;
class HerderSCPDriver : public SCPDriver
{
public:
struct ConsensusData
{
uint64_t mConsensusIndex;
StellarValue mConsensusValue;
ConsensusData(uint64_t index, StellarValue const& b)
: mConsensusIndex(index), mConsensusValue(b)
{
}
};
HerderSCPDriver(Application& app, HerderImpl& herder,
Upgrades const& upgrades,
PendingEnvelopes& pendingEnvelopes);
~HerderSCPDriver();
void bootstrap();
void lostSync();
Herder::State getState() const;
ConsensusData*
trackingSCP() const
{
return mTrackingSCP.get();
}
ConsensusData*
lastTrackingSCP() const
{
return mLastTrackingSCP.get();
}
void restoreSCPState(uint64_t index, StellarValue const& value);
// the ledger index that was last externalized
uint32
lastConsensusLedgerIndex() const
{
assert(mTrackingSCP->mConsensusIndex <= UINT32_MAX);
return static_cast<uint32>(mTrackingSCP->mConsensusIndex);
}
// the ledger index that we expect to externalize next
uint32
nextConsensusLedgerIndex() const
{
return lastConsensusLedgerIndex() + 1;
}
SCP&
getSCP()
{
return mSCP;
}
void recordSCPExecutionMetrics(uint64_t slotIndex);
void recordSCPEvent(uint64_t slotIndex, bool isNomination);
// envelope handling
void signEnvelope(SCPEnvelope& envelope) override;
void emitEnvelope(SCPEnvelope const& envelope) override;
// value validation
SCPDriver::ValidationLevel validateValue(uint64_t slotIndex,
Value const& value,
bool nomination) override;
Value extractValidValue(uint64_t slotIndex, Value const& value) override;
// value marshaling
std::string toShortString(PublicKey const& pk) const override;
std::string getValueString(Value const& v) const override;
// timer handling
void setupTimer(uint64_t slotIndex, int timerID,
std::chrono::milliseconds timeout,
std::function<void()> cb) override;
// core SCP
Value combineCandidates(uint64_t slotIndex,
std::set<Value> const& candidates) override;
void valueExternalized(uint64_t slotIndex, Value const& value) override;
// Submit a value to consider for slotIndex
// previousValue is the value from slotIndex-1
void nominate(uint64_t slotIndex, StellarValue const& value,
TxSetFramePtr proposedSet, StellarValue const& previousValue);
SCPQuorumSetPtr getQSet(Hash const& qSetHash) override;
// listeners
void ballotDidHearFromQuorum(uint64_t slotIndex,
SCPBallot const& ballot) override;
void nominatingValue(uint64_t slotIndex, Value const& value) override;
void updatedCandidateValue(uint64_t slotIndex, Value const& value) override;
void startedBallotProtocol(uint64_t slotIndex,
SCPBallot const& ballot) override;
void acceptedBallotPrepared(uint64_t slotIndex,
SCPBallot const& ballot) override;
void confirmedBallotPrepared(uint64_t slotIndex,
SCPBallot const& ballot) override;
void acceptedCommit(uint64_t slotIndex, SCPBallot const& ballot) override;
optional<VirtualClock::time_point> getPrepareStart(uint64_t slotIndex);
// converts a Value into a StellarValue
// returns false on error
bool toStellarValue(Value const& v, StellarValue& sv);
// validate close time as much as possible
bool checkCloseTime(uint64_t slotIndex, uint64_t lastCloseTime,
StellarValue const& b) const;
private:
Application& mApp;
HerderImpl& mHerder;
LedgerManager& mLedgerManager;
Upgrades const& mUpgrades;
PendingEnvelopes& mPendingEnvelopes;
SCP mSCP;
struct SCPMetrics
{
medida::Meter& mEnvelopeSign;
medida::Meter& mValueValid;
medida::Meter& mValueInvalid;
// listeners
medida::Meter& mCombinedCandidates;
// Timers for nomination and ballot protocols
medida::Timer& mNominateToPrepare;
medida::Timer& mPrepareToExternalize;
SCPMetrics(Application& app);
};
SCPMetrics mSCPMetrics;
// Nomination timeouts per ledger
medida::Histogram& mNominateTimeout;
// Prepare timeouts per ledger
medida::Histogram& mPrepareTimeout;
struct SCPTiming
{
optional<VirtualClock::time_point> mNominationStart;
optional<VirtualClock::time_point> mPrepareStart;
// Nomination timeouts before first prepare
int64_t mNominationTimeoutCount{0};
// Prepare timeouts before externalize
int64_t mPrepareTimeoutCount{0};
};
// Map of time points for each slot to measure key protocol metrics:
// * nomination to first prepare
// * first prepare to externalize
std::map<uint64_t, SCPTiming> mSCPExecutionTimes;
uint32_t mLedgerSeqNominating;
Value mCurrentValue;
// timers used by SCP
// indexed by slotIndex, timerID
std::map<uint64_t, std::map<int, std::unique_ptr<VirtualTimer>>> mSCPTimers;
// if the local instance is tracking the current state of SCP
// herder keeps track of the consensus index and ballot
// when not set, it just means that herder will try to snap to any slot that
// reached consensus
// on startup, this can be set to a value persisted from the database
std::unique_ptr<ConsensusData> mTrackingSCP;
// when losing track of consensus, we remember the consensus value so that
// we can ignore older ledgers (as we potentially receive old messages)
// it only tracks actual consensus values (learned when externalizing)
std::unique_ptr<ConsensusData> mLastTrackingSCP;
void stateChanged();
SCPDriver::ValidationLevel validateValueHelper(uint64_t slotIndex,
StellarValue const& sv,
bool nomination) const;
// returns true if the local instance is in a state compatible with
// this slot
bool isSlotCompatibleWithCurrentState(uint64_t slotIndex) const;
void logQuorumInformation(uint64_t index);
void clearSCPExecutionEvents();
void timerCallbackWrapper(uint64_t slotIndex, int timerID,
std::function<void()> cb);
};
}