rippled
AmendmentTable.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 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/main/Application.h>
21 #include <ripple/app/misc/AmendmentTable.h>
22 #include <ripple/app/rdb/Wallet.h>
23 #include <ripple/core/ConfigSections.h>
24 #include <ripple/protocol/Feature.h>
25 #include <ripple/protocol/STValidation.h>
26 #include <ripple/protocol/TxFlags.h>
27 #include <ripple/protocol/jss.h>
28 #include <boost/format.hpp>
29 #include <boost/regex.hpp>
30 #include <algorithm>
31 #include <mutex>
32 
33 namespace ripple {
34 
36 parseSection(Section const& section)
37 {
38  static boost::regex const re1(
39  "^" // start of line
40  "(?:\\s*)" // whitespace (optional)
41  "([abcdefABCDEF0-9]{64})" // <hexadecimal amendment ID>
42  "(?:\\s+)" // whitespace
43  "(\\S+)" // <description>
44  ,
45  boost::regex_constants::optimize);
46 
48 
49  for (auto const& line : section.lines())
50  {
51  boost::smatch match;
52 
53  if (!boost::regex_match(line, match, re1))
54  Throw<std::runtime_error>(
55  "Invalid entry '" + line + "' in [" + section.name() + "]");
56 
57  uint256 id;
58 
59  if (!id.parseHex(match[1]))
60  Throw<std::runtime_error>(
61  "Invalid amendment ID '" + match[1] + "' in [" +
62  section.name() + "]");
63 
64  names.push_back(std::make_pair(id, match[2]));
65  }
66 
67  return names;
68 }
69 
89 {
90 private:
91  static constexpr NetClock::time_point maxTimeout =
93 
94  // Associates each trusted validator with the last votes we saw from them
95  // and an expiration for that record.
97  {
100  };
102 
103 public:
104  TrustedVotes() = default;
105  TrustedVotes(TrustedVotes const& rhs) = delete;
106  TrustedVotes&
107  operator=(TrustedVotes const& rhs) = delete;
108 
109  // Called when the list of trusted validators changes.
110  //
111  // Call with AmendmentTable::mutex_ locked.
112  void
114  hash_set<PublicKey> const& allTrusted,
115  std::lock_guard<std::mutex> const& lock)
116  {
117  decltype(recordedVotes_) newRecordedVotes;
118  newRecordedVotes.reserve(allTrusted.size());
119 
120  // Make sure every PublicKey in allTrusted is represented in
121  // recordedVotes_. Also make sure recordedVotes_ contains
122  // no additional PublicKeys.
123  for (auto& trusted : allTrusted)
124  {
125  if (recordedVotes_.contains(trusted))
126  {
127  // Preserve this validator's previously saved voting state.
128  newRecordedVotes.insert(recordedVotes_.extract(trusted));
129  }
130  else
131  {
132  // New validators have a starting position of no on everything.
133  // Add the entry with an empty vector and maxTimeout.
134  newRecordedVotes[trusted];
135  }
136  }
137  // The votes of any no-longer-trusted validators will be destroyed
138  // when changedTrustedVotes goes out of scope.
139  recordedVotes_.swap(newRecordedVotes);
140  }
141 
142  // Called when we receive the latest votes.
143  //
144  // Call with AmendmentTable::mutex_ locked.
145  void
147  Rules const& rules,
149  NetClock::time_point const closeTime,
150  std::lock_guard<std::mutex> const& lock)
151  {
152  // When we get an STValidation we save the upVotes it contains, but
153  // we also set an expiration for those upVotes. The following constant
154  // controls the timeout.
155  //
156  // There really is no "best" timeout to choose for when we finally
157  // lose confidence that we know how a validator is voting. But part
158  // of the point of recording validator votes is to avoid flapping of
159  // amendment votes. A 24h timeout says that we will change the local
160  // record of a validator's vote to "no" 24h after the last vote seen
161  // from that validator. So flapping due to that validator being off
162  // line will happen less frequently than every 24 hours.
163  using namespace std::chrono_literals;
164  static constexpr NetClock::duration expiresAfter = 24h;
165 
166  // Walk all validations and replace previous votes from trusted
167  // validators with these newest votes.
168  for (auto const& val : valSet)
169  {
170  // If this validation comes from one of our trusted validators...
171  if (auto const iter = recordedVotes_.find(val->getSignerPublic());
172  iter != recordedVotes_.end())
173  {
174  iter->second.timeout = closeTime + expiresAfter;
175  if (val->isFieldPresent(sfAmendments))
176  {
177  auto const& choices = val->getFieldV256(sfAmendments);
178  iter->second.upVotes.assign(choices.begin(), choices.end());
179  }
180  else
181  {
182  // This validator does not upVote any amendments right now.
183  iter->second.upVotes.clear();
184  }
185  }
186  }
187 
188  // Now remove any expired records from recordedVotes_.
190  recordedVotes_.begin(),
191  recordedVotes_.end(),
192  [&closeTime](decltype(recordedVotes_)::value_type& votes) {
193  if (closeTime > votes.second.timeout)
194  {
195  votes.second.timeout = maxTimeout;
196  votes.second.upVotes.clear();
197  }
198  });
199  }
200 
201  // Return the information needed by AmendmentSet to determine votes.
202  //
203  // Call with AmendmentTable::mutex_ locked.
205  getVotes(Rules const& rules, std::lock_guard<std::mutex> const& lock) const
206  {
208  for (auto& validatorVotes : recordedVotes_)
209  {
210  for (uint256 const& amendment : validatorVotes.second.upVotes)
211  {
212  ret[amendment] += 1;
213  }
214  }
215  return {recordedVotes_.size(), ret};
216  }
217 };
218 
224 {
227 
233  bool enabled = false;
234 
236  bool supported = false;
237 
240 
241  explicit AmendmentState() = default;
242 };
243 
246 {
247 private:
248  // How many yes votes each amendment received
250  Rules const& rules_;
251  // number of trusted validations
252  int trustedValidations_ = 0;
253  // number of votes needed
254  int threshold_ = 0;
255 
256  void
257  computeThreshold(int trustedValidations, Rules const& rules)
258  {
259  threshold_ = !rules_.enabled(fixAmendmentMajorityCalc)
260  ? std::max(
261  1L,
262  static_cast<long>(
263  (trustedValidations_ *
266  : std::max(
267  1L,
268  static_cast<long>(
269  (trustedValidations_ *
272  }
273 
274 public:
276  Rules const& rules,
277  TrustedVotes const& trustedVotes,
278  std::lock_guard<std::mutex> const& lock)
279  : rules_(rules)
280  {
281  // process validations for ledger before flag ledger.
282  auto [trustedCount, newVotes] = trustedVotes.getVotes(rules, lock);
283 
284  trustedValidations_ = trustedCount;
285  votes_.swap(newVotes);
286 
287  computeThreshold(trustedValidations_, rules);
288  }
289 
290  bool
291  passes(uint256 const& amendment) const
292  {
293  auto const& it = votes_.find(amendment);
294 
295  if (it == votes_.end())
296  return false;
297 
298  // Before this fix, it was possible for an amendment to activate with a
299  // percentage slightly less than 80% because we compared for "greater
300  // than or equal to" instead of strictly "greater than".
301  // One validator is an exception, otherwise it is not possible
302  // to gain majority.
303  if (!rules_.enabled(fixAmendmentMajorityCalc) ||
304  trustedValidations_ == 1)
305  return it->second >= threshold_;
306 
307  return it->second > threshold_;
308  }
309 
310  int
311  votes(uint256 const& amendment) const
312  {
313  auto const& it = votes_.find(amendment);
314 
315  if (it == votes_.end())
316  return 0;
317 
318  return it->second;
319  }
320 
321  int
323  {
324  return trustedValidations_;
325  }
326 
327  int
328  threshold() const
329  {
330  return threshold_;
331  }
332 };
333 
334 //------------------------------------------------------------------------------
335 
342 class AmendmentTableImpl final : public AmendmentTable
343 {
344 private:
346 
349 
350  // Record of the last votes seen from trusted validators.
352 
353  // Time that an amendment must hold a majority for
355 
356  // The results of the last voting round - may be empty if
357  // we haven't participated in one yet.
359 
360  // True if an unsupported amendment is enabled
362 
363  // Unset if no unsupported amendments reach majority,
364  // else set to the earliest time an unsupported amendment
365  // will be enabled.
367 
369 
370  // Database which persists veto/unveto vote
372 
373  // Finds or creates state. Must be called with mutex_ locked.
375  add(uint256 const& amendment, std::lock_guard<std::mutex> const& lock);
376 
377  // Finds existing state. Must be called with mutex_ locked.
379  get(uint256 const& amendment, std::lock_guard<std::mutex> const& lock);
380 
381  AmendmentState const*
382  get(uint256 const& amendment,
383  std::lock_guard<std::mutex> const& lock) const;
384 
385  // Injects amendment json into v. Must be called with mutex_ locked.
386  void
387  injectJson(
388  Json::Value& v,
389  uint256 const& amendment,
390  AmendmentState const& state,
391  std::lock_guard<std::mutex> const& lock) const;
392 
393  void
394  persistVote(
395  uint256 const& amendment,
396  std::string const& name,
397  AmendmentVote vote) const;
398 
399 public:
401  Application& app,
402  std::chrono::seconds majorityTime,
403  std::vector<FeatureInfo> const& supported,
404  Section const& enabled,
405  Section const& vetoed,
406  beast::Journal journal);
407 
408  uint256
409  find(std::string const& name) const override;
410 
411  bool
412  veto(uint256 const& amendment) override;
413  bool
414  unVeto(uint256 const& amendment) override;
415 
416  bool
417  enable(uint256 const& amendment) override;
418 
419  bool
420  isEnabled(uint256 const& amendment) const override;
421  bool
422  isSupported(uint256 const& amendment) const override;
423 
424  bool
425  hasUnsupportedEnabled() const override;
426 
428  firstUnsupportedExpected() const override;
429 
431  getJson() const override;
433  getJson(uint256 const&) const override;
434 
435  bool
436  needValidatedLedger(LedgerIndex seq) const override;
437 
438  void
439  doValidatedLedger(
440  LedgerIndex seq,
441  std::set<uint256> const& enabled,
442  majorityAmendments_t const& majority) override;
443 
444  void
445  trustChanged(hash_set<PublicKey> const& allTrusted) override;
446 
448  doValidation(std::set<uint256> const& enabledAmendments) const override;
449 
451  getDesired() const override;
452 
454  doVoting(
455  Rules const& rules,
456  NetClock::time_point closeTime,
457  std::set<uint256> const& enabledAmendments,
458  majorityAmendments_t const& majorityAmendments,
459  std::vector<std::shared_ptr<STValidation>> const& validations) override;
460 };
461 
462 //------------------------------------------------------------------------------
463 
465  Application& app,
466  std::chrono::seconds majorityTime,
467  std::vector<FeatureInfo> const& supported,
468  Section const& enabled,
469  Section const& vetoed,
470  beast::Journal journal)
471  : lastUpdateSeq_(0)
472  , majorityTime_(majorityTime)
473  , unsupportedEnabled_(false)
474  , j_(journal)
475  , db_(app.getWalletDB())
476 {
477  std::lock_guard lock(mutex_);
478 
479  // Find out if the FeatureVotes table exists in WalletDB
480  bool const featureVotesExist = [this]() {
481  auto db = db_.checkoutDb();
482  return createFeatureVotes(*db);
483  }();
484 
485  // Parse supported amendments
486  for (auto const& [name, amendment, votebehavior] : supported)
487  {
488  AmendmentState& s = add(amendment, lock);
489 
490  s.name = name;
491  s.supported = true;
492  switch (votebehavior)
493  {
496  break;
497 
500  break;
501 
504  break;
505  }
506 
507  JLOG(j_.debug()) << "Amendment " << amendment << " (" << s.name
508  << ") is supported and will be "
509  << (s.vote == AmendmentVote::up ? "up" : "down")
510  << " voted by default if not enabled on the ledger.";
511  }
512 
513  hash_set<uint256> detect_conflict;
514  // Parse enabled amendments from config
515  for (std::pair<uint256, std::string> const& a : parseSection(enabled))
516  {
517  if (featureVotesExist)
518  { // If the table existed, warn about duplicate config info
519  JLOG(j_.warn()) << "[amendments] section in config file ignored"
520  " in favor of data in db/wallet.db.";
521  break;
522  }
523  else
524  { // Otherwise transfer config data into the table
525  detect_conflict.insert(a.first);
526  persistVote(a.first, a.second, AmendmentVote::up);
527  }
528  }
529 
530  // Parse vetoed amendments from config
531  for (auto const& a : parseSection(vetoed))
532  {
533  if (featureVotesExist)
534  { // If the table existed, warn about duplicate config info
535  JLOG(j_.warn())
536  << "[veto_amendments] section in config file ignored"
537  " in favor of data in db/wallet.db.";
538  break;
539  }
540  else
541  { // Otherwise transfer config data into the table
542  if (detect_conflict.count(a.first) == 0)
543  {
544  persistVote(a.first, a.second, AmendmentVote::down);
545  }
546  else
547  {
548  JLOG(j_.warn())
549  << "[veto_amendments] section in config has amendment "
550  << '(' << a.first << ", " << a.second
551  << ") both [veto_amendments] and [amendments].";
552  }
553  }
554  }
555 
556  // Read amendment votes from wallet.db
557  auto db = db_.checkoutDb();
559  *db,
560  [&](boost::optional<std::string> amendment_hash,
561  boost::optional<std::string> amendment_name,
562  boost::optional<AmendmentVote> vote) {
563  uint256 amend_hash;
564  if (!amendment_hash || !amendment_name || !vote)
565  {
566  // These fields should never have nulls, but check
567  Throw<std::runtime_error>(
568  "Invalid FeatureVotes row in wallet.db");
569  }
570  if (!amend_hash.parseHex(*amendment_hash))
571  {
572  Throw<std::runtime_error>(
573  "Invalid amendment ID '" + *amendment_hash +
574  " in wallet.db");
575  }
576  if (*vote == AmendmentVote::down)
577  {
578  // Unknown amendments are effectively vetoed already
579  if (auto s = get(amend_hash, lock))
580  {
581  JLOG(j_.info()) << "Amendment {" << *amendment_name << ", "
582  << amend_hash << "} is downvoted.";
583  if (!amendment_name->empty())
584  s->name = *amendment_name;
585  // An obsolete amendment's vote can never be changed
586  if (s->vote != AmendmentVote::obsolete)
587  s->vote = *vote;
588  }
589  }
590  else // up-vote
591  {
592  AmendmentState& s = add(amend_hash, lock);
593 
594  JLOG(j_.debug()) << "Amendment {" << *amendment_name << ", "
595  << amend_hash << "} is upvoted.";
596  if (!amendment_name->empty())
597  s.name = *amendment_name;
598  // An obsolete amendment's vote can never be changed
599  if (s.vote != AmendmentVote::obsolete)
600  s.vote = *vote;
601  }
602  });
603 }
604 
607  uint256 const& amendmentHash,
609 {
610  // call with the mutex held
611  return amendmentMap_[amendmentHash];
612 }
613 
616  uint256 const& amendmentHash,
617  std::lock_guard<std::mutex> const& lock)
618 {
619  // Forward to the const version of get.
620  return const_cast<AmendmentState*>(
621  std::as_const(*this).get(amendmentHash, lock));
622 }
623 
624 AmendmentState const*
626  uint256 const& amendmentHash,
627  std::lock_guard<std::mutex> const&) const
628 {
629  // call with the mutex held
630  auto ret = amendmentMap_.find(amendmentHash);
631 
632  if (ret == amendmentMap_.end())
633  return nullptr;
634 
635  return &ret->second;
636 }
637 
638 uint256
640 {
641  std::lock_guard lock(mutex_);
642 
643  for (auto const& e : amendmentMap_)
644  {
645  if (name == e.second.name)
646  return e.first;
647  }
648 
649  return {};
650 }
651 
652 void
654  uint256 const& amendment,
655  std::string const& name,
656  AmendmentVote vote) const
657 {
658  assert(vote != AmendmentVote::obsolete);
659  auto db = db_.checkoutDb();
660  voteAmendment(*db, amendment, name, vote);
661 }
662 
663 bool
665 {
666  std::lock_guard lock(mutex_);
667  AmendmentState& s = add(amendment, lock);
668 
669  if (s.vote != AmendmentVote::up)
670  return false;
672  persistVote(amendment, s.name, s.vote);
673  return true;
674 }
675 
676 bool
678 {
679  std::lock_guard lock(mutex_);
680  AmendmentState* const s = get(amendment, lock);
681 
682  if (!s || s->vote != AmendmentVote::down)
683  return false;
684  s->vote = AmendmentVote::up;
685  persistVote(amendment, s->name, s->vote);
686  return true;
687 }
688 
689 bool
691 {
692  std::lock_guard lock(mutex_);
693  AmendmentState& s = add(amendment, lock);
694 
695  if (s.enabled)
696  return false;
697 
698  s.enabled = true;
699 
700  if (!s.supported)
701  {
702  JLOG(j_.error()) << "Unsupported amendment " << amendment
703  << " activated.";
704  unsupportedEnabled_ = true;
705  }
706 
707  return true;
708 }
709 
710 bool
711 AmendmentTableImpl::isEnabled(uint256 const& amendment) const
712 {
713  std::lock_guard lock(mutex_);
714  AmendmentState const* s = get(amendment, lock);
715  return s && s->enabled;
716 }
717 
718 bool
720 {
721  std::lock_guard lock(mutex_);
722  AmendmentState const* s = get(amendment, lock);
723  return s && s->supported;
724 }
725 
726 bool
728 {
729  std::lock_guard lock(mutex_);
730  return unsupportedEnabled_;
731 }
732 
735 {
736  std::lock_guard lock(mutex_);
738 }
739 
742 {
743  // Get the list of amendments we support and do not
744  // veto, but that are not already enabled
745  std::vector<uint256> amendments;
746 
747  {
748  std::lock_guard lock(mutex_);
749  amendments.reserve(amendmentMap_.size());
750  for (auto const& e : amendmentMap_)
751  {
752  if (e.second.supported && e.second.vote == AmendmentVote::up &&
753  (enabled.count(e.first) == 0))
754  {
755  amendments.push_back(e.first);
756  JLOG(j_.info()) << "Voting for amendment " << e.second.name;
757  }
758  }
759  }
760 
761  if (!amendments.empty())
762  std::sort(amendments.begin(), amendments.end());
763 
764  return amendments;
765 }
766 
769 {
770  // Get the list of amendments we support and do not veto
771  return doValidation({});
772 }
773 
776  Rules const& rules,
777  NetClock::time_point closeTime,
778  std::set<uint256> const& enabledAmendments,
779  majorityAmendments_t const& majorityAmendments,
781 {
782  JLOG(j_.trace()) << "voting at " << closeTime.time_since_epoch().count()
783  << ": " << enabledAmendments.size() << ", "
784  << majorityAmendments.size() << ", " << valSet.size();
785 
786  std::lock_guard lock(mutex_);
787 
788  // Keep a record of the votes we received.
789  previousTrustedVotes_.recordVotes(rules, valSet, closeTime, lock);
790 
791  // Tally the most recent votes.
792  auto vote =
793  std::make_unique<AmendmentSet>(rules, previousTrustedVotes_, lock);
794  JLOG(j_.debug()) << "Received " << vote->trustedValidations()
795  << " trusted validations, threshold is: "
796  << vote->threshold();
797 
798  // Map of amendments to the action to be taken for each one. The action is
799  // the value of the flags in the pseudo-transaction
801 
802  // process all amendments we know of
803  for (auto const& entry : amendmentMap_)
804  {
805  NetClock::time_point majorityTime = {};
806 
807  bool const hasValMajority = vote->passes(entry.first);
808 
809  {
810  auto const it = majorityAmendments.find(entry.first);
811  if (it != majorityAmendments.end())
812  majorityTime = it->second;
813  }
814 
815  if (enabledAmendments.count(entry.first) != 0)
816  {
817  JLOG(j_.debug()) << entry.first << ": amendment already enabled";
818  }
819  else if (
820  hasValMajority && (majorityTime == NetClock::time_point{}) &&
821  entry.second.vote == AmendmentVote::up)
822  {
823  // Ledger says no majority, validators say yes
824  JLOG(j_.debug()) << entry.first << ": amendment got majority";
825  actions[entry.first] = tfGotMajority;
826  }
827  else if (!hasValMajority && (majorityTime != NetClock::time_point{}))
828  {
829  // Ledger says majority, validators say no
830  JLOG(j_.debug()) << entry.first << ": amendment lost majority";
831  actions[entry.first] = tfLostMajority;
832  }
833  else if (
834  (majorityTime != NetClock::time_point{}) &&
835  ((majorityTime + majorityTime_) <= closeTime) &&
836  entry.second.vote == AmendmentVote::up)
837  {
838  // Ledger says majority held
839  JLOG(j_.debug()) << entry.first << ": amendment majority held";
840  actions[entry.first] = 0;
841  }
842  }
843 
844  // Stash for reporting
845  lastVote_ = std::move(vote);
846  return actions;
847 }
848 
849 bool
851 {
852  std::lock_guard lock(mutex_);
853 
854  // Is there a ledger in which an amendment could have been enabled
855  // between these two ledger sequences?
856 
857  return ((ledgerSeq - 1) / 256) != ((lastUpdateSeq_ - 1) / 256);
858 }
859 
860 void
862  LedgerIndex ledgerSeq,
863  std::set<uint256> const& enabled,
864  majorityAmendments_t const& majority)
865 {
866  for (auto& e : enabled)
867  enable(e);
868 
869  std::lock_guard lock(mutex_);
870 
871  // Remember the ledger sequence of this update.
872  lastUpdateSeq_ = ledgerSeq;
873 
874  // Since we have the whole list in `majority`, reset the time flag, even
875  // if it's currently set. If it's not set when the loop is done, then any
876  // prior unknown amendments have lost majority.
878  for (auto const& [hash, time] : majority)
879  {
880  AmendmentState& s = add(hash, lock);
881 
882  if (s.enabled)
883  continue;
884 
885  if (!s.supported)
886  {
887  JLOG(j_.info()) << "Unsupported amendment " << hash
888  << " reached majority at " << to_string(time);
891  }
892  }
895 }
896 
897 void
899 {
900  std::lock_guard lock(mutex_);
901  previousTrustedVotes_.trustChanged(allTrusted, lock);
902 }
903 
904 void
906  Json::Value& v,
907  const uint256& id,
908  const AmendmentState& fs,
909  std::lock_guard<std::mutex> const&) const
910 {
911  if (!fs.name.empty())
912  v[jss::name] = fs.name;
913 
914  v[jss::supported] = fs.supported;
915  if (!fs.enabled)
916  {
917  if (fs.vote == AmendmentVote::obsolete)
918  v[jss::vetoed] = "Obsolete";
919  else
920  v[jss::vetoed] = fs.vote == AmendmentVote::down;
921  }
922  v[jss::enabled] = fs.enabled;
923 
924  if (!fs.enabled && lastVote_)
925  {
926  auto const votesTotal = lastVote_->trustedValidations();
927  auto const votesNeeded = lastVote_->threshold();
928  auto const votesFor = lastVote_->votes(id);
929 
930  v[jss::count] = votesFor;
931  v[jss::validations] = votesTotal;
932 
933  if (votesNeeded)
934  v[jss::threshold] = votesNeeded;
935  }
936 }
937 
940 {
942  {
943  std::lock_guard lock(mutex_);
944  for (auto const& e : amendmentMap_)
945  {
946  injectJson(
947  ret[to_string(e.first)] = Json::objectValue,
948  e.first,
949  e.second,
950  lock);
951  }
952  }
953  return ret;
954 }
955 
957 AmendmentTableImpl::getJson(uint256 const& amendmentID) const
958 {
960  Json::Value& jAmendment = (ret[to_string(amendmentID)] = Json::objectValue);
961 
962  {
963  std::lock_guard lock(mutex_);
964  AmendmentState const* a = get(amendmentID, lock);
965  if (a)
966  injectJson(jAmendment, amendmentID, *a, lock);
967  }
968 
969  return ret;
970 }
971 
974  Application& app,
975  std::chrono::seconds majorityTime,
977  Section const& enabled,
978  Section const& vetoed,
979  beast::Journal journal)
980 {
981  return std::make_unique<AmendmentTableImpl>(
982  app, majorityTime, supported, enabled, vetoed, journal);
983 }
984 
985 } // namespace ripple
ripple::tfGotMajority
constexpr std::uint32_t tfGotMajority
Definition: TxFlags.h:119
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:42
ripple::Application
Definition: Application.h:116
ripple::AmendmentTableImpl::db_
DatabaseCon & db_
Definition: AmendmentTable.cpp:371
ripple::AmendmentState::supported
bool supported
Indicates an amendment that this server has code support for.
Definition: AmendmentTable.cpp:236
ripple::tfLostMajority
constexpr std::uint32_t tfLostMajority
Definition: TxFlags.h:120
ripple::AmendmentTableImpl::lastUpdateSeq_
std::uint32_t lastUpdateSeq_
Definition: AmendmentTable.cpp:348
std::for_each
T for_each(T... args)
ripple::AmendmentVote::up
@ up
ripple::AmendmentState
Current state of an amendment.
Definition: AmendmentTable.cpp:223
ripple::AmendmentSet::AmendmentSet
AmendmentSet(Rules const &rules, TrustedVotes const &trustedVotes, std::lock_guard< std::mutex > const &lock)
Definition: AmendmentTable.cpp:275
std::string
STL class.
ripple::Rules::enabled
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:94
std::shared_ptr
STL class.
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:308
ripple::AmendmentVote::obsolete
@ obsolete
ripple::AmendmentTableImpl::firstUnsupportedExpected_
std::optional< NetClock::time_point > firstUnsupportedExpected_
Definition: AmendmentTable.cpp:366
std::unordered_set
STL class.
ripple::AmendmentTableImpl::getDesired
std::vector< uint256 > getDesired() const override
Definition: AmendmentTable.cpp:768
std::pair
ripple::AmendmentTableImpl::mutex_
std::mutex mutex_
Definition: AmendmentTable.cpp:345
ripple::AmendmentTableImpl::unsupportedEnabled_
bool unsupportedEnabled_
Definition: AmendmentTable.cpp:361
ripple::AmendmentTableImpl::doValidation
std::vector< uint256 > doValidation(std::set< uint256 > const &enabledAmendments) const override
Definition: AmendmentTable.cpp:741
ripple::createFeatureVotes
bool createFeatureVotes(soci::session &session)
createFeatureVotes Creates the FeatureVote table if it does not exist.
Definition: Wallet.cpp:225
std::vector
STL class.
std::unordered_map::find
T find(T... args)
std::unordered_set::size
T size(T... args)
ripple::VoteBehavior::DefaultNo
@ DefaultNo
std::chrono::duration
ripple::AmendmentTableImpl::find
uint256 find(std::string const &name) const override
Definition: AmendmentTable.cpp:639
beast::Journal::warn
Stream warn() const
Definition: Journal.h:326
ripple::AmendmentSet::votes_
hash_map< uint256, int > votes_
Definition: AmendmentTable.cpp:249
std::lock_guard
STL class.
ripple::AmendmentTableImpl::unVeto
bool unVeto(uint256 const &amendment) override
Definition: AmendmentTable.cpp:677
ripple::AmendmentState::vote
AmendmentVote vote
If an amendment is down-voted, a server will not vote to enable it.
Definition: AmendmentTable.cpp:226
ripple::AmendmentSet
The status of all amendments requested in a given window.
Definition: AmendmentTable.cpp:245
ripple::TrustedVotes::recordedVotes_
hash_map< PublicKey, UpvotesAndTimeout > recordedVotes_
Definition: AmendmentTable.cpp:101
std::as_const
T as_const(T... args)
ripple::AmendmentTableImpl
Track the list of "amendments".
Definition: AmendmentTable.cpp:342
std::sort
T sort(T... args)
algorithm
ripple::parseSection
static std::vector< std::pair< uint256, std::string > > parseSection(Section const &section)
Definition: AmendmentTable.cpp:36
ripple::VoteBehavior::Obsolete
@ Obsolete
std::vector::push_back
T push_back(T... args)
ripple::AmendmentSet::passes
bool passes(uint256 const &amendment) const
Definition: AmendmentTable.cpp:291
ripple::AmendmentVote::down
@ down
ripple::base_uint< 256 >
ripple::Section::name
std::string const & name() const
Returns the name of this section.
Definition: BasicConfig.h:59
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
ripple::AmendmentSet::threshold
int threshold() const
Definition: AmendmentTable.cpp:328
ripple::DatabaseCon::checkoutDb
LockedSociSession checkoutDb()
Definition: DatabaseCon.h:178
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::AmendmentTableImpl::firstUnsupportedExpected
std::optional< NetClock::time_point > firstUnsupportedExpected() const override
Definition: AmendmentTable.cpp:734
ripple::preFixAmendmentMajorityCalcThreshold
constexpr std::ratio< 204, 256 > preFixAmendmentMajorityCalcThreshold
The minimum amount of support an amendment should have.
Definition: SystemParameters.h:83
ripple::fixAmendmentMajorityCalc
const uint256 fixAmendmentMajorityCalc
ripple::AmendmentTableImpl::AmendmentTableImpl
AmendmentTableImpl(Application &app, std::chrono::seconds majorityTime, std::vector< FeatureInfo > const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
Definition: AmendmentTable.cpp:464
ripple::TrustedVotes::maxTimeout
static constexpr NetClock::time_point maxTimeout
Definition: AmendmentTable.cpp:91
ripple::AmendmentTableImpl::doVoting
std::map< uint256, std::uint32_t > doVoting(Rules const &rules, NetClock::time_point closeTime, std::set< uint256 > const &enabledAmendments, majorityAmendments_t const &majorityAmendments, std::vector< std::shared_ptr< STValidation >> const &validations) override
Definition: AmendmentTable.cpp:775
ripple::readAmendments
void readAmendments(soci::session &session, std::function< void(boost::optional< std::string > amendment_hash, boost::optional< std::string > amendment_name, boost::optional< AmendmentVote > vote)> const &callback)
readAmendments Reads all amendments from the FeatureVotes table.
Definition: Wallet.cpp:249
ripple::AmendmentSet::rules_
Rules const & rules_
Definition: AmendmentTable.cpp:250
ripple::AmendmentTableImpl::get
AmendmentState * get(uint256 const &amendment, std::lock_guard< std::mutex > const &lock)
Definition: AmendmentTable.cpp:615
ripple::AmendmentTableImpl::isSupported
bool isSupported(uint256 const &amendment) const override
Definition: AmendmentTable.cpp:719
beast::Journal::error
Stream error() const
Definition: Journal.h:332
beast::Journal::info
Stream info() const
Definition: Journal.h:320
std::chrono::time_point
ripple::Section::lines
std::vector< std::string > const & lines() const
Returns all the lines in the section.
Definition: BasicConfig.h:68
ripple::TrustedVotes::getVotes
std::pair< int, hash_map< uint256, int > > getVotes(Rules const &rules, std::lock_guard< std::mutex > const &lock) const
Definition: AmendmentTable.cpp:205
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint32_t
ripple::TrustedVotes::trustChanged
void trustChanged(hash_set< PublicKey > const &allTrusted, std::lock_guard< std::mutex > const &lock)
Definition: AmendmentTable.cpp:113
std::map
STL class.
ripple::TrustedVotes::UpvotesAndTimeout
Definition: AmendmentTable.cpp:96
ripple::TrustedVotes::operator=
TrustedVotes & operator=(TrustedVotes const &rhs)=delete
ripple::AmendmentTableImpl::previousTrustedVotes_
TrustedVotes previousTrustedVotes_
Definition: AmendmentTable.cpp:351
ripple::AmendmentTableImpl::veto
bool veto(uint256 const &amendment) override
Definition: AmendmentTable.cpp:664
ripple::TrustedVotes::UpvotesAndTimeout::upVotes
std::vector< uint256 > upVotes
Definition: AmendmentTable.cpp:98
std::unordered_map::swap
T swap(T... args)
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:357
ripple::TrustedVotes::recordVotes
void recordVotes(Rules const &rules, std::vector< std::shared_ptr< STValidation >> const &valSet, NetClock::time_point const closeTime, std::lock_guard< std::mutex > const &lock)
Definition: AmendmentTable.cpp:146
ripple::TrustedVotes::UpvotesAndTimeout::timeout
NetClock::time_point timeout
Definition: AmendmentTable.cpp:99
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::AmendmentTableImpl::injectJson
void injectJson(Json::Value &v, uint256 const &amendment, AmendmentState const &state, std::lock_guard< std::mutex > const &lock) const
Definition: AmendmentTable.cpp:905
ripple::AmendmentSet::computeThreshold
void computeThreshold(int trustedValidations, Rules const &rules)
Definition: AmendmentTable.cpp:257
ripple::AmendmentTableImpl::amendmentMap_
hash_map< uint256, AmendmentState > amendmentMap_
Definition: AmendmentTable.cpp:347
ripple::AmendmentTableImpl::lastVote_
std::unique_ptr< AmendmentSet > lastVote_
Definition: AmendmentTable.cpp:358
std::unordered_set::insert
T insert(T... args)
ripple::AmendmentTableImpl::majorityTime_
const std::chrono::seconds majorityTime_
Definition: AmendmentTable.cpp:354
ripple::voteAmendment
void voteAmendment(soci::session &session, uint256 const &amendment, std::string const &name, AmendmentVote vote)
voteAmendment Set the veto value for a particular amendment.
Definition: Wallet.cpp:285
ripple::AmendmentState::enabled
bool enabled
Indicates that the amendment has been enabled.
Definition: AmendmentTable.cpp:233
ripple::AmendmentTableImpl::getJson
Json::Value getJson() const override
Definition: AmendmentTable.cpp:939
ripple::DatabaseCon
Definition: DatabaseCon.h:81
ripple::AmendmentState::name
std::string name
The name of this amendment, possibly empty.
Definition: AmendmentTable.cpp:239
std::unordered_set::count
T count(T... args)
std::string::empty
T empty(T... args)
ripple::Rules
Rules controlling protocol behavior.
Definition: Rules.h:33
ripple::AmendmentVote
AmendmentVote
Definition: Wallet.h:147
std::optional
mutex
beast::Journal::debug
Stream debug() const
Definition: Journal.h:314
ripple::TrustedVotes::TrustedVotes
TrustedVotes()=default
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::make_AmendmentTable
std::unique_ptr< AmendmentTable > make_AmendmentTable(Application &app, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
Definition: AmendmentTable.cpp:973
std::make_pair
T make_pair(T... args)
std::unordered_map::end
T end(T... args)
ripple::AmendmentTableImpl::add
AmendmentState & add(uint256 const &amendment, std::lock_guard< std::mutex > const &lock)
Definition: AmendmentTable.cpp:606
ripple::AmendmentSet::trustedValidations
int trustedValidations() const
Definition: AmendmentTable.cpp:322
ripple::AmendmentTableImpl::isEnabled
bool isEnabled(uint256 const &amendment) const override
Definition: AmendmentTable.cpp:711
std::chrono::time_point::max
T max(T... args)
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:496
ripple::AmendmentTableImpl::j_
const beast::Journal j_
Definition: AmendmentTable.cpp:368
ripple::AmendmentTable
The amendment table stores the list of enabled and potential amendments.
Definition: AmendmentTable.h:37
ripple::AmendmentTableImpl::needValidatedLedger
bool needValidatedLedger(LedgerIndex seq) const override
Called to determine whether the amendment logic needs to process a new validated ledger.
Definition: AmendmentTable.cpp:850
ripple::AmendmentSet::votes
int votes(uint256 const &amendment) const
Definition: AmendmentTable.cpp:311
std::unique_ptr
STL class.
ripple::TrustedVotes
TrustedVotes records the most recent votes from trusted validators.
Definition: AmendmentTable.cpp:88
std::unordered_map
STL class.
ripple::AmendmentTableImpl::trustChanged
void trustChanged(hash_set< PublicKey > const &allTrusted) override
Definition: AmendmentTable.cpp:898
ripple::AmendmentTableImpl::persistVote
void persistVote(uint256 const &amendment, std::string const &name, AmendmentVote vote) const
Definition: AmendmentTable.cpp:653
std::set
STL class.
ripple::postFixAmendmentMajorityCalcThreshold
constexpr std::ratio< 80, 100 > postFixAmendmentMajorityCalcThreshold
Definition: SystemParameters.h:85
ripple::AmendmentTableImpl::doValidatedLedger
void doValidatedLedger(LedgerIndex seq, std::set< uint256 > const &enabled, majorityAmendments_t const &majority) override
Definition: AmendmentTable.cpp:861
ripple::AmendmentTableImpl::enable
bool enable(uint256 const &amendment) override
Definition: AmendmentTable.cpp:690
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::sfAmendments
const SF_VECTOR256 sfAmendments
ripple::get
T & get(EitherAmount &amt)
Definition: AmountSpec.h:118
ripple::AmendmentTableImpl::hasUnsupportedEnabled
bool hasUnsupportedEnabled() const override
returns true if one or more amendments on the network have been enabled that this server does not sup...
Definition: AmendmentTable.cpp:727
ripple::VoteBehavior::DefaultYes
@ DefaultYes