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,
154  STValidation::ref val,
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  boost::optional<PublicKey> masterKey =
162  app.validators().getTrustedKey(signingKey);
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  bool shouldRelay = false;
171  RCLValidations& validations = app.getValidations();
172  beast::Journal const j = validations.adaptor().journal();
173 
174  auto dmp = [&](beast::Journal::Stream s, std::string const& msg) {
175  s << "Val for " << hash
176  << (val->isTrusted() ? " trusted/" : " UNtrusted/")
177  << (val->isFull() ? "full" : "partial") << " from "
178  << (masterKey ? toBase58(TokenType::NodePublic, *masterKey)
179  : "unknown")
180  << " signing key " << toBase58(TokenType::NodePublic, signingKey)
181  << " " << msg << " src=" << source;
182  };
183 
184  if (!val->isFieldPresent(sfLedgerSequence))
185  {
186  if (j.error())
187  dmp(j.error(), "missing ledger sequence field");
188  return false;
189  }
190 
191  // masterKey is seated only if validator is trusted or listed
192  if (masterKey)
193  {
194  ValStatus const outcome = validations.add(calcNodeID(*masterKey), val);
195  if (j.debug())
196  dmp(j.debug(), to_string(outcome));
197 
198  if (outcome == ValStatus::badSeq && j.warn())
199  {
200  auto const seq = val->getFieldU32(sfLedgerSequence);
201  dmp(j.warn(),
202  "already validated sequence at or past " + std::to_string(seq));
203  }
204 
205  if (val->isTrusted() && outcome == ValStatus::current)
206  {
208  hash, val->getFieldU32(sfLedgerSequence));
209  shouldRelay = true;
210  }
211  }
212  else
213  {
214  JLOG(j.debug()) << "Val for " << hash << " from "
215  << toBase58(TokenType::NodePublic, signingKey)
216  << " not added UNlisted";
217  }
218 
219  // This currently never forwards untrusted validations, though we may
220  // reconsider in the future. From @JoelKatz:
221  // The idea was that we would have a certain number of validation slots with
222  // priority going to validators we trusted. Remaining slots might be
223  // allocated to validators that were listed by publishers we trusted but
224  // that we didn't choose to trust. The shorter term plan was just to forward
225  // untrusted validations if peers wanted them or if we had the
226  // ability/bandwidth to. None of that was implemented.
227  return shouldRelay;
228 }
229 
230 } // 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
ripple::keylet::skip
static const skip_t skip
Definition: Indexes.h:147
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::RCLValidatedLedger::minSeq
Seq minSeq() const
Definition: RCLValidations.cpp:62
ripple::RCLValidatedLedger::MakeGenesis
Definition: RCLValidations.h:152
ripple::RCLValidatedLedger::ledgerID_
ID ledgerID_
Definition: RCLValidations.h:188
ripple::RCLValidatedLedger::ancestors_
std::vector< uint256 > ancestors_
Definition: RCLValidations.h:190
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
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:219
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:147
ripple::handleNewValidation
bool handleNewValidation(Application &app, STValidation::ref val, std::string const &source)
Handle a new validation.
Definition: RCLValidations.cpp:152
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:592
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:226
std::to_string
T to_string(T... args)
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
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:189
ripple::RCLValidatedLedger::operator[]
ID operator[](Seq const &s) const
Lookup the ID of the ancestor ledger.
Definition: RCLValidations.cpp:79
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::sfHashes
const SF_Vec256 sfHashes(access, STI_VECTOR256, 2, "Hashes")
Definition: SField.h:488
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:225
ripple::TokenType::NodePublic
@ NodePublic
ripple::Validations< RCLValidationsAdaptor >
mutex
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::jtADVANCE
@ jtADVANCE
Definition: Job.h:53
std::max
T max(T... args)
ripple::Validations::adaptor
Adaptor const & adaptor() const
Return the adaptor instance.
Definition: Validations.h:556
ripple::RCLValidatedLedger::Seq
LedgerIndex Seq
Definition: RCLValidations.h:151