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/ValidatorList.h>
26#include <xrpld/core/JobQueue.h>
27#include <xrpld/core/TimeKeeper.h>
28#include <xrpld/perflog/PerfLog.h>
29
30#include <xrpl/basics/Log.h>
31#include <xrpl/basics/chrono.h>
32
33#include <memory>
34
35namespace ripple {
36
38 : ledgerID_{0}, ledgerSeq_{0}, j_{beast::Journal::getNullSink()}
39{
40}
41
45 : ledgerID_{ledger->info().hash}, ledgerSeq_{ledger->seq()}, j_{j}
46{
47 auto const hashIndex = ledger->read(keylet::skip());
48 if (hashIndex)
49 {
50 XRPL_ASSERT(
51 hashIndex->getFieldU32(sfLastLedgerSequence) == (seq() - 1),
52 "ripple::RCLValidatedLedger::RCLValidatedLedger(Ledger) : valid "
53 "last ledger sequence");
54 ancestors_ = hashIndex->getFieldV256(sfHashes).value();
55 }
56 else
57 JLOG(j_.warn()) << "Ledger " << ledgerSeq_ << ":" << ledgerID_
58 << " missing recent ancestor hashes";
59}
60
61auto
63{
64 return seq() - std::min(seq(), static_cast<Seq>(ancestors_.size()));
65}
66
67auto
69{
70 return ledgerSeq_;
71}
72auto
74{
75 return ledgerID_;
76}
77
78auto
80{
81 if (s >= minSeq() && s <= seq())
82 {
83 if (s == seq())
84 return ledgerID_;
85 Seq const diff = seq() - s;
86 return ancestors_[ancestors_.size() - diff];
87 }
88
89 JLOG(j_.warn()) << "Unable to determine hash of ancestor seq=" << s
90 << " from ledger hash=" << ledgerID_
91 << " seq=" << ledgerSeq_ << " (available: " << minSeq()
92 << "-" << seq() << ")";
93 // Default ID that is less than all others
94 return ID{0};
95}
96
97// Return the sequence number of the earliest possible mismatching ancestor
100{
102
103 // Find overlapping interval for known sequence for the ledgers
104 Seq const lower = std::max(a.minSeq(), b.minSeq());
105 Seq const upper = std::min(a.seq(), b.seq());
106
107 Seq curr = upper;
108 while (curr != Seq{0} && a[curr] != b[curr] && curr >= lower)
109 --curr;
110
111 // If the searchable interval mismatches entirely, then we have to
112 // assume the ledgers mismatch starting post genesis ledger
113 return (curr < lower) ? Seq{1} : (curr + Seq{1});
114}
115
120
123{
124 return app_.timeKeeper().closeTime();
125}
126
129{
130 using namespace std::chrono_literals;
131 auto ledger = perf::measureDurationAndLog(
132 [&]() { return app_.getLedgerMaster().getLedgerByHash(hash); },
133 "getLedgerByHash",
134 10ms,
135 j_);
136
137 if (!ledger)
138 {
139 JLOG(j_.warn())
140 << "Need validated ledger for preferred ledger analysis " << hash;
141
142 Application* pApp = &app_;
143
145 jtADVANCE, "getConsensusLedger2", [pApp, hash, this]() {
146 JLOG(j_.debug())
147 << "JOB advanceLedger getConsensusLedger2 started";
150 });
151 return std::nullopt;
152 }
153
154 XRPL_ASSERT(
155 !ledger->open() && ledger->isImmutable(),
156 "ripple::RCLValidationsAdaptor::acquire : valid ledger state");
157 XRPL_ASSERT(
158 ledger->info().hash == hash,
159 "ripple::RCLValidationsAdaptor::acquire : ledger hash match");
160
161 return RCLValidatedLedger(std::move(ledger), j_);
162}
163
164void
166 Application& app,
168 std::string const& source,
169 BypassAccept const bypassAccept,
171{
172 auto const& signingKey = val->getSignerPublic();
173 auto const& hash = val->getLedgerHash();
174 auto const seq = val->getFieldU32(sfLedgerSequence);
175
176 // Ensure validation is marked as trusted if signer currently trusted
177 auto masterKey = app.validators().getTrustedKey(signingKey);
178
179 if (!val->isTrusted() && masterKey)
180 val->setTrusted();
181
182 // If not currently trusted, see if signer is currently listed
183 if (!masterKey)
184 masterKey = app.validators().getListedKey(signingKey);
185
186 auto& validations = app.getValidations();
187
188 // masterKey is seated only if validator is trusted or listed
189 auto const outcome =
190 validations.add(calcNodeID(masterKey.value_or(signingKey)), val);
191
192 if (outcome == ValStatus::current)
193 {
194 if (val->isTrusted())
195 {
196 if (bypassAccept == BypassAccept::yes)
197 {
198 XRPL_ASSERT(
199 j, "ripple::handleNewValidation : journal is available");
200 if (j.has_value())
201 {
202 JLOG(j->trace()) << "Bypassing checkAccept for validation "
203 << val->getLedgerHash();
204 }
205 }
206 else
207 {
208 app.getLedgerMaster().checkAccept(hash, seq);
209 }
210 }
211 return;
212 }
213
214 // Ensure that problematic validations from validators we trust are
215 // logged at the highest possible level.
216 //
217 // One might think that we should more than just log: we ought to also
218 // not relay validations that fail these checks. Alas, and somewhat
219 // counterintuitively, we *especially* want to forward such validations,
220 // so that our peers will also observe them and take independent notice of
221 // such validators, informing their operators.
222 if (auto const ls = val->isTrusted()
223 ? validations.adaptor().journal().error()
224 : validations.adaptor().journal().info();
225 ls.active())
226 {
227 auto const id = [&masterKey, &signingKey]() {
228 auto ret = toBase58(TokenType::NodePublic, signingKey);
229
230 if (masterKey && masterKey != signingKey)
231 ret += ":" + toBase58(TokenType::NodePublic, *masterKey);
232
233 return ret;
234 }();
235
236 if (outcome == ValStatus::conflicting)
237 ls << "Byzantine Behavior Detector: "
238 << (val->isTrusted() ? "trusted " : "untrusted ") << id
239 << ": Conflicting validation for " << seq << "!\n["
240 << val->getSerializer().slice() << "]";
241
242 if (outcome == ValStatus::multiple)
243 ls << "Byzantine Behavior Detector: "
244 << (val->isTrusted() ? "trusted " : "untrusted ") << id
245 << ": Multiple validations for " << seq << "/" << hash << "!\n["
246 << val->getSerializer().slice() << "]";
247 }
248}
249
250} // namespace ripple
A generic endpoint for log messages.
Definition Journal.h:60
Stream debug() const
Definition Journal.h:328
Stream warn() const
Definition Journal.h:340
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:168
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.
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 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:196
auto measureDurationAndLog(Func &&func, std::string const &actionDescription, std::chrono::duration< Rep, Period > maxDelay, beast::Journal const &journal)
Definition PerfLog.h:187
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
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.
@ jtADVANCE
Definition Job.h:67
T has_value(T... args)