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 bool
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  bool shouldRelay = false;
170  RCLValidations& validations = app.getValidations();
171  beast::Journal const j = validations.adaptor().journal();
172 
173  auto dmp = [&](beast::Journal::Stream s, std::string const& msg) {
174  std::string id = toBase58(TokenType::NodePublic, signingKey);
175 
176  if (masterKey)
177  id += ":" + toBase58(TokenType::NodePublic, *masterKey);
178 
179  s << (val->isTrusted() ? "trusted" : "untrusted") << " "
180  << (val->isFull() ? "full" : "partial") << " validation: " << hash
181  << " from " << id << " via " << source << ": " << msg << "\n"
182  << " [" << val->getSerializer().slice() << "]";
183  };
184 
185  if (!val->isFieldPresent(sfLedgerSequence))
186  {
187  if (j.error())
188  dmp(j.error(), "missing ledger sequence field");
189  return false;
190  }
191 
192  // masterKey is seated only if validator is trusted or listed
193  if (masterKey)
194  {
195  ValStatus const outcome = validations.add(calcNodeID(*masterKey), val);
196 
197  if (j.debug())
198  dmp(j.debug(), to_string(outcome));
199 
200  if (outcome == ValStatus::conflicting && j.warn())
201  {
202  auto const seq = val->getFieldU32(sfLedgerSequence);
203  dmp(j.warn(),
204  "conflicting validations issued for " + to_string(seq) +
205  " (likely from a Byzantine validator)");
206  }
207 
208  if (outcome == ValStatus::multiple && j.warn())
209  {
210  auto const seq = val->getFieldU32(sfLedgerSequence);
211  dmp(j.warn(),
212  "multiple validations issued for " + to_string(seq) +
213  " (multiple validators operating with the same key?)");
214  }
215 
216  if (outcome == ValStatus::badSeq && j.warn())
217  {
218  auto const seq = val->getFieldU32(sfLedgerSequence);
219  dmp(j.debug(),
220  "already validated sequence at or past " + std::to_string(seq));
221  }
222 
223  if (val->isTrusted() && outcome == ValStatus::current)
224  {
226  hash, val->getFieldU32(sfLedgerSequence));
227  shouldRelay = true;
228  }
229  }
230  else
231  {
232  JLOG(j.debug()) << "Val for " << hash << " from "
233  << toBase58(TokenType::NodePublic, signingKey)
234  << " not added UNlisted";
235  }
236 
237  // This currently never forwards untrusted validations, though we may
238  // reconsider in the future. From @JoelKatz:
239  // The idea was that we would have a certain number of validation slots with
240  // priority going to validators we trusted. Remaining slots might be
241  // allocated to validators that were listed by publishers we trusted but
242  // that we didn't choose to trust. The shorter term plan was just to forward
243  // untrusted validations if peers wanted them or if we had the
244  // ability/bandwidth to. None of that was implemented.
245  return shouldRelay;
246 }
247 
248 } // 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:569
ripple::mismatch
RCLValidatedLedger::Seq mismatch(RCLValidatedLedger const &a, RCLValidatedLedger const &b)
Definition: RCLValidations.cpp:98
ripple::Application
Definition: Application.h:94
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:173
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:132
ripple::STObject::getSerializer
Serializer getSerializer() const
Definition: STObject.h:366
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:1667
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:41
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::ValStatus::badSeq
@ badSeq
A validation violates the increasing seq requirement.
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:580
ripple::base_uint< 256 >
ripple::RCLValidatedLedger::RCLValidatedLedger
RCLValidatedLedger(MakeGenesis)
Definition: RCLValidations.cpp:40
ripple::sfLastLedgerSequence
const SF_U32 sfLastLedgerSequence(access, STI_UINT32, 27, "LastLedgerSequence")
Definition: SField.h:379
thread
ripple::Validations::add
ValStatus add(NodeID const &nodeID, Validation const &val)
Add a new validation.
Definition: Validations.h:611
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
std::to_string
T to_string(T... args)
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
ripple::sfLedgerSequence
const SF_U32 sfLedgerSequence(access, STI_UINT32, 6, "LedgerSequence")
Definition: SField.h:357
beast::Journal::error
Stream error() const
Definition: Journal.h:333
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:998
ripple::Application::validators
virtual ValidatorList & validators()=0
std::min
T min(T... args)
ripple::ValStatus::conflicting
@ conflicting
Multiple validations for different ledgers by a single validator.
ripple::sfHashes
const SF_Vec256 sfHashes(access, STI_VECTOR256, 2, "Hashes")
Definition: SField.h:490
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:256
ripple::RCLValidationsAdaptor::app_
Application & app_
Definition: RCLValidations.h:231
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:401
ripple::STValidation::setTrusted
void setTrusted()
Definition: STValidation.h:182
ripple::handleNewValidation
bool handleNewValidation(Application &app, std::shared_ptr< STValidation > const &val, std::string const &source)
Handle a new validation.
Definition: RCLValidations.cpp:152
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::Validations::adaptor
Adaptor const & adaptor() const
Return the adaptor instance.
Definition: Validations.h:575
ripple::RCLValidatedLedger::Seq
LedgerIndex Seq
Definition: RCLValidations.h:157