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  {
93  result.reserve(amendments.size());
94  for (auto const& a : amendments)
95  {
97  }
98  return result;
99  }
100 
102  makeDefaultYes(uint256 const amendment)
103  {
105  {to_string(amendment), amendment, DefaultVote::yes}};
106  return result;
107  }
108 
109  // All useful amendments are supported amendments.
110  // Enabled amendments are typically a subset of supported amendments.
111  // Vetoed amendments should be supported but not enabled.
112  // Unsupported amendments may be added to the AmendmentTable.
114  "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
115  "l", "m", "n", "o", "p", "q", "r", "s", "t", "u"};
117  enabled_{"b", "d", "f", "h", "j", "l", "n", "p"};
118  std::vector<std::string> const vetoed_{"a", "c", "e"};
121 
124 
126 
127 public:
128  AmendmentTable_test() : journal("AmendmentTable_test", *this)
129  {
130  }
131 
134  Application& app,
135  std::chrono::seconds majorityTime,
137  Section const& enabled,
138  Section const& vetoed)
139  {
140  return make_AmendmentTable(
141  app, majorityTime, supported, enabled, vetoed, journal);
142  }
143 
146  test::jtx::Env& env,
147  std::chrono::seconds majorityTime,
149  Section const& enabled,
150  Section const& vetoed)
151  {
152  return makeTable(env.app(), majorityTime, supported, enabled, vetoed);
153  }
154 
157  {
158  return makeTable(
159  env.app(),
160  majorityTime,
164  }
165 
166  void
168  {
169  testcase("Construction");
170  test::jtx::Env env{*this, makeConfig()};
171  auto table = makeTable(env, weeks(1));
172 
173  for (auto const& a : supportedYes_)
174  {
175  BEAST_EXPECT(table->isSupported(amendmentId(a)));
176  }
177 
178  for (auto const& a : enabled_)
179  {
180  BEAST_EXPECT(table->isSupported(amendmentId(a)));
181  }
182 
183  for (auto const& a : vetoed_)
184  {
185  BEAST_EXPECT(table->isSupported(amendmentId(a)));
186  BEAST_EXPECT(!table->isEnabled(amendmentId(a)));
187  }
188  }
189 
190  void
192  {
193  testcase("Name to ID mapping");
194 
195  test::jtx::Env env{*this, makeConfig()};
196  auto table = makeTable(env, weeks(1));
197 
198  for (auto const& a : supportedYes_)
199  BEAST_EXPECT(table->find(a) == amendmentId(a));
200  for (auto const& a : enabled_)
201  BEAST_EXPECT(table->find(a) == amendmentId(a));
202 
203  for (auto const& a : vetoed_)
204  BEAST_EXPECT(table->find(a) == amendmentId(a));
205  for (auto const& a : unsupported_)
206  BEAST_EXPECT(!table->find(a));
207  for (auto const& a : unsupportedMajority_)
208  BEAST_EXPECT(!table->find(a));
209 
210  // Vetoing an unsupported amendment should add the amendment to table.
211  // Verify that unsupportedID is not in table.
212  uint256 const unsupportedID = amendmentId(unsupported_[0]);
213  {
214  Json::Value const unsupp =
215  table->getJson(unsupportedID)[to_string(unsupportedID)];
216  BEAST_EXPECT(unsupp.size() == 0);
217  }
218 
219  // After vetoing unsupportedID verify that it is in table.
220  table->veto(unsupportedID);
221  {
222  Json::Value const unsupp =
223  table->getJson(unsupportedID)[to_string(unsupportedID)];
224  BEAST_EXPECT(unsupp[jss::vetoed].asBool());
225  }
226  }
227 
228  void
230  {
231  auto const yesVotes = makeDefaultYes(supportedYes_);
232  auto const section = makeSection(vetoed_);
233  auto const id = to_string(amendmentId(enabled_[0]));
234 
235  testcase("Bad Config");
236 
237  { // Two arguments are required - we pass one
238  Section test = section;
239  test.append(id);
240 
241  try
242  {
243  test::jtx::Env env{*this, makeConfig()};
244  if (makeTable(env, weeks(2), yesVotes, test, emptySection))
245  fail("Accepted only amendment ID");
246  }
247  catch (std::exception const& e)
248  {
249  BEAST_EXPECT(
250  e.what() == "Invalid entry '" + id + "' in [Test]");
251  }
252  }
253 
254  { // Two arguments are required - we pass three
255  Section test = section;
256  test.append(id + " Test Name");
257 
258  try
259  {
260  test::jtx::Env env{*this, makeConfig()};
261  if (makeTable(env, weeks(2), yesVotes, test, emptySection))
262  fail("Accepted extra arguments");
263  }
264  catch (std::exception const& e)
265  {
266  BEAST_EXPECT(
267  e.what() ==
268  "Invalid entry '" + id + " Test Name' in [Test]");
269  }
270  }
271 
272  {
273  auto sid = id;
274  sid.resize(sid.length() - 1);
275 
276  Section test = section;
277  test.append(sid + " Name");
278 
279  try
280  {
281  test::jtx::Env env{*this, makeConfig()};
282  if (makeTable(env, weeks(2), yesVotes, test, emptySection))
283  fail("Accepted short amendment ID");
284  }
285  catch (std::exception const& e)
286  {
287  BEAST_EXPECT(
288  e.what() == "Invalid entry '" + sid + " Name' in [Test]");
289  }
290  }
291 
292  {
293  auto sid = id;
294  sid.resize(sid.length() + 1, '0');
295 
296  Section test = section;
297  test.append(sid + " Name");
298 
299  try
300  {
301  test::jtx::Env env{*this, makeConfig()};
302  if (makeTable(env, weeks(2), yesVotes, test, emptySection))
303  fail("Accepted long amendment ID");
304  }
305  catch (std::exception const& e)
306  {
307  BEAST_EXPECT(
308  e.what() == "Invalid entry '" + sid + " Name' in [Test]");
309  }
310  }
311 
312  {
313  auto sid = id;
314  sid.resize(sid.length() - 1);
315  sid.push_back('Q');
316 
317  Section test = section;
318  test.append(sid + " Name");
319 
320  try
321  {
322  test::jtx::Env env{*this, makeConfig()};
323  if (makeTable(env, weeks(2), yesVotes, test, emptySection))
324  fail("Accepted non-hex amendment ID");
325  }
326  catch (std::exception const& e)
327  {
328  BEAST_EXPECT(
329  e.what() == "Invalid entry '" + sid + " Name' in [Test]");
330  }
331  }
332  }
333 
334  void
336  {
337  testcase("enable and veto");
338 
339  test::jtx::Env env{*this, makeConfig()};
341 
342  // Note which entries are enabled
343  std::set<uint256> allEnabled;
344  for (auto const& a : enabled_)
345  allEnabled.insert(amendmentId(a));
346 
347  for (uint256 const& a : allEnabled)
348  BEAST_EXPECT(table->enable(a));
349 
350  // So far all enabled amendments are supported.
351  BEAST_EXPECT(!table->hasUnsupportedEnabled());
352 
353  // Verify all enables are enabled and nothing else.
354  for (std::string const& a : supportedYes_)
355  {
356  uint256 const supportedID = amendmentId(a);
357  bool const enabled = table->isEnabled(supportedID);
358  bool const found = allEnabled.find(supportedID) != allEnabled.end();
359  BEAST_EXPECTS(
360  enabled == found,
361  a + (enabled ? " enabled " : " disabled ") +
362  (found ? " found" : " not found"));
363  }
364 
365  // All supported and unVetoed amendments should be returned as desired.
366  {
367  std::set<uint256> vetoed;
368  for (std::string const& a : vetoed_)
369  vetoed.insert(amendmentId(a));
370 
371  std::vector<uint256> const desired = table->getDesired();
372  for (uint256 const& a : desired)
373  BEAST_EXPECT(vetoed.count(a) == 0);
374 
375  // Unveto an amendment that is already not vetoed. Shouldn't
376  // hurt anything, but the values returned by getDesired()
377  // shouldn't change.
378  BEAST_EXPECT(!table->unVeto(amendmentId(supportedYes_[1])));
379  BEAST_EXPECT(desired == table->getDesired());
380  }
381 
382  // UnVeto one of the vetoed amendments. It should now be desired.
383  {
384  uint256 const unvetoedID = amendmentId(vetoed_[0]);
385  BEAST_EXPECT(table->unVeto(unvetoedID));
386 
387  std::vector<uint256> const desired = table->getDesired();
388  BEAST_EXPECT(
389  std::find(desired.begin(), desired.end(), unvetoedID) !=
390  desired.end());
391  }
392 
393  // Veto all supported amendments. Now desired should be empty.
394  for (std::string const& a : supportedYes_)
395  {
396  table->veto(amendmentId(a));
397  }
398  BEAST_EXPECT(table->getDesired().empty());
399 
400  // Enable an unsupported amendment.
401  {
402  BEAST_EXPECT(!table->hasUnsupportedEnabled());
403  table->enable(amendmentId(unsupported_[0]));
404  BEAST_EXPECT(table->hasUnsupportedEnabled());
405  }
406  }
407 
409  makeValidators(int num)
410  {
412  ret.reserve(num);
413  for (int i = 0; i < num; ++i)
414  {
416  }
417  return ret;
418  }
419 
420  static NetClock::time_point
422  {
423  return NetClock::time_point{w};
424  }
425 
426  // Execute a pretend consensus round for a flag ledger
427  void
429  uint256 const& feat,
430  AmendmentTable& table,
431  weeks week,
432  std::vector<std::pair<PublicKey, SecretKey>> const& validators,
433  std::vector<std::pair<uint256, int>> const& votes,
434  std::vector<uint256>& ourVotes,
435  std::set<uint256>& enabled,
436  majorityAmendments_t& majority)
437  {
438  // Do a round at the specified time
439  // Returns the amendments we voted for
440 
441  // Parameters:
442  // table: Our table of known and vetoed amendments
443  // validators: The addreses of validators we trust
444  // votes: Amendments and the number of validators who vote for them
445  // ourVotes: The amendments we vote for in our validation
446  // enabled: In/out enabled amendments
447  // majority: In/our majority amendments (and when they got a majority)
448 
449  auto const roundTime = weekTime(week);
450 
451  // Build validations
453  validations.reserve(validators.size());
454 
455  int i = 0;
456  for (auto const& [pub, sec] : validators)
457  {
458  ++i;
459  std::vector<uint256> field;
460 
461  for (auto const& [hash, nVotes] : votes)
462  {
463  if (feat == fixAmendmentMajorityCalc ? nVotes >= i : nVotes > i)
464  {
465  // We vote yes on this amendment
466  field.push_back(hash);
467  }
468  }
469 
470  auto v = std::make_shared<STValidation>(
472  pub,
473  sec,
474  calcNodeID(pub),
475  [&field](STValidation& v) {
476  if (!field.empty())
477  v.setFieldV256(
479  v.setFieldU32(sfLedgerSequence, 6180339);
480  });
481 
482  validations.emplace_back(v);
483  }
484 
485  ourVotes = table.doValidation(enabled);
486 
487  auto actions = table.doVoting(
488  Rules({feat}), roundTime, enabled, majority, validations);
489  for (auto const& [hash, action] : actions)
490  {
491  // This code assumes other validators do as we do
492 
493  switch (action)
494  {
495  case 0:
496  // amendment goes from majority to enabled
497  if (enabled.find(hash) != enabled.end())
498  Throw<std::runtime_error>("enabling already enabled");
499  if (majority.find(hash) == majority.end())
500  Throw<std::runtime_error>("enabling without majority");
501  enabled.insert(hash);
502  majority.erase(hash);
503  break;
504 
505  case tfGotMajority:
506  if (majority.find(hash) != majority.end())
507  Throw<std::runtime_error>(
508  "got majority while having majority");
509  majority[hash] = roundTime;
510  break;
511 
512  case tfLostMajority:
513  if (majority.find(hash) == majority.end())
514  Throw<std::runtime_error>(
515  "lost majority without majority");
516  majority.erase(hash);
517  break;
518 
519  default:
520  Throw<std::runtime_error>("unknown action");
521  }
522  }
523  }
524 
525  // No vote on unknown amendment
526  void
528  {
529  testcase("Vote NO on unknown");
530 
531  auto const testAmendment = amendmentId("TestAmendment");
532  auto const validators = makeValidators(10);
533 
534  test::jtx::Env env{*this};
535  auto table =
537 
539  std::vector<uint256> ourVotes;
540  std::set<uint256> enabled;
541  majorityAmendments_t majority;
542 
543  doRound(
544  feat,
545  *table,
546  weeks{1},
547  validators,
548  votes,
549  ourVotes,
550  enabled,
551  majority);
552  BEAST_EXPECT(ourVotes.empty());
553  BEAST_EXPECT(enabled.empty());
554  BEAST_EXPECT(majority.empty());
555 
556  votes.emplace_back(testAmendment, validators.size());
557 
558  doRound(
559  feat,
560  *table,
561  weeks{2},
562  validators,
563  votes,
564  ourVotes,
565  enabled,
566  majority);
567  BEAST_EXPECT(ourVotes.empty());
568  BEAST_EXPECT(enabled.empty());
569 
570  majority[testAmendment] = weekTime(weeks{1});
571 
572  // Note that the simulation code assumes others behave as we do,
573  // so the amendment won't get enabled
574  doRound(
575  feat,
576  *table,
577  weeks{5},
578  validators,
579  votes,
580  ourVotes,
581  enabled,
582  majority);
583  BEAST_EXPECT(ourVotes.empty());
584  BEAST_EXPECT(enabled.empty());
585  }
586 
587  // No vote on vetoed amendment
588  void
589  testNoOnVetoed(uint256 const& feat)
590  {
591  testcase("Vote NO on vetoed");
592 
593  auto const testAmendment = amendmentId("vetoedAmendment");
594 
595  test::jtx::Env env{*this};
596  auto table = makeTable(
597  env, weeks(2), emptyYes, emptySection, makeSection(testAmendment));
598 
599  auto const validators = makeValidators(10);
600 
602  std::vector<uint256> ourVotes;
603  std::set<uint256> enabled;
604  majorityAmendments_t majority;
605 
606  doRound(
607  feat,
608  *table,
609  weeks{1},
610  validators,
611  votes,
612  ourVotes,
613  enabled,
614  majority);
615  BEAST_EXPECT(ourVotes.empty());
616  BEAST_EXPECT(enabled.empty());
617  BEAST_EXPECT(majority.empty());
618 
619  votes.emplace_back(testAmendment, validators.size());
620 
621  doRound(
622  feat,
623  *table,
624  weeks{2},
625  validators,
626  votes,
627  ourVotes,
628  enabled,
629  majority);
630  BEAST_EXPECT(ourVotes.empty());
631  BEAST_EXPECT(enabled.empty());
632 
633  majority[testAmendment] = weekTime(weeks{1});
634 
635  doRound(
636  feat,
637  *table,
638  weeks{5},
639  validators,
640  votes,
641  ourVotes,
642  enabled,
643  majority);
644  BEAST_EXPECT(ourVotes.empty());
645  BEAST_EXPECT(enabled.empty());
646  }
647 
648  // Vote on and enable known, not-enabled amendment
649  void
650  testVoteEnable(uint256 const& feat)
651  {
652  testcase("voteEnable");
653 
654  test::jtx::Env env{*this};
655  auto table = makeTable(
656  env,
657  weeks(2),
659  emptySection,
660  emptySection);
661 
662  auto const validators = makeValidators(10);
664  std::vector<uint256> ourVotes;
665  std::set<uint256> enabled;
666  majorityAmendments_t majority;
667 
668  // Week 1: We should vote for all known amendments not enabled
669  doRound(
670  feat,
671  *table,
672  weeks{1},
673  validators,
674  votes,
675  ourVotes,
676  enabled,
677  majority);
678  BEAST_EXPECT(ourVotes.size() == supportedYes_.size());
679  BEAST_EXPECT(enabled.empty());
680  for (auto const& i : supportedYes_)
681  BEAST_EXPECT(majority.find(amendmentId(i)) == majority.end());
682 
683  // Now, everyone votes for this feature
684  for (auto const& i : supportedYes_)
685  votes.emplace_back(amendmentId(i), validators.size());
686 
687  // Week 2: We should recognize a majority
688  doRound(
689  feat,
690  *table,
691  weeks{2},
692  validators,
693  votes,
694  ourVotes,
695  enabled,
696  majority);
697  BEAST_EXPECT(ourVotes.size() == supportedYes_.size());
698  BEAST_EXPECT(enabled.empty());
699 
700  for (auto const& i : supportedYes_)
701  BEAST_EXPECT(majority[amendmentId(i)] == weekTime(weeks{2}));
702 
703  // Week 5: We should enable the amendment
704  doRound(
705  feat,
706  *table,
707  weeks{5},
708  validators,
709  votes,
710  ourVotes,
711  enabled,
712  majority);
713  BEAST_EXPECT(enabled.size() == supportedYes_.size());
714 
715  // Week 6: We should remove it from our votes and from having a majority
716  doRound(
717  feat,
718  *table,
719  weeks{6},
720  validators,
721  votes,
722  ourVotes,
723  enabled,
724  majority);
725  BEAST_EXPECT(enabled.size() == supportedYes_.size());
726  BEAST_EXPECT(ourVotes.empty());
727  for (auto const& i : supportedYes_)
728  BEAST_EXPECT(majority.find(amendmentId(i)) == majority.end());
729  }
730 
731  // Detect majority at 80%, enable later
732  void
734  {
735  testcase("detectMajority");
736 
737  auto const testAmendment = amendmentId("detectMajority");
738  test::jtx::Env env{*this};
739  auto table = makeTable(
740  env,
741  weeks(2),
742  makeDefaultYes(testAmendment),
743  emptySection,
744  emptySection);
745 
746  auto const validators = makeValidators(16);
747 
748  std::set<uint256> enabled;
749  majorityAmendments_t majority;
750 
751  for (int i = 0; i <= 17; ++i)
752  {
754  std::vector<uint256> ourVotes;
755 
756  if ((i > 0) && (i < 17))
757  votes.emplace_back(testAmendment, i);
758 
759  doRound(
760  feat,
761  *table,
762  weeks{i},
763  validators,
764  votes,
765  ourVotes,
766  enabled,
767  majority);
768 
769  if (i < 13) // 13 => 13/16 = 0.8125 => > 80%
770  {
771  // We are voting yes, not enabled, no majority
772  BEAST_EXPECT(!ourVotes.empty());
773  BEAST_EXPECT(enabled.empty());
774  BEAST_EXPECT(majority.empty());
775  }
776  else if (i < 15)
777  {
778  // We have a majority, not enabled, keep voting
779  BEAST_EXPECT(!ourVotes.empty());
780  BEAST_EXPECT(!majority.empty());
781  BEAST_EXPECT(enabled.empty());
782  }
783  else if (i == 15)
784  {
785  // enable, keep voting, remove from majority
786  BEAST_EXPECT(!ourVotes.empty());
787  BEAST_EXPECT(majority.empty());
788  BEAST_EXPECT(!enabled.empty());
789  }
790  else
791  {
792  // Done, we should be enabled and not voting
793  BEAST_EXPECT(ourVotes.empty());
794  BEAST_EXPECT(majority.empty());
795  BEAST_EXPECT(!enabled.empty());
796  }
797  }
798  }
799 
800  // Detect loss of majority
801  void
803  {
804  testcase("lostMajority");
805 
806  auto const testAmendment = amendmentId("lostMajority");
807  auto const validators = makeValidators(16);
808 
809  test::jtx::Env env{*this};
810  auto table = makeTable(
811  env,
812  weeks(8),
813  makeDefaultYes(testAmendment),
814  emptySection,
815  emptySection);
816 
817  std::set<uint256> enabled;
818  majorityAmendments_t majority;
819 
820  {
821  // establish majority
823  std::vector<uint256> ourVotes;
824 
825  votes.emplace_back(testAmendment, validators.size());
826 
827  doRound(
828  feat,
829  *table,
830  weeks{1},
831  validators,
832  votes,
833  ourVotes,
834  enabled,
835  majority);
836 
837  BEAST_EXPECT(enabled.empty());
838  BEAST_EXPECT(!majority.empty());
839  }
840 
841  for (int i = 1; i < 8; ++i)
842  {
844  std::vector<uint256> ourVotes;
845 
846  // Gradually reduce support
847  votes.emplace_back(testAmendment, validators.size() - i);
848 
849  doRound(
850  feat,
851  *table,
852  weeks{i + 1},
853  validators,
854  votes,
855  ourVotes,
856  enabled,
857  majority);
858 
859  if (i < 4) // 16 - 3 = 13 => 13/16 = 0.8125 => > 80%
860  { // 16 - 4 = 12 => 12/16 = 0.75 => < 80%
861  // We are voting yes, not enabled, majority
862  BEAST_EXPECT(!ourVotes.empty());
863  BEAST_EXPECT(enabled.empty());
864  BEAST_EXPECT(!majority.empty());
865  }
866  else
867  {
868  // No majority, not enabled, keep voting
869  BEAST_EXPECT(!ourVotes.empty());
870  BEAST_EXPECT(majority.empty());
871  BEAST_EXPECT(enabled.empty());
872  }
873  }
874  }
875 
876  void
878  {
879  testcase("hasUnsupportedEnabled");
880 
881  using namespace std::chrono_literals;
882  weeks constexpr w(1);
883  test::jtx::Env env{*this, makeConfig()};
884  auto table = makeTable(env, w);
885  BEAST_EXPECT(!table->hasUnsupportedEnabled());
886  BEAST_EXPECT(!table->firstUnsupportedExpected());
887  BEAST_EXPECT(table->needValidatedLedger(1));
888 
889  std::set<uint256> enabled;
892  unsupported_.end(),
893  [&enabled](auto const& s) { enabled.insert(amendmentId(s)); });
894 
895  majorityAmendments_t majority;
896  table->doValidatedLedger(1, enabled, majority);
897  BEAST_EXPECT(table->hasUnsupportedEnabled());
898  BEAST_EXPECT(!table->firstUnsupportedExpected());
899 
900  NetClock::duration t{1000s};
904  [&majority, &t](auto const& s) {
905  majority[amendmentId(s)] = NetClock::time_point{--t};
906  });
907 
908  table->doValidatedLedger(1, enabled, majority);
909  BEAST_EXPECT(table->hasUnsupportedEnabled());
910  BEAST_EXPECT(
911  table->firstUnsupportedExpected() &&
912  *table->firstUnsupportedExpected() == NetClock::time_point{t} + w);
913 
914  // Make sure the table knows when it needs an update.
915  BEAST_EXPECT(!table->needValidatedLedger(256));
916  BEAST_EXPECT(table->needValidatedLedger(257));
917  }
918 
919  void
920  testFeature(uint256 const& feat)
921  {
922  testNoOnUnknown(feat);
923  testNoOnVetoed(feat);
924  testVoteEnable(feat);
925  testDetectMajority(feat);
926  testLostMajority(feat);
927  }
928 
929  void
930  run() override
931  {
932  testConstruct();
933  testGet();
934  testBadConfig();
935  testEnableVeto();
937  testFeature({});
939  }
940 };
941 
942 BEAST_DEFINE_TESTSUITE(AmendmentTable, app, ripple);
943 
944 } // namespace ripple
ripple::tfGotMajority
constexpr std::uint32_t tfGotMajority
Definition: TxFlags.h:109
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:42
ripple::Application
Definition: Application.h:115
ripple::tfLostMajority
constexpr std::uint32_t tfLostMajority
Definition: TxFlags.h:110
std::for_each
T for_each(T... args)
ripple::AmendmentTable_test::journal
test::SuiteJournal journal
Definition: AmendmentTable_test.cpp:125
ripple::AmendmentTable_test::supportedYes_
const std::vector< std::string > supportedYes_
Definition: AmendmentTable_test.cpp:113
ripple::AmendmentTable_test::testVoteEnable
void testVoteEnable(uint256 const &feat)
Definition: AmendmentTable_test.cpp:650
ripple::AmendmentTable_test::unsupported_
const std::vector< std::string > unsupported_
Definition: AmendmentTable_test.cpp:119
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::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:299
ripple::AmendmentTable_test::makeValidators
std::vector< std::pair< PublicKey, SecretKey > > makeValidators(int num)
Definition: AmendmentTable_test.cpp:409
ripple::AmendmentTable_test::makeSection
static Section makeSection(uint256 const &amendment)
Definition: AmendmentTable_test.cpp:71
ripple::sfLedgerSequence
const SF_UINT32 sfLedgerSequence
std::pair
std::vector::reserve
T reserve(T... args)
ripple::AmendmentTable_test::testConstruct
void testConstruct()
Definition: AmendmentTable_test.cpp:167
std::vector< std::string >
std::find
T find(T... args)
std::vector::size
T size(T... args)
std::chrono::seconds
ripple::AmendmentTable_test::makeDefaultYes
static std::vector< AmendmentTable::FeatureInfo > makeDefaultYes(uint256 const amendment)
Definition: AmendmentTable_test.cpp:102
ripple::QualityDirection::in
@ in
ripple::AmendmentTable_test::testNoOnUnknown
void testNoOnUnknown(uint256 const &feat)
Definition: AmendmentTable_test.cpp:527
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
ripple::AmendmentTable_test::testHasUnsupported
void testHasUnsupported()
Definition: AmendmentTable_test.cpp:877
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
ripple::base_uint::data
pointer data()
Definition: base_uint.h:115
ripple::AmendmentTable_test::weekTime
static NetClock::time_point weekTime(weeks w)
Definition: AmendmentTable_test.cpp:421
ripple::STValidation
Definition: STValidation.h:44
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:512
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::unsupportedMajority_
const std::vector< std::string > unsupportedMajority_
Definition: AmendmentTable_test.cpp:120
ripple::base_uint< 256 >
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:335
ripple::weeks
std::chrono::duration< int, std::ratio_multiply< days::period, std::ratio< 7 > >> weeks
Definition: chrono.h:41
ripple::DefaultVote::yes
@ yes
ripple::AmendmentTable_test::makeTable
std::unique_ptr< AmendmentTable > makeTable(test::jtx::Env &env, std::chrono::seconds majorityTime)
Definition: AmendmentTable_test.cpp:156
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::map
STL class.
ripple::AmendmentTable_test::vetoed_
const std::vector< std::string > vetoed_
Definition: AmendmentTable_test.cpp:118
ripple::AmendmentTable_test::emptySection
const Section emptySection
Definition: AmendmentTable_test.cpp:122
ripple::test::SuiteJournal
Definition: SuiteJournal.h:88
ripple::KeyType::secp256k1
@ secp256k1
ripple::AmendmentTable_test::testDetectMajority
void testDetectMajority(uint256 const &feat)
Definition: AmendmentTable_test.cpp:733
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::doRound
void doRound(uint256 const &feat, AmendmentTable &table, weeks week, 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:428
ripple::AmendmentTable_test::testGet
void testGet()
Definition: AmendmentTable_test.cpp:191
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:145
std::vector::begin
T begin(T... args)
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::emptyYes
const std::vector< AmendmentTable::FeatureInfo > emptyYes
Definition: AmendmentTable_test.cpp:123
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
std::set::count
T count(T... args)
ripple::STVector256
Definition: STVector256.h:29
ripple::AmendmentTable_test::makeSection
static Section makeSection(std::string const &name, std::vector< std::string > const &amendments)
Definition: AmendmentTable_test.cpp:54
std::map::empty
T empty(T... args)
ripple::Rules
Rules controlling protocol behavior.
Definition: Rules.h:33
ripple::AmendmentTable_test::testFeature
void testFeature(uint256 const &feat)
Definition: AmendmentTable_test.cpp:920
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
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:789
std::vector::end
T end(T... args)
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:133
ripple::AmendmentTable_test::makeDefaultYes
static std::vector< AmendmentTable::FeatureInfo > makeDefaultYes(std::vector< std::string > const &amendments)
Definition: AmendmentTable_test.cpp:90
ripple::hash_append
void hash_append(Hasher &h, ValidatorBlobInfo const &blobInfo)
Definition: ValidatorList.h:897
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::AmendmentTable_test
AmendmentTable_test()
Definition: AmendmentTable_test.cpp:128
ripple::AmendmentTable_test::testBadConfig
void testBadConfig()
Definition: AmendmentTable_test.cpp:229
std::set
STL class.
ripple::AmendmentTable_test::run
void run() override
Definition: AmendmentTable_test.cpp:930
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:117
ripple::AmendmentTable_test::testNoOnVetoed
void testNoOnVetoed(uint256 const &feat)
Definition: AmendmentTable_test.cpp:589
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
std::exception::what
T what(T... args)
ripple::AmendmentTable_test::testLostMajority
void testLostMajority(uint256 const &feat)
Definition: AmendmentTable_test.cpp:802
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::sfAmendments
const SF_VECTOR256 sfAmendments