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_ << " (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 {
100  using Seq = RCLValidatedLedger::Seq;
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  auto ledger = app_.getLedgerMaster().getLedgerByHash(hash);
130  if (!ledger)
131  {
132  JLOG(j_.debug())
133  << "Need validated ledger for preferred ledger analysis " << hash;
134 
135  Application* pApp = &app_;
136 
138  jtADVANCE, "getConsensusLedger", [pApp, hash]() {
139  pApp->getInboundLedgers().acquire(
141  });
142  return std::nullopt;
143  }
144 
145  assert(!ledger->open() && ledger->isImmutable());
146  assert(ledger->info().hash == hash);
147 
148  return RCLValidatedLedger(std::move(ledger), j_);
149 }
150 
151 void
153  Application& app,
155  std::string const& source)
156 {
157  auto const& signingKey = val->getSignerPublic();
158  auto const& hash = val->getLedgerHash();
159  auto const seq = val->getFieldU32(sfLedgerSequence);
160 
161  // Ensure validation is marked as trusted if signer currently trusted
162  auto masterKey = app.validators().getTrustedKey(signingKey);
163 
164  if (!val->isTrusted() && masterKey)
165  val->setTrusted();
166 
167  // If not currently trusted, see if signer is currently listed
168  if (!masterKey)
169  masterKey = app.validators().getListedKey(signingKey);
170 
171  auto& validations = app.getValidations();
172 
173  // masterKey is seated only if validator is trusted or listed
174  auto const outcome =
175  validations.add(calcNodeID(masterKey.value_or(signingKey)), val);
176 
177  if (outcome == ValStatus::current)
178  {
179  if (val->isTrusted())
180  app.getLedgerMaster().checkAccept(hash, seq);
181  return;
182  }
183 
184  // Ensure that problematic validations from validators we trust are
185  // logged at the highest possible level.
186  //
187  // One might think that we should more than just log: we ought to also
188  // not relay validations that fail these checks. Alas, and somewhat
189  // counterintuitively, we *especially* want to forward such validations,
190  // so that our peers will also observe them and take independent notice of
191  // such validators, informing their operators.
192  if (auto const ls = val->isTrusted()
193  ? validations.adaptor().journal().error()
194  : validations.adaptor().journal().info();
195  ls.active())
196  {
197  auto const id = [&masterKey, &signingKey]() {
198  auto ret = toBase58(TokenType::NodePublic, signingKey);
199 
200  if (masterKey && masterKey != signingKey)
201  ret += ":" + toBase58(TokenType::NodePublic, *masterKey);
202 
203  return ret;
204  }();
205 
206  if (outcome == ValStatus::conflicting)
207  ls << "Byzantine Behavior Detector: "
208  << (val->isTrusted() ? "trusted " : "untrusted ") << id
209  << ": Conflicting validation for " << seq << "!\n["
210  << val->getSerializer().slice() << "]";
211 
212  if (outcome == ValStatus::multiple)
213  ls << "Byzantine Behavior Detector: "
214  << (val->isTrusted() ? "trusted " : "untrusted ") << id
215  << ": Multiple validations for " << seq << "/" << hash << "!\n["
216  << val->getSerializer().slice() << "]";
217  }
218 }
219 
220 } // namespace ripple
ripple::mismatch
RCLValidatedLedger::Seq mismatch(RCLValidatedLedger const &a, RCLValidatedLedger const &b)
Definition: RCLValidations.cpp:98
ripple::Application
Definition: Application.h:115
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:303
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:82
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:104
ripple::keylet::skip
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition: Indexes.cpp:145
ripple::STObject::getSerializer
Serializer getSerializer() const
Definition: STObject.h:898
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::LedgerMaster::getLedgerByHash
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
Definition: LedgerMaster.cpp:1854
ripple::RCLValidationsAdaptor::now
NetClock::time_point now() const
Current time used to determine if validations are stale.
Definition: RCLValidations.cpp:121
ripple::JobQueue::addJob
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition: JobQueue.h:166
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:115
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:245
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
ripple::STValidation::getSignerPublic
PublicKey const & getSignerPublic() const noexcept
Definition: STValidation.h:233
thread
ripple::Validations::add
ValStatus add(NodeID const &nodeID, Validation const &val)
Add a new validation.
Definition: Validations.h:622
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:127
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.
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:1042
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:193
ripple::RCLValidationsAdaptor::app_
Application & app_
Definition: RCLValidations.h:231
ripple::STValidation::setTrusted
void setTrusted()
Definition: STValidation.h:251
ripple::TokenType::NodePublic
@ NodePublic
std::optional
mutex
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::jtADVANCE
@ jtADVANCE
Definition: Job.h:68
std::max
T max(T... args)
ripple::STObject::getFieldU32
std::uint32_t getFieldU32(SField const &field) const
Definition: STObject.cpp:559
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:152
ripple::RCLValidatedLedger::Seq
LedgerIndex Seq
Definition: RCLValidations.h:157