rippled
Loading...
Searching...
No Matches
RCLValidations.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2017 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/consensus/RCLValidations.h>
21#include <xrpld/app/ledger/InboundLedger.h>
22#include <xrpld/app/ledger/InboundLedgers.h>
23#include <xrpld/app/ledger/LedgerMaster.h>
24#include <xrpld/app/main/Application.h>
25#include <xrpld/app/misc/NetworkOPs.h>
26#include <xrpld/app/misc/ValidatorList.h>
27#include <xrpld/consensus/LedgerTiming.h>
28#include <xrpld/core/JobQueue.h>
29#include <xrpld/core/TimeKeeper.h>
30#include <xrpld/perflog/PerfLog.h>
31#include <xrpl/basics/Log.h>
32#include <xrpl/basics/StringUtilities.h>
33#include <xrpl/basics/chrono.h>
34#include <memory>
35#include <mutex>
36#include <thread>
37
38namespace ripple {
39
41 : ledgerID_{0}, ledgerSeq_{0}, j_{beast::Journal::getNullSink()}
42{
43}
44
48 : ledgerID_{ledger->info().hash}, ledgerSeq_{ledger->seq()}, j_{j}
49{
50 auto const hashIndex = ledger->read(keylet::skip());
51 if (hashIndex)
52 {
53 XRPL_ASSERT(
54 hashIndex->getFieldU32(sfLastLedgerSequence) == (seq() - 1),
55 "ripple::RCLValidatedLedger::RCLValidatedLedger(Ledger) : valid "
56 "last ledger sequence");
57 ancestors_ = hashIndex->getFieldV256(sfHashes).value();
58 }
59 else
60 JLOG(j_.warn()) << "Ledger " << ledgerSeq_ << ":" << ledgerID_
61 << " missing recent ancestor hashes";
62}
63
64auto
66{
67 return seq() - std::min(seq(), static_cast<Seq>(ancestors_.size()));
68}
69
70auto
72{
73 return ledgerSeq_;
74}
75auto
77{
78 return ledgerID_;
79}
80
81auto
83{
84 if (s >= minSeq() && s <= seq())
85 {
86 if (s == seq())
87 return ledgerID_;
88 Seq const diff = seq() - s;
89 return ancestors_[ancestors_.size() - diff];
90 }
91
92 JLOG(j_.warn()) << "Unable to determine hash of ancestor seq=" << s
93 << " from ledger hash=" << ledgerID_
94 << " seq=" << ledgerSeq_ << " (available: " << minSeq()
95 << "-" << seq() << ")";
96 // Default ID that is less than all others
97 return ID{0};
98}
99
100// Return the sequence number of the earliest possible mismatching ancestor
103{
105
106 // Find overlapping interval for known sequence for the ledgers
107 Seq const lower = std::max(a.minSeq(), b.minSeq());
108 Seq const upper = std::min(a.seq(), b.seq());
109
110 Seq curr = upper;
111 while (curr != Seq{0} && a[curr] != b[curr] && curr >= lower)
112 --curr;
113
114 // If the searchable interval mismatches entirely, then we have to
115 // assume the ledgers mismatch starting post genesis ledger
116 return (curr < lower) ? Seq{1} : (curr + Seq{1});
117}
118
120 : app_(app), j_(j)
121{
122}
123
126{
127 return app_.timeKeeper().closeTime();
128}
129
132{
133 using namespace std::chrono_literals;
134 auto ledger = perf::measureDurationAndLog(
135 [&]() { return app_.getLedgerMaster().getLedgerByHash(hash); },
136 "getLedgerByHash",
137 10ms,
138 j_);
139
140 if (!ledger)
141 {
142 JLOG(j_.debug())
143 << "Need validated ledger for preferred ledger analysis " << hash;
144
145 Application* pApp = &app_;
146
148 jtADVANCE, "getConsensusLedger2", [pApp, hash, this]() {
149 JLOG(j_.debug())
150 << "JOB advanceLedger getConsensusLedger2 started";
153 });
154 return std::nullopt;
155 }
156
157 XRPL_ASSERT(
158 !ledger->open() && ledger->isImmutable(),
159 "ripple::RCLValidationsAdaptor::acquire : valid ledger state");
160 XRPL_ASSERT(
161 ledger->info().hash == hash,
162 "ripple::RCLValidationsAdaptor::acquire : ledger hash match");
163
164 return RCLValidatedLedger(std::move(ledger), j_);
165}
166
167void
169 Application& app,
171 std::string const& source,
172 BypassAccept const bypassAccept,
174{
175 auto const& signingKey = val->getSignerPublic();
176 auto const& hash = val->getLedgerHash();
177 auto const seq = val->getFieldU32(sfLedgerSequence);
178
179 // Ensure validation is marked as trusted if signer currently trusted
180 auto masterKey = app.validators().getTrustedKey(signingKey);
181
182 if (!val->isTrusted() && masterKey)
183 val->setTrusted();
184
185 // If not currently trusted, see if signer is currently listed
186 if (!masterKey)
187 masterKey = app.validators().getListedKey(signingKey);
188
189 auto& validations = app.getValidations();
190
191 // masterKey is seated only if validator is trusted or listed
192 auto const outcome =
193 validations.add(calcNodeID(masterKey.value_or(signingKey)), val);
194
195 if (outcome == ValStatus::current)
196 {
197 if (val->isTrusted())
198 {
199 if (bypassAccept == BypassAccept::yes)
200 {
201 XRPL_ASSERT(
202 j, "ripple::handleNewValidation : journal is available");
203 if (j.has_value())
204 {
205 JLOG(j->trace()) << "Bypassing checkAccept for validation "
206 << val->getLedgerHash();
207 }
208 }
209 else
210 {
211 app.getLedgerMaster().checkAccept(hash, seq);
212 }
213 }
214 return;
215 }
216
217 // Ensure that problematic validations from validators we trust are
218 // logged at the highest possible level.
219 //
220 // One might think that we should more than just log: we ought to also
221 // not relay validations that fail these checks. Alas, and somewhat
222 // counterintuitively, we *especially* want to forward such validations,
223 // so that our peers will also observe them and take independent notice of
224 // such validators, informing their operators.
225 if (auto const ls = val->isTrusted()
226 ? validations.adaptor().journal().error()
227 : validations.adaptor().journal().info();
228 ls.active())
229 {
230 auto const id = [&masterKey, &signingKey]() {
231 auto ret = toBase58(TokenType::NodePublic, signingKey);
232
233 if (masterKey && masterKey != signingKey)
234 ret += ":" + toBase58(TokenType::NodePublic, *masterKey);
235
236 return ret;
237 }();
238
239 if (outcome == ValStatus::conflicting)
240 ls << "Byzantine Behavior Detector: "
241 << (val->isTrusted() ? "trusted " : "untrusted ") << id
242 << ": Conflicting validation for " << seq << "!\n["
243 << val->getSerializer().slice() << "]";
244
245 if (outcome == ValStatus::multiple)
246 ls << "Byzantine Behavior Detector: "
247 << (val->isTrusted() ? "trusted " : "untrusted ") << id
248 << ": Multiple validations for " << seq << "/" << hash << "!\n["
249 << val->getSerializer().slice() << "]";
250 }
251}
252
253} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:59
Stream debug() const
Definition: Journal.h:317
Stream warn() const
Definition: Journal.h:329
virtual RCLValidations & getValidations()=0
virtual TimeKeeper & timeKeeper()=0
virtual JobQueue & getJobQueue()=0
virtual InboundLedgers & getInboundLedgers()=0
virtual ValidatorList & validators()=0
virtual LedgerMaster & getLedgerMaster()=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:166
void checkAccept(std::shared_ptr< Ledger const > const &ledger)
Wraps a ledger instance for use in generic Validations LedgerTrie.
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_
Seq seq() const
The sequence (index) of the ledger.
std::optional< RCLValidatedLedger > acquire(LedgerHash const &id)
Attempt to acquire the ledger with given id from the network.
RCLValidationsAdaptor(Application &app, beast::Journal j)
NetClock::time_point now() const
Current time used to determine if validations are stale.
time_point closeTime() const
Returns the predicted close time, in network time.
Definition: TimeKeeper.h:76
ValStatus add(NodeID const &nodeID, Validation const &val)
Add a new validation.
Definition: Validations.h:623
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
std::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
T max(T... args)
T min(T... args)
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition: Indexes.cpp:172
auto measureDurationAndLog(Func &&func, const std::string &actionDescription, std::chrono::duration< Rep, Period > maxDelay, const beast::Journal &journal)
Definition: PerfLog.h:184
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:106
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.
RCLValidatedLedger::Seq mismatch(RCLValidatedLedger const &a, RCLValidatedLedger const &b)
@ 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.
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:303
@ jtADVANCE
Definition: Job.h:67
T has_value(T... args)