rippled
Loading...
Searching...
No Matches
RCLValidations.cpp
1#include <xrpld/app/consensus/RCLValidations.h>
2#include <xrpld/app/ledger/InboundLedger.h>
3#include <xrpld/app/ledger/InboundLedgers.h>
4#include <xrpld/app/ledger/LedgerMaster.h>
5#include <xrpld/app/main/Application.h>
6#include <xrpld/app/misc/ValidatorList.h>
7#include <xrpld/core/TimeKeeper.h>
8
9#include <xrpl/basics/Log.h>
10#include <xrpl/basics/chrono.h>
11#include <xrpl/core/JobQueue.h>
12#include <xrpl/core/PerfLog.h>
13
14#include <memory>
15
16namespace xrpl {
17
19 : ledgerID_{0}, ledgerSeq_{0}, j_{beast::Journal::getNullSink()}
20{
21}
22
26 : ledgerID_{ledger->header().hash}, ledgerSeq_{ledger->seq()}, j_{j}
27{
28 auto const hashIndex = ledger->read(keylet::skip());
29 if (hashIndex)
30 {
31 XRPL_ASSERT(
32 hashIndex->getFieldU32(sfLastLedgerSequence) == (seq() - 1),
33 "xrpl::RCLValidatedLedger::RCLValidatedLedger(Ledger) : valid "
34 "last ledger sequence");
35 ancestors_ = hashIndex->getFieldV256(sfHashes).value();
36 }
37 else
38 JLOG(j_.warn()) << "Ledger " << ledgerSeq_ << ":" << ledgerID_
39 << " missing recent ancestor hashes";
40}
41
42auto
44{
45 return seq() - std::min(seq(), static_cast<Seq>(ancestors_.size()));
46}
47
48auto
50{
51 return ledgerSeq_;
52}
53auto
55{
56 return ledgerID_;
57}
58
59auto
61{
62 if (s >= minSeq() && s <= seq())
63 {
64 if (s == seq())
65 return ledgerID_;
66 Seq const diff = seq() - s;
67 return ancestors_[ancestors_.size() - diff];
68 }
69
70 JLOG(j_.warn()) << "Unable to determine hash of ancestor seq=" << s
71 << " from ledger hash=" << ledgerID_
72 << " seq=" << ledgerSeq_ << " (available: " << minSeq()
73 << "-" << seq() << ")";
74 // Default ID that is less than all others
75 return ID{0};
76}
77
78// Return the sequence number of the earliest possible mismatching ancestor
81{
83
84 // Find overlapping interval for known sequence for the ledgers
85 Seq const lower = std::max(a.minSeq(), b.minSeq());
86 Seq const upper = std::min(a.seq(), b.seq());
87
88 Seq curr = upper;
89 while (curr != Seq{0} && a[curr] != b[curr] && curr >= lower)
90 --curr;
91
92 // If the searchable interval mismatches entirely, then we have to
93 // assume the ledgers mismatch starting post genesis ledger
94 return (curr < lower) ? Seq{1} : (curr + Seq{1});
95}
96
101
104{
105 return app_.timeKeeper().closeTime();
106}
107
110{
111 using namespace std::chrono_literals;
112 auto ledger = perf::measureDurationAndLog(
113 [&]() { return app_.getLedgerMaster().getLedgerByHash(hash); },
114 "getLedgerByHash",
115 10ms,
116 j_);
117
118 if (!ledger)
119 {
120 JLOG(j_.warn())
121 << "Need validated ledger for preferred ledger analysis " << hash;
122
123 Application* pApp = &app_;
124
125 app_.getJobQueue().addJob(jtADVANCE, "GetConsL2", [pApp, hash, this]() {
126 JLOG(j_.debug()) << "JOB advanceLedger getConsensusLedger2 started";
129 });
130 return std::nullopt;
131 }
132
133 XRPL_ASSERT(
134 !ledger->open() && ledger->isImmutable(),
135 "xrpl::RCLValidationsAdaptor::acquire : valid ledger state");
136 XRPL_ASSERT(
137 ledger->header().hash == hash,
138 "xrpl::RCLValidationsAdaptor::acquire : ledger hash match");
139
140 return RCLValidatedLedger(std::move(ledger), j_);
141}
142
143void
145 Application& app,
147 std::string const& source,
148 BypassAccept const bypassAccept,
150{
151 auto const& signingKey = val->getSignerPublic();
152 auto const& hash = val->getLedgerHash();
153 auto const seq = val->getFieldU32(sfLedgerSequence);
154
155 // Ensure validation is marked as trusted if signer currently trusted
156 auto masterKey = app.validators().getTrustedKey(signingKey);
157
158 if (!val->isTrusted() && masterKey)
159 val->setTrusted();
160
161 // If not currently trusted, see if signer is currently listed
162 if (!masterKey)
163 masterKey = app.validators().getListedKey(signingKey);
164
165 auto& validations = app.getValidations();
166
167 // masterKey is seated only if validator is trusted or listed
168 auto const outcome =
169 validations.add(calcNodeID(masterKey.value_or(signingKey)), val);
170
171 if (outcome == ValStatus::current)
172 {
173 if (val->isTrusted())
174 {
175 if (bypassAccept == BypassAccept::yes)
176 {
177 XRPL_ASSERT(
178 j, "xrpl::handleNewValidation : journal is available");
179 if (j.has_value())
180 {
181 JLOG(j->trace()) << "Bypassing checkAccept for validation "
182 << val->getLedgerHash();
183 }
184 }
185 else
186 {
187 app.getLedgerMaster().checkAccept(hash, seq);
188 }
189 }
190 return;
191 }
192
193 // Ensure that problematic validations from validators we trust are
194 // logged at the highest possible level.
195 //
196 // One might think that we should more than just log: we ought to also
197 // not relay validations that fail these checks. Alas, and somewhat
198 // counterintuitively, we *especially* want to forward such validations,
199 // so that our peers will also observe them and take independent notice of
200 // such validators, informing their operators.
201 if (auto const ls = val->isTrusted()
202 ? validations.adaptor().journal().error()
203 : validations.adaptor().journal().info();
204 ls.active())
205 {
206 auto const id = [&masterKey, &signingKey]() {
207 auto ret = toBase58(TokenType::NodePublic, signingKey);
208
209 if (masterKey && masterKey != signingKey)
210 ret += ":" + toBase58(TokenType::NodePublic, *masterKey);
211
212 return ret;
213 }();
214
215 if (outcome == ValStatus::conflicting)
216 ls << "Byzantine Behavior Detector: "
217 << (val->isTrusted() ? "trusted " : "untrusted ") << id
218 << ": Conflicting validation for " << seq << "!\n["
219 << val->getSerializer().slice() << "]";
220
221 if (outcome == ValStatus::multiple)
222 ls << "Byzantine Behavior Detector: "
223 << (val->isTrusted() ? "trusted " : "untrusted ") << id
224 << ": Multiple validations for " << seq << "/" << hash << "!\n["
225 << val->getSerializer().slice() << "]";
226 }
227}
228
229} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:41
Stream debug() const
Definition Journal.h:309
Stream warn() const
Definition Journal.h:321
virtual InboundLedgers & getInboundLedgers()=0
virtual LedgerMaster & getLedgerMaster()=0
virtual TimeKeeper & timeKeeper()=0
virtual RCLValidations & getValidations()=0
virtual JobQueue & getJobQueue()=0
virtual ValidatorList & validators()=0
virtual void acquireAsync(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason reason)=0
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition JobQueue.h:148
void checkAccept(std::shared_ptr< Ledger const > const &ledger)
Wraps a ledger instance for use in generic Validations LedgerTrie.
Seq seq() const
The sequence (index) of the ledger.
ID id() const
The ID (hash) of the ledger.
ID operator[](Seq const &s) const
Lookup the ID of the ancestor ledger.
std::vector< uint256 > ancestors_
std::optional< RCLValidatedLedger > acquire(LedgerHash const &id)
Attempt to acquire the ledger with given id from the network.
NetClock::time_point now() const
Current time used to determine if validations are stale.
RCLValidationsAdaptor(Application &app, beast::Journal j)
time_point closeTime() const
Returns the predicted close time, in network time.
Definition TimeKeeper.h:57
ValStatus add(NodeID const &nodeID, Validation const &val)
Add a new validation.
std::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
T is_same_v
T max(T... args)
T min(T... args)
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition Indexes.cpp:178
auto measureDurationAndLog(Func &&func, std::string const &actionDescription, std::chrono::duration< Rep, Period > maxDelay, beast::Journal const &journal)
Definition PerfLog.h:167
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
@ current
This was a new validation and was added.
@ conflicting
Multiple validations by a validator for different ledgers.
@ multiple
Multiple validations by a validator for the same ledger.
@ jtADVANCE
Definition Job.h:47
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
RCLValidatedLedger::Seq mismatch(RCLValidatedLedger const &a, RCLValidatedLedger const &b)
void handleNewValidation(Application &app, std::shared_ptr< STValidation > const &val, std::string const &source, BypassAccept const bypassAccept, std::optional< beast::Journal > j)
Handle a new validation.
T has_value(T... args)