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