rippled
AmendmentTable_test.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/misc/AmendmentTable.h>
21 #include <ripple/basics/BasicConfig.h>
22 #include <ripple/basics/Log.h>
23 #include <ripple/basics/chrono.h>
24 #include <ripple/beast/unit_test.h>
25 #include <ripple/core/ConfigSections.h>
26 #include <ripple/protocol/Feature.h>
27 #include <ripple/protocol/PublicKey.h>
28 #include <ripple/protocol/STValidation.h>
29 #include <ripple/protocol/SecretKey.h>
30 #include <ripple/protocol/TxFlags.h>
31 #include <ripple/protocol/digest.h>
32 #include <ripple/protocol/jss.h>
33 #include <test/jtx/Env.h>
34 #include <test/unit_test/SuiteJournal.h>
35 
36 namespace ripple {
37 
38 class AmendmentTable_test final : public beast::unit_test::suite
39 {
40 private:
41  static uint256
43  {
44  sha256_hasher h;
45  using beast::hash_append;
46  hash_append(h, in);
47  auto const d = static_cast<sha256_hasher::result_type>(h);
48  uint256 result;
49  std::memcpy(result.data(), d.data(), d.size());
50  return result;
51  }
52 
53  static Section
55  std::string const& name,
56  std::vector<std::string> const& amendments)
57  {
58  Section section(name);
59  for (auto const& a : amendments)
60  section.append(to_string(amendmentId(a)) + " " + a);
61  return section;
62  }
63 
64  static Section
66  {
67  return makeSection("Test", amendments);
68  }
69 
70  static Section
71  makeSection(uint256 const& amendment)
72  {
73  Section section("Test");
74  section.append(to_string(amendment) + " " + to_string(amendment));
75  return section;
76  }
77 
80  {
81  auto cfg = test::jtx::envconfig();
82  cfg->section(SECTION_AMENDMENTS) =
83  makeSection(SECTION_AMENDMENTS, enabled_);
84  cfg->section(SECTION_VETO_AMENDMENTS) =
85  makeSection(SECTION_VETO_AMENDMENTS, vetoed_);
86  return cfg;
87  }
88 
91  std::vector<std::string> const& amendments,
92  VoteBehavior voteBehavior)
93  {
95  result.reserve(amendments.size());
96  for (auto const& a : amendments)
97  {
98  result.emplace_back(a, amendmentId(a), voteBehavior);
99  }
100  return result;
101  }
102 
105  {
106  return makeFeatureInfo(amendments, VoteBehavior::DefaultYes);
107  }
108 
110  makeDefaultYes(uint256 const amendment)
111  {
113  {to_string(amendment), amendment, VoteBehavior::DefaultYes}};
114  return result;
115  }
116 
119  {
120  return makeFeatureInfo(amendments, VoteBehavior::DefaultNo);
121  }
122 
125  {
126  return makeFeatureInfo(amendments, VoteBehavior::Obsolete);
127  }
128 
129  template <class Arg, class... Args>
130  static size_t
131  totalsize(std::vector<Arg> const& src, Args const&... args)
132  {
133  if constexpr (sizeof...(args) > 0)
134  return src.size() + totalsize(args...);
135  return src.size();
136  }
137 
138  template <class Arg, class... Args>
139  static void
141  std::vector<Arg>& dest,
142  std::vector<Arg> const& src,
143  Args const&... args)
144  {
145  assert(dest.capacity() >= dest.size() + src.size());
146  std::copy(src.begin(), src.end(), std::back_inserter(dest));
147  if constexpr (sizeof...(args) > 0)
148  combine_arg(dest, args...);
149  }
150 
151  template <class Arg, class... Args>
152  static std::vector<Arg>
154  // Pass "left" by value. The values will need to be copied one way or
155  // another, so just reuse it.
156  std::vector<Arg> left,
157  std::vector<Arg> const& right,
158  Args const&... args)
159  {
160  left.reserve(totalsize(left, right, args...));
161 
162  combine_arg(left, right, args...);
163 
164  return left;
165  }
166 
167  // All useful amendments are supported amendments.
168  // Enabled amendments are typically a subset of supported amendments.
169  // Vetoed amendments should be supported but not enabled.
170  // Unsupported amendments may be added to the AmendmentTable.
172  yes_{"g", "i", "k", "m", "o", "q", "r", "s", "t", "u"};
174  enabled_{"b", "d", "f", "h", "j", "l", "n", "p"};
175  std::vector<std::string> const vetoed_{"a", "c", "e"};
176  std::vector<std::string> const obsolete_{"0", "1", "2"};
181 
184 
186 
187 public:
188  AmendmentTable_test() : journal_("AmendmentTable_test", *this)
189  {
190  }
191 
194  Application& app,
195  std::chrono::seconds majorityTime,
197  Section const& enabled,
198  Section const& vetoed)
199  {
200  return make_AmendmentTable(
201  app, majorityTime, supported, enabled, vetoed, journal_);
202  }
203 
206  test::jtx::Env& env,
207  std::chrono::seconds majorityTime,
209  Section const& enabled,
210  Section const& vetoed)
211  {
212  return makeTable(env.app(), majorityTime, supported, enabled, vetoed);
213  }
214 
217  {
218  static std::vector<AmendmentTable::FeatureInfo> const supported =
219  combine(
221  // Use non-intuitive default votes for "enabled_" and "vetoed_"
222  // so that when the tests later explicitly enable or veto them,
223  // we can be certain that they are not simply going by their
224  // default vote setting.
228  return makeTable(
229  env.app(),
230  majorityTime,
231  supported,
234  }
235 
236  void
238  {
239  testcase("Construction");
240  test::jtx::Env env{*this, makeConfig()};
241  auto table = makeTable(env, weeks(1));
242 
243  for (auto const& a : allSupported_)
244  BEAST_EXPECT(table->isSupported(amendmentId(a)));
245 
246  for (auto const& a : yes_)
247  BEAST_EXPECT(table->isSupported(amendmentId(a)));
248 
249  for (auto const& a : enabled_)
250  BEAST_EXPECT(table->isSupported(amendmentId(a)));
251 
252  for (auto const& a : vetoed_)
253  {
254  BEAST_EXPECT(table->isSupported(amendmentId(a)));
255  BEAST_EXPECT(!table->isEnabled(amendmentId(a)));
256  }
257 
258  for (auto const& a : obsolete_)
259  {
260  BEAST_EXPECT(table->isSupported(amendmentId(a)));
261  BEAST_EXPECT(!table->isEnabled(amendmentId(a)));
262  }
263  }
264 
265  void
267  {
268  testcase("Name to ID mapping");
269 
270  test::jtx::Env env{*this, makeConfig()};
271  auto table = makeTable(env, weeks(1));
272 
273  for (auto const& a : yes_)
274  BEAST_EXPECT(table->find(a) == amendmentId(a));
275  for (auto const& a : enabled_)
276  BEAST_EXPECT(table->find(a) == amendmentId(a));
277  for (auto const& a : vetoed_)
278  BEAST_EXPECT(table->find(a) == amendmentId(a));
279  for (auto const& a : obsolete_)
280  BEAST_EXPECT(table->find(a) == amendmentId(a));
281  for (auto const& a : unsupported_)
282  BEAST_EXPECT(!table->find(a));
283  for (auto const& a : unsupportedMajority_)
284  BEAST_EXPECT(!table->find(a));
285 
286  // Vetoing an unsupported amendment should add the amendment to table.
287  // Verify that unsupportedID is not in table.
288  uint256 const unsupportedID = amendmentId(unsupported_[0]);
289  {
290  Json::Value const unsupp =
291  table->getJson(unsupportedID, true)[to_string(unsupportedID)];
292  BEAST_EXPECT(unsupp.size() == 0);
293  }
294 
295  // After vetoing unsupportedID verify that it is in table.
296  table->veto(unsupportedID);
297  {
298  Json::Value const unsupp =
299  table->getJson(unsupportedID, true)[to_string(unsupportedID)];
300  BEAST_EXPECT(unsupp[jss::vetoed].asBool());
301  }
302  }
303 
304  void
306  {
307  auto const yesVotes = makeDefaultYes(yes_);
308  auto const section = makeSection(vetoed_);
309  auto const id = to_string(amendmentId(enabled_[0]));
310 
311  testcase("Bad Config");
312 
313  { // Two arguments are required - we pass one
314  Section test = section;
315  test.append(id);
316 
317  try
318  {
319  test::jtx::Env env{*this, makeConfig()};
320  if (makeTable(env, weeks(2), yesVotes, test, emptySection_))
321  fail("Accepted only amendment ID");
322  }
323  catch (std::exception const& e)
324  {
325  BEAST_EXPECT(
326  e.what() == "Invalid entry '" + id + "' in [Test]");
327  }
328  }
329 
330  { // Two arguments are required - we pass three
331  Section test = section;
332  test.append(id + " Test Name");
333 
334  try
335  {
336  test::jtx::Env env{*this, makeConfig()};
337  if (makeTable(env, weeks(2), yesVotes, test, emptySection_))
338  fail("Accepted extra arguments");
339  }
340  catch (std::exception const& e)
341  {
342  BEAST_EXPECT(
343  e.what() ==
344  "Invalid entry '" + id + " Test Name' in [Test]");
345  }
346  }
347 
348  {
349  auto sid = id;
350  sid.resize(sid.length() - 1);
351 
352  Section test = section;
353  test.append(sid + " Name");
354 
355  try
356  {
357  test::jtx::Env env{*this, makeConfig()};
358  if (makeTable(env, weeks(2), yesVotes, test, emptySection_))
359  fail("Accepted short amendment ID");
360  }
361  catch (std::exception const& e)
362  {
363  BEAST_EXPECT(
364  e.what() == "Invalid entry '" + sid + " Name' in [Test]");
365  }
366  }
367 
368  {
369  auto sid = id;
370  sid.resize(sid.length() + 1, '0');
371 
372  Section test = section;
373  test.append(sid + " Name");
374 
375  try
376  {
377  test::jtx::Env env{*this, makeConfig()};
378  if (makeTable(env, weeks(2), yesVotes, test, emptySection_))
379  fail("Accepted long amendment ID");
380  }
381  catch (std::exception const& e)
382  {
383  BEAST_EXPECT(
384  e.what() == "Invalid entry '" + sid + " Name' in [Test]");
385  }
386  }
387 
388  {
389  auto sid = id;
390  sid.resize(sid.length() - 1);
391  sid.push_back('Q');
392 
393  Section test = section;
394  test.append(sid + " Name");
395 
396  try
397  {
398  test::jtx::Env env{*this, makeConfig()};
399  if (makeTable(env, weeks(2), yesVotes, test, emptySection_))
400  fail("Accepted non-hex amendment ID");
401  }
402  catch (std::exception const& e)
403  {
404  BEAST_EXPECT(
405  e.what() == "Invalid entry '" + sid + " Name' in [Test]");
406  }
407  }
408  }
409 
410  void
412  {
413  testcase("enable and veto");
414 
415  test::jtx::Env env{*this, makeConfig()};
417 
418  // Note which entries are enabled (convert the amendment names to IDs)
419  std::set<uint256> allEnabled;
420  for (auto const& a : enabled_)
421  allEnabled.insert(amendmentId(a));
422 
423  for (uint256 const& a : allEnabled)
424  BEAST_EXPECT(table->enable(a));
425 
426  // So far all enabled amendments are supported.
427  BEAST_EXPECT(!table->hasUnsupportedEnabled());
428 
429  // Verify all enables are enabled and nothing else.
430  for (std::string const& a : yes_)
431  {
432  uint256 const supportedID = amendmentId(a);
433  bool const enabled = table->isEnabled(supportedID);
434  bool const found = allEnabled.find(supportedID) != allEnabled.end();
435  BEAST_EXPECTS(
436  enabled == found,
437  a + (enabled ? " enabled " : " disabled ") +
438  (found ? " found" : " not found"));
439  }
440 
441  // All supported and unVetoed amendments should be returned as desired.
442  {
443  std::set<uint256> vetoed;
444  for (std::string const& a : vetoed_)
445  vetoed.insert(amendmentId(a));
446 
447  std::vector<uint256> const desired = table->getDesired();
448  for (uint256 const& a : desired)
449  BEAST_EXPECT(vetoed.count(a) == 0);
450 
451  // Unveto an amendment that is already not vetoed. Shouldn't
452  // hurt anything, but the values returned by getDesired()
453  // shouldn't change.
454  BEAST_EXPECT(!table->unVeto(amendmentId(yes_[1])));
455  BEAST_EXPECT(desired == table->getDesired());
456  }
457 
458  // UnVeto one of the vetoed amendments. It should now be desired.
459  {
460  uint256 const unvetoedID = amendmentId(vetoed_[0]);
461  BEAST_EXPECT(table->unVeto(unvetoedID));
462 
463  std::vector<uint256> const desired = table->getDesired();
464  BEAST_EXPECT(
465  std::find(desired.begin(), desired.end(), unvetoedID) !=
466  desired.end());
467  }
468 
469  // Veto all supported amendments. Now desired should be empty.
470  for (std::string const& a : allSupported_)
471  {
472  table->veto(amendmentId(a));
473  }
474  BEAST_EXPECT(table->getDesired().empty());
475 
476  // Enable an unsupported amendment.
477  {
478  BEAST_EXPECT(!table->hasUnsupportedEnabled());
479  table->enable(amendmentId(unsupported_[0]));
480  BEAST_EXPECT(table->hasUnsupportedEnabled());
481  }
482  }
483 
484  // Make a list of trusted validators.
485  // Register the validators with AmendmentTable and return the list.
488  {
490  ret.reserve(num);
491  hash_set<PublicKey> trustedValidators;
492  trustedValidators.reserve(num);
493  for (int i = 0; i < num; ++i)
494  {
495  auto const& back =
497  trustedValidators.insert(back.first);
498  }
499  table->trustChanged(trustedValidators);
500  return ret;
501  }
502 
503  static NetClock::time_point
505  {
506  return NetClock::time_point{h};
507  }
508 
509  // Execute a pretend consensus round for a flag ledger
510  void
512  Rules const& rules,
513  AmendmentTable& table,
514  std::chrono::hours hour,
515  std::vector<std::pair<PublicKey, SecretKey>> const& validators,
516  std::vector<std::pair<uint256, int>> const& votes,
517  std::vector<uint256>& ourVotes,
518  std::set<uint256>& enabled,
519  majorityAmendments_t& majority)
520  {
521  // Do a round at the specified time
522  // Returns the amendments we voted for
523 
524  // Parameters:
525  // table: Our table of known and vetoed amendments
526  // validators: The addreses of validators we trust
527  // votes: Amendments and the number of validators who vote for them
528  // ourVotes: The amendments we vote for in our validation
529  // enabled: In/out enabled amendments
530  // majority: In/our majority amendments (and when they got a majority)
531 
532  auto const roundTime = hourTime(hour);
533 
534  // Build validations
536  validations.reserve(validators.size());
537 
538  int i = 0;
539  for (auto const& [pub, sec] : validators)
540  {
541  ++i;
542  std::vector<uint256> field;
543 
544  for (auto const& [hash, nVotes] : votes)
545  {
546  if (rules.enabled(fixAmendmentMajorityCalc) ? nVotes >= i
547  : nVotes > i)
548  {
549  // We vote yes on this amendment
550  field.push_back(hash);
551  }
552  }
553 
554  auto v = std::make_shared<STValidation>(
556  pub,
557  sec,
558  calcNodeID(pub),
559  [&field](STValidation& v) {
560  if (!field.empty())
561  v.setFieldV256(
563  v.setFieldU32(sfLedgerSequence, 6180339);
564  });
565 
566  validations.emplace_back(v);
567  }
568 
569  ourVotes = table.doValidation(enabled);
570 
571  auto actions =
572  table.doVoting(rules, roundTime, enabled, majority, validations);
573  for (auto const& [hash, action] : actions)
574  {
575  // This code assumes other validators do as we do
576 
577  switch (action)
578  {
579  case 0:
580  // amendment goes from majority to enabled
581  if (enabled.find(hash) != enabled.end())
582  Throw<std::runtime_error>("enabling already enabled");
583  if (majority.find(hash) == majority.end())
584  Throw<std::runtime_error>("enabling without majority");
585  enabled.insert(hash);
586  majority.erase(hash);
587  break;
588 
589  case tfGotMajority:
590  if (majority.find(hash) != majority.end())
591  Throw<std::runtime_error>(
592  "got majority while having majority");
593  majority[hash] = roundTime;
594  break;
595 
596  case tfLostMajority:
597  if (majority.find(hash) == majority.end())
598  Throw<std::runtime_error>(
599  "lost majority without majority");
600  majority.erase(hash);
601  break;
602 
603  default:
604  Throw<std::runtime_error>("unknown action");
605  }
606  }
607  }
608 
609  // No vote on unknown amendment
610  void
612  {
613  testcase("Vote NO on unknown");
614 
615  auto const testAmendment = amendmentId("TestAmendment");
616 
617  test::jtx::Env env{*this, feat};
618  auto table =
620 
621  auto const validators = makeValidators(10, table);
622 
624  std::vector<uint256> ourVotes;
625  std::set<uint256> enabled;
626  majorityAmendments_t majority;
627 
628  doRound(
629  env.current()->rules(),
630  *table,
631  weeks{1},
632  validators,
633  votes,
634  ourVotes,
635  enabled,
636  majority);
637  BEAST_EXPECT(ourVotes.empty());
638  BEAST_EXPECT(enabled.empty());
639  BEAST_EXPECT(majority.empty());
640 
641  uint256 const unsupportedID = amendmentId(unsupported_[0]);
642  {
643  Json::Value const unsupp =
644  table->getJson(unsupportedID, false)[to_string(unsupportedID)];
645  BEAST_EXPECT(unsupp.size() == 0);
646  }
647 
648  table->veto(unsupportedID);
649  {
650  Json::Value const unsupp =
651  table->getJson(unsupportedID, false)[to_string(unsupportedID)];
652  BEAST_EXPECT(!unsupp[jss::vetoed].asBool());
653  }
654 
655  votes.emplace_back(testAmendment, validators.size());
656 
657  votes.emplace_back(testAmendment, validators.size());
658 
659  doRound(
660  env.current()->rules(),
661  *table,
662  weeks{2},
663  validators,
664  votes,
665  ourVotes,
666  enabled,
667  majority);
668  BEAST_EXPECT(ourVotes.empty());
669  BEAST_EXPECT(enabled.empty());
670 
671  majority[testAmendment] = hourTime(weeks{1});
672 
673  // Note that the simulation code assumes others behave as we do,
674  // so the amendment won't get enabled
675  doRound(
676  env.current()->rules(),
677  *table,
678  weeks{5},
679  validators,
680  votes,
681  ourVotes,
682  enabled,
683  majority);
684  BEAST_EXPECT(ourVotes.empty());
685  BEAST_EXPECT(enabled.empty());
686  }
687 
688  // No vote on vetoed amendment
689  void
691  {
692  testcase("Vote NO on vetoed");
693 
694  auto const testAmendment = amendmentId("vetoedAmendment");
695 
696  test::jtx::Env env{*this, feat};
697  auto table = makeTable(
698  env,
699  weeks(2),
700  emptyYes_,
702  makeSection(testAmendment));
703 
704  auto const validators = makeValidators(10, table);
705 
707  std::vector<uint256> ourVotes;
708  std::set<uint256> enabled;
709  majorityAmendments_t majority;
710 
711  doRound(
712  env.current()->rules(),
713  *table,
714  weeks{1},
715  validators,
716  votes,
717  ourVotes,
718  enabled,
719  majority);
720  BEAST_EXPECT(ourVotes.empty());
721  BEAST_EXPECT(enabled.empty());
722  BEAST_EXPECT(majority.empty());
723 
724  votes.emplace_back(testAmendment, validators.size());
725 
726  doRound(
727  env.current()->rules(),
728  *table,
729  weeks{2},
730  validators,
731  votes,
732  ourVotes,
733  enabled,
734  majority);
735  BEAST_EXPECT(ourVotes.empty());
736  BEAST_EXPECT(enabled.empty());
737 
738  majority[testAmendment] = hourTime(weeks{1});
739 
740  doRound(
741  env.current()->rules(),
742  *table,
743  weeks{5},
744  validators,
745  votes,
746  ourVotes,
747  enabled,
748  majority);
749  BEAST_EXPECT(ourVotes.empty());
750  BEAST_EXPECT(enabled.empty());
751  }
752 
753  // Vote on and enable known, not-enabled amendment
754  void
756  {
757  testcase("voteEnable");
758 
759  test::jtx::Env env{*this, feat};
760  auto table = makeTable(
762 
763  auto const validators = makeValidators(10, table);
764 
766  std::vector<uint256> ourVotes;
767  std::set<uint256> enabled;
768  majorityAmendments_t majority;
769 
770  // Week 1: We should vote for all known amendments not enabled
771  doRound(
772  env.current()->rules(),
773  *table,
774  weeks{1},
775  validators,
776  votes,
777  ourVotes,
778  enabled,
779  majority);
780  BEAST_EXPECT(ourVotes.size() == yes_.size());
781  BEAST_EXPECT(enabled.empty());
782  for (auto const& i : yes_)
783  BEAST_EXPECT(majority.find(amendmentId(i)) == majority.end());
784 
785  // Now, everyone votes for this feature
786  for (auto const& i : yes_)
787  votes.emplace_back(amendmentId(i), validators.size());
788 
789  // Week 2: We should recognize a majority
790  doRound(
791  env.current()->rules(),
792  *table,
793  weeks{2},
794  validators,
795  votes,
796  ourVotes,
797  enabled,
798  majority);
799  BEAST_EXPECT(ourVotes.size() == yes_.size());
800  BEAST_EXPECT(enabled.empty());
801 
802  for (auto const& i : yes_)
803  BEAST_EXPECT(majority[amendmentId(i)] == hourTime(weeks{2}));
804 
805  // Week 5: We should enable the amendment
806  doRound(
807  env.current()->rules(),
808  *table,
809  weeks{5},
810  validators,
811  votes,
812  ourVotes,
813  enabled,
814  majority);
815  BEAST_EXPECT(enabled.size() == yes_.size());
816 
817  // Week 6: We should remove it from our votes and from having a majority
818  doRound(
819  env.current()->rules(),
820  *table,
821  weeks{6},
822  validators,
823  votes,
824  ourVotes,
825  enabled,
826  majority);
827  BEAST_EXPECT(enabled.size() == yes_.size());
828  BEAST_EXPECT(ourVotes.empty());
829  for (auto const& i : yes_)
830  BEAST_EXPECT(majority.find(amendmentId(i)) == majority.end());
831  }
832 
833  // Detect majority at 80%, enable later
834  void
836  {
837  testcase("detectMajority");
838 
839  auto const testAmendment = amendmentId("detectMajority");
840  test::jtx::Env env{*this, feat};
841  auto table = makeTable(
842  env,
843  weeks(2),
844  makeDefaultYes(testAmendment),
846  emptySection_);
847 
848  auto const validators = makeValidators(16, table);
849 
850  std::set<uint256> enabled;
851  majorityAmendments_t majority;
852 
853  for (int i = 0; i <= 17; ++i)
854  {
856  std::vector<uint256> ourVotes;
857 
858  if ((i > 0) && (i < 17))
859  votes.emplace_back(testAmendment, i);
860 
861  doRound(
862  env.current()->rules(),
863  *table,
864  weeks{i},
865  validators,
866  votes,
867  ourVotes,
868  enabled,
869  majority);
870 
871  if (i < 13) // 13 => 13/16 = 0.8125 => > 80%
872  {
873  // We are voting yes, not enabled, no majority
874  BEAST_EXPECT(!ourVotes.empty());
875  BEAST_EXPECT(enabled.empty());
876  BEAST_EXPECT(majority.empty());
877  }
878  else if (i < 15)
879  {
880  // We have a majority, not enabled, keep voting
881  BEAST_EXPECT(!ourVotes.empty());
882  BEAST_EXPECT(!majority.empty());
883  BEAST_EXPECT(enabled.empty());
884  }
885  else if (i == 15)
886  {
887  // enable, keep voting, remove from majority
888  BEAST_EXPECT(!ourVotes.empty());
889  BEAST_EXPECT(majority.empty());
890  BEAST_EXPECT(!enabled.empty());
891  }
892  else
893  {
894  // Done, we should be enabled and not voting
895  BEAST_EXPECT(ourVotes.empty());
896  BEAST_EXPECT(majority.empty());
897  BEAST_EXPECT(!enabled.empty());
898  }
899  }
900  }
901 
902  // Detect loss of majority
903  void
905  {
906  testcase("lostMajority");
907 
908  auto const testAmendment = amendmentId("lostMajority");
909 
910  test::jtx::Env env{*this, feat};
911  auto table = makeTable(
912  env,
913  weeks(8),
914  makeDefaultYes(testAmendment),
916  emptySection_);
917 
918  auto const validators = makeValidators(16, table);
919 
920  std::set<uint256> enabled;
921  majorityAmendments_t majority;
922 
923  {
924  // establish majority
926  std::vector<uint256> ourVotes;
927 
928  votes.emplace_back(testAmendment, validators.size());
929 
930  doRound(
931  env.current()->rules(),
932  *table,
933  weeks{1},
934  validators,
935  votes,
936  ourVotes,
937  enabled,
938  majority);
939 
940  BEAST_EXPECT(enabled.empty());
941  BEAST_EXPECT(!majority.empty());
942  }
943 
944  for (int i = 1; i < 8; ++i)
945  {
947  std::vector<uint256> ourVotes;
948 
949  // Gradually reduce support
950  votes.emplace_back(testAmendment, validators.size() - i);
951 
952  doRound(
953  env.current()->rules(),
954  *table,
955  weeks{i + 1},
956  validators,
957  votes,
958  ourVotes,
959  enabled,
960  majority);
961 
962  if (i < 4) // 16 - 3 = 13 => 13/16 = 0.8125 => > 80%
963  { // 16 - 4 = 12 => 12/16 = 0.75 => < 80%
964  // We are voting yes, not enabled, majority
965  BEAST_EXPECT(!ourVotes.empty());
966  BEAST_EXPECT(enabled.empty());
967  BEAST_EXPECT(!majority.empty());
968  }
969  else
970  {
971  // No majority, not enabled, keep voting
972  BEAST_EXPECT(!ourVotes.empty());
973  BEAST_EXPECT(majority.empty());
974  BEAST_EXPECT(enabled.empty());
975  }
976  }
977  }
978 
979  // Exercise the UNL changing while voting is in progress.
980  void
982  {
983  // This test doesn't work without fixAmendmentMajorityCalc enabled.
984  if (!feat[fixAmendmentMajorityCalc])
985  return;
986 
987  testcase("changedUNL");
988 
989  auto const testAmendment = amendmentId("changedUNL");
990  test::jtx::Env env{*this, feat};
991  auto table = makeTable(
992  env,
993  weeks(8),
994  makeDefaultYes(testAmendment),
996  emptySection_);
997 
999  makeValidators(10, table);
1000 
1001  std::set<uint256> enabled;
1002  majorityAmendments_t majority;
1003 
1004  {
1005  // 10 validators with 2 voting against won't get majority.
1007  std::vector<uint256> ourVotes;
1008 
1009  votes.emplace_back(testAmendment, validators.size() - 2);
1010 
1011  doRound(
1012  env.current()->rules(),
1013  *table,
1014  weeks{1},
1015  validators,
1016  votes,
1017  ourVotes,
1018  enabled,
1019  majority);
1020 
1021  BEAST_EXPECT(enabled.empty());
1022  BEAST_EXPECT(majority.empty());
1023  }
1024 
1025  // Add one new validator to the UNL.
1027 
1028  // A lambda that updates the AmendmentTable with the latest
1029  // trusted validators.
1030  auto callTrustChanged =
1031  [](std::vector<std::pair<PublicKey, SecretKey>> const& validators,
1032  std::unique_ptr<AmendmentTable> const& table) {
1033  // We need a hash_set to pass to trustChanged.
1034  hash_set<PublicKey> trustedValidators;
1035  trustedValidators.reserve(validators.size());
1036  std::for_each(
1037  validators.begin(),
1038  validators.end(),
1039  [&trustedValidators](auto const& val) {
1040  trustedValidators.insert(val.first);
1041  });
1042 
1043  // Tell the AmendmentTable that the UNL changed.
1044  table->trustChanged(trustedValidators);
1045  };
1046 
1047  // Tell the table that there's been a change in trusted validators.
1048  callTrustChanged(validators, table);
1049 
1050  {
1051  // 11 validators with 2 voting against gains majority.
1053  std::vector<uint256> ourVotes;
1054 
1055  votes.emplace_back(testAmendment, validators.size() - 2);
1056 
1057  doRound(
1058  env.current()->rules(),
1059  *table,
1060  weeks{2},
1061  validators,
1062  votes,
1063  ourVotes,
1064  enabled,
1065  majority);
1066 
1067  BEAST_EXPECT(enabled.empty());
1068  BEAST_EXPECT(!majority.empty());
1069  }
1070  {
1071  // One of the validators goes flaky and doesn't send validations
1072  // (without the UNL changing) so the amendment loses majority.
1073  std::pair<PublicKey, SecretKey> const savedValidator =
1074  validators.front();
1075  validators.erase(validators.begin());
1076 
1078  std::vector<uint256> ourVotes;
1079 
1080  votes.emplace_back(testAmendment, validators.size() - 2);
1081 
1082  doRound(
1083  env.current()->rules(),
1084  *table,
1085  weeks{3},
1086  validators,
1087  votes,
1088  ourVotes,
1089  enabled,
1090  majority);
1091 
1092  BEAST_EXPECT(enabled.empty());
1093  BEAST_EXPECT(majority.empty());
1094 
1095  // Simulate the validator re-syncing to the network by adding it
1096  // back to the validators vector
1097  validators.insert(validators.begin(), savedValidator);
1098 
1099  votes.front().second = validators.size() - 2;
1100 
1101  doRound(
1102  env.current()->rules(),
1103  *table,
1104  weeks{4},
1105  validators,
1106  votes,
1107  ourVotes,
1108  enabled,
1109  majority);
1110 
1111  BEAST_EXPECT(enabled.empty());
1112  BEAST_EXPECT(!majority.empty());
1113 
1114  // Finally, remove one validator from the UNL and see that majority
1115  // is lost.
1116  validators.erase(validators.begin());
1117 
1118  // Tell the table that there's been a change in trusted validators.
1119  callTrustChanged(validators, table);
1120 
1121  votes.front().second = validators.size() - 2;
1122 
1123  doRound(
1124  env.current()->rules(),
1125  *table,
1126  weeks{5},
1127  validators,
1128  votes,
1129  ourVotes,
1130  enabled,
1131  majority);
1132 
1133  BEAST_EXPECT(enabled.empty());
1134  BEAST_EXPECT(majority.empty());
1135  }
1136  }
1137 
1138  // Exercise a validator losing connectivity and then regaining it after
1139  // extended delays. Depending on how long that delay is an amendment
1140  // either will or will not go live.
1141  void
1143  {
1144  // This test doesn't work without fixAmendmentMajorityCalc enabled.
1145  if (!feat[fixAmendmentMajorityCalc])
1146  return;
1147 
1148  testcase("validatorFlapping");
1149 
1150  // We run a test where a validator flaps on and off every 23 hours
1151  // and another one one where it flaps on and off every 25 hours.
1152  //
1153  // Since the local validator vote record expires after 24 hours,
1154  // with 23 hour flapping the amendment will go live. But with 25
1155  // hour flapping the amendment will not go live.
1156  for (int flapRateHours : {23, 25})
1157  {
1158  test::jtx::Env env{*this, feat};
1159  auto const testAmendment = amendmentId("validatorFlapping");
1160  auto table = makeTable(
1161  env,
1162  weeks(1),
1163  makeDefaultYes(testAmendment),
1164  emptySection_,
1165  emptySection_);
1166 
1167  // Make two lists of validators, one with a missing validator, to
1168  // make it easy to simulate validator flapping.
1169  auto const allValidators = makeValidators(11, table);
1170  decltype(allValidators) const mostValidators(
1171  allValidators.begin() + 1, allValidators.end());
1172  BEAST_EXPECT(allValidators.size() == mostValidators.size() + 1);
1173 
1174  std::set<uint256> enabled;
1175  majorityAmendments_t majority;
1176 
1178  std::vector<uint256> ourVotes;
1179 
1180  votes.emplace_back(testAmendment, allValidators.size() - 2);
1181 
1182  int delay = flapRateHours;
1183  // Loop for 1 week plus a day.
1184  for (int hour = 1; hour < (24 * 8); ++hour)
1185  {
1186  decltype(allValidators) const& thisHoursValidators =
1187  (delay < flapRateHours) ? mostValidators : allValidators;
1188  delay = delay == flapRateHours ? 0 : delay + 1;
1189 
1190  votes.front().second = thisHoursValidators.size() - 2;
1191 
1192  using namespace std::chrono;
1193  doRound(
1194  env.current()->rules(),
1195  *table,
1196  hours(hour),
1197  thisHoursValidators,
1198  votes,
1199  ourVotes,
1200  enabled,
1201  majority);
1202 
1203  if (hour <= (24 * 7) || flapRateHours > 24)
1204  {
1205  // The amendment should not be enabled under any
1206  // circumstance until one week has elapsed.
1207  BEAST_EXPECT(enabled.empty());
1208 
1209  // If flapping is less than 24 hours, there should be
1210  // no flapping. Otherwise we should only have majority
1211  // if allValidators vote -- which means there are no
1212  // missing validators.
1213  bool const expectMajority = (delay <= 24)
1214  ? true
1215  : &thisHoursValidators == &allValidators;
1216  BEAST_EXPECT(majority.empty() != expectMajority);
1217  }
1218  else
1219  {
1220  // We're...
1221  // o Past one week, and
1222  // o AmendmentFlapping was less than 24 hours.
1223  // The amendment should be enabled.
1224  BEAST_EXPECT(!enabled.empty());
1225  BEAST_EXPECT(majority.empty());
1226  }
1227  }
1228  }
1229  }
1230 
1231  void
1233  {
1234  testcase("hasUnsupportedEnabled");
1235 
1236  using namespace std::chrono_literals;
1237  weeks constexpr w(1);
1238  test::jtx::Env env{*this, makeConfig()};
1239  auto table = makeTable(env, w);
1240  BEAST_EXPECT(!table->hasUnsupportedEnabled());
1241  BEAST_EXPECT(!table->firstUnsupportedExpected());
1242  BEAST_EXPECT(table->needValidatedLedger(1));
1243 
1244  std::set<uint256> enabled;
1245  std::for_each(
1246  unsupported_.begin(),
1247  unsupported_.end(),
1248  [&enabled](auto const& s) { enabled.insert(amendmentId(s)); });
1249 
1250  majorityAmendments_t majority;
1251  table->doValidatedLedger(1, enabled, majority);
1252  BEAST_EXPECT(table->hasUnsupportedEnabled());
1253  BEAST_EXPECT(!table->firstUnsupportedExpected());
1254 
1255  NetClock::duration t{1000s};
1256  std::for_each(
1259  [&majority, &t](auto const& s) {
1260  majority[amendmentId(s)] = NetClock::time_point{--t};
1261  });
1262 
1263  table->doValidatedLedger(1, enabled, majority);
1264  BEAST_EXPECT(table->hasUnsupportedEnabled());
1265  BEAST_EXPECT(
1266  table->firstUnsupportedExpected() &&
1267  *table->firstUnsupportedExpected() == NetClock::time_point{t} + w);
1268 
1269  // Make sure the table knows when it needs an update.
1270  BEAST_EXPECT(!table->needValidatedLedger(256));
1271  BEAST_EXPECT(table->needValidatedLedger(257));
1272  }
1273 
1274  void
1276  {
1277  testNoOnUnknown(feat);
1278  testNoOnVetoed(feat);
1279  testVoteEnable(feat);
1280  testDetectMajority(feat);
1281  testLostMajority(feat);
1282  testChangedUNL(feat);
1283  testValidatorFlapping(feat);
1284  }
1285 
1286  void
1287  run() override
1288  {
1290  FeatureBitset const fixMajorityCalc{fixAmendmentMajorityCalc};
1291 
1292  testConstruct();
1293  testGet();
1294  testBadConfig();
1295  testEnableVeto();
1297  testFeature(all - fixMajorityCalc);
1298  testFeature(all);
1299  }
1300 };
1301 
1302 BEAST_DEFINE_TESTSUITE(AmendmentTable, app, ripple);
1303 
1304 } // 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::AmendmentTable_test::allSupported_
const std::vector< std::string > allSupported_
Definition: AmendmentTable_test.cpp:177
ripple::tfLostMajority
constexpr std::uint32_t tfLostMajority
Definition: TxFlags.h:120
std::for_each
T for_each(T... args)
ripple::AmendmentTable_test::makeDefaultNo
static std::vector< AmendmentTable::FeatureInfo > makeDefaultNo(std::vector< std::string > const &amendments)
Definition: AmendmentTable_test.cpp:118
ripple::AmendmentTable_test::unsupported_
const std::vector< std::string > unsupported_
Definition: AmendmentTable_test.cpp:179
ripple::openssl_sha256_hasher
SHA-256 digest.
Definition: digest.h:90
ripple::AmendmentTable::doVoting
virtual 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 &valSet)=0
std::string
STL class.
ripple::Rules::enabled
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:94
ripple::AmendmentTable_test::hourTime
static NetClock::time_point hourTime(std::chrono::hours h)
Definition: AmendmentTable_test.cpp:504
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
std::exception
STL class.
ripple::calcNodeID
NodeID calcNodeID(PublicKey const &pk)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:303
ripple::AmendmentTable_test::makeSection
static Section makeSection(uint256 const &amendment)
Definition: AmendmentTable_test.cpp:71
ripple::sfLedgerSequence
const SF_UINT32 sfLedgerSequence
ripple::AmendmentTable_test::testValidatorFlapping
void testValidatorFlapping(FeatureBitset const &feat)
Definition: AmendmentTable_test.cpp:1142
std::unordered_set
STL class.
std::pair
std::vector::reserve
T reserve(T... args)
ripple::TxSearched::all
@ all
ripple::AmendmentTable_test::testConstruct
void testConstruct()
Definition: AmendmentTable_test.cpp:237
std::vector< std::string >
std::find
T find(T... args)
std::vector::size
T size(T... args)
ripple::VoteBehavior::DefaultNo
@ DefaultNo
std::back_inserter
T back_inserter(T... args)
std::chrono::seconds
ripple::AmendmentTable_test::makeDefaultYes
static std::vector< AmendmentTable::FeatureInfo > makeDefaultYes(uint256 const amendment)
Definition: AmendmentTable_test.cpp:110
ripple::AmendmentTable_test::testChangedUNL
void testChangedUNL(FeatureBitset const &feat)
Definition: AmendmentTable_test.cpp:981
ripple::QualityDirection::in
@ in
ripple::AmendmentTable_test::testNoOnUnknown
void testNoOnUnknown(FeatureBitset const &feat)
Definition: AmendmentTable_test.cpp:611
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
ripple::AmendmentTable_test::testHasUnsupported
void testHasUnsupported()
Definition: AmendmentTable_test.cpp:1232
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:54
std::vector::front
T front(T... args)
ripple::base_uint::data
pointer data()
Definition: base_uint.h:122
ripple::STValidation
Definition: STValidation.h:44
ripple::VoteBehavior::Obsolete
@ Obsolete
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:519
ripple::Section::append
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
Definition: BasicConfig.cpp:38
ripple::AmendmentTable_test::makeValidators
std::vector< std::pair< PublicKey, SecretKey > > makeValidators(int num, std::unique_ptr< AmendmentTable > const &table)
Definition: AmendmentTable_test.cpp:487
ripple::AmendmentTable_test::emptySection_
const Section emptySection_
Definition: AmendmentTable_test.cpp:182
ripple::AmendmentTable_test::unsupportedMajority_
const std::vector< std::string > unsupportedMajority_
Definition: AmendmentTable_test.cpp:180
ripple::base_uint< 256 >
std::vector::capacity
T capacity(T... args)
ripple::AmendmentTable::doValidation
virtual std::vector< uint256 > doValidation(std::set< uint256 > const &enabled) const =0
ripple::AmendmentTable_test::testEnableVeto
void testEnableVeto()
Definition: AmendmentTable_test.cpp:411
ripple::weeks
std::chrono::duration< int, std::ratio_multiply< days::period, std::ratio< 7 > >> weeks
Definition: chrono.h:44
ripple::AmendmentTable_test::testNoOnVetoed
void testNoOnVetoed(FeatureBitset const &feat)
Definition: AmendmentTable_test.cpp:690
ripple::VoteBehavior
VoteBehavior
Definition: Feature.h:69
ripple::AmendmentTable_test::totalsize
static size_t totalsize(std::vector< Arg > const &src, Args const &... args)
Definition: AmendmentTable_test.cpp:131
ripple::AmendmentTable_test::makeTable
std::unique_ptr< AmendmentTable > makeTable(test::jtx::Env &env, std::chrono::seconds majorityTime)
Definition: AmendmentTable_test.cpp:216
ripple::fixAmendmentMajorityCalc
const uint256 fixAmendmentMajorityCalc
std::array< std::uint8_t, 32 >
std::chrono::time_point
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
std::map::erase
T erase(T... args)
std::copy
T copy(T... args)
ripple::AmendmentTable_test::testFeature
void testFeature(FeatureBitset const &feat)
Definition: AmendmentTable_test.cpp:1275
ripple::AmendmentTable_test::yes_
const std::vector< std::string > yes_
Definition: AmendmentTable_test.cpp:172
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
ripple::AmendmentTable_test::makeObsolete
static std::vector< AmendmentTable::FeatureInfo > makeObsolete(std::vector< std::string > const &amendments)
Definition: AmendmentTable_test.cpp:124
std::map
STL class.
ripple::AmendmentTable_test::vetoed_
const std::vector< std::string > vetoed_
Definition: AmendmentTable_test.cpp:175
ripple::test::SuiteJournal
Definition: SuiteJournal.h:88
ripple::KeyType::secp256k1
@ secp256k1
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::AmendmentTable_test::testGet
void testGet()
Definition: AmendmentTable_test.cpp:266
ripple::AmendmentTable_test::emptyYes_
const std::vector< AmendmentTable::FeatureInfo > emptyYes_
Definition: AmendmentTable_test.cpp:183
ripple::AmendmentTable_test::makeTable
std::unique_ptr< AmendmentTable > makeTable(test::jtx::Env &env, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed)
Definition: AmendmentTable_test.cpp:205
std::vector::begin
T begin(T... args)
ripple::AmendmentTable_test::obsolete_
const std::vector< std::string > obsolete_
Definition: AmendmentTable_test.cpp:176
std::set::insert
T insert(T... args)
beast::hash_append
std::enable_if_t< is_contiguously_hashable< T, Hasher >::value > hash_append(Hasher &h, T const &t) noexcept
Logically concatenate input data to a Hasher.
Definition: hash_append.h:236
ripple::AmendmentTable_test::journal_
test::SuiteJournal journal_
Definition: AmendmentTable_test.cpp:185
ripple::AmendmentTable_test::makeSection
static Section makeSection(std::vector< std::string > const &amendments)
Definition: AmendmentTable_test.cpp:65
ripple::AmendmentTable_test::makeConfig
std::unique_ptr< Config > makeConfig()
Definition: AmendmentTable_test.cpp:79
ripple::FeatureBitset
Definition: Feature.h:113
std::set::count
T count(T... args)
ripple::STVector256
Definition: STVector256.h:30
ripple::AmendmentTable_test::makeSection
static Section makeSection(std::string const &name, std::vector< std::string > const &amendments)
Definition: AmendmentTable_test.cpp:54
std::vector::empty
T empty(T... args)
ripple::Rules
Rules controlling protocol behavior.
Definition: Rules.h:33
ripple::AmendmentTable_test::combine
static std::vector< Arg > combine(std::vector< Arg > left, std::vector< Arg > const &right, Args const &... args)
Definition: AmendmentTable_test.cpp:153
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
std::memcpy
T memcpy(T... args)
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
ripple::AmendmentTable_test::makeFeatureInfo
static std::vector< AmendmentTable::FeatureInfo > makeFeatureInfo(std::vector< std::string > const &amendments, VoteBehavior voteBehavior)
Definition: AmendmentTable_test.cpp:90
std::vector::end
T end(T... args)
ripple::AmendmentTable_test::testVoteEnable
void testVoteEnable(FeatureBitset const &feat)
Definition: AmendmentTable_test.cpp:755
ripple::AmendmentTable_test::testDetectMajority
void testDetectMajority(FeatureBitset const &feat)
Definition: AmendmentTable_test.cpp:835
ripple::AmendmentTable_test::testLostMajority
void testLostMajority(FeatureBitset const &feat)
Definition: AmendmentTable_test.cpp:904
ripple::AmendmentTable_test
Definition: AmendmentTable_test.cpp:38
ripple::AmendmentTable_test::makeTable
std::unique_ptr< AmendmentTable > makeTable(Application &app, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed)
Definition: AmendmentTable_test.cpp:193
ripple::AmendmentTable_test::makeDefaultYes
static std::vector< AmendmentTable::FeatureInfo > makeDefaultYes(std::vector< std::string > const &amendments)
Definition: AmendmentTable_test.cpp:104
ripple::hash_append
void hash_append(Hasher &h, ValidatorBlobInfo const &blobInfo)
Definition: ValidatorList.h:909
ripple::AmendmentTable
The amendment table stores the list of enabled and potential amendments.
Definition: AmendmentTable.h:37
std::unique_ptr
STL class.
ripple::AmendmentTable_test::doRound
void doRound(Rules const &rules, AmendmentTable &table, std::chrono::hours hour, std::vector< std::pair< PublicKey, SecretKey >> const &validators, std::vector< std::pair< uint256, int >> const &votes, std::vector< uint256 > &ourVotes, std::set< uint256 > &enabled, majorityAmendments_t &majority)
Definition: AmendmentTable_test.cpp:511
ripple::AmendmentTable_test::AmendmentTable_test
AmendmentTable_test()
Definition: AmendmentTable_test.cpp:188
ripple::AmendmentTable_test::testBadConfig
void testBadConfig()
Definition: AmendmentTable_test.cpp:305
std::set
STL class.
ripple::AmendmentTable_test::run
void run() override
Definition: AmendmentTable_test.cpp:1287
ripple::AmendmentTable_test::amendmentId
static uint256 amendmentId(std::string in)
Definition: AmendmentTable_test.cpp:42
ripple::AmendmentTable_test::enabled_
const std::vector< std::string > enabled_
Definition: AmendmentTable_test.cpp:174
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::sfAmendments
const SF_VECTOR256 sfAmendments
ripple::AmendmentTable_test::combine_arg
static void combine_arg(std::vector< Arg > &dest, std::vector< Arg > const &src, Args const &... args)
Definition: AmendmentTable_test.cpp:140
std::chrono
ripple::VoteBehavior::DefaultYes
@ DefaultYes