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/protocol/HashPrefix.h>
25 #include <ripple/protocol/PublicKey.h>
26 #include <ripple/protocol/SecretKey.h>
27 #include <ripple/protocol/Sign.h>
28 #include <ripple/protocol/digest.h>
29 #include <test/jtx.h>
30 
31 namespace ripple {
32 namespace test {
33 
34 class ValidatorList_test : public beast::unit_test::suite
35 {
36 private:
37  struct Validator
38  {
42  };
43 
44  static PublicKey
46  {
48  }
49 
50  static PublicKey
52  {
54  }
55 
56  static std::string
58  PublicKey const& pk,
59  SecretKey const& sk,
60  PublicKey const& spk,
61  SecretKey const& ssk,
62  int seq)
63  {
64  STObject st(sfGeneric);
65  st[sfSequence] = seq;
66  st[sfPublicKey] = pk;
67 
69  {
70  st[sfSigningPubKey] = spk;
71  sign(st, HashPrefix::manifest, *publicKeyType(spk), ssk);
72  }
73 
74  sign(
75  st,
77  *publicKeyType(pk),
78  sk,
80 
81  Serializer s;
82  st.add(s);
83 
84  return std::string(static_cast<char const*>(s.data()), s.size());
85  }
86 
87  static std::string
89  {
90  STObject st(sfGeneric);
92  st[sfPublicKey] = pk;
93 
94  sign(
95  st,
97  *publicKeyType(pk),
98  sk,
100 
101  Serializer s;
102  st.add(s);
103 
104  return std::string(static_cast<char const*>(s.data()), s.size());
105  }
106 
107  static Validator
109  {
110  auto const secret = randomSecretKey();
111  auto const masterPublic = derivePublicKey(KeyType::ed25519, secret);
112  auto const signingKeys = randomKeyPair(KeyType::secp256k1);
113  return {
114  masterPublic,
115  signingKeys.first,
117  masterPublic,
118  secret,
119  signingKeys.first,
120  signingKeys.second,
121  1))};
122  }
123 
126  std::vector<Validator> const& validators,
127  std::size_t sequence,
129  {
130  std::string data = "{\"sequence\":" + std::to_string(sequence) +
131  ",\"expiration\":" + std::to_string(expiration) +
132  ",\"validators\":[";
133 
134  for (auto const& val : validators)
135  {
136  data += "{\"validation_public_key\":\"" + strHex(val.masterPublic) +
137  "\",\"manifest\":\"" + val.manifest + "\"},";
138  }
139 
140  data.pop_back();
141  data += "]}";
142  return base64_encode(data);
143  }
144 
147  std::string const& blob,
149  {
150  auto const data = base64_decode(blob);
151  return strHex(sign(keys.first, keys.second, makeSlice(data)));
152  }
153 
154  static hash_set<NodeID>
156  {
157  hash_set<NodeID> res;
158  res.reserve(pks.size());
159  for (auto const& pk : pks)
160  res.insert(calcNodeID(pk));
161  return res;
162  }
163 
164  void
166  {
167  testcase("Genesis Quorum");
168 
169  ManifestCache manifests;
170  jtx::Env env(*this);
171  auto& app = env.app();
172  {
173  auto trustedKeys = std::make_unique<ValidatorList>(
174  manifests,
175  manifests,
176  env.timeKeeper(),
177  app.config().legacy("database_path"),
178  env.journal);
179  BEAST_EXPECT(trustedKeys->quorum() == 1);
180  }
181  {
182  std::size_t minQuorum = 0;
183  auto trustedKeys = std::make_unique<ValidatorList>(
184  manifests,
185  manifests,
186  env.timeKeeper(),
187  app.config().legacy("database_path"),
188  env.journal,
189  minQuorum);
190  BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
191  }
192  }
193 
194  void
196  {
197  testcase("Config Load");
198 
199  jtx::Env env(*this);
200  auto& app = env.app();
201  PublicKey emptyLocalKey;
202  std::vector<std::string> const emptyCfgKeys;
203  std::vector<std::string> const emptyCfgPublishers;
204 
205  auto const localSigningKeys = randomKeyPair(KeyType::secp256k1);
206  auto const localSigningPublicOuter = localSigningKeys.first;
207  auto const localSigningSecret = localSigningKeys.second;
208  auto const localMasterSecret = randomSecretKey();
209  auto const localMasterPublic =
210  derivePublicKey(KeyType::ed25519, localMasterSecret);
211 
212  std::string const cfgManifest(makeManifestString(
213  localMasterPublic,
214  localMasterSecret,
215  localSigningPublicOuter,
216  localSigningSecret,
217  1));
218 
219  auto format = [](PublicKey const& publicKey,
220  char const* comment = nullptr) {
221  auto ret = toBase58(TokenType::NodePublic, publicKey);
222 
223  if (comment)
224  ret += comment;
225 
226  return ret;
227  };
228 
229  std::vector<PublicKey> configList;
230  configList.reserve(8);
231 
232  while (configList.size() != 8)
233  configList.push_back(randomNode());
234 
235  // Correct configuration
236  std::vector<std::string> cfgKeys(
237  {format(configList[0]),
238  format(configList[1], " Comment"),
239  format(configList[2], " Multi Word Comment"),
240  format(configList[3], " Leading Whitespace"),
241  format(configList[4], " Trailing Whitespace "),
242  format(configList[5], " Leading & Trailing Whitespace "),
243  format(
244  configList[6],
245  " Leading, Trailing & Internal Whitespace "),
246  format(configList[7], " ")});
247 
248  {
249  ManifestCache manifests;
250  auto trustedKeys = std::make_unique<ValidatorList>(
251  manifests,
252  manifests,
253  env.timeKeeper(),
254  app.config().legacy("database_path"),
255  env.journal);
256 
257  // Correct (empty) configuration
258  BEAST_EXPECT(trustedKeys->load(
259  emptyLocalKey, emptyCfgKeys, emptyCfgPublishers));
260 
261  // load local validator key with or without manifest
262  BEAST_EXPECT(trustedKeys->load(
263  localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers));
264  BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
265 
266  manifests.applyManifest(*deserializeManifest(cfgManifest));
267  BEAST_EXPECT(trustedKeys->load(
268  localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers));
269 
270  BEAST_EXPECT(trustedKeys->listed(localMasterPublic));
271  BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
272  }
273  {
274  // load should add validator keys from config
275  ManifestCache manifests;
276  auto trustedKeys = std::make_unique<ValidatorList>(
277  manifests,
278  manifests,
279  env.timeKeeper(),
280  app.config().legacy("database_path"),
281  env.journal);
282 
283  BEAST_EXPECT(
284  trustedKeys->load(emptyLocalKey, cfgKeys, emptyCfgPublishers));
285 
286  for (auto const& n : configList)
287  BEAST_EXPECT(trustedKeys->listed(n));
288 
289  // load should accept Ed25519 master public keys
290  auto const masterNode1 = randomMasterKey();
291  auto const masterNode2 = randomMasterKey();
292 
293  std::vector<std::string> cfgMasterKeys(
294  {format(masterNode1), format(masterNode2, " Comment")});
295  BEAST_EXPECT(trustedKeys->load(
296  emptyLocalKey, cfgMasterKeys, emptyCfgPublishers));
297  BEAST_EXPECT(trustedKeys->listed(masterNode1));
298  BEAST_EXPECT(trustedKeys->listed(masterNode2));
299 
300  // load should reject invalid config keys
301  BEAST_EXPECT(!trustedKeys->load(
302  emptyLocalKey, {"NotAPublicKey"}, emptyCfgPublishers));
303  BEAST_EXPECT(!trustedKeys->load(
304  emptyLocalKey,
305  {format(randomNode(), "!")},
306  emptyCfgPublishers));
307 
308  // load terminates when encountering an invalid entry
309  auto const goodKey = randomNode();
310  BEAST_EXPECT(!trustedKeys->load(
311  emptyLocalKey,
312  {format(randomNode(), "!"), format(goodKey)},
313  emptyCfgPublishers));
314  BEAST_EXPECT(!trustedKeys->listed(goodKey));
315  }
316  {
317  // local validator key on config list
318  ManifestCache manifests;
319  auto trustedKeys = std::make_unique<ValidatorList>(
320  manifests,
321  manifests,
322  env.timeKeeper(),
323  app.config().legacy("database_path"),
324  env.journal);
325 
326  auto const localSigningPublic =
327  parseBase58<PublicKey>(TokenType::NodePublic, cfgKeys.front());
328 
329  BEAST_EXPECT(trustedKeys->load(
330  *localSigningPublic, cfgKeys, emptyCfgPublishers));
331 
332  BEAST_EXPECT(trustedKeys->localPublicKey() == localSigningPublic);
333  BEAST_EXPECT(trustedKeys->listed(*localSigningPublic));
334  for (auto const& n : configList)
335  BEAST_EXPECT(trustedKeys->listed(n));
336  }
337  {
338  // local validator key not 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 = randomNode();
348  BEAST_EXPECT(trustedKeys->load(
349  localSigningPublic, cfgKeys, emptyCfgPublishers));
350 
351  BEAST_EXPECT(trustedKeys->localPublicKey() == localSigningPublic);
352  BEAST_EXPECT(trustedKeys->listed(localSigningPublic));
353  for (auto const& n : configList)
354  BEAST_EXPECT(trustedKeys->listed(n));
355  }
356  {
357  // local validator key (with manifest) not on config list
358  ManifestCache manifests;
359  auto trustedKeys = std::make_unique<ValidatorList>(
360  manifests,
361  manifests,
362  env.timeKeeper(),
363  app.config().legacy("database_path"),
364  env.journal);
365 
366  manifests.applyManifest(*deserializeManifest(cfgManifest));
367 
368  BEAST_EXPECT(trustedKeys->load(
369  localSigningPublicOuter, cfgKeys, emptyCfgPublishers));
370 
371  BEAST_EXPECT(trustedKeys->localPublicKey() == localMasterPublic);
372  BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
373  BEAST_EXPECT(trustedKeys->listed(localMasterPublic));
374  for (auto const& n : configList)
375  BEAST_EXPECT(trustedKeys->listed(n));
376  }
377  {
378  ManifestCache manifests;
379  auto trustedKeys = std::make_unique<ValidatorList>(
380  manifests,
381  manifests,
382  env.timeKeeper(),
383  app.config().legacy("database_path"),
384  env.journal);
385 
386  // load should reject invalid validator list signing keys
387  std::vector<std::string> badPublishers({"NotASigningKey"});
388  BEAST_EXPECT(
389  !trustedKeys->load(emptyLocalKey, emptyCfgKeys, badPublishers));
390 
391  // load should reject validator list signing keys with invalid
392  // encoding
395  badPublishers.clear();
396  for (auto const& key : keys)
397  badPublishers.push_back(toBase58(TokenType::NodePublic, key));
398 
399  BEAST_EXPECT(
400  !trustedKeys->load(emptyLocalKey, emptyCfgKeys, badPublishers));
401  for (auto const& key : keys)
402  BEAST_EXPECT(!trustedKeys->trustedPublisher(key));
403 
404  // load should accept valid validator list publisher keys
405  std::vector<std::string> cfgPublishers;
406  for (auto const& key : keys)
407  cfgPublishers.push_back(strHex(key));
408 
409  BEAST_EXPECT(
410  trustedKeys->load(emptyLocalKey, emptyCfgKeys, cfgPublishers));
411  for (auto const& key : keys)
412  BEAST_EXPECT(trustedKeys->trustedPublisher(key));
413  }
414  {
415  // Attempt to load a publisher key that has been revoked.
416  // Should fail
417  ManifestCache valManifests;
418  ManifestCache pubManifests;
419  auto trustedKeys = std::make_unique<ValidatorList>(
420  valManifests,
421  pubManifests,
422  env.timeKeeper(),
423  app.config().legacy("database_path"),
424  env.journal);
425 
426  auto const pubRevokedSecret = randomSecretKey();
427  auto const pubRevokedPublic =
428  derivePublicKey(KeyType::ed25519, pubRevokedSecret);
429  auto const pubRevokedSigning = randomKeyPair(KeyType::secp256k1);
430  // make this manifest revoked (seq num = max)
431  // -- thus should not be loaded
433  pubRevokedPublic,
434  pubRevokedSecret,
435  pubRevokedSigning.first,
436  pubRevokedSigning.second,
438 
439  // this one is not revoked (and not in manifest cache at all.)
440  auto legitKey = randomMasterKey();
441 
442  std::vector<std::string> cfgPublishers = {
443  strHex(pubRevokedPublic), strHex(legitKey)};
444  BEAST_EXPECT(
445  trustedKeys->load(emptyLocalKey, emptyCfgKeys, cfgPublishers));
446 
447  BEAST_EXPECT(!trustedKeys->trustedPublisher(pubRevokedPublic));
448  BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey));
449  }
450  }
451 
452  void
454  {
455  testcase("Apply list");
456 
457  std::string const siteUri = "testApplyList.test";
458 
459  ManifestCache manifests;
460  jtx::Env env(*this);
461  auto& app = env.app();
462  auto trustedKeys = std::make_unique<ValidatorList>(
463  manifests,
464  manifests,
465  env.app().timeKeeper(),
466  app.config().legacy("database_path"),
467  env.journal);
468 
469  auto const publisherSecret = randomSecretKey();
470  auto const publisherPublic =
471  derivePublicKey(KeyType::ed25519, publisherSecret);
472  auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1);
473  auto const manifest1 = base64_encode(makeManifestString(
474  publisherPublic,
475  publisherSecret,
476  pubSigningKeys1.first,
477  pubSigningKeys1.second,
478  1));
479 
480  std::vector<std::string> cfgKeys1({strHex(publisherPublic)});
481  PublicKey emptyLocalKey;
482  std::vector<std::string> emptyCfgKeys;
483 
484  BEAST_EXPECT(trustedKeys->load(emptyLocalKey, emptyCfgKeys, cfgKeys1));
485 
486  auto constexpr listSize = 20;
488  list1.reserve(listSize);
489  while (list1.size() < listSize)
490  list1.push_back(randomValidator());
491 
493  list2.reserve(listSize);
494  while (list2.size() < listSize)
495  list2.push_back(randomValidator());
496 
497  // do not apply expired list
498  auto const version = 1;
499  auto const sequence = 1;
500  auto const expiredblob = makeList(
501  list1, sequence, env.timeKeeper().now().time_since_epoch().count());
502  auto const expiredSig = signList(expiredblob, pubSigningKeys1);
503 
504  BEAST_EXPECT(
506  trustedKeys
507  ->applyList(
508  manifest1, expiredblob, expiredSig, version, siteUri)
509  .disposition);
510 
511  // apply single list
512  using namespace std::chrono_literals;
513  NetClock::time_point const expiration = env.timeKeeper().now() + 3600s;
514  auto const blob1 =
515  makeList(list1, sequence, expiration.time_since_epoch().count());
516  auto const sig1 = signList(blob1, pubSigningKeys1);
517 
518  BEAST_EXPECT(
520  trustedKeys->applyList(manifest1, blob1, sig1, version, siteUri)
521  .disposition);
522 
523  for (auto const& val : list1)
524  {
525  BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
526  BEAST_EXPECT(trustedKeys->listed(val.signingPublic));
527  }
528 
529  // do not use list from untrusted publisher
530  auto const untrustedManifest = base64_encode(makeManifestString(
531  randomMasterKey(),
532  publisherSecret,
533  pubSigningKeys1.first,
534  pubSigningKeys1.second,
535  1));
536 
537  BEAST_EXPECT(
539  trustedKeys
540  ->applyList(untrustedManifest, blob1, sig1, version, siteUri)
541  .disposition);
542 
543  // do not use list with unhandled version
544  auto const badVersion = 666;
545  BEAST_EXPECT(
547  trustedKeys->applyList(manifest1, blob1, sig1, badVersion, siteUri)
548  .disposition);
549 
550  // apply list with highest sequence number
551  auto const sequence2 = 2;
552  auto const blob2 =
553  makeList(list2, sequence2, expiration.time_since_epoch().count());
554  auto const sig2 = signList(blob2, pubSigningKeys1);
555 
556  BEAST_EXPECT(
558  trustedKeys->applyList(manifest1, blob2, sig2, version, siteUri)
559  .disposition);
560 
561  for (auto const& val : list1)
562  {
563  BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
564  BEAST_EXPECT(!trustedKeys->listed(val.signingPublic));
565  }
566 
567  for (auto const& val : list2)
568  {
569  BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
570  BEAST_EXPECT(trustedKeys->listed(val.signingPublic));
571  }
572 
573  // do not re-apply lists with past or current sequence numbers
574  BEAST_EXPECT(
576  trustedKeys->applyList(manifest1, blob1, sig1, version, siteUri)
577  .disposition);
578 
579  BEAST_EXPECT(
581  trustedKeys->applyList(manifest1, blob2, sig2, version, siteUri)
582  .disposition);
583 
584  // apply list with new publisher key updated by manifest
585  auto const pubSigningKeys2 = randomKeyPair(KeyType::secp256k1);
586  auto manifest2 = base64_encode(makeManifestString(
587  publisherPublic,
588  publisherSecret,
589  pubSigningKeys2.first,
590  pubSigningKeys2.second,
591  2));
592 
593  auto const sequence3 = 3;
594  auto const blob3 =
595  makeList(list1, sequence3, expiration.time_since_epoch().count());
596  auto const sig3 = signList(blob3, pubSigningKeys2);
597 
598  BEAST_EXPECT(
600  trustedKeys->applyList(manifest2, blob3, sig3, version, siteUri)
601  .disposition);
602 
603  auto const sequence4 = 4;
604  auto const blob4 =
605  makeList(list1, sequence4, expiration.time_since_epoch().count());
606  auto const badSig = signList(blob4, pubSigningKeys1);
607  BEAST_EXPECT(
609  trustedKeys->applyList(manifest1, blob4, badSig, version, siteUri)
610  .disposition);
611 
612  // do not apply list with revoked publisher key
613  // applied list is removed due to revoked publisher key
614  auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
615  auto maxManifest = base64_encode(
616  makeRevocationString(publisherPublic, publisherSecret));
617 
618  auto const sequence5 = 5;
619  auto const blob5 =
620  makeList(list1, sequence5, expiration.time_since_epoch().count());
621  auto const sig5 = signList(blob5, signingKeysMax);
622 
623  BEAST_EXPECT(
625  trustedKeys->applyList(maxManifest, blob5, sig5, version, siteUri)
626  .disposition);
627 
628  BEAST_EXPECT(!trustedKeys->trustedPublisher(publisherPublic));
629  for (auto const& val : list1)
630  {
631  BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
632  BEAST_EXPECT(!trustedKeys->listed(val.signingPublic));
633  }
634  }
635 
636  void
638  {
639  testcase("Update trusted");
640 
641  std::string const siteUri = "testUpdateTrusted.test";
642 
643  PublicKey emptyLocalKeyOuter;
644  ManifestCache manifestsOuter;
645  jtx::Env env(*this);
646  auto& app = env.app();
647  auto trustedKeysOuter = std::make_unique<ValidatorList>(
648  manifestsOuter,
649  manifestsOuter,
650  env.timeKeeper(),
651  app.config().legacy("database_path"),
652  env.journal);
653 
654  std::vector<std::string> cfgPublishersOuter;
655  hash_set<NodeID> activeValidatorsOuter;
656 
657  std::size_t const maxKeys = 40;
658  {
659  std::vector<std::string> cfgKeys;
660  cfgKeys.reserve(maxKeys);
661  hash_set<NodeID> unseenValidators;
662 
663  while (cfgKeys.size() != maxKeys)
664  {
665  auto const valKey = randomNode();
666  cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
667  if (cfgKeys.size() <= maxKeys - 5)
668  activeValidatorsOuter.emplace(calcNodeID(valKey));
669  else
670  unseenValidators.emplace(calcNodeID(valKey));
671  }
672 
673  BEAST_EXPECT(trustedKeysOuter->load(
674  emptyLocalKeyOuter, cfgKeys, cfgPublishersOuter));
675 
676  // updateTrusted should make all configured validators trusted
677  // even if they are not active/seen
678  TrustChanges changes =
679  trustedKeysOuter->updateTrusted(activeValidatorsOuter);
680 
681  for (auto const& val : unseenValidators)
682  activeValidatorsOuter.emplace(val);
683 
684  BEAST_EXPECT(changes.added == activeValidatorsOuter);
685  BEAST_EXPECT(changes.removed.empty());
686  BEAST_EXPECT(
687  trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
688  for (auto const& val : cfgKeys)
689  {
690  if (auto const valKey =
691  parseBase58<PublicKey>(TokenType::NodePublic, val))
692  {
693  BEAST_EXPECT(trustedKeysOuter->listed(*valKey));
694  BEAST_EXPECT(trustedKeysOuter->trusted(*valKey));
695  }
696  else
697  fail();
698  }
699 
700  changes = trustedKeysOuter->updateTrusted(activeValidatorsOuter);
701  BEAST_EXPECT(changes.added.empty());
702  BEAST_EXPECT(changes.removed.empty());
703  BEAST_EXPECT(
704  trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
705  }
706  {
707  // update with manifests
708  auto const masterPrivate = randomSecretKey();
709  auto const masterPublic =
710  derivePublicKey(KeyType::ed25519, masterPrivate);
711 
712  std::vector<std::string> cfgKeys(
713  {toBase58(TokenType::NodePublic, masterPublic)});
714 
715  BEAST_EXPECT(trustedKeysOuter->load(
716  emptyLocalKeyOuter, cfgKeys, cfgPublishersOuter));
717 
718  auto const signingKeys1 = randomKeyPair(KeyType::secp256k1);
719  auto const signingPublic1 = signingKeys1.first;
720  activeValidatorsOuter.emplace(calcNodeID(masterPublic));
721 
722  // Should not trust ephemeral signing key if there is no manifest
723  TrustChanges changes =
724  trustedKeysOuter->updateTrusted(activeValidatorsOuter);
725  BEAST_EXPECT(changes.added == asNodeIDs({masterPublic}));
726  BEAST_EXPECT(changes.removed.empty());
727  BEAST_EXPECT(
728  trustedKeysOuter->quorum() == std::ceil((maxKeys + 1) * 0.8f));
729  BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
730  BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
731  BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
732  BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
733 
734  // Should trust the ephemeral signing key from the applied manifest
736  masterPublic,
737  masterPrivate,
738  signingPublic1,
739  signingKeys1.second,
740  1));
741 
742  BEAST_EXPECT(
743  manifestsOuter.applyManifest(std::move(*m1)) ==
745  BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
746  BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
747  BEAST_EXPECT(trustedKeysOuter->listed(signingPublic1));
748  BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic1));
749 
750  // Should only trust the ephemeral signing key
751  // from the newest applied manifest
752  auto const signingKeys2 = randomKeyPair(KeyType::secp256k1);
753  auto const signingPublic2 = signingKeys2.first;
755  masterPublic,
756  masterPrivate,
757  signingPublic2,
758  signingKeys2.second,
759  2));
760  BEAST_EXPECT(
761  manifestsOuter.applyManifest(std::move(*m2)) ==
763  BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
764  BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
765  BEAST_EXPECT(trustedKeysOuter->listed(signingPublic2));
766  BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic2));
767  BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
768  BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
769 
770  // Should not trust keys from revoked master public key
771  auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
772  auto const signingPublicMax = signingKeysMax.first;
773  activeValidatorsOuter.emplace(calcNodeID(signingPublicMax));
774  auto mMax = deserializeManifest(
775  makeRevocationString(masterPublic, masterPrivate));
776 
777  BEAST_EXPECT(mMax->revoked());
778  BEAST_EXPECT(
779  manifestsOuter.applyManifest(std::move(*mMax)) ==
781  BEAST_EXPECT(
782  manifestsOuter.getSigningKey(masterPublic) == masterPublic);
783  BEAST_EXPECT(manifestsOuter.revoked(masterPublic));
784 
785  // Revoked key remains trusted until list is updated
786  BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
787  BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
788 
789  changes = trustedKeysOuter->updateTrusted(activeValidatorsOuter);
790  BEAST_EXPECT(changes.removed == asNodeIDs({masterPublic}));
791  BEAST_EXPECT(changes.added.empty());
792  BEAST_EXPECT(
793  trustedKeysOuter->quorum() == std::ceil(maxKeys * 0.8f));
794  BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
795  BEAST_EXPECT(!trustedKeysOuter->trusted(masterPublic));
796  BEAST_EXPECT(!trustedKeysOuter->listed(signingPublicMax));
797  BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublicMax));
798  BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic2));
799  BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic2));
800  BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
801  BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
802  }
803  {
804  // Make quorum unattainable if lists from any publishers are
805  // unavailable
806  auto trustedKeys = std::make_unique<ValidatorList>(
807  manifestsOuter,
808  manifestsOuter,
809  env.timeKeeper(),
810  app.config().legacy("database_path"),
811  env.journal);
812  auto const publisherSecret = randomSecretKey();
813  auto const publisherPublic =
814  derivePublicKey(KeyType::ed25519, publisherSecret);
815 
816  std::vector<std::string> cfgPublishers({strHex(publisherPublic)});
817  std::vector<std::string> emptyCfgKeys;
818 
819  BEAST_EXPECT(trustedKeys->load(
820  emptyLocalKeyOuter, emptyCfgKeys, cfgPublishers));
821 
822  TrustChanges changes =
823  trustedKeys->updateTrusted(activeValidatorsOuter);
824  BEAST_EXPECT(changes.removed.empty());
825  BEAST_EXPECT(changes.added.empty());
826  BEAST_EXPECT(
827  trustedKeys->quorum() ==
829  }
830  {
831  // Should use custom minimum quorum
832  std::size_t const minQuorum = 1;
833  ManifestCache manifests;
834  auto trustedKeys = std::make_unique<ValidatorList>(
835  manifests,
836  manifests,
837  env.timeKeeper(),
838  app.config().legacy("database_path"),
839  env.journal,
840  minQuorum);
841 
842  std::size_t n = 10;
843  std::vector<std::string> cfgKeys;
844  cfgKeys.reserve(n);
845  hash_set<NodeID> expectedTrusted;
846  hash_set<NodeID> activeValidators;
847  NodeID toBeSeen;
848 
849  while (cfgKeys.size() < n)
850  {
851  auto const valKey = randomNode();
852  cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
853  expectedTrusted.emplace(calcNodeID(valKey));
854  if (cfgKeys.size() < std::ceil(n * 0.8f))
855  activeValidators.emplace(calcNodeID(valKey));
856  else if (cfgKeys.size() < std::ceil(n * 0.8f))
857  toBeSeen = calcNodeID(valKey);
858  }
859 
860  BEAST_EXPECT(trustedKeys->load(
861  emptyLocalKeyOuter, cfgKeys, cfgPublishersOuter));
862 
863  TrustChanges changes = trustedKeys->updateTrusted(activeValidators);
864  BEAST_EXPECT(changes.removed.empty());
865  BEAST_EXPECT(changes.added == expectedTrusted);
866  BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
867 
868  // Use normal quorum when seen validators >= quorum
869  activeValidators.emplace(toBeSeen);
870  changes = trustedKeys->updateTrusted(activeValidators);
871  BEAST_EXPECT(changes.removed.empty());
872  BEAST_EXPECT(changes.added.empty());
873  BEAST_EXPECT(trustedKeys->quorum() == std::ceil(n * 0.8f));
874  }
875  {
876  // Remove expired published list
877  auto trustedKeys = std::make_unique<ValidatorList>(
878  manifestsOuter,
879  manifestsOuter,
880  env.app().timeKeeper(),
881  app.config().legacy("database_path"),
882  env.journal);
883 
884  PublicKey emptyLocalKey;
885  std::vector<std::string> emptyCfgKeys;
886  auto const publisherKeys = randomKeyPair(KeyType::secp256k1);
887  auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
889  publisherKeys.first,
890  publisherKeys.second,
891  pubSigningKeys.first,
892  pubSigningKeys.second,
893  1));
894 
895  std::vector<std::string> cfgKeys({strHex(publisherKeys.first)});
896 
897  BEAST_EXPECT(
898  trustedKeys->load(emptyLocalKey, emptyCfgKeys, cfgKeys));
899 
901  hash_set<NodeID> activeValidators(
902  asNodeIDs({list[0].masterPublic, list[1].masterPublic}));
903 
904  // do not apply expired list
905  auto const version = 1;
906  auto const sequence = 1;
907  using namespace std::chrono_literals;
909  env.timeKeeper().now() + 60s;
910  auto const blob =
911  makeList(list, sequence, expiration.time_since_epoch().count());
912  auto const sig = signList(blob, pubSigningKeys);
913 
914  BEAST_EXPECT(
916  trustedKeys->applyList(manifest, blob, sig, version, siteUri)
917  .disposition);
918 
919  TrustChanges changes = trustedKeys->updateTrusted(activeValidators);
920  BEAST_EXPECT(changes.removed.empty());
921  BEAST_EXPECT(changes.added == activeValidators);
922  for (Validator const& val : list)
923  {
924  BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
925  BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
926  }
927  BEAST_EXPECT(trustedKeys->quorum() == 2);
928 
929  env.timeKeeper().set(expiration);
930  changes = trustedKeys->updateTrusted(activeValidators);
931  BEAST_EXPECT(changes.removed == activeValidators);
932  BEAST_EXPECT(changes.added.empty());
933  BEAST_EXPECT(!trustedKeys->trusted(list[0].masterPublic));
934  BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
935  BEAST_EXPECT(
936  trustedKeys->quorum() ==
938 
939  // (Re)trust validators from new valid list
940  std::vector<Validator> list2({list[0], randomValidator()});
941  activeValidators.insert(calcNodeID(list2[1].masterPublic));
942  auto const sequence2 = 2;
943  NetClock::time_point const expiration2 =
944  env.timeKeeper().now() + 60s;
945  auto const blob2 = makeList(
946  list2, sequence2, expiration2.time_since_epoch().count());
947  auto const sig2 = signList(blob2, pubSigningKeys);
948 
949  BEAST_EXPECT(
951  trustedKeys->applyList(manifest, blob2, sig2, version, siteUri)
952  .disposition);
953 
954  changes = trustedKeys->updateTrusted(activeValidators);
955  BEAST_EXPECT(changes.removed.empty());
956  BEAST_EXPECT(
957  changes.added ==
958  asNodeIDs({list2[0].masterPublic, list2[1].masterPublic}));
959  for (Validator const& val : list2)
960  {
961  BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
962  BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
963  }
964  BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
965  BEAST_EXPECT(!trustedKeys->trusted(list[1].signingPublic));
966  BEAST_EXPECT(trustedKeys->quorum() == 2);
967  }
968  {
969  // Test 1-9 configured validators
970  auto trustedKeys = std::make_unique<ValidatorList>(
971  manifestsOuter,
972  manifestsOuter,
973  env.timeKeeper(),
974  app.config().legacy("database_path"),
975  env.journal);
976 
977  std::vector<std::string> cfgPublishers;
978  hash_set<NodeID> activeValidators;
979  hash_set<PublicKey> activeKeys;
980 
981  std::vector<std::string> cfgKeys;
982  cfgKeys.reserve(9);
983 
984  while (cfgKeys.size() < cfgKeys.capacity())
985  {
986  auto const valKey = randomNode();
987  cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
988  activeValidators.emplace(calcNodeID(valKey));
989  activeKeys.emplace(valKey);
990  BEAST_EXPECT(trustedKeys->load(
991  emptyLocalKeyOuter, cfgKeys, cfgPublishers));
992  TrustChanges changes =
993  trustedKeys->updateTrusted(activeValidators);
994  BEAST_EXPECT(changes.removed.empty());
995  BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
996  BEAST_EXPECT(
997  trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
998  for (auto const& key : activeKeys)
999  BEAST_EXPECT(trustedKeys->trusted(key));
1000  }
1001  }
1002  {
1003  // Test 2-9 configured validators as validator
1004  auto trustedKeys = std::make_unique<ValidatorList>(
1005  manifestsOuter,
1006  manifestsOuter,
1007  env.timeKeeper(),
1008  app.config().legacy("database_path"),
1009  env.journal);
1010 
1011  auto const localKey = randomNode();
1012  std::vector<std::string> cfgPublishers;
1013  hash_set<NodeID> activeValidators;
1014  hash_set<PublicKey> activeKeys;
1015  std::vector<std::string> cfgKeys{
1016  toBase58(TokenType::NodePublic, localKey)};
1017  cfgKeys.reserve(9);
1018 
1019  while (cfgKeys.size() < cfgKeys.capacity())
1020  {
1021  auto const valKey = randomNode();
1022  cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1023  activeValidators.emplace(calcNodeID(valKey));
1024  activeKeys.emplace(valKey);
1025 
1026  BEAST_EXPECT(
1027  trustedKeys->load(localKey, cfgKeys, cfgPublishers));
1028  TrustChanges changes =
1029  trustedKeys->updateTrusted(activeValidators);
1030  BEAST_EXPECT(changes.removed.empty());
1031  if (cfgKeys.size() > 2)
1032  BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
1033  else
1034  BEAST_EXPECT(
1035  changes.added == asNodeIDs({localKey, valKey}));
1036 
1037  BEAST_EXPECT(
1038  trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1039 
1040  for (auto const& key : activeKeys)
1041  BEAST_EXPECT(trustedKeys->trusted(key));
1042  }
1043  }
1044  {
1045  // Trusted set should include all validators from multiple lists
1046  ManifestCache manifests;
1047  auto trustedKeys = std::make_unique<ValidatorList>(
1048  manifests,
1049  manifests,
1050  env.timeKeeper(),
1051  app.config().legacy("database_path"),
1052  env.journal);
1053 
1054  hash_set<NodeID> activeValidators;
1055  std::vector<Validator> valKeys;
1056  valKeys.reserve(maxKeys);
1057 
1058  while (valKeys.size() != maxKeys)
1059  {
1060  valKeys.push_back(randomValidator());
1061  activeValidators.emplace(
1062  calcNodeID(valKeys.back().masterPublic));
1063  }
1064 
1065  auto addPublishedList = [this,
1066  &env,
1067  &trustedKeys,
1068  &valKeys,
1069  &siteUri]() {
1070  auto const publisherSecret = randomSecretKey();
1071  auto const publisherPublic =
1072  derivePublicKey(KeyType::ed25519, publisherSecret);
1073  auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1075  publisherPublic,
1076  publisherSecret,
1077  pubSigningKeys.first,
1078  pubSigningKeys.second,
1079  1));
1080 
1081  std::vector<std::string> cfgPublishers(
1082  {strHex(publisherPublic)});
1083  PublicKey emptyLocalKey;
1084  std::vector<std::string> emptyCfgKeys;
1085 
1086  BEAST_EXPECT(trustedKeys->load(
1087  emptyLocalKey, emptyCfgKeys, cfgPublishers));
1088 
1089  auto const version = 1;
1090  auto const sequence = 1;
1091  using namespace std::chrono_literals;
1093  env.timeKeeper().now() + 3600s;
1094  auto const blob = makeList(
1095  valKeys, sequence, expiration.time_since_epoch().count());
1096  auto const sig = signList(blob, pubSigningKeys);
1097 
1098  BEAST_EXPECT(
1100  trustedKeys
1101  ->applyList(manifest, blob, sig, version, siteUri)
1102  .disposition);
1103  };
1104 
1105  // Apply multiple published lists
1106  for (auto i = 0; i < 3; ++i)
1107  addPublishedList();
1108 
1109  TrustChanges changes = trustedKeys->updateTrusted(activeValidators);
1110 
1111  BEAST_EXPECT(
1112  trustedKeys->quorum() == std::ceil(valKeys.size() * 0.8f));
1113 
1114  hash_set<NodeID> added;
1115  for (auto const& val : valKeys)
1116  {
1117  BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1118  added.insert(calcNodeID(val.masterPublic));
1119  }
1120  BEAST_EXPECT(changes.added == added);
1121  BEAST_EXPECT(changes.removed.empty());
1122  }
1123  }
1124 
1125  void
1127  {
1128  testcase("Expires");
1129 
1130  std::string const siteUri = "testExpires.test";
1131 
1132  jtx::Env env(*this);
1133  auto& app = env.app();
1134 
1135  auto toStr = [](PublicKey const& publicKey) {
1136  return toBase58(TokenType::NodePublic, publicKey);
1137  };
1138 
1139  // Config listed keys
1140  {
1141  ManifestCache manifests;
1142  auto trustedKeys = std::make_unique<ValidatorList>(
1143  manifests,
1144  manifests,
1145  env.timeKeeper(),
1146  app.config().legacy("database_path"),
1147  env.journal);
1148 
1149  // Empty list has no expiration
1150  BEAST_EXPECT(trustedKeys->expires() == boost::none);
1151 
1152  // Config listed keys have maximum expiry
1153  PublicKey emptyLocalKey;
1154  PublicKey localCfgListed = randomNode();
1155  trustedKeys->load(emptyLocalKey, {toStr(localCfgListed)}, {});
1156  BEAST_EXPECT(
1157  trustedKeys->expires() &&
1158  trustedKeys->expires().get() == NetClock::time_point::max());
1159  BEAST_EXPECT(trustedKeys->listed(localCfgListed));
1160  }
1161 
1162  // Published keys with expirations
1163  {
1164  ManifestCache manifests;
1165  auto trustedKeys = std::make_unique<ValidatorList>(
1166  manifests,
1167  manifests,
1168  env.app().timeKeeper(),
1169  app.config().legacy("database_path"),
1170  env.journal);
1171 
1172  std::vector<Validator> validators = {randomValidator()};
1173  hash_set<NodeID> activeValidators;
1174  for (Validator const& val : validators)
1175  activeValidators.insert(calcNodeID(val.masterPublic));
1176  // Store prepared list data to control when it is applied
1177  struct PreparedList
1178  {
1180  std::string blob;
1181  std::string sig;
1182  int version;
1184  };
1185 
1186  using namespace std::chrono_literals;
1187  auto addPublishedList = [this, &env, &trustedKeys, &validators]() {
1188  auto const publisherSecret = randomSecretKey();
1189  auto const publisherPublic =
1190  derivePublicKey(KeyType::ed25519, publisherSecret);
1191  auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1193  publisherPublic,
1194  publisherSecret,
1195  pubSigningKeys.first,
1196  pubSigningKeys.second,
1197  1));
1198 
1199  std::vector<std::string> cfgPublishers(
1200  {strHex(publisherPublic)});
1201  PublicKey emptyLocalKey;
1202  std::vector<std::string> emptyCfgKeys;
1203 
1204  BEAST_EXPECT(trustedKeys->load(
1205  emptyLocalKey, emptyCfgKeys, cfgPublishers));
1206 
1207  auto const version = 1;
1208  auto const sequence = 1;
1210  env.timeKeeper().now() + 3600s;
1211  auto const blob = makeList(
1212  validators,
1213  sequence,
1214  expiration.time_since_epoch().count());
1215  auto const sig = signList(blob, pubSigningKeys);
1216 
1217  return PreparedList{manifest, blob, sig, version, expiration};
1218  };
1219 
1220  // Configure two publishers and prepare 2 lists
1221  PreparedList prep1 = addPublishedList();
1222  env.timeKeeper().set(env.timeKeeper().now() + 200s);
1223  PreparedList prep2 = addPublishedList();
1224 
1225  // Initially, no list has been published, so no known expiration
1226  BEAST_EXPECT(trustedKeys->expires() == boost::none);
1227 
1228  // Apply first list
1229  BEAST_EXPECT(
1231  trustedKeys
1232  ->applyList(
1233  prep1.manifest,
1234  prep1.blob,
1235  prep1.sig,
1236  prep1.version,
1237  siteUri)
1238  .disposition);
1239 
1240  // One list still hasn't published, so expiration is still unknown
1241  BEAST_EXPECT(trustedKeys->expires() == boost::none);
1242 
1243  // Apply second list
1244  BEAST_EXPECT(
1246  trustedKeys
1247  ->applyList(
1248  prep2.manifest,
1249  prep2.blob,
1250  prep2.sig,
1251  prep2.version,
1252  siteUri)
1253  .disposition);
1254 
1255  // We now have loaded both lists, so expiration is known
1256  BEAST_EXPECT(
1257  trustedKeys->expires() &&
1258  trustedKeys->expires().get() == prep1.expiration);
1259 
1260  // Advance past the first list's expiration, but it remains the
1261  // earliest expiration
1262  env.timeKeeper().set(prep1.expiration + 1s);
1263  trustedKeys->updateTrusted(activeValidators);
1264  BEAST_EXPECT(
1265  trustedKeys->expires() &&
1266  trustedKeys->expires().get() == prep1.expiration);
1267  }
1268  }
1269 
1270  void
1272  {
1273  testcase("NegativeUNL");
1274  jtx::Env env(*this);
1275  PublicKey emptyLocalKey;
1276  ManifestCache manifests;
1277 
1278  auto createValidatorList =
1279  [&](std::uint32_t vlSize,
1280  boost::optional<std::size_t> minimumQuorum = {})
1282  auto trustedKeys = std::make_shared<ValidatorList>(
1283  manifests,
1284  manifests,
1285  env.timeKeeper(),
1286  env.app().config().legacy("database_path"),
1287  env.journal,
1288  minimumQuorum);
1289 
1290  std::vector<std::string> cfgPublishers;
1291  std::vector<std::string> cfgKeys;
1292  hash_set<NodeID> activeValidators;
1293  cfgKeys.reserve(vlSize);
1294  while (cfgKeys.size() < cfgKeys.capacity())
1295  {
1296  auto const valKey = randomNode();
1297  cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1298  activeValidators.emplace(calcNodeID(valKey));
1299  }
1300  if (trustedKeys->load(emptyLocalKey, cfgKeys, cfgPublishers))
1301  {
1302  trustedKeys->updateTrusted(activeValidators);
1303  if (trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f))
1304  return trustedKeys;
1305  }
1306  return nullptr;
1307  };
1308 
1309  /*
1310  * Test NegativeUNL
1311  * == Combinations ==
1312  * -- UNL size: 34, 35, 57
1313  * -- nUNL size: 0%, 20%, 30%, 50%
1314  *
1315  * == with UNL size 60
1316  * -- set == get,
1317  * -- check quorum, with nUNL size: 0, 12, 30, 18
1318  * -- nUNL overlap: |nUNL - UNL| = 5, with nUNL size: 18
1319  * -- with command line minimumQuorum = 50%,
1320  * seen_reliable affected by nUNL
1321  */
1322 
1323  {
1324  hash_set<NodeID> activeValidators;
1325  //== Combinations ==
1326  std::array<std::uint32_t, 4> unlSizes = {34, 35, 39, 60};
1327  std::array<std::uint32_t, 4> nUnlPercent = {0, 20, 30, 50};
1328  for (auto us : unlSizes)
1329  {
1330  for (auto np : nUnlPercent)
1331  {
1332  auto validators = createValidatorList(us);
1333  BEAST_EXPECT(validators);
1334  if (validators)
1335  {
1336  std::uint32_t nUnlSize = us * np / 100;
1337  auto unl = validators->getTrustedMasterKeys();
1338  hash_set<PublicKey> nUnl;
1339  auto it = unl.begin();
1340  for (std::uint32_t i = 0; i < nUnlSize; ++i)
1341  {
1342  nUnl.insert(*it);
1343  ++it;
1344  }
1345  validators->setNegativeUNL(nUnl);
1346  validators->updateTrusted(activeValidators);
1347  BEAST_EXPECT(
1348  validators->quorum() ==
1349  static_cast<std::size_t>(std::ceil(
1350  std::max((us - nUnlSize) * 0.8f, us * 0.6f))));
1351  }
1352  }
1353  }
1354  }
1355 
1356  {
1357  //== with UNL size 60
1358  auto validators = createValidatorList(60);
1359  BEAST_EXPECT(validators);
1360  if (validators)
1361  {
1362  hash_set<NodeID> activeValidators;
1363  auto unl = validators->getTrustedMasterKeys();
1364  BEAST_EXPECT(unl.size() == 60);
1365  {
1366  //-- set == get,
1367  //-- check quorum, with nUNL size: 0, 30, 18, 12
1368  auto nUnlChange = [&](std::uint32_t nUnlSize,
1369  std::uint32_t quorum) -> bool {
1370  hash_set<PublicKey> nUnl;
1371  auto it = unl.begin();
1372  for (std::uint32_t i = 0; i < nUnlSize; ++i)
1373  {
1374  nUnl.insert(*it);
1375  ++it;
1376  }
1377  validators->setNegativeUNL(nUnl);
1378  auto nUnl_temp = validators->getNegativeUNL();
1379  if (nUnl_temp.size() == nUnl.size())
1380  {
1381  for (auto& n : nUnl_temp)
1382  {
1383  if (nUnl.find(n) == nUnl.end())
1384  return false;
1385  }
1386  validators->updateTrusted(activeValidators);
1387  return validators->quorum() == quorum;
1388  }
1389  return false;
1390  };
1391  BEAST_EXPECT(nUnlChange(0, 48));
1392  BEAST_EXPECT(nUnlChange(30, 36));
1393  BEAST_EXPECT(nUnlChange(18, 36));
1394  BEAST_EXPECT(nUnlChange(12, 39));
1395  }
1396 
1397  {
1398  // nUNL overlap: |nUNL - UNL| = 5, with nUNL size: 18
1399  auto nUnl = validators->getNegativeUNL();
1400  BEAST_EXPECT(nUnl.size() == 12);
1401  std::size_t ss = 33;
1402  std::vector<uint8_t> data(ss, 0);
1403  data[0] = 0xED;
1404  for (int i = 0; i < 6; ++i)
1405  {
1406  Slice s(data.data(), ss);
1407  data[1]++;
1408  nUnl.emplace(s);
1409  }
1410  validators->setNegativeUNL(nUnl);
1411  validators->updateTrusted(activeValidators);
1412  BEAST_EXPECT(validators->quorum() == 39);
1413  }
1414  }
1415  }
1416 
1417  {
1418  //== with UNL size 60
1419  //-- with command line minimumQuorum = 50%,
1420  // seen_reliable affected by nUNL
1421  auto validators = createValidatorList(60, 30);
1422  BEAST_EXPECT(validators);
1423  if (validators)
1424  {
1425  hash_set<NodeID> activeValidators;
1426  hash_set<PublicKey> unl = validators->getTrustedMasterKeys();
1427  auto it = unl.begin();
1428  for (std::uint32_t i = 0; i < 50; ++i)
1429  {
1430  activeValidators.insert(calcNodeID(*it));
1431  ++it;
1432  }
1433  validators->updateTrusted(activeValidators);
1434  BEAST_EXPECT(validators->quorum() == 48);
1435  hash_set<PublicKey> nUnl;
1436  it = unl.begin();
1437  for (std::uint32_t i = 0; i < 20; ++i)
1438  {
1439  nUnl.insert(*it);
1440  ++it;
1441  }
1442  validators->setNegativeUNL(nUnl);
1443  validators->updateTrusted(activeValidators);
1444  BEAST_EXPECT(validators->quorum() == 30);
1445  }
1446  }
1447  }
1448 
1449 public:
1450  void
1451  run() override
1452  {
1454  testConfigLoad();
1455  testApplyList();
1457  testExpires();
1458  testNegativeUNL();
1459  }
1460 };
1461 
1463 
1464 } // namespace test
1465 } // namespace ripple
ripple::test::ValidatorList_test::Validator
Definition: ValidatorList_test.cpp:37
ripple::test::ValidatorList_test::randomNode
static PublicKey randomNode()
Definition: ValidatorList_test.cpp:45
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
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountDelete, app, ripple)
std::string
STL class.
std::shared_ptr
STL class.
ripple::test::ValidatorList_test::Validator::manifest
std::string manifest
Definition: ValidatorList_test.cpp:41
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::publicKeyType
boost::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:203
ripple::test::ValidatorList_test::testConfigLoad
void testConfigLoad()
Definition: ValidatorList_test.cpp:195
ripple::TrustChanges
Changes in trusted nodes after updating validator list.
Definition: ValidatorList.h:68
ripple::ListDisposition::stale
@ stale
Trusted publisher key, but seq is too old.
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::HashPrefix::manifest
@ manifest
Manifest.
ripple::sfSigningPubKey
const SF_Blob sfSigningPubKey(access, STI_VL, 3, "SigningPubKey")
Definition: SField.h:459
std::vector
STL class.
std::unordered_set::find
T find(T... args)
std::initializer_list::size
T size(T... args)
ripple::sfSequence
const SF_U32 sfSequence(access, STI_UINT32, 4, "Sequence")
Definition: SField.h:356
ripple::base64_encode
std::string base64_encode(std::uint8_t const *data, std::size_t len)
Definition: base64.cpp:236
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:57
ripple::sfMasterSignature
const SF_Blob sfMasterSignature(access, STI_VL, 18, "MasterSignature", SField::sMD_Default, SField::notSigning)
Definition: SField.h:474
ripple::test::ValidatorList_test::run
void run() override
Definition: ValidatorList_test.cpp:1451
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:34
ripple::test::ValidatorList_test::testApplyList
void testApplyList()
Definition: ValidatorList_test.cpp:453
std::unordered_set::emplace
T emplace(T... args)
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::test::jtx::Env::app
Application & app()
Definition: Env.h:240
std::vector::back
T back(T... args)
ripple::Application::timeKeeper
virtual TimeKeeper & timeKeeper()=0
std::vector::clear
T clear(T... args)
ripple::test::ValidatorList_test::testExpires
void testExpires()
Definition: ValidatorList_test.cpp:1126
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::test::jtx::expiration
Set Expiration on a JTx.
Definition: Check_test.cpp:29
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:165
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::test::ValidatorList_test::makeList
std::string makeList(std::vector< Validator > const &validators, std::size_t sequence, std::size_t expiration)
Definition: ValidatorList_test.cpp:125
ripple::derivePublicKey
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:205
ripple::ValidatorList
Definition: ValidatorList.h:119
ripple::Application::config
virtual Config & config()=0
ripple::TrustChanges::removed
hash_set< NodeID > removed
Definition: ValidatorList.h:73
ripple::test::ValidatorList_test::randomValidator
static Validator randomValidator()
Definition: ValidatorList_test.cpp:108
ripple::test::ValidatorList_test::makeRevocationString
static std::string makeRevocationString(PublicKey const &pk, SecretKey const &sk)
Definition: ValidatorList_test.cpp:88
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:349
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:1271
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::ListDisposition::untrusted
@ untrusted
List signed by untrusted publisher key.
ripple::ManifestCache::getSigningKey
PublicKey getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
Definition: app/misc/impl/Manifest.cpp:289
ripple::test::ValidatorList_test::randomMasterKey
static PublicKey randomMasterKey()
Definition: ValidatorList_test.cpp:51
std::uint32_t
ripple::test::jtx::sig
Set the regular signature on a JTx.
Definition: sig.h:33
ripple::SecretKey
A secret key.
Definition: SecretKey.h:36
ripple::ListDisposition::unsupported_version
@ unsupported_version
List version is not supported.
std::ceil
T ceil(T... args)
ripple::test::ValidatorList_test::Validator::masterPublic
PublicKey masterPublic
Definition: ValidatorList_test.cpp:39
ripple::KeyType::secp256k1
@ secp256k1
ripple::ManifestDisposition::accepted
@ accepted
Manifest is valid.
ripple::Serializer
Definition: Serializer.h:39
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:260
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:32
ripple::ManifestCache
Remembers manifests with the highest sequence number.
Definition: Manifest.h:209
ripple::STObject
Definition: STObject.h:51
ripple::sfPublicKey
const SF_Blob sfPublicKey(access, STI_VL, 1, "PublicKey")
Definition: SField.h:457
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::deserializeManifest
boost::optional< Manifest > deserializeManifest(Slice s)
Constructs Manifest from serialized string.
Definition: app/misc/impl/Manifest.cpp:38
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:351
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:124
ripple::test::ValidatorList_test::Validator::signingPublic
PublicKey signingPublic
Definition: ValidatorList_test.cpp:40
ripple::ListDisposition::same_sequence
@ same_sequence
Same sequence as current list.
std::unordered_set::begin
T begin(T... args)
std::unordered_set::insert
T insert(T... args)
ripple::ListDisposition::invalid
@ invalid
Invalid format or signature.
ripple::test::ValidatorList_test::asNodeIDs
static hash_set< NodeID > asNodeIDs(std::initializer_list< PublicKey > const &pks)
Definition: ValidatorList_test.cpp:155
ripple::test::ValidatorList_test::testUpdateTrusted
void testUpdateTrusted()
Definition: ValidatorList_test.cpp:637
ripple::TrustChanges::added
hash_set< NodeID > added
Definition: ValidatorList.h:72
ripple::TokenType::NodePublic
@ NodePublic
std::size_t
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:67
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:361
ripple::test::ValidatorList_test::signList
std::string signList(std::string const &blob, std::pair< PublicKey, SecretKey > const &keys)
Definition: ValidatorList_test.cpp:146
std::numeric_limits
ripple::ListDisposition::accepted
@ accepted
List is valid.
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:167
std::initializer_list