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/DatabaseCon.h>
32 #include <ripple/core/JobQueue.h>
33 #include <ripple/core/TimeKeeper.h>
34 #include <memory>
35 #include <mutex>
36 #include <thread>
37 
38 namespace ripple {
39 
41  : ledgerID_{0}, ledgerSeq_{0}, j_{beast::Journal::getNullSink()}
42 {
43 }
44 
46  std::shared_ptr<Ledger const> const& ledger,
48  : ledgerID_{ledger->info().hash}, ledgerSeq_{ledger->seq()}, j_{j}
49 {
50  auto const hashIndex = ledger->read(keylet::skip());
51  if (hashIndex)
52  {
53  assert(hashIndex->getFieldU32(sfLastLedgerSequence) == (seq() - 1));
54  ancestors_ = hashIndex->getFieldV256(sfHashes).value();
55  }
56  else
57  JLOG(j_.warn()) << "Ledger " << ledgerSeq_ << ":" << ledgerID_
58  << " missing recent ancestor hashes";
59 }
60 
61 auto
63 {
64  return seq() - std::min(seq(), static_cast<Seq>(ancestors_.size()));
65 }
66 
67 auto
69 {
70  return ledgerSeq_;
71 }
72 auto
74 {
75  return ledgerID_;
76 }
77 
78 auto
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_;
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 
126 boost::optional<RCLValidatedLedger>
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](Job&) {
139  pApp->getInboundLedgers().acquire(
141  });
142  return boost::none;
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  PublicKey const& signingKey = val->getSignerPublic();
158  uint256 const& hash = val->getLedgerHash();
159 
160  // Ensure validation is marked as trusted if signer currently trusted
161  auto masterKey = app.validators().getTrustedKey(signingKey);
162  if (!val->isTrusted() && masterKey)
163  val->setTrusted();
164 
165  // If not currently trusted, see if signer is currently listed
166  if (!masterKey)
167  masterKey = app.validators().getListedKey(signingKey);
168 
169  RCLValidations& validations = app.getValidations();
170  beast::Journal const j = validations.adaptor().journal();
171 
172  auto dmp = [&](beast::Journal::Stream s, std::string const& msg) {
173  std::string id = toBase58(TokenType::NodePublic, signingKey);
174 
175  if (masterKey)
176  id += ":" + toBase58(TokenType::NodePublic, *masterKey);
177 
178  s << (val->isTrusted() ? "trusted" : "untrusted") << " "
179  << (val->isFull() ? "full" : "partial") << " validation: " << hash
180  << " from " << id << " via " << source << ": " << msg << "\n"
181  << " [" << val->getSerializer().slice() << "]";
182  };
183 
184  // masterKey is seated only if validator is trusted or listed
185  if (masterKey)
186  {
187  ValStatus const outcome = validations.add(calcNodeID(*masterKey), val);
188  auto const seq = val->getFieldU32(sfLedgerSequence);
189 
190  if (j.debug())
191  dmp(j.debug(), to_string(outcome));
192 
193  // One might think that we would not wish to relay validations that
194  // fail these checks. Somewhat counterintuitively, we actually want
195  // to do it for validations that we receive but deem suspicious, so
196  // that our peers will also observe them and realize they're bad.
197  if (outcome == ValStatus::conflicting && j.warn())
198  {
199  dmp(j.warn(),
200  "conflicting validations issued for " + to_string(seq) +
201  " (likely from a Byzantine validator)");
202  }
203 
204  if (outcome == ValStatus::multiple && j.warn())
205  {
206  dmp(j.warn(),
207  "multiple validations issued for " + to_string(seq) +
208  " (multiple validators operating with the same key?)");
209  }
210 
211  if (val->isTrusted() && outcome == ValStatus::current)
212  app.getLedgerMaster().checkAccept(hash, seq);
213  }
214  else
215  {
216  JLOG(j.debug()) << "Val for " << hash << " from "
217  << toBase58(TokenType::NodePublic, signingKey)
218  << " not added UNlisted";
219  }
220 }
221 
222 } // namespace ripple
ripple::ValidatorList::getListedKey
boost::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
Definition: ValidatorList.cpp:1376
ripple::mismatch
RCLValidatedLedger::Seq mismatch(RCLValidatedLedger const &a, RCLValidatedLedger const &b)
Definition: RCLValidations.cpp:98
ripple::Application
Definition: Application.h:101
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::STValidation::isTrusted
bool isTrusted() const
Definition: STValidation.h:176
ripple::sfLedgerSequence
const SF_UINT32 sfLedgerSequence
ripple::STValidation::isFull
bool isFull() const
Definition: STValidation.cpp:114
ripple::RCLValidatedLedger::minSeq
Seq minSeq() const
Definition: RCLValidations.cpp:62
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:63
ripple::RCLValidatedLedger::ancestors_
std::vector< uint256 > ancestors_
Definition: RCLValidations.h:196
ripple::RCLValidationsAdaptor::acquire
boost::optional< RCLValidatedLedger > acquire(LedgerHash const &id)
Attempt to acquire the ledger with given id from the network.
Definition: RCLValidations.cpp:127
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:146
ripple::STObject::getSerializer
Serializer getSerializer() const
Definition: STObject.h:367
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::ValStatus
ValStatus
Status of newly received validation.
Definition: Validations.h:164
ripple::SBoxCmp::diff
@ diff
ripple::LedgerMaster::getLedgerByHash
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
Definition: LedgerMaster.cpp:1776
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::RCLValidationsAdaptor::journal
beast::Journal journal() const
Definition: RCLValidations.h:225
ripple::RCLValidatedLedger::id
ID id() const
The ID (hash) of the ledger.
Definition: RCLValidations.cpp:73
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:45
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::Application::getInboundLedgers
virtual InboundLedgers & getInboundLedgers()=0
ripple::RCLValidatedLedger::seq
Seq seq() const
The sequence (index) of the ledger.
Definition: RCLValidations.cpp:68
ripple::ValidatorList::getTrustedKey
boost::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
Definition: ValidatorList.cpp:1398
ripple::base_uint< 256 >
ripple::RCLValidatedLedger::RCLValidatedLedger
RCLValidatedLedger(MakeGenesis)
Definition: RCLValidations.cpp:40
thread
ripple::Validations::add
ValStatus add(NodeID const &nodeID, Validation const &val)
Add a new validation.
Definition: Validations.h:614
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::RCLValidationsAdaptor::j_
beast::Journal j_
Definition: RCLValidations.h:232
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:63
beast::Journal::Stream
Provide a light-weight way to check active() before string formatting.
Definition: Journal.h:194
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:79
ripple::ValStatus::multiple
@ multiple
Multiple validations for the same ledger from multiple validators.
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:82
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:1037
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 for different ledgers by a single validator.
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:185
ripple::TokenType::NodePublic
@ NodePublic
ripple::Validations< RCLValidationsAdaptor >
mutex
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::STValidation::getSignerPublic
PublicKey getSignerPublic() const
Definition: STValidation.cpp:108
ripple::jtADVANCE
@ jtADVANCE
Definition: Job.h:53
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::Validations::adaptor
Adaptor const & adaptor() const
Return the adaptor instance.
Definition: Validations.h:578
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