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  bool isAdmin,
392  std::lock_guard<std::mutex> const& lock) const;
393 
394  void
395  persistVote(
396  uint256 const& amendment,
397  std::string const& name,
398  AmendmentVote vote) const;
399 
400 public:
402  Application& app,
403  std::chrono::seconds majorityTime,
404  std::vector<FeatureInfo> const& supported,
405  Section const& enabled,
406  Section const& vetoed,
407  beast::Journal journal);
408 
409  uint256
410  find(std::string const& name) const override;
411 
412  bool
413  veto(uint256 const& amendment) override;
414  bool
415  unVeto(uint256 const& amendment) override;
416 
417  bool
418  enable(uint256 const& amendment) override;
419 
420  bool
421  isEnabled(uint256 const& amendment) const override;
422  bool
423  isSupported(uint256 const& amendment) const override;
424 
425  bool
426  hasUnsupportedEnabled() const override;
427 
429  firstUnsupportedExpected() const override;
430 
432  getJson(bool isAdmin) const override;
434  getJson(uint256 const&, bool isAdmin) const override;
435 
436  bool
437  needValidatedLedger(LedgerIndex seq) const override;
438 
439  void
440  doValidatedLedger(
441  LedgerIndex seq,
442  std::set<uint256> const& enabled,
443  majorityAmendments_t const& majority) override;
444 
445  void
446  trustChanged(hash_set<PublicKey> const& allTrusted) override;
447 
449  doValidation(std::set<uint256> const& enabledAmendments) const override;
450 
452  getDesired() const override;
453 
455  doVoting(
456  Rules const& rules,
457  NetClock::time_point closeTime,
458  std::set<uint256> const& enabledAmendments,
459  majorityAmendments_t const& majorityAmendments,
460  std::vector<std::shared_ptr<STValidation>> const& validations) override;
461 };
462 
463 //------------------------------------------------------------------------------
464 
466  Application& app,
467  std::chrono::seconds majorityTime,
468  std::vector<FeatureInfo> const& supported,
469  Section const& enabled,
470  Section const& vetoed,
471  beast::Journal journal)
472  : lastUpdateSeq_(0)
473  , majorityTime_(majorityTime)
474  , unsupportedEnabled_(false)
475  , j_(journal)
476  , db_(app.getWalletDB())
477 {
478  std::lock_guard lock(mutex_);
479 
480  // Find out if the FeatureVotes table exists in WalletDB
481  bool const featureVotesExist = [this]() {
482  auto db = db_.checkoutDb();
483  return createFeatureVotes(*db);
484  }();
485 
486  // Parse supported amendments
487  for (auto const& [name, amendment, votebehavior] : supported)
488  {
489  AmendmentState& s = add(amendment, lock);
490 
491  s.name = name;
492  s.supported = true;
493  switch (votebehavior)
494  {
497  break;
498 
501  break;
502 
505  break;
506  }
507 
508  JLOG(j_.debug()) << "Amendment " << amendment << " (" << s.name
509  << ") is supported and will be "
510  << (s.vote == AmendmentVote::up ? "up" : "down")
511  << " voted by default if not enabled on the ledger.";
512  }
513 
514  hash_set<uint256> detect_conflict;
515  // Parse enabled amendments from config
516  for (std::pair<uint256, std::string> const& a : parseSection(enabled))
517  {
518  if (featureVotesExist)
519  { // If the table existed, warn about duplicate config info
520  JLOG(j_.warn()) << "[amendments] section in config file ignored"
521  " in favor of data in db/wallet.db.";
522  break;
523  }
524  else
525  { // Otherwise transfer config data into the table
526  detect_conflict.insert(a.first);
527  persistVote(a.first, a.second, AmendmentVote::up);
528  }
529  }
530 
531  // Parse vetoed amendments from config
532  for (auto const& a : parseSection(vetoed))
533  {
534  if (featureVotesExist)
535  { // If the table existed, warn about duplicate config info
536  JLOG(j_.warn())
537  << "[veto_amendments] section in config file ignored"
538  " in favor of data in db/wallet.db.";
539  break;
540  }
541  else
542  { // Otherwise transfer config data into the table
543  if (detect_conflict.count(a.first) == 0)
544  {
545  persistVote(a.first, a.second, AmendmentVote::down);
546  }
547  else
548  {
549  JLOG(j_.warn())
550  << "[veto_amendments] section in config has amendment "
551  << '(' << a.first << ", " << a.second
552  << ") both [veto_amendments] and [amendments].";
553  }
554  }
555  }
556 
557  // Read amendment votes from wallet.db
558  auto db = db_.checkoutDb();
560  *db,
561  [&](boost::optional<std::string> amendment_hash,
562  boost::optional<std::string> amendment_name,
563  boost::optional<AmendmentVote> vote) {
564  uint256 amend_hash;
565  if (!amendment_hash || !amendment_name || !vote)
566  {
567  // These fields should never have nulls, but check
568  Throw<std::runtime_error>(
569  "Invalid FeatureVotes row in wallet.db");
570  }
571  if (!amend_hash.parseHex(*amendment_hash))
572  {
573  Throw<std::runtime_error>(
574  "Invalid amendment ID '" + *amendment_hash +
575  " in wallet.db");
576  }
577  if (*vote == AmendmentVote::down)
578  {
579  // Unknown amendments are effectively vetoed already
580  if (auto s = get(amend_hash, lock))
581  {
582  JLOG(j_.info()) << "Amendment {" << *amendment_name << ", "
583  << amend_hash << "} is downvoted.";
584  if (!amendment_name->empty())
585  s->name = *amendment_name;
586  // An obsolete amendment's vote can never be changed
587  if (s->vote != AmendmentVote::obsolete)
588  s->vote = *vote;
589  }
590  }
591  else // up-vote
592  {
593  AmendmentState& s = add(amend_hash, lock);
594 
595  JLOG(j_.debug()) << "Amendment {" << *amendment_name << ", "
596  << amend_hash << "} is upvoted.";
597  if (!amendment_name->empty())
598  s.name = *amendment_name;
599  // An obsolete amendment's vote can never be changed
600  if (s.vote != AmendmentVote::obsolete)
601  s.vote = *vote;
602  }
603  });
604 }
605 
608  uint256 const& amendmentHash,
610 {
611  // call with the mutex held
612  return amendmentMap_[amendmentHash];
613 }
614 
617  uint256 const& amendmentHash,
618  std::lock_guard<std::mutex> const& lock)
619 {
620  // Forward to the const version of get.
621  return const_cast<AmendmentState*>(
622  std::as_const(*this).get(amendmentHash, lock));
623 }
624 
625 AmendmentState const*
627  uint256 const& amendmentHash,
628  std::lock_guard<std::mutex> const&) const
629 {
630  // call with the mutex held
631  auto ret = amendmentMap_.find(amendmentHash);
632 
633  if (ret == amendmentMap_.end())
634  return nullptr;
635 
636  return &ret->second;
637 }
638 
639 uint256
641 {
642  std::lock_guard lock(mutex_);
643 
644  for (auto const& e : amendmentMap_)
645  {
646  if (name == e.second.name)
647  return e.first;
648  }
649 
650  return {};
651 }
652 
653 void
655  uint256 const& amendment,
656  std::string const& name,
657  AmendmentVote vote) const
658 {
659  assert(vote != AmendmentVote::obsolete);
660  auto db = db_.checkoutDb();
661  voteAmendment(*db, amendment, name, vote);
662 }
663 
664 bool
666 {
667  std::lock_guard lock(mutex_);
668  AmendmentState& s = add(amendment, lock);
669 
670  if (s.vote != AmendmentVote::up)
671  return false;
673  persistVote(amendment, s.name, s.vote);
674  return true;
675 }
676 
677 bool
679 {
680  std::lock_guard lock(mutex_);
681  AmendmentState* const s = get(amendment, lock);
682 
683  if (!s || s->vote != AmendmentVote::down)
684  return false;
685  s->vote = AmendmentVote::up;
686  persistVote(amendment, s->name, s->vote);
687  return true;
688 }
689 
690 bool
692 {
693  std::lock_guard lock(mutex_);
694  AmendmentState& s = add(amendment, lock);
695 
696  if (s.enabled)
697  return false;
698 
699  s.enabled = true;
700 
701  if (!s.supported)
702  {
703  JLOG(j_.error()) << "Unsupported amendment " << amendment
704  << " activated.";
705  unsupportedEnabled_ = true;
706  }
707 
708  return true;
709 }
710 
711 bool
712 AmendmentTableImpl::isEnabled(uint256 const& amendment) const
713 {
714  std::lock_guard lock(mutex_);
715  AmendmentState const* s = get(amendment, lock);
716  return s && s->enabled;
717 }
718 
719 bool
721 {
722  std::lock_guard lock(mutex_);
723  AmendmentState const* s = get(amendment, lock);
724  return s && s->supported;
725 }
726 
727 bool
729 {
730  std::lock_guard lock(mutex_);
731  return unsupportedEnabled_;
732 }
733 
736 {
737  std::lock_guard lock(mutex_);
739 }
740 
743 {
744  // Get the list of amendments we support and do not
745  // veto, but that are not already enabled
746  std::vector<uint256> amendments;
747 
748  {
749  std::lock_guard lock(mutex_);
750  amendments.reserve(amendmentMap_.size());
751  for (auto const& e : amendmentMap_)
752  {
753  if (e.second.supported && e.second.vote == AmendmentVote::up &&
754  (enabled.count(e.first) == 0))
755  {
756  amendments.push_back(e.first);
757  JLOG(j_.info()) << "Voting for amendment " << e.second.name;
758  }
759  }
760  }
761 
762  if (!amendments.empty())
763  std::sort(amendments.begin(), amendments.end());
764 
765  return amendments;
766 }
767 
770 {
771  // Get the list of amendments we support and do not veto
772  return doValidation({});
773 }
774 
777  Rules const& rules,
778  NetClock::time_point closeTime,
779  std::set<uint256> const& enabledAmendments,
780  majorityAmendments_t const& majorityAmendments,
782 {
783  JLOG(j_.trace()) << "voting at " << closeTime.time_since_epoch().count()
784  << ": " << enabledAmendments.size() << ", "
785  << majorityAmendments.size() << ", " << valSet.size();
786 
787  std::lock_guard lock(mutex_);
788 
789  // Keep a record of the votes we received.
790  previousTrustedVotes_.recordVotes(rules, valSet, closeTime, lock);
791 
792  // Tally the most recent votes.
793  auto vote =
794  std::make_unique<AmendmentSet>(rules, previousTrustedVotes_, lock);
795  JLOG(j_.debug()) << "Received " << vote->trustedValidations()
796  << " trusted validations, threshold is: "
797  << vote->threshold();
798 
799  // Map of amendments to the action to be taken for each one. The action is
800  // the value of the flags in the pseudo-transaction
802 
803  // process all amendments we know of
804  for (auto const& entry : amendmentMap_)
805  {
806  NetClock::time_point majorityTime = {};
807 
808  bool const hasValMajority = vote->passes(entry.first);
809 
810  {
811  auto const it = majorityAmendments.find(entry.first);
812  if (it != majorityAmendments.end())
813  majorityTime = it->second;
814  }
815 
816  if (enabledAmendments.count(entry.first) != 0)
817  {
818  JLOG(j_.debug()) << entry.first << ": amendment already enabled";
819  }
820  else if (
821  hasValMajority && (majorityTime == NetClock::time_point{}) &&
822  entry.second.vote == AmendmentVote::up)
823  {
824  // Ledger says no majority, validators say yes
825  JLOG(j_.debug()) << entry.first << ": amendment got majority";
826  actions[entry.first] = tfGotMajority;
827  }
828  else if (!hasValMajority && (majorityTime != NetClock::time_point{}))
829  {
830  // Ledger says majority, validators say no
831  JLOG(j_.debug()) << entry.first << ": amendment lost majority";
832  actions[entry.first] = tfLostMajority;
833  }
834  else if (
835  (majorityTime != NetClock::time_point{}) &&
836  ((majorityTime + majorityTime_) <= closeTime) &&
837  entry.second.vote == AmendmentVote::up)
838  {
839  // Ledger says majority held
840  JLOG(j_.debug()) << entry.first << ": amendment majority held";
841  actions[entry.first] = 0;
842  }
843  }
844 
845  // Stash for reporting
846  lastVote_ = std::move(vote);
847  return actions;
848 }
849 
850 bool
852 {
853  std::lock_guard lock(mutex_);
854 
855  // Is there a ledger in which an amendment could have been enabled
856  // between these two ledger sequences?
857 
858  return ((ledgerSeq - 1) / 256) != ((lastUpdateSeq_ - 1) / 256);
859 }
860 
861 void
863  LedgerIndex ledgerSeq,
864  std::set<uint256> const& enabled,
865  majorityAmendments_t const& majority)
866 {
867  for (auto& e : enabled)
868  enable(e);
869 
870  std::lock_guard lock(mutex_);
871 
872  // Remember the ledger sequence of this update.
873  lastUpdateSeq_ = ledgerSeq;
874 
875  // Since we have the whole list in `majority`, reset the time flag, even
876  // if it's currently set. If it's not set when the loop is done, then any
877  // prior unknown amendments have lost majority.
879  for (auto const& [hash, time] : majority)
880  {
881  AmendmentState& s = add(hash, lock);
882 
883  if (s.enabled)
884  continue;
885 
886  if (!s.supported)
887  {
888  JLOG(j_.info()) << "Unsupported amendment " << hash
889  << " reached majority at " << to_string(time);
892  }
893  }
896 }
897 
898 void
900 {
901  std::lock_guard lock(mutex_);
902  previousTrustedVotes_.trustChanged(allTrusted, lock);
903 }
904 
905 void
907  Json::Value& v,
908  const uint256& id,
909  const AmendmentState& fs,
910  bool isAdmin,
911  std::lock_guard<std::mutex> const&) const
912 {
913  if (!fs.name.empty())
914  v[jss::name] = fs.name;
915 
916  v[jss::supported] = fs.supported;
917  if (!fs.enabled && isAdmin)
918  {
919  if (fs.vote == AmendmentVote::obsolete)
920  v[jss::vetoed] = "Obsolete";
921  else
922  v[jss::vetoed] = fs.vote == AmendmentVote::down;
923  }
924  v[jss::enabled] = fs.enabled;
925 
926  if (!fs.enabled && lastVote_ && isAdmin)
927  {
928  auto const votesTotal = lastVote_->trustedValidations();
929  auto const votesNeeded = lastVote_->threshold();
930  auto const votesFor = lastVote_->votes(id);
931 
932  v[jss::count] = votesFor;
933  v[jss::validations] = votesTotal;
934 
935  if (votesNeeded)
936  v[jss::threshold] = votesNeeded;
937  }
938 }
939 
942 {
944  {
945  std::lock_guard lock(mutex_);
946  for (auto const& e : amendmentMap_)
947  {
948  injectJson(
949  ret[to_string(e.first)] = Json::objectValue,
950  e.first,
951  e.second,
952  isAdmin,
953  lock);
954  }
955  }
956  return ret;
957 }
958 
960 AmendmentTableImpl::getJson(uint256 const& amendmentID, bool isAdmin) const
961 {
963 
964  {
965  std::lock_guard lock(mutex_);
966  AmendmentState const* a = get(amendmentID, lock);
967  if (a)
968  {
969  Json::Value& jAmendment =
970  (ret[to_string(amendmentID)] = Json::objectValue);
971  injectJson(jAmendment, amendmentID, *a, isAdmin, lock);
972  }
973  }
974 
975  return ret;
976 }
977 
980  Application& app,
981  std::chrono::seconds majorityTime,
983  Section const& enabled,
984  Section const& vetoed,
985  beast::Journal journal)
986 {
987  return std::make_unique<AmendmentTableImpl>(
988  app, majorityTime, supported, enabled, vetoed, journal);
989 }
990 
991 } // namespace ripple
ripple::isAdmin
bool isAdmin(Port const &port, Json::Value const &params, beast::IP::Address const &remoteIp)
Definition: Role.cpp:84
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:769
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:742
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:640
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:678
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::AmendmentTableImpl::getJson
Json::Value getJson(bool isAdmin) const override
Definition: AmendmentTable.cpp:941
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
ripple::AmendmentTableImpl::injectJson
void injectJson(Json::Value &v, uint256 const &amendment, AmendmentState const &state, bool isAdmin, std::lock_guard< std::mutex > const &lock) const
Definition: AmendmentTable.cpp:906
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:735
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:465
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:776
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:616
ripple::AmendmentTableImpl::isSupported
bool isSupported(uint256 const &amendment) const override
Definition: AmendmentTable.cpp:720
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:665
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::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::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:38
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:979
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:607
ripple::AmendmentSet::trustedValidations
int trustedValidations() const
Definition: AmendmentTable.cpp:322
ripple::AmendmentTableImpl::isEnabled
bool isEnabled(uint256 const &amendment) const override
Definition: AmendmentTable.cpp:712
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:851
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:899
ripple::AmendmentTableImpl::persistVote
void persistVote(uint256 const &amendment, std::string const &name, AmendmentVote vote) const
Definition: AmendmentTable.cpp:654
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:862
ripple::AmendmentTableImpl::enable
bool enable(uint256 const &amendment) override
Definition: AmendmentTable.cpp:691
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:728
ripple::VoteBehavior::DefaultYes
@ DefaultYes