rippled
ValidatorList_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright 2015 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/ValidatorList.h>
21 #include <ripple/basics/Slice.h>
22 #include <ripple/basics/base64.h>
23 #include <ripple/basics/strHex.h>
24 #include <ripple/overlay/impl/ProtocolMessage.h>
25 #include <ripple/protocol/HashPrefix.h>
26 #include <ripple/protocol/PublicKey.h>
27 #include <ripple/protocol/SecretKey.h>
28 #include <ripple/protocol/Sign.h>
29 #include <ripple/protocol/digest.h>
30 #include <ripple/protocol/jss.h>
31 #include <ripple/protocol/messages.h>
32 #include <test/jtx.h>
33 
34 #include <boost/beast/core/multi_buffer.hpp>
35 
36 namespace ripple {
37 namespace test {
38 
39 class ValidatorList_test : public beast::unit_test::suite
40 {
41 private:
42  struct Validator
43  {
47  };
48 
49  static PublicKey
51  {
53  }
54 
55  static PublicKey
57  {
59  }
60 
61  static std::string
63  PublicKey const& pk,
64  SecretKey const& sk,
65  PublicKey const& spk,
66  SecretKey const& ssk,
67  int seq)
68  {
69  STObject st(sfGeneric);
70  st[sfSequence] = seq;
71  st[sfPublicKey] = pk;
72 
74  {
75  st[sfSigningPubKey] = spk;
76  sign(st, HashPrefix::manifest, *publicKeyType(spk), ssk);
77  }
78 
79  sign(
80  st,
82  *publicKeyType(pk),
83  sk,
85 
86  Serializer s;
87  st.add(s);
88 
89  return std::string(static_cast<char const*>(s.data()), s.size());
90  }
91 
92  static std::string
94  {
95  STObject st(sfGeneric);
97  st[sfPublicKey] = pk;
98 
99  sign(
100  st,
102  *publicKeyType(pk),
103  sk,
105 
106  Serializer s;
107  st.add(s);
108 
109  return std::string(static_cast<char const*>(s.data()), s.size());
110  }
111 
112  static Validator
114  {
115  auto const secret = randomSecretKey();
116  auto const masterPublic = derivePublicKey(KeyType::ed25519, secret);
117  auto const signingKeys = randomKeyPair(KeyType::secp256k1);
118  return {
119  masterPublic,
120  signingKeys.first,
122  masterPublic,
123  secret,
124  signingKeys.first,
125  signingKeys.second,
126  1))};
127  }
128 
131  std::vector<Validator> const& validators,
132  std::size_t sequence,
133  std::size_t validUntil,
134  std::optional<std::size_t> validFrom = {})
135  {
136  std::string data = "{\"sequence\":" + std::to_string(sequence) +
137  ",\"expiration\":" + std::to_string(validUntil);
138  if (validFrom)
139  data += ",\"effective\":" + std::to_string(*validFrom);
140  data += ",\"validators\":[";
141 
142  for (auto const& val : validators)
143  {
144  data += "{\"validation_public_key\":\"" + strHex(val.masterPublic) +
145  "\",\"manifest\":\"" + val.manifest + "\"},";
146  }
147 
148  data.pop_back();
149  data += "]}";
150  return base64_encode(data);
151  }
152 
155  std::string const& blob,
157  {
158  auto const data = base64_decode(blob);
159  return strHex(sign(keys.first, keys.second, makeSlice(data)));
160  }
161 
162  static hash_set<NodeID>
164  {
165  hash_set<NodeID> res;
166  res.reserve(pks.size());
167  for (auto const& pk : pks)
168  res.insert(calcNodeID(pk));
169  return res;
170  }
171 
172  void
174  ValidatorList::PublisherListStats const& result,
175  PublicKey pubKey,
176  ListDisposition expectedWorst,
177  ListDisposition expectedBest)
178  {
179  BEAST_EXPECT(
181  (result.publisherKey && *result.publisherKey == pubKey));
182  BEAST_EXPECT(result.bestDisposition() == expectedBest);
183  BEAST_EXPECT(result.worstDisposition() == expectedWorst);
184  }
185 
186  void
188  {
189  testcase("Genesis Quorum");
190 
191  ManifestCache manifests;
192  jtx::Env env(*this);
193  auto& app = env.app();
194  {
195  auto trustedKeys = std::make_unique<ValidatorList>(
196  manifests,
197  manifests,
198  env.timeKeeper(),
199  app.config().legacy("database_path"),
200  env.journal);
201  BEAST_EXPECT(trustedKeys->quorum() == 1);
202  }
203  {
204  std::size_t minQuorum = 0;
205  auto trustedKeys = std::make_unique<ValidatorList>(
206  manifests,
207  manifests,
208  env.timeKeeper(),
209  app.config().legacy("database_path"),
210  env.journal,
211  minQuorum);
212  BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
213  }
214  }
215 
216  void
218  {
219  testcase("Config Load");
220 
221  jtx::Env env(
222  *this, jtx::envconfig(), nullptr, beast::severities::kDisabled);
223  auto& app = env.app();
224  PublicKey emptyLocalKey;
225  std::vector<std::string> const emptyCfgKeys;
226  std::vector<std::string> const emptyCfgPublishers;
227 
228  auto const localSigningKeys = randomKeyPair(KeyType::secp256k1);
229  auto const localSigningPublicOuter = localSigningKeys.first;
230  auto const localSigningSecret = localSigningKeys.second;
231  auto const localMasterSecret = randomSecretKey();
232  auto const localMasterPublic =
233  derivePublicKey(KeyType::ed25519, localMasterSecret);
234 
235  std::string const cfgManifest(makeManifestString(
236  localMasterPublic,
237  localMasterSecret,
238  localSigningPublicOuter,
239  localSigningSecret,
240  1));
241 
242  auto format = [](PublicKey const& publicKey,
243  char const* comment = nullptr) {
244  auto ret = toBase58(TokenType::NodePublic, publicKey);
245 
246  if (comment)
247  ret += comment;
248 
249  return ret;
250  };
251 
252  std::vector<PublicKey> configList;
253  configList.reserve(8);
254 
255  while (configList.size() != 8)
256  configList.push_back(randomNode());
257 
258  // Correct configuration
259  std::vector<std::string> cfgKeys(
260  {format(configList[0]),
261  format(configList[1], " Comment"),
262  format(configList[2], " Multi Word Comment"),
263  format(configList[3], " Leading Whitespace"),
264  format(configList[4], " Trailing Whitespace "),
265  format(configList[5], " Leading & Trailing Whitespace "),
266  format(
267  configList[6],
268  " Leading, Trailing & Internal Whitespace "),
269  format(configList[7], " ")});
270 
271  {
272  ManifestCache manifests;
273  auto trustedKeys = std::make_unique<ValidatorList>(
274  manifests,
275  manifests,
276  env.timeKeeper(),
277  app.config().legacy("database_path"),
278  env.journal);
279 
280  // Correct (empty) configuration
281  BEAST_EXPECT(trustedKeys->load(
282  emptyLocalKey, emptyCfgKeys, emptyCfgPublishers));
283 
284  // load local validator key with or without manifest
285  BEAST_EXPECT(trustedKeys->load(
286  localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers));
287  BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
288 
289  manifests.applyManifest(*deserializeManifest(cfgManifest));
290  BEAST_EXPECT(trustedKeys->load(
291  localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers));
292 
293  BEAST_EXPECT(trustedKeys->listed(localMasterPublic));
294  BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
295  }
296  {
297  // load should add validator keys from config
298  ManifestCache manifests;
299  auto trustedKeys = std::make_unique<ValidatorList>(
300  manifests,
301  manifests,
302  env.timeKeeper(),
303  app.config().legacy("database_path"),
304  env.journal);
305 
306  BEAST_EXPECT(
307  trustedKeys->load(emptyLocalKey, cfgKeys, emptyCfgPublishers));
308 
309  for (auto const& n : configList)
310  BEAST_EXPECT(trustedKeys->listed(n));
311 
312  // load should accept Ed25519 master public keys
313  auto const masterNode1 = randomMasterKey();
314  auto const masterNode2 = randomMasterKey();
315 
316  std::vector<std::string> cfgMasterKeys(
317  {format(masterNode1), format(masterNode2, " Comment")});
318  BEAST_EXPECT(trustedKeys->load(
319  emptyLocalKey, cfgMasterKeys, emptyCfgPublishers));
320  BEAST_EXPECT(trustedKeys->listed(masterNode1));
321  BEAST_EXPECT(trustedKeys->listed(masterNode2));
322 
323  // load should reject invalid config keys
324  BEAST_EXPECT(!trustedKeys->load(
325  emptyLocalKey, {"NotAPublicKey"}, emptyCfgPublishers));
326  BEAST_EXPECT(!trustedKeys->load(
327  emptyLocalKey,
328  {format(randomNode(), "!")},
329  emptyCfgPublishers));
330 
331  // load terminates when encountering an invalid entry
332  auto const goodKey = randomNode();
333  BEAST_EXPECT(!trustedKeys->load(
334  emptyLocalKey,
335  {format(randomNode(), "!"), format(goodKey)},
336  emptyCfgPublishers));
337  BEAST_EXPECT(!trustedKeys->listed(goodKey));
338  }
339  {
340  // local validator key on config list
341  ManifestCache manifests;
342  auto trustedKeys = std::make_unique<ValidatorList>(
343  manifests,
344  manifests,
345  env.timeKeeper(),
346  app.config().legacy("database_path"),
347  env.journal);
348 
349  auto const localSigningPublic =
350  parseBase58<PublicKey>(TokenType::NodePublic, cfgKeys.front());
351 
352  BEAST_EXPECT(trustedKeys->load(
353  *localSigningPublic, cfgKeys, emptyCfgPublishers));
354 
355  BEAST_EXPECT(trustedKeys->localPublicKey() == localSigningPublic);
356  BEAST_EXPECT(trustedKeys->listed(*localSigningPublic));
357  for (auto const& n : configList)
358  BEAST_EXPECT(trustedKeys->listed(n));
359  }
360  {
361  // local validator key not on config list
362  ManifestCache manifests;
363  auto trustedKeys = std::make_unique<ValidatorList>(
364  manifests,
365  manifests,
366  env.timeKeeper(),
367  app.config().legacy("database_path"),
368  env.journal);
369 
370  auto const localSigningPublic = randomNode();
371  BEAST_EXPECT(trustedKeys->load(
372  localSigningPublic, cfgKeys, emptyCfgPublishers));
373 
374  BEAST_EXPECT(trustedKeys->localPublicKey() == localSigningPublic);
375  BEAST_EXPECT(trustedKeys->listed(localSigningPublic));
376  for (auto const& n : configList)
377  BEAST_EXPECT(trustedKeys->listed(n));
378  }
379  {
380  // local validator key (with manifest) not on config list
381  ManifestCache manifests;
382  auto trustedKeys = std::make_unique<ValidatorList>(
383  manifests,
384  manifests,
385  env.timeKeeper(),
386  app.config().legacy("database_path"),
387  env.journal);
388 
389  manifests.applyManifest(*deserializeManifest(cfgManifest));
390 
391  BEAST_EXPECT(trustedKeys->load(
392  localSigningPublicOuter, cfgKeys, emptyCfgPublishers));
393 
394  BEAST_EXPECT(trustedKeys->localPublicKey() == localMasterPublic);
395  BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
396  BEAST_EXPECT(trustedKeys->listed(localMasterPublic));
397  for (auto const& n : configList)
398  BEAST_EXPECT(trustedKeys->listed(n));
399  }
400  {
401  ManifestCache manifests;
402  auto trustedKeys = std::make_unique<ValidatorList>(
403  manifests,
404  manifests,
405  env.timeKeeper(),
406  app.config().legacy("database_path"),
407  env.journal);
408 
409  // load should reject invalid validator list signing keys
410  std::vector<std::string> badPublishers({"NotASigningKey"});
411  BEAST_EXPECT(
412  !trustedKeys->load(emptyLocalKey, emptyCfgKeys, badPublishers));
413 
414  // load should reject validator list signing keys with invalid
415  // encoding
418  badPublishers.clear();
419  for (auto const& key : keys)
420  badPublishers.push_back(toBase58(TokenType::NodePublic, key));
421 
422  BEAST_EXPECT(
423  !trustedKeys->load(emptyLocalKey, emptyCfgKeys, badPublishers));
424  for (auto const& key : keys)
425  BEAST_EXPECT(!trustedKeys->trustedPublisher(key));
426 
427  // load should accept valid validator list publisher keys
428  std::vector<std::string> cfgPublishers;
429  for (auto const& key : keys)
430  cfgPublishers.push_back(strHex(key));
431 
432  BEAST_EXPECT(
433  trustedKeys->load(emptyLocalKey, emptyCfgKeys, cfgPublishers));
434  for (auto const& key : keys)
435  BEAST_EXPECT(trustedKeys->trustedPublisher(key));
436  }
437  {
438  // Attempt to load a publisher key that has been revoked.
439  // Should fail
440  ManifestCache valManifests;
441  ManifestCache pubManifests;
442  auto trustedKeys = std::make_unique<ValidatorList>(
443  valManifests,
444  pubManifests,
445  env.timeKeeper(),
446  app.config().legacy("database_path"),
447  env.journal);
448 
449  auto const pubRevokedSecret = randomSecretKey();
450  auto const pubRevokedPublic =
451  derivePublicKey(KeyType::ed25519, pubRevokedSecret);
452  auto const pubRevokedSigning = randomKeyPair(KeyType::secp256k1);
453  // make this manifest revoked (seq num = max)
454  // -- thus should not be loaded
456  pubRevokedPublic,
457  pubRevokedSecret,
458  pubRevokedSigning.first,
459  pubRevokedSigning.second,
461 
462  // this one is not revoked (and not in manifest cache at all.)
463  auto legitKey = randomMasterKey();
464 
465  std::vector<std::string> cfgPublishers = {
466  strHex(pubRevokedPublic), strHex(legitKey)};
467  BEAST_EXPECT(
468  trustedKeys->load(emptyLocalKey, emptyCfgKeys, cfgPublishers));
469 
470  BEAST_EXPECT(!trustedKeys->trustedPublisher(pubRevokedPublic));
471  BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey));
472  }
473  }
474 
475  void
477  {
478  testcase("Apply list");
479  using namespace std::chrono_literals;
480 
481  std::string const siteUri = "testApplyList.test";
482 
483  auto checkAvailable =
484  [this](
485  auto const& trustedKeys,
486  auto const& hexPublic,
487  auto const& manifest,
488  auto const version,
490  expected) {
491  const auto available = trustedKeys->getAvailable(hexPublic);
492 
493  BEAST_EXPECT(!version || available);
494  if (available)
495  {
496  auto const& a = *available;
497  BEAST_EXPECT(a[jss::public_key] == hexPublic);
498  BEAST_EXPECT(a[jss::manifest] == manifest);
499  // Because multiple lists were processed, the version was
500  // overridden
501  BEAST_EXPECT(a[jss::version] == version);
502  if (version == 1)
503  {
504  BEAST_EXPECT(expected.size() == 1);
505  BEAST_EXPECT(a[jss::blob] == expected[0].first);
506  BEAST_EXPECT(a[jss::signature] == expected[0].second);
507  BEAST_EXPECT(!a.isMember(jss::blobs_v2));
508  }
509  else if (BEAST_EXPECT(a.isMember(jss::blobs_v2)))
510  {
511  BEAST_EXPECT(!a.isMember(jss::blob));
512  BEAST_EXPECT(!a.isMember(jss::signature));
513  auto const& blobs_v2 = a[jss::blobs_v2];
514  BEAST_EXPECT(
515  blobs_v2.isArray() &&
516  blobs_v2.size() == expected.size());
517 
518  for (unsigned int i = 0; i < expected.size(); ++i)
519  {
520  BEAST_EXPECT(
521  blobs_v2[i][jss::blob] == expected[i].first);
522  BEAST_EXPECT(
523  blobs_v2[i][jss::signature] ==
524  expected[i].second);
525  }
526  }
527  }
528  };
529 
530  ManifestCache manifests;
531  jtx::Env env(*this);
532  auto& app = env.app();
533  auto trustedKeys = std::make_unique<ValidatorList>(
534  manifests,
535  manifests,
536  env.app().timeKeeper(),
537  app.config().legacy("database_path"),
538  env.journal);
539 
540  auto expectTrusted =
541  [this, &trustedKeys](std::vector<Validator> const& list) {
542  for (auto const& val : list)
543  {
544  BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
545  BEAST_EXPECT(trustedKeys->listed(val.signingPublic));
546  }
547  };
548 
549  auto expectUntrusted =
550  [this, &trustedKeys](std::vector<Validator> const& list) {
551  for (auto const& val : list)
552  {
553  BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
554  BEAST_EXPECT(!trustedKeys->listed(val.signingPublic));
555  }
556  };
557 
558  auto const publisherSecret = randomSecretKey();
559  auto const publisherPublic =
560  derivePublicKey(KeyType::ed25519, publisherSecret);
561  const auto hexPublic =
562  strHex(publisherPublic.begin(), publisherPublic.end());
563  auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1);
564  auto const manifest1 = base64_encode(makeManifestString(
565  publisherPublic,
566  publisherSecret,
567  pubSigningKeys1.first,
568  pubSigningKeys1.second,
569  1));
570 
571  std::vector<std::string> cfgKeys1({strHex(publisherPublic)});
572  PublicKey emptyLocalKey;
573  std::vector<std::string> emptyCfgKeys;
574 
575  BEAST_EXPECT(trustedKeys->load(emptyLocalKey, emptyCfgKeys, cfgKeys1));
576 
578  auto constexpr listSize = 20;
579  auto constexpr numLists = 9;
581  // 1-based to correspond with the individually named blobs below.
582  for (auto i = 1; i <= numLists; ++i)
583  {
584  auto& list = lists[i];
585  list.reserve(listSize);
586  while (list.size() < listSize)
587  list.push_back(randomValidator());
588  }
589  return lists;
590  }();
591 
592  // Attempt an expired list (fail) and a single list (succeed)
593  env.timeKeeper().set(env.timeKeeper().now() + 1s);
594  auto const version = 1;
595  auto const sequence1 = 1;
596  auto const expiredblob = makeList(
597  lists.at(1),
598  sequence1,
599  env.timeKeeper().now().time_since_epoch().count());
600  auto const expiredSig = signList(expiredblob, pubSigningKeys1);
601 
602  NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s;
603  auto const sequence2 = 2;
604  auto const blob2 = makeList(
605  lists.at(2), sequence2, validUntil.time_since_epoch().count());
606  auto const sig2 = signList(blob2, pubSigningKeys1);
607 
608  checkResult(
609  trustedKeys->applyLists(
610  manifest1,
611  version,
612  {{expiredblob, expiredSig, {}}, {blob2, sig2, {}}},
613  siteUri),
614  publisherPublic,
617 
618  expectTrusted(lists.at(2));
619 
620  checkAvailable(
621  trustedKeys, hexPublic, manifest1, version, {{blob2, sig2}});
622 
623  // Do not apply future lists, but process them
624  auto const version2 = 2;
625  auto const sequence7 = 7;
626  auto const effective7 = validUntil - 60s;
627  auto const expiration7 = effective7 + 3600s;
628  auto const blob7 = makeList(
629  lists.at(7),
630  sequence7,
631  expiration7.time_since_epoch().count(),
632  effective7.time_since_epoch().count());
633  auto const sig7 = signList(blob7, pubSigningKeys1);
634 
635  auto const sequence8 = 8;
636  auto const effective8 = expiration7 - 60s;
637  auto const expiration8 = effective8 + 3600s;
638  auto const blob8 = makeList(
639  lists.at(8),
640  sequence8,
641  expiration8.time_since_epoch().count(),
642  effective8.time_since_epoch().count());
643  auto const sig8 = signList(blob8, pubSigningKeys1);
644 
645  checkResult(
646  trustedKeys->applyLists(
647  manifest1,
648  version2,
649  {{blob7, sig7, {}}, {blob8, sig8, {}}},
650  siteUri),
651  publisherPublic,
654 
655  expectUntrusted(lists.at(7));
656  expectUntrusted(lists.at(8));
657 
658  // Do not apply out-of-order future list, but process it
659  auto const sequence6 = 6;
660  auto const effective6 = effective7 - 60s;
661  auto const expiration6 = effective6 + 3600s;
662  auto const blob6 = makeList(
663  lists.at(6),
664  sequence6,
665  expiration6.time_since_epoch().count(),
666  effective6.time_since_epoch().count());
667  auto const sig6 = signList(blob6, pubSigningKeys1);
668 
669  // Process future list that is overridden by a later list
670  auto const sequence6a = 5;
671  auto const effective6a = effective6 + 60s;
672  auto const expiration6a = effective6a + 3600s;
673  auto const blob6a = makeList(
674  lists.at(5),
675  sequence6a,
676  expiration6a.time_since_epoch().count(),
677  effective6a.time_since_epoch().count());
678  auto const sig6a = signList(blob6a, pubSigningKeys1);
679 
680  checkResult(
681  trustedKeys->applyLists(
682  manifest1,
683  version,
684  {{blob6a, sig6a, {}}, {blob6, sig6, {}}},
685  siteUri),
686  publisherPublic,
687  ListDisposition::pending,
688  ListDisposition::pending);
689 
690  expectUntrusted(lists.at(6));
691  expectTrusted(lists.at(2));
692 
693  // Do not apply re-process lists known future sequence numbers
694 
695  checkResult(
696  trustedKeys->applyLists(
697  manifest1,
698  version,
699  {{blob7, sig7, {}}, {blob6, sig6, {}}},
700  siteUri),
701  publisherPublic,
702  ListDisposition::known_sequence,
703  ListDisposition::known_sequence);
704 
705  expectUntrusted(lists.at(6));
706  expectUntrusted(lists.at(7));
707  expectTrusted(lists.at(2));
708 
709  // do not use list from untrusted publisher
710  auto const untrustedManifest = base64_encode(makeManifestString(
711  randomMasterKey(),
712  publisherSecret,
713  pubSigningKeys1.first,
714  pubSigningKeys1.second,
715  1));
716 
717  checkResult(
718  trustedKeys->applyLists(
719  untrustedManifest, version, {{blob2, sig2, {}}}, siteUri),
720  publisherPublic,
721  ListDisposition::untrusted,
722  ListDisposition::untrusted);
723 
724  // do not use list with unhandled version
725  auto const badVersion = 666;
726  checkResult(
727  trustedKeys->applyLists(
728  manifest1, badVersion, {{blob2, sig2, {}}}, siteUri),
729  publisherPublic,
730  ListDisposition::unsupported_version,
731  ListDisposition::unsupported_version);
732 
733  // apply list with highest sequence number
734  auto const sequence3 = 3;
735  auto const blob3 = makeList(
736  lists.at(3), sequence3, validUntil.time_since_epoch().count());
737  auto const sig3 = signList(blob3, pubSigningKeys1);
738 
739  checkResult(
740  trustedKeys->applyLists(
741  manifest1, version, {{blob3, sig3, {}}}, siteUri),
742  publisherPublic,
743  ListDisposition::accepted,
744  ListDisposition::accepted);
745 
746  expectUntrusted(lists.at(1));
747  expectUntrusted(lists.at(2));
748  expectTrusted(lists.at(3));
749 
750  // Note that blob6a is not present, because it was dropped during
751  // processing
752  checkAvailable(
753  trustedKeys,
754  hexPublic,
755  manifest1,
756  2,
757  {{blob3, sig3}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
758 
759  // do not re-apply lists with past or current sequence numbers
760  checkResult(
761  trustedKeys->applyLists(
762  manifest1,
763  version,
764  {{blob2, sig2, {}}, {blob3, sig3, {}}},
765  siteUri),
766  publisherPublic,
767  ListDisposition::stale,
768  ListDisposition::same_sequence);
769 
770  // apply list with new publisher key updated by manifest. Also send some
771  // old lists along with the old manifest
772  auto const pubSigningKeys2 = randomKeyPair(KeyType::secp256k1);
773  auto manifest2 = base64_encode(makeManifestString(
774  publisherPublic,
775  publisherSecret,
776  pubSigningKeys2.first,
777  pubSigningKeys2.second,
778  2));
779 
780  auto const sequence4 = 4;
781  auto const blob4 = makeList(
782  lists.at(4), sequence4, validUntil.time_since_epoch().count());
783  auto const sig4 = signList(blob4, pubSigningKeys2);
784 
785  checkResult(
786  trustedKeys->applyLists(
787  manifest2,
788  version,
789  {{blob2, sig2, manifest1},
790  {blob3, sig3, manifest1},
791  {blob4, sig4, {}}},
792  siteUri),
793  publisherPublic,
794  ListDisposition::stale,
795  ListDisposition::accepted);
796 
797  expectUntrusted(lists.at(2));
798  expectUntrusted(lists.at(3));
799  expectTrusted(lists.at(4));
800 
801  checkAvailable(
802  trustedKeys,
803  hexPublic,
804  manifest2,
805  2,
806  {{blob4, sig4}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
807 
808  auto const sequence5 = 5;
809  auto const blob5 = makeList(
810  lists.at(5), sequence5, validUntil.time_since_epoch().count());
811  auto const badSig = signList(blob5, pubSigningKeys1);
812  checkResult(
813  trustedKeys->applyLists(
814  manifest1, version, {{blob5, badSig, {}}}, siteUri),
815  publisherPublic,
816  ListDisposition::invalid,
817  ListDisposition::invalid);
818 
819  expectUntrusted(lists.at(2));
820  expectUntrusted(lists.at(3));
821  expectTrusted(lists.at(4));
822  expectUntrusted(lists.at(5));
823 
824  // Reprocess the pending list, but the signature is no longer valid
825  checkResult(
826  trustedKeys->applyLists(
827  manifest1,
828  version,
829  {{blob7, sig7, {}}, {blob8, sig8, {}}},
830  siteUri),
831  publisherPublic,
832  ListDisposition::invalid,
833  ListDisposition::invalid);
834 
835  expectTrusted(lists.at(4));
836  expectUntrusted(lists.at(7));
837  expectUntrusted(lists.at(8));
838 
839  // Automatically rotate the first pending already processed list using
840  // updateTrusted. Note that the timekeeper is NOT moved, so the close
841  // time will be ahead of the test's wall clock
842  trustedKeys->updateTrusted(
843  {},
844  effective6 + 1s,
845  env.app().getOPs(),
846  env.app().overlay(),
847  env.app().getHashRouter());
848 
849  expectUntrusted(lists.at(3));
850  expectTrusted(lists.at(6));
851 
852  checkAvailable(
853  trustedKeys,
854  hexPublic,
855  manifest2,
856  2,
857  {{blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
858 
859  // Automatically rotate the LAST pending list using updateTrusted,
860  // bypassing blob7. Note that the timekeeper IS moved, so the provided
861  // close time will be behind the test's wall clock, and thus the wall
862  // clock is used.
863  env.timeKeeper().set(effective8);
864  trustedKeys->updateTrusted(
865  {},
866  effective8 + 1s,
867  env.app().getOPs(),
868  env.app().overlay(),
869  env.app().getHashRouter());
870 
871  expectUntrusted(lists.at(6));
872  expectUntrusted(lists.at(7));
873  expectTrusted(lists.at(8));
874 
875  checkAvailable(trustedKeys, hexPublic, manifest2, 2, {{blob8, sig8}});
876 
877  // resign the pending list with new key and validate it, but it's
878  // already valid Also try reprocessing the pending list with an
879  // explicit manifest
880  // - it is still invalid
881  auto const sig8_2 = signList(blob8, pubSigningKeys2);
882 
883  checkResult(
884  trustedKeys->applyLists(
885  manifest2,
886  version,
887  {{blob8, sig8, manifest1}, {blob8, sig8_2, {}}},
888  siteUri),
889  publisherPublic,
890  ListDisposition::invalid,
891  ListDisposition::same_sequence);
892 
893  expectTrusted(lists.at(8));
894 
895  checkAvailable(trustedKeys, hexPublic, manifest2, 2, {{blob8, sig8}});
896 
897  // do not apply list with revoked publisher key
898  // applied list is removed due to revoked publisher key
899  auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
900  auto maxManifest = base64_encode(
901  makeRevocationString(publisherPublic, publisherSecret));
902 
903  auto const sequence9 = 9;
904  auto const blob9 = makeList(
905  lists.at(9), sequence9, validUntil.time_since_epoch().count());
906  auto const sig9 = signList(blob9, signingKeysMax);
907 
908  checkResult(
909  trustedKeys->applyLists(
910  maxManifest, version, {{blob9, sig9, {}}}, siteUri),
911  publisherPublic,
912  ListDisposition::untrusted,
913  ListDisposition::untrusted);
914 
915  BEAST_EXPECT(!trustedKeys->trustedPublisher(publisherPublic));
916  for (auto const& [num, list] : lists)
917  {
918  (void)num;
919  expectUntrusted(list);
920  }
921 
922  checkAvailable(trustedKeys, hexPublic, manifest2, 0, {});
923  }
924 
925  void
927  {
928  testcase("GetAvailable");
929  using namespace std::chrono_literals;
930 
931  std::string const siteUri = "testApplyList.test";
932 
933  ManifestCache manifests;
934  jtx::Env env(*this);
935  auto& app = env.app();
936  auto trustedKeys = std::make_unique<ValidatorList>(
937  manifests,
938  manifests,
939  env.app().timeKeeper(),
940  app.config().legacy("database_path"),
941  env.journal);
942 
943  auto const publisherSecret = randomSecretKey();
944  auto const publisherPublic =
945  derivePublicKey(KeyType::ed25519, publisherSecret);
946  const auto hexPublic =
947  strHex(publisherPublic.begin(), publisherPublic.end());
948  auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1);
949  auto const manifest = base64_encode(makeManifestString(
950  publisherPublic,
951  publisherSecret,
952  pubSigningKeys1.first,
953  pubSigningKeys1.second,
954  1));
955 
956  std::vector<std::string> cfgKeys1({strHex(publisherPublic)});
957  PublicKey emptyLocalKey;
958  std::vector<std::string> emptyCfgKeys;
959 
960  BEAST_EXPECT(trustedKeys->load(emptyLocalKey, emptyCfgKeys, cfgKeys1));
961 
962  std::vector<Validator> const list = []() {
963  auto constexpr listSize = 20;
965  list.reserve(listSize);
966  while (list.size() < listSize)
967  list.push_back(randomValidator());
968  return list;
969  }();
970 
971  // Process a list
972  env.timeKeeper().set(env.timeKeeper().now() + 1s);
973  NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s;
974  auto const blob =
975  makeList(list, 1, validUntil.time_since_epoch().count());
976  auto const sig = signList(blob, pubSigningKeys1);
977 
978  {
979  // list unavailable
980  auto const available = trustedKeys->getAvailable(hexPublic);
981  BEAST_EXPECT(!available);
982  }
983 
984  BEAST_EXPECT(
985  trustedKeys->applyLists(manifest, 1, {{blob, sig, {}}}, siteUri)
986  .bestDisposition() == ListDisposition::accepted);
987 
988  {
989  // invalid public key
990  auto const available =
991  trustedKeys->getAvailable(hexPublic + "invalid", 1);
992  BEAST_EXPECT(!available);
993  }
994 
995  {
996  // unknown public key
997  auto const badSecret = randomSecretKey();
998  auto const badPublic = derivePublicKey(KeyType::ed25519, badSecret);
999  const auto hexBad = strHex(badPublic.begin(), badPublic.end());
1000 
1001  auto const available = trustedKeys->getAvailable(hexBad, 1);
1002  BEAST_EXPECT(!available);
1003  }
1004  {
1005  // bad version 0
1006  auto const available = trustedKeys->getAvailable(hexPublic, 0);
1007  if (BEAST_EXPECT(available))
1008  {
1009  auto const& a = *available;
1010  BEAST_EXPECT(!a);
1011  }
1012  }
1013  {
1014  // bad version 3
1015  auto const available = trustedKeys->getAvailable(hexPublic, 3);
1016  if (BEAST_EXPECT(available))
1017  {
1018  auto const& a = *available;
1019  BEAST_EXPECT(!a);
1020  }
1021  }
1022  {
1023  // version 1
1024  auto const available = trustedKeys->getAvailable(hexPublic, 1);
1025  if (BEAST_EXPECT(available))
1026  {
1027  auto const& a = *available;
1028  BEAST_EXPECT(a[jss::public_key] == hexPublic);
1029  BEAST_EXPECT(a[jss::manifest] == manifest);
1030  BEAST_EXPECT(a[jss::version] == 1);
1031 
1032  BEAST_EXPECT(a[jss::blob] == blob);
1033  BEAST_EXPECT(a[jss::signature] == sig);
1034  BEAST_EXPECT(!a.isMember(jss::blobs_v2));
1035  }
1036  }
1037 
1038  {
1039  // version 2
1040  auto const available = trustedKeys->getAvailable(hexPublic, 2);
1041  if (BEAST_EXPECT(available))
1042  {
1043  auto const& a = *available;
1044  BEAST_EXPECT(a[jss::public_key] == hexPublic);
1045  BEAST_EXPECT(a[jss::manifest] == manifest);
1046  BEAST_EXPECT(a[jss::version] == 2);
1047 
1048  if (BEAST_EXPECT(a.isMember(jss::blobs_v2)))
1049  {
1050  BEAST_EXPECT(!a.isMember(jss::blob));
1051  BEAST_EXPECT(!a.isMember(jss::signature));
1052  auto const& blobs_v2 = a[jss::blobs_v2];
1053  BEAST_EXPECT(blobs_v2.isArray() && blobs_v2.size() == 1);
1054 
1055  BEAST_EXPECT(blobs_v2[0u][jss::blob] == blob);
1056  BEAST_EXPECT(blobs_v2[0u][jss::signature] == sig);
1057  }
1058  }
1059  }
1060  }
1061 
1062  void
1064  {
1065  testcase("Update trusted");
1066 
1067  std::string const siteUri = "testUpdateTrusted.test";
1068 
1069  PublicKey emptyLocalKeyOuter;
1070  ManifestCache manifestsOuter;
1071  jtx::Env env(*this);
1072  auto& app = env.app();
1073  auto trustedKeysOuter = std::make_unique<ValidatorList>(
1074  manifestsOuter,
1075  manifestsOuter,
1076  env.timeKeeper(),
1077  app.config().legacy("database_path"),
1078  env.journal);
1079 
1080  std::vector<std::string> cfgPublishersOuter;
1081  hash_set<NodeID> activeValidatorsOuter;
1082 
1083  std::size_t const maxKeys = 40;
1084  {
1085  std::vector<std::string> cfgKeys;
1086  cfgKeys.reserve(maxKeys);
1087  hash_set<NodeID> unseenValidators;
1088 
1089  while (cfgKeys.size() != maxKeys)
1090  {
1091  auto const valKey = randomNode();
1092  cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1093  if (cfgKeys.size() <= maxKeys - 5)
1094  activeValidatorsOuter.emplace(calcNodeID(valKey));
1095  else
1096  unseenValidators.emplace(calcNodeID(valKey));
1097  }
1098 
1099  BEAST_EXPECT(trustedKeysOuter->load(
1100  emptyLocalKeyOuter, cfgKeys, cfgPublishersOuter));
1101 
1102  // updateTrusted should make all configured validators trusted
1103  // even if they are not active/seen
1104  TrustChanges changes = trustedKeysOuter->updateTrusted(
1105  activeValidatorsOuter,
1106  env.timeKeeper().now(),
1107  env.app().getOPs(),
1108  env.app().overlay(),
1109  env.app().getHashRouter());
1110 
1111  for (auto const& val : unseenValidators)
1112  activeValidatorsOuter.emplace(val);
1113 
1114  BEAST_EXPECT(changes.added == activeValidatorsOuter);
1115  BEAST_EXPECT(changes.removed.empty());
1116  BEAST_EXPECT(
1117  trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1118  for (auto const& val : cfgKeys)
1119  {
1120  if (auto const valKey =
1121  parseBase58<PublicKey>(TokenType::NodePublic, val))
1122  {
1123  BEAST_EXPECT(trustedKeysOuter->listed(*valKey));
1124  BEAST_EXPECT(trustedKeysOuter->trusted(*valKey));
1125  }
1126  else
1127  fail();
1128  }
1129 
1130  changes = trustedKeysOuter->updateTrusted(
1131  activeValidatorsOuter,
1132  env.timeKeeper().now(),
1133  env.app().getOPs(),
1134  env.app().overlay(),
1135  env.app().getHashRouter());
1136  BEAST_EXPECT(changes.added.empty());
1137  BEAST_EXPECT(changes.removed.empty());
1138  BEAST_EXPECT(
1139  trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1140  }
1141  {
1142  // update with manifests
1143  auto const masterPrivate = randomSecretKey();
1144  auto const masterPublic =
1145  derivePublicKey(KeyType::ed25519, masterPrivate);
1146 
1147  std::vector<std::string> cfgKeys(
1148  {toBase58(TokenType::NodePublic, masterPublic)});
1149 
1150  BEAST_EXPECT(trustedKeysOuter->load(
1151  emptyLocalKeyOuter, cfgKeys, cfgPublishersOuter));
1152 
1153  auto const signingKeys1 = randomKeyPair(KeyType::secp256k1);
1154  auto const signingPublic1 = signingKeys1.first;
1155  activeValidatorsOuter.emplace(calcNodeID(masterPublic));
1156 
1157  // Should not trust ephemeral signing key if there is no manifest
1158  TrustChanges changes = trustedKeysOuter->updateTrusted(
1159  activeValidatorsOuter,
1160  env.timeKeeper().now(),
1161  env.app().getOPs(),
1162  env.app().overlay(),
1163  env.app().getHashRouter());
1164  BEAST_EXPECT(changes.added == asNodeIDs({masterPublic}));
1165  BEAST_EXPECT(changes.removed.empty());
1166  BEAST_EXPECT(
1167  trustedKeysOuter->quorum() == std::ceil((maxKeys + 1) * 0.8f));
1168  BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1169  BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1170  BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
1171  BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
1172 
1173  // Should trust the ephemeral signing key from the applied manifest
1174  auto m1 = deserializeManifest(makeManifestString(
1175  masterPublic,
1176  masterPrivate,
1177  signingPublic1,
1178  signingKeys1.second,
1179  1));
1180 
1181  BEAST_EXPECT(
1182  manifestsOuter.applyManifest(std::move(*m1)) ==
1183  ManifestDisposition::accepted);
1184  BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1185  BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1186  BEAST_EXPECT(trustedKeysOuter->listed(signingPublic1));
1187  BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic1));
1188 
1189  // Should only trust the ephemeral signing key
1190  // from the newest applied manifest
1191  auto const signingKeys2 = randomKeyPair(KeyType::secp256k1);
1192  auto const signingPublic2 = signingKeys2.first;
1193  auto m2 = deserializeManifest(makeManifestString(
1194  masterPublic,
1195  masterPrivate,
1196  signingPublic2,
1197  signingKeys2.second,
1198  2));
1199  BEAST_EXPECT(
1200  manifestsOuter.applyManifest(std::move(*m2)) ==
1201  ManifestDisposition::accepted);
1202  BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1203  BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1204  BEAST_EXPECT(trustedKeysOuter->listed(signingPublic2));
1205  BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic2));
1206  BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
1207  BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
1208 
1209  // Should not trust keys from revoked master public key
1210  auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
1211  auto const signingPublicMax = signingKeysMax.first;
1212  activeValidatorsOuter.emplace(calcNodeID(signingPublicMax));
1213  auto mMax = deserializeManifest(
1214  makeRevocationString(masterPublic, masterPrivate));
1215 
1216  BEAST_EXPECT(mMax->revoked());
1217  BEAST_EXPECT(
1218  manifestsOuter.applyManifest(std::move(*mMax)) ==
1219  ManifestDisposition::accepted);
1220  BEAST_EXPECT(
1221  manifestsOuter.getSigningKey(masterPublic) == masterPublic);
1222  BEAST_EXPECT(manifestsOuter.revoked(masterPublic));
1223 
1224  // Revoked key remains trusted until list is updated
1225  BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1226  BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1227 
1228  changes = trustedKeysOuter->updateTrusted(
1229  activeValidatorsOuter,
1230  env.timeKeeper().now(),
1231  env.app().getOPs(),
1232  env.app().overlay(),
1233  env.app().getHashRouter());
1234  BEAST_EXPECT(changes.removed == asNodeIDs({masterPublic}));
1235  BEAST_EXPECT(changes.added.empty());
1236  BEAST_EXPECT(
1237  trustedKeysOuter->quorum() == std::ceil(maxKeys * 0.8f));
1238  BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1239  BEAST_EXPECT(!trustedKeysOuter->trusted(masterPublic));
1240  BEAST_EXPECT(!trustedKeysOuter->listed(signingPublicMax));
1241  BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublicMax));
1242  BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic2));
1243  BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic2));
1244  BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
1245  BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
1246  }
1247  {
1248  // Make quorum unattainable if lists from any publishers are
1249  // unavailable
1250  auto trustedKeys = std::make_unique<ValidatorList>(
1251  manifestsOuter,
1252  manifestsOuter,
1253  env.timeKeeper(),
1254  app.config().legacy("database_path"),
1255  env.journal);
1256  auto const publisherSecret = randomSecretKey();
1257  auto const publisherPublic =
1258  derivePublicKey(KeyType::ed25519, publisherSecret);
1259 
1260  std::vector<std::string> cfgPublishers({strHex(publisherPublic)});
1261  std::vector<std::string> emptyCfgKeys;
1262 
1263  BEAST_EXPECT(trustedKeys->load(
1264  emptyLocalKeyOuter, emptyCfgKeys, cfgPublishers));
1265 
1266  TrustChanges changes = trustedKeys->updateTrusted(
1267  activeValidatorsOuter,
1268  env.timeKeeper().now(),
1269  env.app().getOPs(),
1270  env.app().overlay(),
1271  env.app().getHashRouter());
1272  BEAST_EXPECT(changes.removed.empty());
1273  BEAST_EXPECT(changes.added.empty());
1274  BEAST_EXPECT(
1275  trustedKeys->quorum() ==
1277  }
1278  {
1279  // Should use custom minimum quorum
1280  std::size_t const minQuorum = 1;
1281  ManifestCache manifests;
1282  auto trustedKeys = std::make_unique<ValidatorList>(
1283  manifests,
1284  manifests,
1285  env.timeKeeper(),
1286  app.config().legacy("database_path"),
1287  env.journal,
1288  minQuorum);
1289 
1290  std::size_t n = 10;
1291  std::vector<std::string> cfgKeys;
1292  cfgKeys.reserve(n);
1293  hash_set<NodeID> expectedTrusted;
1294  hash_set<NodeID> activeValidators;
1295  NodeID toBeSeen;
1296 
1297  while (cfgKeys.size() < n)
1298  {
1299  auto const valKey = randomNode();
1300  cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1301  expectedTrusted.emplace(calcNodeID(valKey));
1302  if (cfgKeys.size() < std::ceil(n * 0.8f))
1303  activeValidators.emplace(calcNodeID(valKey));
1304  else if (cfgKeys.size() < std::ceil(n * 0.8f))
1305  toBeSeen = calcNodeID(valKey);
1306  }
1307 
1308  BEAST_EXPECT(trustedKeys->load(
1309  emptyLocalKeyOuter, cfgKeys, cfgPublishersOuter));
1310 
1311  TrustChanges changes = trustedKeys->updateTrusted(
1312  activeValidators,
1313  env.timeKeeper().now(),
1314  env.app().getOPs(),
1315  env.app().overlay(),
1316  env.app().getHashRouter());
1317  BEAST_EXPECT(changes.removed.empty());
1318  BEAST_EXPECT(changes.added == expectedTrusted);
1319  BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
1320 
1321  // Use configured quorum even when seen validators >= quorum
1322  activeValidators.emplace(toBeSeen);
1323  changes = trustedKeys->updateTrusted(
1324  activeValidators,
1325  env.timeKeeper().now(),
1326  env.app().getOPs(),
1327  env.app().overlay(),
1328  env.app().getHashRouter());
1329  BEAST_EXPECT(changes.removed.empty());
1330  BEAST_EXPECT(changes.added.empty());
1331  BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
1332  }
1333  {
1334  // Remove expired published list
1335  auto trustedKeys = std::make_unique<ValidatorList>(
1336  manifestsOuter,
1337  manifestsOuter,
1338  env.app().timeKeeper(),
1339  app.config().legacy("database_path"),
1340  env.journal);
1341 
1342  PublicKey emptyLocalKey;
1343  std::vector<std::string> emptyCfgKeys;
1344  auto const publisherKeys = randomKeyPair(KeyType::secp256k1);
1345  auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1346  auto const manifest = base64_encode(makeManifestString(
1347  publisherKeys.first,
1348  publisherKeys.second,
1349  pubSigningKeys.first,
1350  pubSigningKeys.second,
1351  1));
1352 
1353  std::vector<std::string> cfgKeys({strHex(publisherKeys.first)});
1354 
1355  BEAST_EXPECT(
1356  trustedKeys->load(emptyLocalKey, emptyCfgKeys, cfgKeys));
1357 
1358  std::vector<Validator> list({randomValidator(), randomValidator()});
1359  hash_set<NodeID> activeValidators(
1360  asNodeIDs({list[0].masterPublic, list[1].masterPublic}));
1361 
1362  // do not apply expired list
1363  auto const version = 1;
1364  auto const sequence = 1;
1365  using namespace std::chrono_literals;
1366  NetClock::time_point const validUntil =
1367  env.timeKeeper().now() + 60s;
1368  auto const blob =
1369  makeList(list, sequence, validUntil.time_since_epoch().count());
1370  auto const sig = signList(blob, pubSigningKeys);
1371 
1372  BEAST_EXPECT(
1373  ListDisposition::accepted ==
1374  trustedKeys
1375  ->applyLists(manifest, version, {{blob, sig, {}}}, siteUri)
1376  .bestDisposition());
1377 
1378  TrustChanges changes = trustedKeys->updateTrusted(
1379  activeValidators,
1380  env.timeKeeper().now(),
1381  env.app().getOPs(),
1382  env.app().overlay(),
1383  env.app().getHashRouter());
1384  BEAST_EXPECT(changes.removed.empty());
1385  BEAST_EXPECT(changes.added == activeValidators);
1386  for (Validator const& val : list)
1387  {
1388  BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1389  BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
1390  }
1391  BEAST_EXPECT(trustedKeys->quorum() == 2);
1392 
1393  env.timeKeeper().set(validUntil);
1394  changes = trustedKeys->updateTrusted(
1395  activeValidators,
1396  env.timeKeeper().now(),
1397  env.app().getOPs(),
1398  env.app().overlay(),
1399  env.app().getHashRouter());
1400  BEAST_EXPECT(changes.removed == activeValidators);
1401  BEAST_EXPECT(changes.added.empty());
1402  BEAST_EXPECT(!trustedKeys->trusted(list[0].masterPublic));
1403  BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
1404  BEAST_EXPECT(
1405  trustedKeys->quorum() ==
1407 
1408  // (Re)trust validators from new valid list
1409  std::vector<Validator> list2({list[0], randomValidator()});
1410  activeValidators.insert(calcNodeID(list2[1].masterPublic));
1411  auto const sequence2 = 2;
1412  NetClock::time_point const expiration2 =
1413  env.timeKeeper().now() + 60s;
1414  auto const blob2 = makeList(
1415  list2, sequence2, expiration2.time_since_epoch().count());
1416  auto const sig2 = signList(blob2, pubSigningKeys);
1417 
1418  BEAST_EXPECT(
1419  ListDisposition::accepted ==
1420  trustedKeys
1421  ->applyLists(
1422  manifest, version, {{blob2, sig2, {}}}, siteUri)
1423  .bestDisposition());
1424 
1425  changes = trustedKeys->updateTrusted(
1426  activeValidators,
1427  env.timeKeeper().now(),
1428  env.app().getOPs(),
1429  env.app().overlay(),
1430  env.app().getHashRouter());
1431  BEAST_EXPECT(changes.removed.empty());
1432  BEAST_EXPECT(
1433  changes.added ==
1434  asNodeIDs({list2[0].masterPublic, list2[1].masterPublic}));
1435  for (Validator const& val : list2)
1436  {
1437  BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1438  BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
1439  }
1440  BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
1441  BEAST_EXPECT(!trustedKeys->trusted(list[1].signingPublic));
1442  BEAST_EXPECT(trustedKeys->quorum() == 2);
1443  }
1444  {
1445  // Test 1-9 configured validators
1446  auto trustedKeys = std::make_unique<ValidatorList>(
1447  manifestsOuter,
1448  manifestsOuter,
1449  env.timeKeeper(),
1450  app.config().legacy("database_path"),
1451  env.journal);
1452 
1453  std::vector<std::string> cfgPublishers;
1454  hash_set<NodeID> activeValidators;
1455  hash_set<PublicKey> activeKeys;
1456 
1457  std::vector<std::string> cfgKeys;
1458  cfgKeys.reserve(9);
1459 
1460  while (cfgKeys.size() < cfgKeys.capacity())
1461  {
1462  auto const valKey = randomNode();
1463  cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1464  activeValidators.emplace(calcNodeID(valKey));
1465  activeKeys.emplace(valKey);
1466  BEAST_EXPECT(trustedKeys->load(
1467  emptyLocalKeyOuter, cfgKeys, cfgPublishers));
1468  TrustChanges changes = trustedKeys->updateTrusted(
1469  activeValidators,
1470  env.timeKeeper().now(),
1471  env.app().getOPs(),
1472  env.app().overlay(),
1473  env.app().getHashRouter());
1474  BEAST_EXPECT(changes.removed.empty());
1475  BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
1476  BEAST_EXPECT(
1477  trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1478  for (auto const& key : activeKeys)
1479  BEAST_EXPECT(trustedKeys->trusted(key));
1480  }
1481  }
1482  {
1483  // Test 2-9 configured validators as validator
1484  auto trustedKeys = std::make_unique<ValidatorList>(
1485  manifestsOuter,
1486  manifestsOuter,
1487  env.timeKeeper(),
1488  app.config().legacy("database_path"),
1489  env.journal);
1490 
1491  auto const localKey = randomNode();
1492  std::vector<std::string> cfgPublishers;
1493  hash_set<NodeID> activeValidators;
1494  hash_set<PublicKey> activeKeys;
1495  std::vector<std::string> cfgKeys{
1496  toBase58(TokenType::NodePublic, localKey)};
1497  cfgKeys.reserve(9);
1498 
1499  while (cfgKeys.size() < cfgKeys.capacity())
1500  {
1501  auto const valKey = randomNode();
1502  cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1503  activeValidators.emplace(calcNodeID(valKey));
1504  activeKeys.emplace(valKey);
1505 
1506  BEAST_EXPECT(
1507  trustedKeys->load(localKey, cfgKeys, cfgPublishers));
1508  TrustChanges changes = trustedKeys->updateTrusted(
1509  activeValidators,
1510  env.timeKeeper().now(),
1511  env.app().getOPs(),
1512  env.app().overlay(),
1513  env.app().getHashRouter());
1514  BEAST_EXPECT(changes.removed.empty());
1515  if (cfgKeys.size() > 2)
1516  BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
1517  else
1518  BEAST_EXPECT(
1519  changes.added == asNodeIDs({localKey, valKey}));
1520 
1521  BEAST_EXPECT(
1522  trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1523 
1524  for (auto const& key : activeKeys)
1525  BEAST_EXPECT(trustedKeys->trusted(key));
1526  }
1527  }
1528  {
1529  // Trusted set should include all validators from multiple lists
1530  ManifestCache manifests;
1531  auto trustedKeys = std::make_unique<ValidatorList>(
1532  manifests,
1533  manifests,
1534  env.timeKeeper(),
1535  app.config().legacy("database_path"),
1536  env.journal);
1537 
1538  hash_set<NodeID> activeValidators;
1539  std::vector<Validator> valKeys;
1540  valKeys.reserve(maxKeys);
1541 
1542  while (valKeys.size() != maxKeys)
1543  {
1544  valKeys.push_back(randomValidator());
1545  activeValidators.emplace(
1546  calcNodeID(valKeys.back().masterPublic));
1547  }
1548 
1549  auto addPublishedList = [this,
1550  &env,
1551  &trustedKeys,
1552  &valKeys,
1553  &siteUri]() {
1554  auto const publisherSecret = randomSecretKey();
1555  auto const publisherPublic =
1556  derivePublicKey(KeyType::ed25519, publisherSecret);
1557  auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1558  auto const manifest = base64_encode(makeManifestString(
1559  publisherPublic,
1560  publisherSecret,
1561  pubSigningKeys.first,
1562  pubSigningKeys.second,
1563  1));
1564 
1565  std::vector<std::string> cfgPublishers(
1566  {strHex(publisherPublic)});
1567  PublicKey emptyLocalKey;
1568  std::vector<std::string> emptyCfgKeys;
1569 
1570  BEAST_EXPECT(trustedKeys->load(
1571  emptyLocalKey, emptyCfgKeys, cfgPublishers));
1572 
1573  auto const version = 1;
1574  auto const sequence = 1;
1575  using namespace std::chrono_literals;
1576  NetClock::time_point const validUntil =
1577  env.timeKeeper().now() + 3600s;
1578  auto const blob = makeList(
1579  valKeys, sequence, validUntil.time_since_epoch().count());
1580  auto const sig = signList(blob, pubSigningKeys);
1581 
1582  BEAST_EXPECT(
1583  ListDisposition::accepted ==
1584  trustedKeys
1585  ->applyLists(
1586  manifest, version, {{blob, sig, {}}}, siteUri)
1587  .bestDisposition());
1588  };
1589 
1590  // Apply multiple published lists
1591  for (auto i = 0; i < 3; ++i)
1592  addPublishedList();
1593 
1594  TrustChanges changes = trustedKeys->updateTrusted(
1595  activeValidators,
1596  env.timeKeeper().now(),
1597  env.app().getOPs(),
1598  env.app().overlay(),
1599  env.app().getHashRouter());
1600 
1601  BEAST_EXPECT(
1602  trustedKeys->quorum() == std::ceil(valKeys.size() * 0.8f));
1603 
1604  hash_set<NodeID> added;
1605  for (auto const& val : valKeys)
1606  {
1607  BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1608  added.insert(calcNodeID(val.masterPublic));
1609  }
1610  BEAST_EXPECT(changes.added == added);
1611  BEAST_EXPECT(changes.removed.empty());
1612  }
1613  }
1614 
1615  void
1617  {
1618  testcase("Expires");
1619 
1620  std::string const siteUri = "testExpires.test";
1621 
1622  jtx::Env env(*this);
1623  auto& app = env.app();
1624 
1625  auto toStr = [](PublicKey const& publicKey) {
1626  return toBase58(TokenType::NodePublic, publicKey);
1627  };
1628 
1629  // Config listed keys
1630  {
1631  ManifestCache manifests;
1632  auto trustedKeys = std::make_unique<ValidatorList>(
1633  manifests,
1634  manifests,
1635  env.timeKeeper(),
1636  app.config().legacy("database_path"),
1637  env.journal);
1638 
1639  // Empty list has no expiration
1640  BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
1641 
1642  // Config listed keys have maximum expiry
1643  PublicKey emptyLocalKey;
1644  PublicKey localCfgListed = randomNode();
1645  trustedKeys->load(emptyLocalKey, {toStr(localCfgListed)}, {});
1646  BEAST_EXPECT(
1647  trustedKeys->expires() &&
1648  trustedKeys->expires().value() == NetClock::time_point::max());
1649  BEAST_EXPECT(trustedKeys->listed(localCfgListed));
1650  }
1651 
1652  // Published keys with expirations
1653  {
1654  ManifestCache manifests;
1655  auto trustedKeys = std::make_unique<ValidatorList>(
1656  manifests,
1657  manifests,
1658  env.app().timeKeeper(),
1659  app.config().legacy("database_path"),
1660  env.journal);
1661 
1662  std::vector<Validator> validators = {randomValidator()};
1663  hash_set<NodeID> activeValidators;
1664  for (Validator const& val : validators)
1665  activeValidators.insert(calcNodeID(val.masterPublic));
1666  // Store prepared list data to control when it is applied
1667  struct PreparedList
1668  {
1669  PublicKey publisherPublic;
1672  int version;
1674  };
1675 
1676  using namespace std::chrono_literals;
1677  auto addPublishedList = [this, &env, &trustedKeys, &validators]() {
1678  auto const publisherSecret = randomSecretKey();
1679  auto const publisherPublic =
1680  derivePublicKey(KeyType::ed25519, publisherSecret);
1681  auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1682  auto const manifest = base64_encode(makeManifestString(
1683  publisherPublic,
1684  publisherSecret,
1685  pubSigningKeys.first,
1686  pubSigningKeys.second,
1687  1));
1688 
1689  std::vector<std::string> cfgPublishers(
1690  {strHex(publisherPublic)});
1691  PublicKey emptyLocalKey;
1692  std::vector<std::string> emptyCfgKeys;
1693 
1694  BEAST_EXPECT(trustedKeys->load(
1695  emptyLocalKey, emptyCfgKeys, cfgPublishers));
1696 
1697  auto const version = 2;
1698  auto const sequence1 = 1;
1699  NetClock::time_point const expiration1 =
1700  env.timeKeeper().now() + 1800s;
1701  auto const blob1 = makeList(
1702  validators,
1703  sequence1,
1704  expiration1.time_since_epoch().count());
1705  auto const sig1 = signList(blob1, pubSigningKeys);
1706 
1707  NetClock::time_point const effective2 = expiration1 - 300s;
1708  NetClock::time_point const expiration2 = effective2 + 1800s;
1709  auto const sequence2 = 2;
1710  auto const blob2 = makeList(
1711  validators,
1712  sequence2,
1713  expiration2.time_since_epoch().count(),
1714  effective2.time_since_epoch().count());
1715  auto const sig2 = signList(blob2, pubSigningKeys);
1716 
1717  return PreparedList{
1718  publisherPublic,
1719  manifest,
1720  {{blob1, sig1, {}}, {blob2, sig2, {}}},
1721  version,
1722  {expiration1, expiration2}};
1723  };
1724 
1725  // Configure two publishers and prepare 2 lists
1726  PreparedList prep1 = addPublishedList();
1727  env.timeKeeper().set(env.timeKeeper().now() + 200s);
1728  PreparedList prep2 = addPublishedList();
1729 
1730  // Initially, no list has been published, so no known expiration
1731  BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
1732 
1733  // Apply first list
1734  checkResult(
1735  trustedKeys->applyLists(
1736  prep1.manifest, prep1.version, prep1.blobs, siteUri),
1737  prep1.publisherPublic,
1738  ListDisposition::pending,
1739  ListDisposition::accepted);
1740 
1741  // One list still hasn't published, so expiration is still
1742  // unknown
1743  BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
1744 
1745  // Apply second list
1746  checkResult(
1747  trustedKeys->applyLists(
1748  prep2.manifest, prep2.version, prep2.blobs, siteUri),
1749  prep2.publisherPublic,
1750  ListDisposition::pending,
1751  ListDisposition::accepted);
1752  // We now have loaded both lists, so expiration is known
1753  BEAST_EXPECT(
1754  trustedKeys->expires() &&
1755  trustedKeys->expires().value() == prep1.expirations.back());
1756 
1757  // Advance past the first list's LAST validFrom date. It remains
1758  // the earliest validUntil, while rotating in the second list
1759  {
1760  env.timeKeeper().set(prep1.expirations.front() - 1s);
1761  auto changes = trustedKeys->updateTrusted(
1762  activeValidators,
1763  env.timeKeeper().now(),
1764  env.app().getOPs(),
1765  env.app().overlay(),
1766  env.app().getHashRouter());
1767  BEAST_EXPECT(
1768  trustedKeys->expires() &&
1769  trustedKeys->expires().value() == prep1.expirations.back());
1770  BEAST_EXPECT(!changes.added.empty());
1771  BEAST_EXPECT(changes.removed.empty());
1772  }
1773 
1774  // Advance past the first list's LAST validUntil, but it remains
1775  // the earliest validUntil, while being invalidated
1776  {
1777  env.timeKeeper().set(prep1.expirations.back() + 1s);
1778  auto changes = trustedKeys->updateTrusted(
1779  activeValidators,
1780  env.timeKeeper().now(),
1781  env.app().getOPs(),
1782  env.app().overlay(),
1783  env.app().getHashRouter());
1784  BEAST_EXPECT(
1785  trustedKeys->expires() &&
1786  trustedKeys->expires().value() == prep1.expirations.back());
1787  BEAST_EXPECT(changes.added.empty());
1788  BEAST_EXPECT(changes.removed.empty());
1789  }
1790  }
1791  }
1792 
1793  void
1795  {
1796  testcase("NegativeUNL");
1797  jtx::Env env(*this);
1798  PublicKey emptyLocalKey;
1799  ManifestCache manifests;
1800 
1801  auto createValidatorList =
1802  [&](std::uint32_t vlSize,
1803  std::optional<std::size_t> minimumQuorum = {})
1805  auto trustedKeys = std::make_shared<ValidatorList>(
1806  manifests,
1807  manifests,
1808  env.timeKeeper(),
1809  env.app().config().legacy("database_path"),
1810  env.journal,
1811  minimumQuorum);
1812 
1813  std::vector<std::string> cfgPublishers;
1814  std::vector<std::string> cfgKeys;
1815  hash_set<NodeID> activeValidators;
1816  cfgKeys.reserve(vlSize);
1817  while (cfgKeys.size() < cfgKeys.capacity())
1818  {
1819  auto const valKey = randomNode();
1820  cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1821  activeValidators.emplace(calcNodeID(valKey));
1822  }
1823  if (trustedKeys->load(emptyLocalKey, cfgKeys, cfgPublishers))
1824  {
1825  trustedKeys->updateTrusted(
1826  activeValidators,
1827  env.timeKeeper().now(),
1828  env.app().getOPs(),
1829  env.app().overlay(),
1830  env.app().getHashRouter());
1831  if (minimumQuorum == trustedKeys->quorum() ||
1832  trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f))
1833  return trustedKeys;
1834  }
1835  return nullptr;
1836  };
1837 
1838  /*
1839  * Test NegativeUNL
1840  * == Combinations ==
1841  * -- UNL size: 34, 35, 57
1842  * -- nUNL size: 0%, 20%, 30%, 50%
1843  *
1844  * == with UNL size 60
1845  * -- set == get,
1846  * -- check quorum, with nUNL size: 0, 12, 30, 18
1847  * -- nUNL overlap: |nUNL - UNL| = 5, with nUNL size: 18
1848  * -- with command line minimumQuorum = 50%,
1849  * seen_reliable affected by nUNL
1850  */
1851 
1852  {
1853  hash_set<NodeID> activeValidators;
1854  //== Combinations ==
1855  std::array<std::uint32_t, 4> unlSizes = {34, 35, 39, 60};
1856  std::array<std::uint32_t, 4> nUnlPercent = {0, 20, 30, 50};
1857  for (auto us : unlSizes)
1858  {
1859  for (auto np : nUnlPercent)
1860  {
1861  auto validators = createValidatorList(us);
1862  BEAST_EXPECT(validators);
1863  if (validators)
1864  {
1865  std::uint32_t nUnlSize = us * np / 100;
1866  auto unl = validators->getTrustedMasterKeys();
1867  hash_set<PublicKey> nUnl;
1868  auto it = unl.begin();
1869  for (std::uint32_t i = 0; i < nUnlSize; ++i)
1870  {
1871  nUnl.insert(*it);
1872  ++it;
1873  }
1874  validators->setNegativeUNL(nUnl);
1875  validators->updateTrusted(
1876  activeValidators,
1877  env.timeKeeper().now(),
1878  env.app().getOPs(),
1879  env.app().overlay(),
1880  env.app().getHashRouter());
1881  BEAST_EXPECT(
1882  validators->quorum() ==
1883  static_cast<std::size_t>(std::ceil(
1884  std::max((us - nUnlSize) * 0.8f, us * 0.6f))));
1885  }
1886  }
1887  }
1888  }
1889 
1890  {
1891  //== with UNL size 60
1892  auto validators = createValidatorList(60);
1893  BEAST_EXPECT(validators);
1894  if (validators)
1895  {
1896  hash_set<NodeID> activeValidators;
1897  auto unl = validators->getTrustedMasterKeys();
1898  BEAST_EXPECT(unl.size() == 60);
1899  {
1900  //-- set == get,
1901  //-- check quorum, with nUNL size: 0, 30, 18, 12
1902  auto nUnlChange = [&](std::uint32_t nUnlSize,
1903  std::uint32_t quorum) -> bool {
1904  hash_set<PublicKey> nUnl;
1905  auto it = unl.begin();
1906  for (std::uint32_t i = 0; i < nUnlSize; ++i)
1907  {
1908  nUnl.insert(*it);
1909  ++it;
1910  }
1911  validators->setNegativeUNL(nUnl);
1912  auto nUnl_temp = validators->getNegativeUNL();
1913  if (nUnl_temp.size() == nUnl.size())
1914  {
1915  for (auto& n : nUnl_temp)
1916  {
1917  if (nUnl.find(n) == nUnl.end())
1918  return false;
1919  }
1920  validators->updateTrusted(
1921  activeValidators,
1922  env.timeKeeper().now(),
1923  env.app().getOPs(),
1924  env.app().overlay(),
1925  env.app().getHashRouter());
1926  return validators->quorum() == quorum;
1927  }
1928  return false;
1929  };
1930  BEAST_EXPECT(nUnlChange(0, 48));
1931  BEAST_EXPECT(nUnlChange(30, 36));
1932  BEAST_EXPECT(nUnlChange(18, 36));
1933  BEAST_EXPECT(nUnlChange(12, 39));
1934  }
1935 
1936  {
1937  // nUNL overlap: |nUNL - UNL| = 5, with nUNL size:
1938  // 18
1939  auto nUnl = validators->getNegativeUNL();
1940  BEAST_EXPECT(nUnl.size() == 12);
1941  std::size_t ss = 33;
1942  std::vector<uint8_t> data(ss, 0);
1943  data[0] = 0xED;
1944  for (int i = 0; i < 6; ++i)
1945  {
1946  Slice s(data.data(), ss);
1947  data[1]++;
1948  nUnl.emplace(s);
1949  }
1950  validators->setNegativeUNL(nUnl);
1951  validators->updateTrusted(
1952  activeValidators,
1953  env.timeKeeper().now(),
1954  env.app().getOPs(),
1955  env.app().overlay(),
1956  env.app().getHashRouter());
1957  BEAST_EXPECT(validators->quorum() == 39);
1958  }
1959  }
1960  }
1961 
1962  {
1963  //== with UNL size 60
1964  //-- with command line minimumQuorum = 50%,
1965  // seen_reliable affected by nUNL
1966  auto validators = createValidatorList(60, 30);
1967  BEAST_EXPECT(validators);
1968  if (validators)
1969  {
1970  hash_set<NodeID> activeValidators;
1971  hash_set<PublicKey> unl = validators->getTrustedMasterKeys();
1972  auto it = unl.begin();
1973  for (std::uint32_t i = 0; i < 50; ++i)
1974  {
1975  activeValidators.insert(calcNodeID(*it));
1976  ++it;
1977  }
1978  validators->updateTrusted(
1979  activeValidators,
1980  env.timeKeeper().now(),
1981  env.app().getOPs(),
1982  env.app().overlay(),
1983  env.app().getHashRouter());
1984  BEAST_EXPECT(validators->quorum() == 30);
1985  hash_set<PublicKey> nUnl;
1986  it = unl.begin();
1987  for (std::uint32_t i = 0; i < 20; ++i)
1988  {
1989  nUnl.insert(*it);
1990  ++it;
1991  }
1992  validators->setNegativeUNL(nUnl);
1993  validators->updateTrusted(
1994  activeValidators,
1995  env.timeKeeper().now(),
1996  env.app().getOPs(),
1997  env.app().overlay(),
1998  env.app().getHashRouter());
1999  BEAST_EXPECT(validators->quorum() == 30);
2000  }
2001  }
2002  }
2003 
2004  void
2006  {
2007  testcase("Sha512 hashing");
2008  // Tests that ValidatorList hash_append helpers with a single blob
2009  // returns the same result as ripple::Sha512Half used by the
2010  // TMValidatorList protocol message handler
2011  std::string const manifest = "This is not really a manifest";
2012  std::string const blob = "This is not really a blob";
2013  std::string const signature = "This is not really a signature";
2014  std::uint32_t const version = 1;
2015 
2016  auto const global = sha512Half(manifest, blob, signature, version);
2017  BEAST_EXPECT(!!global);
2018 
2019  std::vector<ValidatorBlobInfo> blobVector(1);
2020  blobVector[0].blob = blob;
2021  blobVector[0].signature = signature;
2022  BEAST_EXPECT(global == sha512Half(manifest, blobVector, version));
2023  BEAST_EXPECT(global != sha512Half(signature, blobVector, version));
2024 
2025  {
2027  {99, blobVector[0]}};
2028  BEAST_EXPECT(global == sha512Half(manifest, blobMap, version));
2029  BEAST_EXPECT(global != sha512Half(blob, blobMap, version));
2030  }
2031 
2032  {
2033  protocol::TMValidatorList msg1;
2034  msg1.set_manifest(manifest);
2035  msg1.set_blob(blob);
2036  msg1.set_signature(signature);
2037  msg1.set_version(version);
2038  BEAST_EXPECT(global == sha512Half(msg1));
2039  msg1.set_signature(blob);
2040  BEAST_EXPECT(global != sha512Half(msg1));
2041  }
2042 
2043  {
2044  protocol::TMValidatorListCollection msg2;
2045  msg2.set_manifest(manifest);
2046  msg2.set_version(version);
2047  auto& bi = *msg2.add_blobs();
2048  bi.set_blob(blob);
2049  bi.set_signature(signature);
2050  BEAST_EXPECT(global == sha512Half(msg2));
2051  bi.set_manifest(manifest);
2052  BEAST_EXPECT(global != sha512Half(msg2));
2053  }
2054  }
2055 
2056  void
2058  {
2059  testcase("Build and split messages");
2060 
2061  std::uint32_t const manifestCutoff = 7;
2062  auto extractHeader = [this](Message& message) {
2063  auto const& buffer =
2064  message.getBuffer(compression::Compressed::Off);
2065 
2066  boost::beast::multi_buffer buffers;
2067 
2068  // simulate multi-buffer
2069  auto start = buffer.begin();
2070  auto end = buffer.end();
2071  std::vector<std::uint8_t> slice(start, end);
2072  buffers.commit(boost::asio::buffer_copy(
2073  buffers.prepare(slice.size()), boost::asio::buffer(slice)));
2074 
2075  boost::system::error_code ec;
2076  auto header =
2077  detail::parseMessageHeader(ec, buffers.data(), buffers.size());
2078  BEAST_EXPECT(!ec);
2079  return std::make_pair(header, buffers);
2080  };
2081  auto extractProtocolMessage1 = [this,
2082  &extractHeader](Message& message) {
2083  auto [header, buffers] = extractHeader(message);
2084  if (BEAST_EXPECT(header) &&
2085  BEAST_EXPECT(header->message_type == protocol::mtVALIDATORLIST))
2086  {
2087  auto const msg =
2088  detail::parseMessageContent<protocol::TMValidatorList>(
2089  *header, buffers.data());
2090  BEAST_EXPECT(msg);
2091  return msg;
2092  }
2094  };
2095  auto extractProtocolMessage2 = [this,
2096  &extractHeader](Message& message) {
2097  auto [header, buffers] = extractHeader(message);
2098  if (BEAST_EXPECT(header) &&
2099  BEAST_EXPECT(
2100  header->message_type ==
2101  protocol::mtVALIDATORLISTCOLLECTION))
2102  {
2103  auto const msg = detail::parseMessageContent<
2104  protocol::TMValidatorListCollection>(
2105  *header, buffers.data());
2106  BEAST_EXPECT(msg);
2107  return msg;
2108  }
2110  };
2111  auto verifyMessage =
2112  [this,
2113  manifestCutoff,
2114  &extractProtocolMessage1,
2115  &extractProtocolMessage2](
2116  auto const version,
2117  auto const& manifest,
2118  auto const& blobInfos,
2119  auto const& messages,
2121  expectedInfo) {
2122  BEAST_EXPECT(messages.size() == expectedInfo.size());
2123  auto msgIter = expectedInfo.begin();
2124  for (auto const& messageWithHash : messages)
2125  {
2126  if (!BEAST_EXPECT(msgIter != expectedInfo.end()))
2127  break;
2128  if (!BEAST_EXPECT(messageWithHash.message))
2129  continue;
2130  auto const& expectedSeqs = msgIter->second;
2131  auto seqIter = expectedSeqs.begin();
2132  auto const size =
2133  messageWithHash.message
2134  ->getBuffer(compression::Compressed::Off)
2135  .size();
2136  // This size is arbitrary, but shouldn't change
2137  BEAST_EXPECT(size == msgIter->first);
2138  if (expectedSeqs.size() == 1)
2139  {
2140  auto const msg =
2141  extractProtocolMessage1(*messageWithHash.message);
2142  auto const expectedVersion = 1;
2143  if (BEAST_EXPECT(msg))
2144  {
2145  BEAST_EXPECT(msg->version() == expectedVersion);
2146  if (!BEAST_EXPECT(seqIter != expectedSeqs.end()))
2147  continue;
2148  auto const& expectedBlob = blobInfos.at(*seqIter);
2149  BEAST_EXPECT(
2150  (*seqIter < manifestCutoff) ==
2151  !!expectedBlob.manifest);
2152  auto const expectedManifest =
2153  *seqIter < manifestCutoff &&
2154  expectedBlob.manifest
2155  ? *expectedBlob.manifest
2156  : manifest;
2157  BEAST_EXPECT(msg->manifest() == expectedManifest);
2158  BEAST_EXPECT(msg->blob() == expectedBlob.blob);
2159  BEAST_EXPECT(
2160  msg->signature() == expectedBlob.signature);
2161  ++seqIter;
2162  BEAST_EXPECT(seqIter == expectedSeqs.end());
2163 
2164  BEAST_EXPECT(
2165  messageWithHash.hash ==
2166  sha512Half(
2167  expectedManifest,
2168  expectedBlob.blob,
2169  expectedBlob.signature,
2170  expectedVersion));
2171  }
2172  }
2173  else
2174  {
2175  std::vector<ValidatorBlobInfo> hashingBlobs;
2176  hashingBlobs.reserve(msgIter->second.size());
2177 
2178  auto const msg =
2179  extractProtocolMessage2(*messageWithHash.message);
2180  if (BEAST_EXPECT(msg))
2181  {
2182  BEAST_EXPECT(msg->version() == version);
2183  BEAST_EXPECT(msg->manifest() == manifest);
2184  for (auto const& blobInfo : msg->blobs())
2185  {
2186  if (!BEAST_EXPECT(
2187  seqIter != expectedSeqs.end()))
2188  break;
2189  auto const& expectedBlob =
2190  blobInfos.at(*seqIter);
2191  hashingBlobs.push_back(expectedBlob);
2192  BEAST_EXPECT(
2193  blobInfo.has_manifest() ==
2194  !!expectedBlob.manifest);
2195  BEAST_EXPECT(
2196  blobInfo.has_manifest() ==
2197  (*seqIter < manifestCutoff));
2198 
2199  if (*seqIter < manifestCutoff)
2200  BEAST_EXPECT(
2201  blobInfo.manifest() ==
2202  *expectedBlob.manifest);
2203  BEAST_EXPECT(
2204  blobInfo.blob() == expectedBlob.blob);
2205  BEAST_EXPECT(
2206  blobInfo.signature() ==
2207  expectedBlob.signature);
2208  ++seqIter;
2209  }
2210  BEAST_EXPECT(seqIter == expectedSeqs.end());
2211  }
2212  BEAST_EXPECT(
2213  messageWithHash.hash ==
2214  sha512Half(manifest, hashingBlobs, version));
2215  }
2216  ++msgIter;
2217  }
2218  BEAST_EXPECT(msgIter == expectedInfo.end());
2219  };
2220  auto verifyBuildMessages =
2221  [this](
2223  std::size_t expectedSequence,
2224  std::size_t expectedSize) {
2225  BEAST_EXPECT(result.first == expectedSequence);
2226  BEAST_EXPECT(result.second == expectedSize);
2227  };
2228 
2229  std::string const manifest = "This is not a manifest";
2230  std::uint32_t const version = 2;
2231  // Mutable so items can be removed in later tests.
2232  auto const blobInfos = [manifestCutoff = manifestCutoff]() {
2234 
2235  for (auto seq : {5, 6, 7, 10, 12})
2236  {
2237  auto& b = bis[seq];
2239  s << "This is not a blob with sequence " << seq;
2240  b.blob = s.str();
2241  s.str(std::string());
2242  s << "This is not a signature for sequence " << seq;
2243  b.signature = s.str();
2244  if (seq < manifestCutoff)
2245  {
2246  // add a manifest for the "early" blobs
2247  s.str(std::string());
2248  s << "This is not manifest " << seq;
2249  b.manifest = s.str();
2250  }
2251  }
2252  return bis;
2253  }();
2254  auto const maxSequence = blobInfos.rbegin()->first;
2255  BEAST_EXPECT(maxSequence == 12);
2256 
2258 
2259  // Version 1
2260 
2261  // This peer has a VL ahead of our "current"
2262  verifyBuildMessages(
2263  ValidatorList::buildValidatorListMessages(
2264  1, 8, maxSequence, version, manifest, blobInfos, messages),
2265  0,
2266  0);
2267  BEAST_EXPECT(messages.size() == 0);
2268 
2269  // Don't repeat the work if messages is populated, even though the
2270  // peerSequence provided indicates it should. Note that this
2271  // situation is contrived for this test and should never happen in
2272  // real code.
2273  messages.emplace_back();
2274  verifyBuildMessages(
2275  ValidatorList::buildValidatorListMessages(
2276  1, 3, maxSequence, version, manifest, blobInfos, messages),
2277  5,
2278  0);
2279  BEAST_EXPECT(messages.size() == 1 && !messages.front().message);
2280 
2281  // Generate a version 1 message
2282  messages.clear();
2283  verifyBuildMessages(
2284  ValidatorList::buildValidatorListMessages(
2285  1, 3, maxSequence, version, manifest, blobInfos, messages),
2286  5,
2287  1);
2288  if (BEAST_EXPECT(messages.size() == 1) &&
2289  BEAST_EXPECT(messages.front().message))
2290  {
2291  auto const& messageWithHash = messages.front();
2292  auto const msg = extractProtocolMessage1(*messageWithHash.message);
2293  auto const size =
2294  messageWithHash.message->getBuffer(compression::Compressed::Off)
2295  .size();
2296  // This size is arbitrary, but shouldn't change
2297  BEAST_EXPECT(size == 108);
2298  auto const& expected = blobInfos.at(5);
2299  if (BEAST_EXPECT(msg))
2300  {
2301  BEAST_EXPECT(msg->version() == 1);
2302  BEAST_EXPECT(msg->manifest() == *expected.manifest);
2303  BEAST_EXPECT(msg->blob() == expected.blob);
2304  BEAST_EXPECT(msg->signature() == expected.signature);
2305  }
2306  BEAST_EXPECT(
2307  messageWithHash.hash ==
2308  sha512Half(
2309  *expected.manifest, expected.blob, expected.signature, 1));
2310  }
2311 
2312  // Version 2
2313 
2314  messages.clear();
2315 
2316  // This peer has a VL ahead of us.
2317  verifyBuildMessages(
2318  ValidatorList::buildValidatorListMessages(
2319  2,
2320  maxSequence * 2,
2321  maxSequence,
2322  version,
2323  manifest,
2324  blobInfos,
2325  messages),
2326  0,
2327  0);
2328  BEAST_EXPECT(messages.size() == 0);
2329 
2330  // Don't repeat the work if messages is populated, even though the
2331  // peerSequence provided indicates it should. Note that this
2332  // situation is contrived for this test and should never happen in
2333  // real code.
2334  messages.emplace_back();
2335  verifyBuildMessages(
2336  ValidatorList::buildValidatorListMessages(
2337  2, 3, maxSequence, version, manifest, blobInfos, messages),
2338  maxSequence,
2339  0);
2340  BEAST_EXPECT(messages.size() == 1 && !messages.front().message);
2341 
2342  // Generate a version 2 message. Don't send the current
2343  messages.clear();
2344  verifyBuildMessages(
2345  ValidatorList::buildValidatorListMessages(
2346  2, 5, maxSequence, version, manifest, blobInfos, messages),
2347  maxSequence,
2348  4);
2349  verifyMessage(
2350  version, manifest, blobInfos, messages, {{372, {6, 7, 10, 12}}});
2351 
2352  // Test message splitting on size limits.
2353 
2354  // Set a limit that should give two messages
2355  messages.clear();
2356  verifyBuildMessages(
2357  ValidatorList::buildValidatorListMessages(
2358  2, 5, maxSequence, version, manifest, blobInfos, messages, 300),
2359  maxSequence,
2360  4);
2361  verifyMessage(
2362  version,
2363  manifest,
2364  blobInfos,
2365  messages,
2366  {{212, {6, 7}}, {192, {10, 12}}});
2367 
2368  // Set a limit between the size of the two earlier messages so one
2369  // will split and the other won't
2370  messages.clear();
2371  verifyBuildMessages(
2372  ValidatorList::buildValidatorListMessages(
2373  2, 5, maxSequence, version, manifest, blobInfos, messages, 200),
2374  maxSequence,
2375  4);
2376  verifyMessage(
2377  version,
2378  manifest,
2379  blobInfos,
2380  messages,
2381  {{108, {6}}, {108, {7}}, {192, {10, 12}}});
2382 
2383  // Set a limit so that all the VLs are sent individually
2384  messages.clear();
2385  verifyBuildMessages(
2386  ValidatorList::buildValidatorListMessages(
2387  2, 5, maxSequence, version, manifest, blobInfos, messages, 150),
2388  maxSequence,
2389  4);
2390  verifyMessage(
2391  version,
2392  manifest,
2393  blobInfos,
2394  messages,
2395  {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}});
2396 
2397  // Set a limit smaller than some of the messages. Because single
2398  // messages send regardless, they will all still be sent
2399  messages.clear();
2400  verifyBuildMessages(
2401  ValidatorList::buildValidatorListMessages(
2402  2, 5, maxSequence, version, manifest, blobInfos, messages, 108),
2403  maxSequence,
2404  4);
2405  verifyMessage(
2406  version,
2407  manifest,
2408  blobInfos,
2409  messages,
2410  {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}});
2411  }
2412 
2413 public:
2414  void
2415  run() override
2416  {
2417  testGenesisQuorum();
2418  testConfigLoad();
2419  testApplyLists();
2420  testGetAvailable();
2421  testUpdateTrusted();
2422  testExpires();
2423  testNegativeUNL();
2424  testSha512Hash();
2425  testBuildMessages();
2426  }
2427 }; // namespace test
2428 
2430 
2431 } // namespace test
2432 } // namespace ripple
ripple::test::ValidatorList_test::Validator
Definition: ValidatorList_test.cpp:42
ripple::test::Validator
Simulate Validator.
Definition: reduce_relay_test.cpp:310
ripple::ListDisposition::pending
@ pending
List will be valid in the future.
ripple::test::ValidatorList_test::randomNode
static PublicKey randomNode()
Definition: ValidatorList_test.cpp:50
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:241
std::string
STL class.
std::shared_ptr
STL class.
ripple::ListDisposition
ListDisposition
Definition: ValidatorList.h:55
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::test::ValidatorList_test::Validator::manifest
std::string manifest
Definition: ValidatorList_test.cpp:46
ripple::calcNodeID
NodeID calcNodeID(PublicKey const &pk)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:303
beast::severities::kDisabled
@ kDisabled
Definition: Journal.h:41
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:327
ripple::test::ValidatorList_test::testConfigLoad
void testConfigLoad()
Definition: ValidatorList_test.cpp:217
ripple::TrustChanges
Changes in trusted nodes after updating validator list.
Definition: ValidatorList.h:107
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
std::unordered_set
STL class.
std::pair
std::unordered_set::reserve
T reserve(T... args)
ripple::sfSequence
const SF_UINT32 sfSequence
ripple::HashPrefix::manifest
@ manifest
Manifest.
std::vector
STL class.
std::unordered_set::find
T find(T... args)
std::initializer_list::size
T size(T... args)
ripple::base64_encode
std::string base64_encode(std::uint8_t const *data, std::size_t len)
Definition: base64.cpp:236
ripple::sfSigningPubKey
const SF_VL sfSigningPubKey
ripple::test::ValidatorList_test::makeManifestString
static std::string makeManifestString(PublicKey const &pk, SecretKey const &sk, PublicKey const &spk, SecretKey const &ssk, int seq)
Definition: ValidatorList_test.cpp:62
ripple::ValidatorList::PublisherListStats
Describes the result of processing a Validator List (UNL), including some of the information from the...
Definition: ValidatorList.h:278
ripple::test::ValidatorList_test::run
void run() override
Definition: ValidatorList_test.cpp:2415
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::test::ValidatorList_test
Definition: ValidatorList_test.cpp:39
std::unordered_set::emplace
T emplace(T... args)
std::stringstream
STL class.
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:144
ripple::test::jtx::Env::timeKeeper
ManualTimeKeeper & timeKeeper()
Definition: Env.h:253
ripple::ValidatorList::PublisherListStats::bestDisposition
ListDisposition bestDisposition() const
Definition: ValidatorList.cpp:85
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
std::vector::back
T back(T... args)
ripple::test::ValidatorList_test::testSha512Hash
void testSha512Hash()
Definition: ValidatorList_test.cpp:2005
ripple::Application::timeKeeper
virtual TimeKeeper & timeKeeper()=0
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
ripple::ListDisposition::expired
@ expired
List is expired, but has the largest non-pending sequence seen so far.
std::vector::front
T front(T... args)
ripple::test::ValidatorList_test::testBuildMessages
void testBuildMessages()
Definition: ValidatorList_test.cpp:2057
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
std::vector::clear
T clear(T... args)
ripple::test::ValidatorList_test::testExpires
void testExpires()
Definition: ValidatorList_test.cpp:1616
ripple::Serializer::data
void const * data() const noexcept
Definition: Serializer.h:75
std::vector::push_back
T push_back(T... args)
ripple::KeyType::ed25519
@ ed25519
ripple::publicKeyType
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:207
ripple::base_uint< 160, detail::NodeIDTag >
std::vector::capacity
T capacity(T... args)
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
ripple::test::ValidatorList_test::testGenesisQuorum
void testGenesisQuorum()
Definition: ValidatorList_test.cpp:187
std::map::at
T at(T... args)
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::derivePublicKey
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:313
ripple::ValidatorList
Definition: ValidatorList.h:172
ripple::sfMasterSignature
const SF_VL sfMasterSignature
ripple::Application::config
virtual Config & config()=0
ripple::TrustChanges::removed
hash_set< NodeID > removed
Definition: ValidatorList.h:112
ripple::test::ValidatorList_test::randomValidator
static Validator randomValidator()
Definition: ValidatorList_test.cpp:113
ripple::test::ValidatorList_test::makeRevocationString
static std::string makeRevocationString(PublicKey const &pk, SecretKey const &sk)
Definition: ValidatorList_test.cpp:93
std::to_string
T to_string(T... args)
std::array
STL class.
ripple::ManifestCache::revoked
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
Definition: app/misc/impl/Manifest.cpp:351
ripple::base64_decode
std::string base64_decode(std::string const &data)
Definition: base64.cpp:245
std::chrono::time_point
ripple::test::ValidatorList_test::testNegativeUNL
void testNegativeUNL()
Definition: ValidatorList_test.cpp:1794
ripple::BasicConfig::legacy
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
Definition: BasicConfig.cpp:164
ripple::ManifestCache::getSigningKey
PublicKey getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
Definition: app/misc/impl/Manifest.cpp:291
ripple::test::ValidatorList_test::randomMasterKey
static PublicKey randomMasterKey()
Definition: ValidatorList_test.cpp:56
ripple::test::ValidatorList_test::makeList
std::string makeList(std::vector< Validator > const &validators, std::size_t sequence, std::size_t validUntil, std::optional< std::size_t > validFrom={})
Definition: ValidatorList_test.cpp:130
std::uint32_t
ripple::test::jtx::sig
Set the regular signature on a JTx.
Definition: sig.h:34
ripple::SecretKey
A secret key.
Definition: SecretKey.h:36
std::map
STL class.
std::ceil
T ceil(T... args)
ripple::test::ValidatorList_test::Validator::masterPublic
PublicKey masterPublic
Definition: ValidatorList_test.cpp:44
ripple::KeyType::secp256k1
@ secp256k1
ripple::Serializer
Definition: Serializer.h:39
ripple::Message
Definition: overlay/Message.h:53
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::ManifestCache
Remembers manifests with the highest sequence number.
Definition: Manifest.h:231
ripple::STObject::add
void add(Serializer &s) const override
Definition: STObject.cpp:85
ripple::STObject
Definition: STObject.h:51
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::Serializer::size
std::size_t size() const noexcept
Definition: Serializer.h:69
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:238
ripple::test::ValidatorList_test::Validator::signingPublic
PublicKey signingPublic
Definition: ValidatorList_test.cpp:45
ripple::ListDisposition::same_sequence
@ same_sequence
Same sequence as current list.
std::unordered_set::begin
T begin(T... args)
ripple::test::ValidatorList_test::testApplyLists
void testApplyLists()
Definition: ValidatorList_test.cpp:476
std::unordered_set::insert
T insert(T... args)
ripple::sha512Half
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:216
ripple::test::ValidatorList_test::asNodeIDs
static hash_set< NodeID > asNodeIDs(std::initializer_list< PublicKey > const &pks)
Definition: ValidatorList_test.cpp:163
ripple::test::ValidatorList_test::testUpdateTrusted
void testUpdateTrusted()
Definition: ValidatorList_test.cpp:1063
ripple::ValidatorList::PublisherListStats::worstDisposition
ListDisposition worstDisposition() const
Definition: ValidatorList.cpp:92
ripple::Application::overlay
virtual Overlay & overlay()=0
ripple::test::ValidatorList_test::checkResult
void checkResult(ValidatorList::PublisherListStats const &result, PublicKey pubKey, ListDisposition expectedWorst, ListDisposition expectedBest)
Definition: ValidatorList_test.cpp:173
ripple::ValidatorList::PublisherListStats::publisherKey
std::optional< PublicKey > publisherKey
Definition: ValidatorList.h:298
ripple::TrustChanges::added
hash_set< NodeID > added
Definition: ValidatorList.h:111
ripple::TokenType::NodePublic
@ NodePublic
std::optional< std::size_t >
std::stringstream::str
T str(T... args)
std::size_t
std::make_pair
T make_pair(T... args)
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
std::unordered_set::end
T end(T... args)
ripple::deserializeManifest
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
Definition: app/misc/impl/Manifest.cpp:53
ripple::test::ManualTimeKeeper::now
time_point now() const override
Returns the estimate of wall time, in network time.
Definition: ManualTimeKeeper.cpp:37
std::numeric_limits::max
T max(T... args)
ripple::test::ManualTimeKeeper::set
void set(time_point now)
Definition: ManualTimeKeeper.cpp:81
ripple::ManifestCache::applyManifest
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition: app/misc/impl/Manifest.cpp:363
ripple::test::ValidatorList_test::signList
std::string signList(std::string const &blob, std::pair< PublicKey, SecretKey > const &keys)
Definition: ValidatorList_test.cpp:154
std::numeric_limits
ripple::sfPublicKey
const SF_VL sfPublicKey
ripple::Application::getHashRouter
virtual HashRouter & getHashRouter()=0
ripple::ListDisposition::accepted
@ accepted
List is valid.
ripple::PublisherStatus::available
@ available
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::randomSecretKey
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:281
std::map::rbegin
T rbegin(T... args)
std::initializer_list
ripple::test::ValidatorList_test::testGetAvailable
void testGetAvailable()
Definition: ValidatorList_test.cpp:926