rippled
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 <ripple/app/consensus/RCLValidations.h>
21 #include <ripple/app/ledger/InboundLedger.h>
22 #include <ripple/app/ledger/InboundLedgers.h>
23 #include <ripple/app/ledger/LedgerMaster.h>
24 #include <ripple/app/main/Application.h>
25 #include <ripple/app/misc/NetworkOPs.h>
26 #include <ripple/app/misc/ValidatorList.h>
27 #include <ripple/basics/Log.h>
28 #include <ripple/basics/StringUtilities.h>
29 #include <ripple/basics/chrono.h>
30 #include <ripple/consensus/LedgerTiming.h>
31 #include <ripple/core/JobQueue.h>
32 #include <ripple/core/TimeKeeper.h>
33 #include <memory>
34 #include <mutex>
35 #include <thread>
36 
37 namespace ripple {
38 
40  : ledgerID_{0}, ledgerSeq_{0}, j_{beast::Journal::getNullSink()}
41 {
42 }
43 
45  std::shared_ptr<Ledger const> const& ledger,
47  : ledgerID_{ledger->info().hash}, ledgerSeq_{ledger->seq()}, j_{j}
48 {
49  auto const hashIndex = ledger->read(keylet::skip());
50  if (hashIndex)
51  {
52  assert(hashIndex->getFieldU32(sfLastLedgerSequence) == (seq() - 1));
53  ancestors_ = hashIndex->getFieldV256(sfHashes).value();
54  }
55  else
56  JLOG(j_.warn()) << "Ledger " << ledgerSeq_ << ":" << ledgerID_
57  << " missing recent ancestor hashes";
58 }
59 
60 auto
62 {
63  return seq() - std::min(seq(), static_cast<Seq>(ancestors_.size()));
64 }
65 
66 auto
68 {
69  return ledgerSeq_;
70 }
71 auto
73 {
74  return ledgerID_;
75 }
76 
77 auto
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_;
91  // Default ID that is less than all others
92  return ID{0};
93 }
94 
95 // Return the sequence number of the earliest possible mismatching ancestor
98 {
99  using Seq = RCLValidatedLedger::Seq;
100 
101  // Find overlapping interval for known sequence for the ledgers
102  Seq const lower = std::max(a.minSeq(), b.minSeq());
103  Seq const upper = std::min(a.seq(), b.seq());
104 
105  Seq curr = upper;
106  while (curr != Seq{0} && a[curr] != b[curr] && curr >= lower)
107  --curr;
108 
109  // If the searchable interval mismatches entirely, then we have to
110  // assume the ledgers mismatch starting post genesis ledger
111  return (curr < lower) ? Seq{1} : (curr + Seq{1});
112 }
113 
115  : app_(app), j_(j)
116 {
117 }
118 
121 {
122  return app_.timeKeeper().closeTime();
123 }
124 
127 {
128  auto ledger = app_.getLedgerMaster().getLedgerByHash(hash);
129  if (!ledger)
130  {
131  JLOG(j_.debug())
132  << "Need validated ledger for preferred ledger analysis " << hash;
133 
134  Application* pApp = &app_;
135 
137  jtADVANCE, "getConsensusLedger", [pApp, hash](Job&) {
138  pApp->getInboundLedgers().acquire(
140  });
141  return std::nullopt;
142  }
143 
144  assert(!ledger->open() && ledger->isImmutable());
145  assert(ledger->info().hash == hash);
146 
147  return RCLValidatedLedger(std::move(ledger), j_);
148 }
149 
150 void
152  Application& app,
154  std::string const& source)
155 {
156  auto const& signingKey = val->getSignerPublic();
157  auto const& hash = val->getLedgerHash();
158  auto const seq = val->getFieldU32(sfLedgerSequence);
159 
160  // Ensure validation is marked as trusted if signer currently trusted
161  auto masterKey = app.validators().getTrustedKey(signingKey);
162 
163  if (!val->isTrusted() && masterKey)
164  val->setTrusted();
165 
166  // If not currently trusted, see if signer is currently listed
167  if (!masterKey)
168  masterKey = app.validators().getListedKey(signingKey);
169 
170  auto& validations = app.getValidations();
171 
172  // masterKey is seated only if validator is trusted or listed
173  auto const outcome =
174  validations.add(calcNodeID(masterKey.value_or(signingKey)), val);
175 
176  if (outcome == ValStatus::current)
177  {
178  if (val->isTrusted())
179  app.getLedgerMaster().checkAccept(hash, seq);
180  return;
181  }
182 
183  // Ensure that problematic validations from validators we trust are
184  // logged at the highest possible level.
185  //
186  // One might think that we should more than just log: we ought to also
187  // not relay validations that fail these checks. Alas, and somewhat
188  // counterintuitively, we *especially* want to forward such validations,
189  // so that our peers will also observe them and take independent notice of
190  // such validators, informing their operators.
191  if (auto const ls = val->isTrusted()
192  ? validations.adaptor().journal().fatal()
193  : validations.adaptor().journal().warn();
194  ls.active())
195  {
196  auto const id = [&masterKey, &signingKey]() {
197  auto ret = toBase58(TokenType::NodePublic, signingKey);
198 
199  if (masterKey && masterKey != signingKey)
200  ret += ":" + toBase58(TokenType::NodePublic, *masterKey);
201 
202  return ret;
203  }();
204 
205  if (outcome == ValStatus::conflicting)
206  ls << "Byzantine Behavior Detector: "
207  << (val->isTrusted() ? "trusted " : "untrusted ") << id
208  << ": Conflicting validation for " << seq << "!\n["
209  << val->getSerializer().slice() << "]";
210 
211  if (outcome == ValStatus::multiple)
212  ls << "Byzantine Behavior Detector: "
213  << (val->isTrusted() ? "trusted " : "untrusted ") << id
214  << ": Multiple validations for " << seq << "/" << hash << "!\n["
215  << val->getSerializer().slice() << "]";
216  }
217 }
218 
219 } // namespace ripple
ripple::mismatch
RCLValidatedLedger::Seq mismatch(RCLValidatedLedger const &a, RCLValidatedLedger const &b)
Definition: RCLValidations.cpp:97
ripple::Application
Definition: Application.h:103
std::string
STL class.
ripple::InboundLedger::Reason::CONSENSUS
@ CONSENSUS
std::shared_ptr
STL class.
ripple::calcNodeID
NodeID calcNodeID(PublicKey const &pk)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:299
ripple::sfLedgerSequence
const SF_UINT32 sfLedgerSequence
ripple::RCLValidatedLedger::minSeq
Seq minSeq() const
Definition: RCLValidations.cpp:61
ripple::RCLValidatedLedger::MakeGenesis
Definition: RCLValidations.h:158
ripple::RCLValidatedLedger::ledgerID_
ID ledgerID_
Definition: RCLValidations.h:194
ripple::STValidation::getLedgerHash
uint256 getLedgerHash() const
Definition: STValidation.cpp:65
ripple::RCLValidatedLedger::ancestors_
std::vector< uint256 > ancestors_
Definition: RCLValidations.h:196
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
ripple::keylet::skip
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition: Indexes.cpp:142
ripple::STObject::getSerializer
Serializer getSerializer() const
Definition: STObject.h:367
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::SBoxCmp::diff
@ diff
ripple::LedgerMaster::getLedgerByHash
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
Definition: LedgerMaster.cpp:1803
ripple::RCLValidationsAdaptor::now
NetClock::time_point now() const
Current time used to determine if validations are stale.
Definition: RCLValidations.cpp:120
ripple::JobQueue::addJob
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition: JobQueue.h:165
ripple::RCLValidatedLedger::id
ID id() const
The ID (hash) of the ledger.
Definition: RCLValidations.cpp:72
ripple::Application::timeKeeper
virtual TimeKeeper & timeKeeper()=0
ripple::RCLValidationsAdaptor::RCLValidationsAdaptor
RCLValidationsAdaptor(Application &app, beast::Journal j)
Definition: RCLValidations.cpp:114
beast::Journal::getNullSink
static Sink & getNullSink()
Returns a Sink which does nothing.
Definition: beast_Journal.cpp:72
ripple::RCLValidatedLedger
Wraps a ledger instance for use in generic Validations LedgerTrie.
Definition: RCLValidations.h:153
ripple::STValidation::isTrusted
bool isTrusted() const noexcept
Definition: STValidation.h:182
ripple::STValidation::getSignerPublic
PublicKey const & getSignerPublic() const noexcept
Definition: STValidation.h:164
ripple::Application::getInboundLedgers
virtual InboundLedgers & getInboundLedgers()=0
ripple::ValidatorList::getTrustedKey
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
Definition: ValidatorList.cpp:1396
ripple::RCLValidatedLedger::seq
Seq seq() const
The sequence (index) of the ledger.
Definition: RCLValidations.cpp:67
ripple::base_uint< 256 >
ripple::RCLValidatedLedger::RCLValidatedLedger
RCLValidatedLedger(MakeGenesis)
Definition: RCLValidations.cpp:39
thread
ripple::Validations::add
ValStatus add(NodeID const &nodeID, Validation const &val)
Add a new validation.
Definition: Validations.h:620
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::ValidatorList::getListedKey
std::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
Definition: ValidatorList.cpp:1374
ripple::RCLValidationsAdaptor::j_
beast::Journal j_
Definition: RCLValidations.h:232
ripple::RCLValidationsAdaptor::acquire
std::optional< RCLValidatedLedger > acquire(LedgerHash const &id)
Attempt to acquire the ledger with given id from the network.
Definition: RCLValidations.cpp:126
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:63
std::chrono::time_point
ripple::RCLValidatedLedger::ledgerSeq_
Seq ledgerSeq_
Definition: RCLValidations.h:195
ripple::RCLValidatedLedger::operator[]
ID operator[](Seq const &s) const
Lookup the ID of the ancestor ledger.
Definition: RCLValidations.cpp:78
ripple::ValStatus::multiple
@ multiple
Multiple validations by a validator for the same ledger.
ripple::TimeKeeper::closeTime
virtual time_point closeTime() const =0
Returns the close time, in network time.
ripple::ValStatus::current
@ current
This was a new validation and was added.
ripple::Job
Definition: Job.h:85
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::Application::getValidations
virtual RCLValidations & getValidations()=0
std::uint32_t
memory
ripple::LedgerMaster::checkAccept
void checkAccept(std::shared_ptr< Ledger const > const &ledger)
Definition: LedgerMaster.cpp:1032
ripple::Application::validators
virtual ValidatorList & validators()=0
std::min
T min(T... args)
ripple::sfHashes
const SF_VECTOR256 sfHashes
ripple::ValStatus::conflicting
@ conflicting
Multiple validations by a validator for different ledgers.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::ReadView::seq
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition: ReadView.h:260
ripple::RCLValidationsAdaptor::app_
Application & app_
Definition: RCLValidations.h:231
ripple::STValidation::setTrusted
void setTrusted()
Definition: STValidation.h:191
ripple::TokenType::NodePublic
@ NodePublic
std::optional
mutex
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::jtADVANCE
@ jtADVANCE
Definition: Job.h:56
std::max
T max(T... args)
ripple::STObject::getFieldU32
std::uint32_t getFieldU32(SField const &field) const
Definition: STObject.cpp:532
ripple::sfLastLedgerSequence
const SF_UINT32 sfLastLedgerSequence
ripple::handleNewValidation
void handleNewValidation(Application &app, std::shared_ptr< STValidation > const &val, std::string const &source)
Handle a new validation.
Definition: RCLValidations.cpp:151
ripple::RCLValidatedLedger::Seq
LedgerIndex Seq
Definition: RCLValidations.h:157