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