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