rippled
Loading...
Searching...
No Matches
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 <test/jtx.h>
21#include <xrpld/app/misc/ValidatorList.h>
22#include <xrpld/overlay/detail/ProtocolMessage.h>
23#include <xrpl/basics/Slice.h>
24#include <xrpl/basics/base64.h>
25#include <xrpl/basics/strHex.h>
26#include <xrpl/protocol/HashPrefix.h>
27#include <xrpl/protocol/PublicKey.h>
28#include <xrpl/protocol/SecretKey.h>
29#include <xrpl/protocol/Sign.h>
30#include <xrpl/protocol/digest.h>
31#include <xrpl/protocol/jss.h>
32#include <xrpl/protocol/messages.h>
33
34#include <boost/beast/core/multi_buffer.hpp>
35
36namespace ripple {
37namespace test {
38
40{
41private:
42 struct Validator
43 {
47 };
48
49 static PublicKey
51 {
53 }
54
55 static PublicKey
57 {
59 }
60
61 static std::string
63 PublicKey const& pk,
64 SecretKey const& sk,
65 PublicKey const& spk,
66 SecretKey const& ssk,
67 int seq)
68 {
70 st[sfSequence] = seq;
71 st[sfPublicKey] = pk;
72
74 {
75 st[sfSigningPubKey] = spk;
77 }
78
79 sign(
80 st,
82 *publicKeyType(pk),
83 sk,
84 sfMasterSignature);
85
86 Serializer s;
87 st.add(s);
88
89 return std::string(static_cast<char const*>(s.data()), s.size());
90 }
91
92 static std::string
94 {
97 st[sfPublicKey] = pk;
98
99 sign(
100 st,
102 *publicKeyType(pk),
103 sk,
104 sfMasterSignature);
105
106 Serializer s;
107 st.add(s);
108
109 return std::string(static_cast<char const*>(s.data()), s.size());
110 }
111
112 static Validator
114 {
115 auto const secret = randomSecretKey();
116 auto const masterPublic = derivePublicKey(KeyType::ed25519, secret);
117 auto const signingKeys = randomKeyPair(KeyType::secp256k1);
118 return {
119 masterPublic,
120 signingKeys.first,
122 masterPublic,
123 secret,
124 signingKeys.first,
125 signingKeys.second,
126 1))};
127 }
128
131 std::vector<Validator> const& validators,
132 std::size_t sequence,
133 std::size_t validUntil,
134 std::optional<std::size_t> validFrom = {})
135 {
136 std::string data = "{\"sequence\":" + std::to_string(sequence) +
137 ",\"expiration\":" + std::to_string(validUntil);
138 if (validFrom)
139 data += ",\"effective\":" + std::to_string(*validFrom);
140 data += ",\"validators\":[";
141
142 for (auto const& val : validators)
143 {
144 data += "{\"validation_public_key\":\"" + strHex(val.masterPublic) +
145 "\",\"manifest\":\"" + val.manifest + "\"},";
146 }
147
148 data.pop_back();
149 data += "]}";
150 return base64_encode(data);
151 }
152
155 std::string const& blob,
157 {
158 auto const data = base64_decode(blob);
159 return strHex(sign(keys.first, keys.second, makeSlice(data)));
160 }
161
162 static hash_set<NodeID>
164 {
166 res.reserve(pks.size());
167 for (auto const& pk : pks)
168 res.insert(calcNodeID(pk));
169 return res;
170 }
171
172 void
175 PublicKey pubKey,
176 ListDisposition expectedWorst,
177 ListDisposition expectedBest)
178 {
179 BEAST_EXPECT(
181 (result.publisherKey && *result.publisherKey == pubKey));
182 BEAST_EXPECT(result.bestDisposition() == expectedBest);
183 BEAST_EXPECT(result.worstDisposition() == expectedWorst);
184 }
185
186 void
188 {
189 testcase("Genesis Quorum");
190
191 ManifestCache manifests;
192 jtx::Env env(*this);
193 auto& app = env.app();
194 {
195 auto trustedKeys = std::make_unique<ValidatorList>(
196 manifests,
197 manifests,
198 env.timeKeeper(),
199 app.config().legacy("database_path"),
200 env.journal);
201 BEAST_EXPECT(trustedKeys->quorum() == 1);
202 }
203 {
204 std::size_t minQuorum = 0;
205 auto trustedKeys = std::make_unique<ValidatorList>(
206 manifests,
207 manifests,
208 env.timeKeeper(),
209 app.config().legacy("database_path"),
210 env.journal,
211 minQuorum);
212 BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
213 }
214 }
215
216 void
218 {
219 testcase("Config Load");
220
221 jtx::Env env(
223 auto& app = env.app();
224 std::vector<std::string> const emptyCfgKeys;
225 std::vector<std::string> const emptyCfgPublishers;
226
227 auto const localSigningKeys = randomKeyPair(KeyType::secp256k1);
228 auto const localSigningPublicOuter = localSigningKeys.first;
229 auto const localSigningSecret = localSigningKeys.second;
230 auto const localMasterSecret = randomSecretKey();
231 auto const localMasterPublic =
232 derivePublicKey(KeyType::ed25519, localMasterSecret);
233
234 std::string const cfgManifest(makeManifestString(
235 localMasterPublic,
236 localMasterSecret,
237 localSigningPublicOuter,
238 localSigningSecret,
239 1));
240
241 auto format = [](PublicKey const& publicKey,
242 char const* comment = nullptr) {
243 auto ret = toBase58(TokenType::NodePublic, publicKey);
244
245 if (comment)
246 ret += comment;
247
248 return ret;
249 };
250
251 std::vector<PublicKey> configList;
252 configList.reserve(8);
253
254 while (configList.size() != 8)
255 configList.push_back(randomNode());
256
257 // Correct configuration
259 {format(configList[0]),
260 format(configList[1], " Comment"),
261 format(configList[2], " Multi Word Comment"),
262 format(configList[3], " Leading Whitespace"),
263 format(configList[4], " Trailing Whitespace "),
264 format(configList[5], " Leading & Trailing Whitespace "),
265 format(
266 configList[6],
267 " Leading, Trailing & Internal Whitespace "),
268 format(configList[7], " ")});
269
270 {
271 ManifestCache manifests;
272 auto trustedKeys = std::make_unique<ValidatorList>(
273 manifests,
274 manifests,
275 env.timeKeeper(),
276 app.config().legacy("database_path"),
277 env.journal);
278
279 // Correct (empty) configuration
280 BEAST_EXPECT(
281 trustedKeys->load({}, emptyCfgKeys, emptyCfgPublishers));
282
283 // load local validator key with or without manifest
284 BEAST_EXPECT(trustedKeys->load(
285 localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers));
286 BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
287
288 manifests.applyManifest(*deserializeManifest(cfgManifest));
289 BEAST_EXPECT(trustedKeys->load(
290 localSigningPublicOuter, emptyCfgKeys, emptyCfgPublishers));
291
292 BEAST_EXPECT(trustedKeys->listed(localMasterPublic));
293 BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
294 }
295 {
296 // load should add validator keys from config
297 ManifestCache manifests;
298 auto trustedKeys = std::make_unique<ValidatorList>(
299 manifests,
300 manifests,
301 env.timeKeeper(),
302 app.config().legacy("database_path"),
303 env.journal);
304
305 BEAST_EXPECT(trustedKeys->load({}, cfgKeys, emptyCfgPublishers));
306
307 for (auto const& n : configList)
308 BEAST_EXPECT(trustedKeys->listed(n));
309
310 // load should accept Ed25519 master public keys
311 auto const masterNode1 = randomMasterKey();
312 auto const masterNode2 = randomMasterKey();
313
314 std::vector<std::string> cfgMasterKeys(
315 {format(masterNode1), format(masterNode2, " Comment")});
316 BEAST_EXPECT(
317 trustedKeys->load({}, cfgMasterKeys, emptyCfgPublishers));
318 BEAST_EXPECT(trustedKeys->listed(masterNode1));
319 BEAST_EXPECT(trustedKeys->listed(masterNode2));
320
321 // load should reject invalid config keys
322 BEAST_EXPECT(
323 !trustedKeys->load({}, {"NotAPublicKey"}, emptyCfgPublishers));
324 BEAST_EXPECT(!trustedKeys->load(
325 {}, {format(randomNode(), "!")}, emptyCfgPublishers));
326
327 // load terminates when encountering an invalid entry
328 auto const goodKey = randomNode();
329 BEAST_EXPECT(!trustedKeys->load(
330 {},
331 {format(randomNode(), "!"), format(goodKey)},
332 emptyCfgPublishers));
333 BEAST_EXPECT(!trustedKeys->listed(goodKey));
334 }
335 {
336 // local validator key on config list
337 ManifestCache manifests;
338 auto trustedKeys = std::make_unique<ValidatorList>(
339 manifests,
340 manifests,
341 env.timeKeeper(),
342 app.config().legacy("database_path"),
343 env.journal);
344
345 auto const localSigningPublic =
346 parseBase58<PublicKey>(TokenType::NodePublic, cfgKeys.front());
347
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 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 auto const localSigningPublic = randomNode();
367 BEAST_EXPECT(trustedKeys->load(
368 localSigningPublic, cfgKeys, emptyCfgPublishers));
369
370 BEAST_EXPECT(trustedKeys->localPublicKey() == localSigningPublic);
371 BEAST_EXPECT(trustedKeys->listed(localSigningPublic));
372 for (auto const& n : configList)
373 BEAST_EXPECT(trustedKeys->listed(n));
374 }
375 {
376 // local validator key (with manifest) not on config list
377 ManifestCache manifests;
378 auto trustedKeys = std::make_unique<ValidatorList>(
379 manifests,
380 manifests,
381 env.timeKeeper(),
382 app.config().legacy("database_path"),
383 env.journal);
384
385 manifests.applyManifest(*deserializeManifest(cfgManifest));
386
387 BEAST_EXPECT(trustedKeys->load(
388 localSigningPublicOuter, cfgKeys, emptyCfgPublishers));
389
390 BEAST_EXPECT(trustedKeys->localPublicKey() == localMasterPublic);
391 BEAST_EXPECT(trustedKeys->listed(localSigningPublicOuter));
392 BEAST_EXPECT(trustedKeys->listed(localMasterPublic));
393 for (auto const& n : configList)
394 BEAST_EXPECT(trustedKeys->listed(n));
395 }
396 {
397 ManifestCache manifests;
398 auto trustedKeys = std::make_unique<ValidatorList>(
399 manifests,
400 manifests,
401 env.timeKeeper(),
402 app.config().legacy("database_path"),
403 env.journal);
404
405 // load should reject invalid validator list signing keys
406 std::vector<std::string> badPublishers({"NotASigningKey"});
407 BEAST_EXPECT(!trustedKeys->load({}, emptyCfgKeys, badPublishers));
408
409 // load should reject validator list signing keys with invalid
410 // encoding
413 badPublishers.clear();
414 for (auto const& key : keys)
415 badPublishers.push_back(toBase58(TokenType::NodePublic, key));
416
417 BEAST_EXPECT(!trustedKeys->load({}, emptyCfgKeys, badPublishers));
418 for (auto const& key : keys)
419 BEAST_EXPECT(!trustedKeys->trustedPublisher(key));
420
421 // load should accept valid validator list publisher keys
422 std::vector<std::string> cfgPublishers;
423 for (auto const& key : keys)
424 cfgPublishers.push_back(strHex(key));
425
426 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
427 for (auto const& key : keys)
428 BEAST_EXPECT(trustedKeys->trustedPublisher(key));
429 BEAST_EXPECT(
430 trustedKeys->getListThreshold() == keys.size() / 2 + 1);
431 }
432 {
433 ManifestCache manifests;
434 auto trustedKeys = std::make_unique<ValidatorList>(
435 manifests,
436 manifests,
437 env.timeKeeper(),
438 app.config().legacy("database_path"),
439 env.journal);
440
445 randomMasterKey()});
446 std::vector<std::string> cfgPublishers;
447 for (auto const& key : keys)
448 cfgPublishers.push_back(strHex(key));
449
450 // explicitly set the list threshold
451 BEAST_EXPECT(trustedKeys->load(
452 {}, emptyCfgKeys, cfgPublishers, std::size_t(2)));
453 for (auto const& key : keys)
454 BEAST_EXPECT(trustedKeys->trustedPublisher(key));
455 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
456 }
457 {
458 // Attempt to load a publisher key that has been revoked.
459 // Should fail
460 ManifestCache valManifests;
461 ManifestCache pubManifests;
462 auto trustedKeys = std::make_unique<ValidatorList>(
463 valManifests,
464 pubManifests,
465 env.timeKeeper(),
466 app.config().legacy("database_path"),
467 env.journal);
468
469 auto const pubRevokedSecret = randomSecretKey();
470 auto const pubRevokedPublic =
471 derivePublicKey(KeyType::ed25519, pubRevokedSecret);
472 auto const pubRevokedSigning = randomKeyPair(KeyType::secp256k1);
473 // make this manifest revoked (seq num = max)
474 // -- thus should not be loaded
476 pubRevokedPublic,
477 pubRevokedSecret,
478 pubRevokedSigning.first,
479 pubRevokedSigning.second,
481
482 // these two are not revoked (and not in the manifest cache at all.)
483 auto legitKey1 = randomMasterKey();
484 auto legitKey2 = randomMasterKey();
485
486 std::vector<std::string> cfgPublishers = {
487 strHex(pubRevokedPublic), strHex(legitKey1), strHex(legitKey2)};
488 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
489
490 BEAST_EXPECT(!trustedKeys->trustedPublisher(pubRevokedPublic));
491 BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey1));
492 BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey2));
493 // 2 is the threshold for 3 publishers (even though 1 is revoked)
494 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
495 }
496 {
497 // One (of two) publisher keys has been revoked, the user had
498 // explicitly set validator list threshold to 2.
499 ManifestCache valManifests;
500 ManifestCache pubManifests;
501 auto trustedKeys = std::make_unique<ValidatorList>(
502 valManifests,
503 pubManifests,
504 env.timeKeeper(),
505 app.config().legacy("database_path"),
506 env.journal);
507
508 auto const pubRevokedSecret = randomSecretKey();
509 auto const pubRevokedPublic =
510 derivePublicKey(KeyType::ed25519, pubRevokedSecret);
511 auto const pubRevokedSigning = randomKeyPair(KeyType::secp256k1);
512 // make this manifest revoked (seq num = max)
513 // -- thus should not be loaded
515 pubRevokedPublic,
516 pubRevokedSecret,
517 pubRevokedSigning.first,
518 pubRevokedSigning.second,
520
521 // this one is not revoked (and not in the manifest cache at all.)
522 auto legitKey = randomMasterKey();
523
524 std::vector<std::string> cfgPublishers = {
525 strHex(pubRevokedPublic), strHex(legitKey)};
526 BEAST_EXPECT(trustedKeys->load(
527 {}, emptyCfgKeys, cfgPublishers, std::size_t(2)));
528
529 BEAST_EXPECT(!trustedKeys->trustedPublisher(pubRevokedPublic));
530 BEAST_EXPECT(trustedKeys->trustedPublisher(legitKey));
531 // 2 is the threshold, as requested in configuration
532 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
533 }
534 }
535
536 void
538 {
539 testcase("Apply list");
540 using namespace std::chrono_literals;
541
542 std::string const siteUri = "testApplyList.test";
543
544 auto checkAvailable =
545 [this](
546 auto const& trustedKeys,
547 auto const& hexPublic,
548 auto const& manifest,
549 auto const version,
551 expected) {
552 const auto available = trustedKeys->getAvailable(hexPublic);
553
554 BEAST_EXPECT(!version || available);
555 if (available)
556 {
557 auto const& a = *available;
558 BEAST_EXPECT(a[jss::public_key] == hexPublic);
559 BEAST_EXPECT(a[jss::manifest] == manifest);
560 // Because multiple lists were processed, the version was
561 // overridden
562 BEAST_EXPECT(a[jss::version] == version);
563 if (version == 1)
564 {
565 BEAST_EXPECT(expected.size() == 1);
566 BEAST_EXPECT(a[jss::blob] == expected[0].first);
567 BEAST_EXPECT(a[jss::signature] == expected[0].second);
568 BEAST_EXPECT(!a.isMember(jss::blobs_v2));
569 }
570 else if (BEAST_EXPECT(a.isMember(jss::blobs_v2)))
571 {
572 BEAST_EXPECT(!a.isMember(jss::blob));
573 BEAST_EXPECT(!a.isMember(jss::signature));
574 auto const& blobs_v2 = a[jss::blobs_v2];
575 BEAST_EXPECT(
576 blobs_v2.isArray() &&
577 blobs_v2.size() == expected.size());
578
579 for (unsigned int i = 0; i < expected.size(); ++i)
580 {
581 BEAST_EXPECT(
582 blobs_v2[i][jss::blob] == expected[i].first);
583 BEAST_EXPECT(
584 blobs_v2[i][jss::signature] ==
585 expected[i].second);
586 }
587 }
588 }
589 };
590
591 ManifestCache manifests;
592 jtx::Env env(*this);
593 auto& app = env.app();
594 auto trustedKeys = std::make_unique<ValidatorList>(
595 manifests,
596 manifests,
597 env.app().timeKeeper(),
598 app.config().legacy("database_path"),
599 env.journal);
600
601 auto expectTrusted =
602 [this, &trustedKeys](std::vector<Validator> const& list) {
603 for (auto const& val : list)
604 {
605 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
606 BEAST_EXPECT(trustedKeys->listed(val.signingPublic));
607 }
608 };
609
610 auto expectUntrusted =
611 [this, &trustedKeys](std::vector<Validator> const& list) {
612 for (auto const& val : list)
613 {
614 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
615 BEAST_EXPECT(!trustedKeys->listed(val.signingPublic));
616 }
617 };
618
619 auto const publisherSecret = randomSecretKey();
620 auto const publisherPublic =
621 derivePublicKey(KeyType::ed25519, publisherSecret);
622 const auto hexPublic =
623 strHex(publisherPublic.begin(), publisherPublic.end());
624 auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1);
625 auto const manifest1 = base64_encode(makeManifestString(
626 publisherPublic,
627 publisherSecret,
628 pubSigningKeys1.first,
629 pubSigningKeys1.second,
630 1));
631
632 std::vector<std::string> cfgKeys1({strHex(publisherPublic)});
633 std::vector<std::string> emptyCfgKeys;
634
635 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys1));
636
638 auto constexpr listSize = 20;
639 auto constexpr numLists = 9;
641 // 1-based to correspond with the individually named blobs below.
642 for (auto i = 1; i <= numLists; ++i)
643 {
644 auto& list = lists[i];
645 list.reserve(listSize);
646 while (list.size() < listSize)
647 list.push_back(randomValidator());
648 }
649 return lists;
650 }();
651
652 // Attempt an expired list (fail) and a single list (succeed)
653 env.timeKeeper().set(env.timeKeeper().now() + 1s);
654 auto const version = 1;
655 auto const sequence1 = 1;
656 auto const expiredblob = makeList(
657 lists.at(1),
658 sequence1,
659 env.timeKeeper().now().time_since_epoch().count());
660 auto const expiredSig = signList(expiredblob, pubSigningKeys1);
661
662 NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s;
663 auto const sequence2 = 2;
664 auto const blob2 = makeList(
665 lists.at(2), sequence2, validUntil.time_since_epoch().count());
666 auto const sig2 = signList(blob2, pubSigningKeys1);
667
669 trustedKeys->applyLists(
670 manifest1,
671 version,
672 {{expiredblob, expiredSig, {}}, {blob2, sig2, {}}},
673 siteUri),
674 publisherPublic,
677
678 expectTrusted(lists.at(2));
679
680 checkAvailable(
681 trustedKeys, hexPublic, manifest1, version, {{blob2, sig2}});
682
683 // Do not apply future lists, but process them
684 auto const version2 = 2;
685 auto const sequence7 = 7;
686 auto const effective7 = validUntil - 60s;
687 auto const expiration7 = effective7 + 3600s;
688 auto const blob7 = makeList(
689 lists.at(7),
690 sequence7,
691 expiration7.time_since_epoch().count(),
692 effective7.time_since_epoch().count());
693 auto const sig7 = signList(blob7, pubSigningKeys1);
694
695 auto const sequence8 = 8;
696 auto const effective8 = expiration7 - 60s;
697 auto const expiration8 = effective8 + 3600s;
698 auto const blob8 = makeList(
699 lists.at(8),
700 sequence8,
701 expiration8.time_since_epoch().count(),
702 effective8.time_since_epoch().count());
703 auto const sig8 = signList(blob8, pubSigningKeys1);
704
705 checkResult(
706 trustedKeys->applyLists(
707 manifest1,
708 version2,
709 {{blob7, sig7, {}}, {blob8, sig8, {}}},
710 siteUri),
711 publisherPublic,
712 ListDisposition::pending,
713 ListDisposition::pending);
714
715 expectUntrusted(lists.at(7));
716 expectUntrusted(lists.at(8));
717
718 // Do not apply out-of-order future list, but process it
719 auto const sequence6 = 6;
720 auto const effective6 = effective7 - 60s;
721 auto const expiration6 = effective6 + 3600s;
722 auto const blob6 = makeList(
723 lists.at(6),
724 sequence6,
725 expiration6.time_since_epoch().count(),
726 effective6.time_since_epoch().count());
727 auto const sig6 = signList(blob6, pubSigningKeys1);
728
729 // Process future list that is overridden by a later list
730 auto const sequence6a = 5;
731 auto const effective6a = effective6 + 60s;
732 auto const expiration6a = effective6a + 3600s;
733 auto const blob6a = makeList(
734 lists.at(5),
735 sequence6a,
736 expiration6a.time_since_epoch().count(),
737 effective6a.time_since_epoch().count());
738 auto const sig6a = signList(blob6a, pubSigningKeys1);
739
740 checkResult(
741 trustedKeys->applyLists(
742 manifest1,
743 version,
744 {{blob6a, sig6a, {}}, {blob6, sig6, {}}},
745 siteUri),
746 publisherPublic,
747 ListDisposition::pending,
748 ListDisposition::pending);
749
750 expectUntrusted(lists.at(6));
751 expectTrusted(lists.at(2));
752
753 // Do not apply re-process lists known future sequence numbers
754
755 checkResult(
756 trustedKeys->applyLists(
757 manifest1,
758 version,
759 {{blob7, sig7, {}}, {blob6, sig6, {}}},
760 siteUri),
761 publisherPublic,
762 ListDisposition::known_sequence,
763 ListDisposition::known_sequence);
764
765 expectUntrusted(lists.at(6));
766 expectUntrusted(lists.at(7));
767 expectTrusted(lists.at(2));
768
769 // do not use list from untrusted publisher
770 auto const untrustedManifest = base64_encode(makeManifestString(
771 randomMasterKey(),
772 publisherSecret,
773 pubSigningKeys1.first,
774 pubSigningKeys1.second,
775 1));
776
777 checkResult(
778 trustedKeys->applyLists(
779 untrustedManifest, version, {{blob2, sig2, {}}}, siteUri),
780 publisherPublic,
781 ListDisposition::untrusted,
782 ListDisposition::untrusted);
783
784 // do not use list with unhandled version
785 auto const badVersion = 666;
786 checkResult(
787 trustedKeys->applyLists(
788 manifest1, badVersion, {{blob2, sig2, {}}}, siteUri),
789 publisherPublic,
790 ListDisposition::unsupported_version,
791 ListDisposition::unsupported_version);
792
793 // apply list with highest sequence number
794 auto const sequence3 = 3;
795 auto const blob3 = makeList(
796 lists.at(3), sequence3, validUntil.time_since_epoch().count());
797 auto const sig3 = signList(blob3, pubSigningKeys1);
798
799 checkResult(
800 trustedKeys->applyLists(
801 manifest1, version, {{blob3, sig3, {}}}, siteUri),
802 publisherPublic,
803 ListDisposition::accepted,
804 ListDisposition::accepted);
805
806 expectUntrusted(lists.at(1));
807 expectUntrusted(lists.at(2));
808 expectTrusted(lists.at(3));
809
810 // Note that blob6a is not present, because it was dropped during
811 // processing
812 checkAvailable(
813 trustedKeys,
814 hexPublic,
815 manifest1,
816 2,
817 {{blob3, sig3}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
818
819 // do not re-apply lists with past or current sequence numbers
820 checkResult(
821 trustedKeys->applyLists(
822 manifest1,
823 version,
824 {{blob2, sig2, {}}, {blob3, sig3, {}}},
825 siteUri),
826 publisherPublic,
827 ListDisposition::stale,
828 ListDisposition::same_sequence);
829
830 // apply list with new publisher key updated by manifest. Also send some
831 // old lists along with the old manifest
832 auto const pubSigningKeys2 = randomKeyPair(KeyType::secp256k1);
833 auto manifest2 = base64_encode(makeManifestString(
834 publisherPublic,
835 publisherSecret,
836 pubSigningKeys2.first,
837 pubSigningKeys2.second,
838 2));
839
840 auto const sequence4 = 4;
841 auto const blob4 = makeList(
842 lists.at(4), sequence4, validUntil.time_since_epoch().count());
843 auto const sig4 = signList(blob4, pubSigningKeys2);
844
845 checkResult(
846 trustedKeys->applyLists(
847 manifest2,
848 version,
849 {{blob2, sig2, manifest1},
850 {blob3, sig3, manifest1},
851 {blob4, sig4, {}}},
852 siteUri),
853 publisherPublic,
854 ListDisposition::stale,
855 ListDisposition::accepted);
856
857 expectUntrusted(lists.at(2));
858 expectUntrusted(lists.at(3));
859 expectTrusted(lists.at(4));
860
861 checkAvailable(
862 trustedKeys,
863 hexPublic,
864 manifest2,
865 2,
866 {{blob4, sig4}, {blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
867
868 auto const sequence5 = 5;
869 auto const blob5 = makeList(
870 lists.at(5), sequence5, validUntil.time_since_epoch().count());
871 auto const badSig = signList(blob5, pubSigningKeys1);
872 checkResult(
873 trustedKeys->applyLists(
874 manifest1, version, {{blob5, badSig, {}}}, siteUri),
875 publisherPublic,
876 ListDisposition::invalid,
877 ListDisposition::invalid);
878
879 expectUntrusted(lists.at(2));
880 expectUntrusted(lists.at(3));
881 expectTrusted(lists.at(4));
882 expectUntrusted(lists.at(5));
883
884 // Reprocess the pending list, but the signature is no longer valid
885 checkResult(
886 trustedKeys->applyLists(
887 manifest1,
888 version,
889 {{blob7, sig7, {}}, {blob8, sig8, {}}},
890 siteUri),
891 publisherPublic,
892 ListDisposition::invalid,
893 ListDisposition::invalid);
894
895 expectTrusted(lists.at(4));
896 expectUntrusted(lists.at(7));
897 expectUntrusted(lists.at(8));
898
899 // Automatically rotate the first pending already processed list using
900 // updateTrusted. Note that the timekeeper is NOT moved, so the close
901 // time will be ahead of the test's wall clock
902 trustedKeys->updateTrusted(
903 {},
904 effective6 + 1s,
905 env.app().getOPs(),
906 env.app().overlay(),
907 env.app().getHashRouter());
908
909 expectUntrusted(lists.at(3));
910 expectTrusted(lists.at(6));
911
912 checkAvailable(
913 trustedKeys,
914 hexPublic,
915 manifest2,
916 2,
917 {{blob6, sig6}, {blob7, sig7}, {blob8, sig8}});
918
919 // Automatically rotate the LAST pending list using updateTrusted,
920 // bypassing blob7. Note that the timekeeper IS moved, so the provided
921 // close time will be behind the test's wall clock, and thus the wall
922 // clock is used.
923 env.timeKeeper().set(effective8);
924 trustedKeys->updateTrusted(
925 {},
926 effective8 + 1s,
927 env.app().getOPs(),
928 env.app().overlay(),
929 env.app().getHashRouter());
930
931 expectUntrusted(lists.at(6));
932 expectUntrusted(lists.at(7));
933 expectTrusted(lists.at(8));
934
935 checkAvailable(trustedKeys, hexPublic, manifest2, 2, {{blob8, sig8}});
936
937 // resign the pending list with new key and validate it, but it's
938 // already valid Also try reprocessing the pending list with an
939 // explicit manifest
940 // - it is still invalid
941 auto const sig8_2 = signList(blob8, pubSigningKeys2);
942
943 checkResult(
944 trustedKeys->applyLists(
945 manifest2,
946 version,
947 {{blob8, sig8, manifest1}, {blob8, sig8_2, {}}},
948 siteUri),
949 publisherPublic,
950 ListDisposition::invalid,
951 ListDisposition::same_sequence);
952
953 expectTrusted(lists.at(8));
954
955 checkAvailable(trustedKeys, hexPublic, manifest2, 2, {{blob8, sig8}});
956
957 // do not apply list with revoked publisher key
958 // applied list is removed due to revoked publisher key
959 auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
960 auto maxManifest = base64_encode(
961 makeRevocationString(publisherPublic, publisherSecret));
962
963 auto const sequence9 = 9;
964 auto const blob9 = makeList(
965 lists.at(9), sequence9, validUntil.time_since_epoch().count());
966 auto const sig9 = signList(blob9, signingKeysMax);
967
968 checkResult(
969 trustedKeys->applyLists(
970 maxManifest, version, {{blob9, sig9, {}}}, siteUri),
971 publisherPublic,
972 ListDisposition::untrusted,
973 ListDisposition::untrusted);
974
975 BEAST_EXPECT(!trustedKeys->trustedPublisher(publisherPublic));
976 for (auto const& [num, list] : lists)
977 {
978 (void)num;
979 expectUntrusted(list);
980 }
981
982 checkAvailable(trustedKeys, hexPublic, manifest2, 0, {});
983 }
984
985 void
987 {
988 testcase("GetAvailable");
989 using namespace std::chrono_literals;
990
991 std::string const siteUri = "testApplyList.test";
992
993 ManifestCache manifests;
994 jtx::Env env(*this);
995 auto& app = env.app();
996 auto trustedKeys = std::make_unique<ValidatorList>(
997 manifests,
998 manifests,
999 env.app().timeKeeper(),
1000 app.config().legacy("database_path"),
1001 env.journal);
1002
1003 auto const publisherSecret = randomSecretKey();
1004 auto const publisherPublic =
1005 derivePublicKey(KeyType::ed25519, publisherSecret);
1006 const auto hexPublic =
1007 strHex(publisherPublic.begin(), publisherPublic.end());
1008 auto const pubSigningKeys1 = randomKeyPair(KeyType::secp256k1);
1009 auto const manifest = base64_encode(makeManifestString(
1010 publisherPublic,
1011 publisherSecret,
1012 pubSigningKeys1.first,
1013 pubSigningKeys1.second,
1014 1));
1015
1016 std::vector<std::string> cfgKeys1({strHex(publisherPublic)});
1017 std::vector<std::string> emptyCfgKeys;
1018
1019 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys1));
1020
1021 std::vector<Validator> const list = []() {
1022 auto constexpr listSize = 20;
1024 list.reserve(listSize);
1025 while (list.size() < listSize)
1026 list.push_back(randomValidator());
1027 return list;
1028 }();
1029
1030 // Process a list
1031 env.timeKeeper().set(env.timeKeeper().now() + 1s);
1032 NetClock::time_point const validUntil = env.timeKeeper().now() + 3600s;
1033 auto const blob =
1034 makeList(list, 1, validUntil.time_since_epoch().count());
1035 auto const sig = signList(blob, pubSigningKeys1);
1036
1037 {
1038 // list unavailable
1039 auto const available = trustedKeys->getAvailable(hexPublic);
1040 BEAST_EXPECT(!available);
1041 }
1042
1043 BEAST_EXPECT(
1044 trustedKeys->applyLists(manifest, 1, {{blob, sig, {}}}, siteUri)
1045 .bestDisposition() == ListDisposition::accepted);
1046
1047 {
1048 // invalid public key
1049 auto const available =
1050 trustedKeys->getAvailable(hexPublic + "invalid", 1);
1051 BEAST_EXPECT(!available);
1052 }
1053
1054 {
1055 // unknown public key
1056 auto const badSecret = randomSecretKey();
1057 auto const badPublic = derivePublicKey(KeyType::ed25519, badSecret);
1058 const auto hexBad = strHex(badPublic.begin(), badPublic.end());
1059
1060 auto const available = trustedKeys->getAvailable(hexBad, 1);
1061 BEAST_EXPECT(!available);
1062 }
1063 {
1064 // bad version 0
1065 auto const available = trustedKeys->getAvailable(hexPublic, 0);
1066 if (BEAST_EXPECT(available))
1067 {
1068 auto const& a = *available;
1069 BEAST_EXPECT(!a);
1070 }
1071 }
1072 {
1073 // bad version 3
1074 auto const available = trustedKeys->getAvailable(hexPublic, 3);
1075 if (BEAST_EXPECT(available))
1076 {
1077 auto const& a = *available;
1078 BEAST_EXPECT(!a);
1079 }
1080 }
1081 {
1082 // version 1
1083 auto const available = trustedKeys->getAvailable(hexPublic, 1);
1084 if (BEAST_EXPECT(available))
1085 {
1086 auto const& a = *available;
1087 BEAST_EXPECT(a[jss::public_key] == hexPublic);
1088 BEAST_EXPECT(a[jss::manifest] == manifest);
1089 BEAST_EXPECT(a[jss::version] == 1);
1090
1091 BEAST_EXPECT(a[jss::blob] == blob);
1092 BEAST_EXPECT(a[jss::signature] == sig);
1093 BEAST_EXPECT(!a.isMember(jss::blobs_v2));
1094 }
1095 }
1096
1097 {
1098 // version 2
1099 auto const available = trustedKeys->getAvailable(hexPublic, 2);
1100 if (BEAST_EXPECT(available))
1101 {
1102 auto const& a = *available;
1103 BEAST_EXPECT(a[jss::public_key] == hexPublic);
1104 BEAST_EXPECT(a[jss::manifest] == manifest);
1105 BEAST_EXPECT(a[jss::version] == 2);
1106
1107 if (BEAST_EXPECT(a.isMember(jss::blobs_v2)))
1108 {
1109 BEAST_EXPECT(!a.isMember(jss::blob));
1110 BEAST_EXPECT(!a.isMember(jss::signature));
1111 auto const& blobs_v2 = a[jss::blobs_v2];
1112 BEAST_EXPECT(blobs_v2.isArray() && blobs_v2.size() == 1);
1113
1114 BEAST_EXPECT(blobs_v2[0u][jss::blob] == blob);
1115 BEAST_EXPECT(blobs_v2[0u][jss::signature] == sig);
1116 }
1117 }
1118 }
1119 }
1120
1121 void
1123 {
1124 testcase("Update trusted");
1125
1126 std::string const siteUri = "testUpdateTrusted.test";
1127
1128 ManifestCache manifestsOuter;
1129 jtx::Env env(*this);
1130 auto& app = env.app();
1131 auto trustedKeysOuter = std::make_unique<ValidatorList>(
1132 manifestsOuter,
1133 manifestsOuter,
1134 env.timeKeeper(),
1135 app.config().legacy("database_path"),
1136 env.journal);
1137
1138 std::vector<std::string> cfgPublishersOuter;
1139 hash_set<NodeID> activeValidatorsOuter;
1140
1141 std::size_t const maxKeys = 40;
1142 {
1144 cfgKeys.reserve(maxKeys);
1145 hash_set<NodeID> unseenValidators;
1146
1147 while (cfgKeys.size() != maxKeys)
1148 {
1149 auto const valKey = randomNode();
1150 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1151 if (cfgKeys.size() <= maxKeys - 5)
1152 activeValidatorsOuter.emplace(calcNodeID(valKey));
1153 else
1154 unseenValidators.emplace(calcNodeID(valKey));
1155 }
1156
1157 BEAST_EXPECT(
1158 trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter));
1159
1160 // updateTrusted should make all configured validators trusted
1161 // even if they are not active/seen
1162 TrustChanges changes = trustedKeysOuter->updateTrusted(
1163 activeValidatorsOuter,
1164 env.timeKeeper().now(),
1165 env.app().getOPs(),
1166 env.app().overlay(),
1167 env.app().getHashRouter());
1168
1169 for (auto const& val : unseenValidators)
1170 activeValidatorsOuter.emplace(val);
1171
1172 BEAST_EXPECT(changes.added == activeValidatorsOuter);
1173 BEAST_EXPECT(changes.removed.empty());
1174 BEAST_EXPECT(
1175 trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1176 for (auto const& val : cfgKeys)
1177 {
1178 if (auto const valKey =
1179 parseBase58<PublicKey>(TokenType::NodePublic, val))
1180 {
1181 BEAST_EXPECT(trustedKeysOuter->listed(*valKey));
1182 BEAST_EXPECT(trustedKeysOuter->trusted(*valKey));
1183 }
1184 else
1185 fail();
1186 }
1187
1188 changes = trustedKeysOuter->updateTrusted(
1189 activeValidatorsOuter,
1190 env.timeKeeper().now(),
1191 env.app().getOPs(),
1192 env.app().overlay(),
1193 env.app().getHashRouter());
1194 BEAST_EXPECT(changes.added.empty());
1195 BEAST_EXPECT(changes.removed.empty());
1196 BEAST_EXPECT(
1197 trustedKeysOuter->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1198 }
1199 {
1200 // update with manifests
1201 auto const masterPrivate = randomSecretKey();
1202 auto const masterPublic =
1203 derivePublicKey(KeyType::ed25519, masterPrivate);
1204
1206 {toBase58(TokenType::NodePublic, masterPublic)});
1207
1208 BEAST_EXPECT(
1209 trustedKeysOuter->load({}, cfgKeys, cfgPublishersOuter));
1210
1211 auto const signingKeys1 = randomKeyPair(KeyType::secp256k1);
1212 auto const signingPublic1 = signingKeys1.first;
1213 activeValidatorsOuter.emplace(calcNodeID(masterPublic));
1214
1215 // Should not trust ephemeral signing key if there is no manifest
1216 TrustChanges changes = trustedKeysOuter->updateTrusted(
1217 activeValidatorsOuter,
1218 env.timeKeeper().now(),
1219 env.app().getOPs(),
1220 env.app().overlay(),
1221 env.app().getHashRouter());
1222 BEAST_EXPECT(changes.added == asNodeIDs({masterPublic}));
1223 BEAST_EXPECT(changes.removed.empty());
1224 BEAST_EXPECT(
1225 trustedKeysOuter->quorum() == std::ceil((maxKeys + 1) * 0.8f));
1226 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1227 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1228 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
1229 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
1230
1231 // Should trust the ephemeral signing key from the applied manifest
1232 auto m1 = deserializeManifest(makeManifestString(
1233 masterPublic,
1234 masterPrivate,
1235 signingPublic1,
1236 signingKeys1.second,
1237 1));
1238
1239 BEAST_EXPECT(
1240 manifestsOuter.applyManifest(std::move(*m1)) ==
1241 ManifestDisposition::accepted);
1242 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1243 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1244 BEAST_EXPECT(trustedKeysOuter->listed(signingPublic1));
1245 BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic1));
1246
1247 // Should only trust the ephemeral signing key
1248 // from the newest applied manifest
1249 auto const signingKeys2 = randomKeyPair(KeyType::secp256k1);
1250 auto const signingPublic2 = signingKeys2.first;
1251 auto m2 = deserializeManifest(makeManifestString(
1252 masterPublic,
1253 masterPrivate,
1254 signingPublic2,
1255 signingKeys2.second,
1256 2));
1257 BEAST_EXPECT(
1258 manifestsOuter.applyManifest(std::move(*m2)) ==
1259 ManifestDisposition::accepted);
1260 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1261 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1262 BEAST_EXPECT(trustedKeysOuter->listed(signingPublic2));
1263 BEAST_EXPECT(trustedKeysOuter->trusted(signingPublic2));
1264 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
1265 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
1266
1267 // Should not trust keys from revoked master public key
1268 auto const signingKeysMax = randomKeyPair(KeyType::secp256k1);
1269 auto const signingPublicMax = signingKeysMax.first;
1270 activeValidatorsOuter.emplace(calcNodeID(signingPublicMax));
1271 auto mMax = deserializeManifest(
1272 makeRevocationString(masterPublic, masterPrivate));
1273
1274 BEAST_EXPECT(mMax->revoked());
1275 BEAST_EXPECT(
1276 manifestsOuter.applyManifest(std::move(*mMax)) ==
1277 ManifestDisposition::accepted);
1278 BEAST_EXPECT(
1279 manifestsOuter.getSigningKey(masterPublic) == masterPublic);
1280 BEAST_EXPECT(manifestsOuter.revoked(masterPublic));
1281
1282 // Revoked key remains trusted until list is updated
1283 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1284 BEAST_EXPECT(trustedKeysOuter->trusted(masterPublic));
1285
1286 changes = trustedKeysOuter->updateTrusted(
1287 activeValidatorsOuter,
1288 env.timeKeeper().now(),
1289 env.app().getOPs(),
1290 env.app().overlay(),
1291 env.app().getHashRouter());
1292 BEAST_EXPECT(changes.removed == asNodeIDs({masterPublic}));
1293 BEAST_EXPECT(changes.added.empty());
1294 BEAST_EXPECT(
1295 trustedKeysOuter->quorum() == std::ceil(maxKeys * 0.8f));
1296 BEAST_EXPECT(trustedKeysOuter->listed(masterPublic));
1297 BEAST_EXPECT(!trustedKeysOuter->trusted(masterPublic));
1298 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublicMax));
1299 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublicMax));
1300 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic2));
1301 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic2));
1302 BEAST_EXPECT(!trustedKeysOuter->listed(signingPublic1));
1303 BEAST_EXPECT(!trustedKeysOuter->trusted(signingPublic1));
1304 }
1305 {
1306 // Make quorum unattainable if lists from any publishers are
1307 // unavailable
1308 auto trustedKeys = std::make_unique<ValidatorList>(
1309 manifestsOuter,
1310 manifestsOuter,
1311 env.timeKeeper(),
1312 app.config().legacy("database_path"),
1313 env.journal);
1314 auto const publisherSecret = randomSecretKey();
1315 auto const publisherPublic =
1316 derivePublicKey(KeyType::ed25519, publisherSecret);
1317
1318 std::vector<std::string> cfgPublishers({strHex(publisherPublic)});
1319 std::vector<std::string> emptyCfgKeys;
1320
1321 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
1322
1323 TrustChanges changes = trustedKeys->updateTrusted(
1324 activeValidatorsOuter,
1325 env.timeKeeper().now(),
1326 env.app().getOPs(),
1327 env.app().overlay(),
1328 env.app().getHashRouter());
1329 BEAST_EXPECT(changes.removed.empty());
1330 BEAST_EXPECT(changes.added.empty());
1331 BEAST_EXPECT(
1332 trustedKeys->quorum() ==
1334 }
1335 {
1336 // Trust explicitly listed validators also when list threshold is
1337 // higher than 1
1338 auto trustedKeys = std::make_unique<ValidatorList>(
1339 manifestsOuter,
1340 manifestsOuter,
1341 env.timeKeeper(),
1342 app.config().legacy("database_path"),
1343 env.journal);
1344 auto const masterPrivate = randomSecretKey();
1345 auto const masterPublic =
1346 derivePublicKey(KeyType::ed25519, masterPrivate);
1348 {toBase58(TokenType::NodePublic, masterPublic)});
1349
1350 auto const publisher1Secret = randomSecretKey();
1351 auto const publisher1Public =
1352 derivePublicKey(KeyType::ed25519, publisher1Secret);
1353 auto const publisher2Secret = randomSecretKey();
1354 auto const publisher2Public =
1355 derivePublicKey(KeyType::ed25519, publisher2Secret);
1356 std::vector<std::string> cfgPublishers(
1357 {strHex(publisher1Public), strHex(publisher2Public)});
1358
1359 BEAST_EXPECT(
1360 trustedKeys->load({}, cfgKeys, cfgPublishers, std::size_t(2)));
1361
1362 TrustChanges changes = trustedKeys->updateTrusted(
1363 activeValidatorsOuter,
1364 env.timeKeeper().now(),
1365 env.app().getOPs(),
1366 env.app().overlay(),
1367 env.app().getHashRouter());
1368 BEAST_EXPECT(changes.removed.empty());
1369 BEAST_EXPECT(changes.added.size() == 1);
1370 BEAST_EXPECT(trustedKeys->listed(masterPublic));
1371 BEAST_EXPECT(trustedKeys->trusted(masterPublic));
1372 }
1373 {
1374 // Should use custom minimum quorum
1375 std::size_t const minQuorum = 1;
1376 ManifestCache manifests;
1377 auto trustedKeys = std::make_unique<ValidatorList>(
1378 manifests,
1379 manifests,
1380 env.timeKeeper(),
1381 app.config().legacy("database_path"),
1382 env.journal,
1383 minQuorum);
1384
1385 std::size_t n = 10;
1387 cfgKeys.reserve(n);
1388 hash_set<NodeID> expectedTrusted;
1389 hash_set<NodeID> activeValidators;
1390 NodeID toBeSeen;
1391
1392 while (cfgKeys.size() < n)
1393 {
1394 auto const valKey = randomNode();
1395 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1396 expectedTrusted.emplace(calcNodeID(valKey));
1397 if (cfgKeys.size() < std::ceil(n * 0.8f))
1398 activeValidators.emplace(calcNodeID(valKey));
1399 else if (cfgKeys.size() < std::ceil(n * 0.8f))
1400 toBeSeen = calcNodeID(valKey);
1401 }
1402
1403 BEAST_EXPECT(trustedKeys->load({}, cfgKeys, cfgPublishersOuter));
1404
1405 TrustChanges changes = trustedKeys->updateTrusted(
1406 activeValidators,
1407 env.timeKeeper().now(),
1408 env.app().getOPs(),
1409 env.app().overlay(),
1410 env.app().getHashRouter());
1411 BEAST_EXPECT(changes.removed.empty());
1412 BEAST_EXPECT(changes.added == expectedTrusted);
1413 BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
1414
1415 // Use configured quorum even when seen validators >= quorum
1416 activeValidators.emplace(toBeSeen);
1417 changes = trustedKeys->updateTrusted(
1418 activeValidators,
1419 env.timeKeeper().now(),
1420 env.app().getOPs(),
1421 env.app().overlay(),
1422 env.app().getHashRouter());
1423 BEAST_EXPECT(changes.removed.empty());
1424 BEAST_EXPECT(changes.added.empty());
1425 BEAST_EXPECT(trustedKeys->quorum() == minQuorum);
1426 }
1427 {
1428 // Remove expired published list
1429 auto trustedKeys = std::make_unique<ValidatorList>(
1430 manifestsOuter,
1431 manifestsOuter,
1432 env.app().timeKeeper(),
1433 app.config().legacy("database_path"),
1434 env.journal);
1435
1436 std::vector<std::string> emptyCfgKeys;
1437 auto const publisherKeys = randomKeyPair(KeyType::secp256k1);
1438 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1439 auto const manifest = base64_encode(makeManifestString(
1440 publisherKeys.first,
1441 publisherKeys.second,
1442 pubSigningKeys.first,
1443 pubSigningKeys.second,
1444 1));
1445
1446 std::vector<std::string> cfgKeys({strHex(publisherKeys.first)});
1447
1448 BEAST_EXPECT(trustedKeys->load({}, emptyCfgKeys, cfgKeys));
1449
1450 std::vector<Validator> list({randomValidator(), randomValidator()});
1451 hash_set<NodeID> activeValidators(
1452 asNodeIDs({list[0].masterPublic, list[1].masterPublic}));
1453
1454 // do not apply expired list
1455 auto const version = 1;
1456 auto const sequence = 1;
1457 using namespace std::chrono_literals;
1458 NetClock::time_point const validUntil =
1459 env.timeKeeper().now() + 60s;
1460 auto const blob =
1461 makeList(list, sequence, validUntil.time_since_epoch().count());
1462 auto const sig = signList(blob, pubSigningKeys);
1463
1464 BEAST_EXPECT(
1465 ListDisposition::accepted ==
1466 trustedKeys
1467 ->applyLists(manifest, version, {{blob, sig, {}}}, siteUri)
1468 .bestDisposition());
1469
1470 TrustChanges changes = trustedKeys->updateTrusted(
1471 activeValidators,
1472 env.timeKeeper().now(),
1473 env.app().getOPs(),
1474 env.app().overlay(),
1475 env.app().getHashRouter());
1476 BEAST_EXPECT(changes.removed.empty());
1477 BEAST_EXPECT(changes.added == activeValidators);
1478 for (Validator const& val : list)
1479 {
1480 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1481 BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
1482 }
1483 BEAST_EXPECT(trustedKeys->quorum() == 2);
1484
1485 env.timeKeeper().set(validUntil);
1486 changes = trustedKeys->updateTrusted(
1487 activeValidators,
1488 env.timeKeeper().now(),
1489 env.app().getOPs(),
1490 env.app().overlay(),
1491 env.app().getHashRouter());
1492 BEAST_EXPECT(changes.removed == activeValidators);
1493 BEAST_EXPECT(changes.added.empty());
1494 BEAST_EXPECT(!trustedKeys->trusted(list[0].masterPublic));
1495 BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
1496 BEAST_EXPECT(
1497 trustedKeys->quorum() ==
1499
1500 // (Re)trust validators from new valid list
1501 std::vector<Validator> list2({list[0], randomValidator()});
1502 activeValidators.insert(calcNodeID(list2[1].masterPublic));
1503 auto const sequence2 = 2;
1504 NetClock::time_point const expiration2 =
1505 env.timeKeeper().now() + 60s;
1506 auto const blob2 = makeList(
1507 list2, sequence2, expiration2.time_since_epoch().count());
1508 auto const sig2 = signList(blob2, pubSigningKeys);
1509
1510 BEAST_EXPECT(
1511 ListDisposition::accepted ==
1512 trustedKeys
1513 ->applyLists(
1514 manifest, version, {{blob2, sig2, {}}}, siteUri)
1515 .bestDisposition());
1516
1517 changes = trustedKeys->updateTrusted(
1518 activeValidators,
1519 env.timeKeeper().now(),
1520 env.app().getOPs(),
1521 env.app().overlay(),
1522 env.app().getHashRouter());
1523 BEAST_EXPECT(changes.removed.empty());
1524 BEAST_EXPECT(
1525 changes.added ==
1526 asNodeIDs({list2[0].masterPublic, list2[1].masterPublic}));
1527 for (Validator const& val : list2)
1528 {
1529 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1530 BEAST_EXPECT(trustedKeys->trusted(val.signingPublic));
1531 }
1532 BEAST_EXPECT(!trustedKeys->trusted(list[1].masterPublic));
1533 BEAST_EXPECT(!trustedKeys->trusted(list[1].signingPublic));
1534 BEAST_EXPECT(trustedKeys->quorum() == 2);
1535 }
1536 {
1537 // Test 1-9 configured validators
1538 auto trustedKeys = std::make_unique<ValidatorList>(
1539 manifestsOuter,
1540 manifestsOuter,
1541 env.timeKeeper(),
1542 app.config().legacy("database_path"),
1543 env.journal);
1544
1545 std::vector<std::string> cfgPublishers;
1546 hash_set<NodeID> activeValidators;
1547 hash_set<PublicKey> activeKeys;
1548
1550 cfgKeys.reserve(9);
1551
1552 while (cfgKeys.size() < cfgKeys.capacity())
1553 {
1554 auto const valKey = randomNode();
1555 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1556 activeValidators.emplace(calcNodeID(valKey));
1557 activeKeys.emplace(valKey);
1558 BEAST_EXPECT(trustedKeys->load({}, cfgKeys, cfgPublishers));
1559 TrustChanges changes = trustedKeys->updateTrusted(
1560 activeValidators,
1561 env.timeKeeper().now(),
1562 env.app().getOPs(),
1563 env.app().overlay(),
1564 env.app().getHashRouter());
1565 BEAST_EXPECT(changes.removed.empty());
1566 BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
1567 BEAST_EXPECT(
1568 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1569 for (auto const& key : activeKeys)
1570 BEAST_EXPECT(trustedKeys->trusted(key));
1571 }
1572 }
1573 {
1574 // Test 2-9 configured validators as validator
1575 auto trustedKeys = std::make_unique<ValidatorList>(
1576 manifestsOuter,
1577 manifestsOuter,
1578 env.timeKeeper(),
1579 app.config().legacy("database_path"),
1580 env.journal);
1581
1582 auto const localKey = randomNode();
1583 std::vector<std::string> cfgPublishers;
1584 hash_set<NodeID> activeValidators;
1585 hash_set<PublicKey> activeKeys;
1587 toBase58(TokenType::NodePublic, localKey)};
1588 cfgKeys.reserve(9);
1589
1590 while (cfgKeys.size() < cfgKeys.capacity())
1591 {
1592 auto const valKey = randomNode();
1593 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
1594 activeValidators.emplace(calcNodeID(valKey));
1595 activeKeys.emplace(valKey);
1596
1597 BEAST_EXPECT(
1598 trustedKeys->load(localKey, cfgKeys, cfgPublishers));
1599 TrustChanges changes = trustedKeys->updateTrusted(
1600 activeValidators,
1601 env.timeKeeper().now(),
1602 env.app().getOPs(),
1603 env.app().overlay(),
1604 env.app().getHashRouter());
1605 BEAST_EXPECT(changes.removed.empty());
1606 if (cfgKeys.size() > 2)
1607 BEAST_EXPECT(changes.added == asNodeIDs({valKey}));
1608 else
1609 BEAST_EXPECT(
1610 changes.added == asNodeIDs({localKey, valKey}));
1611
1612 BEAST_EXPECT(
1613 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f));
1614
1615 for (auto const& key : activeKeys)
1616 BEAST_EXPECT(trustedKeys->trusted(key));
1617 }
1618 }
1619 {
1620 // Trusted set should include all validators from multiple lists
1621 ManifestCache manifests;
1622 auto trustedKeys = std::make_unique<ValidatorList>(
1623 manifests,
1624 manifests,
1625 env.timeKeeper(),
1626 app.config().legacy("database_path"),
1627 env.journal);
1628
1629 hash_set<NodeID> activeValidators;
1630 std::vector<Validator> valKeys;
1631 valKeys.reserve(maxKeys);
1632
1633 while (valKeys.size() != maxKeys)
1634 {
1635 valKeys.push_back(randomValidator());
1636 activeValidators.emplace(
1637 calcNodeID(valKeys.back().masterPublic));
1638 }
1639
1640 // locals[0]: from 0 to maxKeys - 4
1641 // locals[1]: from 1 to maxKeys - 2
1642 // locals[2]: from 2 to maxKeys
1643 constexpr static int publishers = 3;
1644 std::array<
1645 std::pair<
1646 decltype(valKeys)::const_iterator,
1647 decltype(valKeys)::const_iterator>,
1648 publishers>
1649 locals = {
1650 std::make_pair(valKeys.cbegin(), valKeys.cend() - 4),
1651 std::make_pair(valKeys.cbegin() + 1, valKeys.cend() - 2),
1652 std::make_pair(valKeys.cbegin() + 2, valKeys.cend()),
1653 };
1654
1655 auto addPublishedList = [&, this](int i) {
1656 auto const publisherSecret = randomSecretKey();
1657 auto const publisherPublic =
1658 derivePublicKey(KeyType::ed25519, publisherSecret);
1659 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1660 auto const manifest = base64_encode(makeManifestString(
1661 publisherPublic,
1662 publisherSecret,
1663 pubSigningKeys.first,
1664 pubSigningKeys.second,
1665 1));
1666
1667 std::vector<std::string> cfgPublishers(
1668 {strHex(publisherPublic)});
1669 std::vector<std::string> emptyCfgKeys;
1670
1671 // Threshold of 1 will result in a union of all the lists
1672 BEAST_EXPECT(trustedKeys->load(
1673 {}, emptyCfgKeys, cfgPublishers, std::size_t(1)));
1674
1675 auto const version = 1;
1676 auto const sequence = 1;
1677 using namespace std::chrono_literals;
1678 NetClock::time_point const validUntil =
1679 env.timeKeeper().now() + 3600s;
1680 std::vector<Validator> localKeys{
1681 locals[i].first, locals[i].second};
1682 auto const blob = makeList(
1683 localKeys, sequence, validUntil.time_since_epoch().count());
1684 auto const sig = signList(blob, pubSigningKeys);
1685
1686 BEAST_EXPECT(
1687 ListDisposition::accepted ==
1688 trustedKeys
1689 ->applyLists(
1690 manifest, version, {{blob, sig, {}}}, siteUri)
1691 .bestDisposition());
1692 };
1693
1694 // Apply multiple published lists
1695 for (auto i = 0; i < publishers; ++i)
1696 addPublishedList(i);
1697 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
1698
1699 TrustChanges changes = trustedKeys->updateTrusted(
1700 activeValidators,
1701 env.timeKeeper().now(),
1702 env.app().getOPs(),
1703 env.app().overlay(),
1704 env.app().getHashRouter());
1705
1706 BEAST_EXPECT(
1707 trustedKeys->quorum() == std::ceil(valKeys.size() * 0.8f));
1708
1709 hash_set<NodeID> added;
1710 for (auto const& val : valKeys)
1711 {
1712 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1713 added.insert(calcNodeID(val.masterPublic));
1714 }
1715 BEAST_EXPECT(changes.added == added);
1716 BEAST_EXPECT(changes.removed.empty());
1717 }
1718 {
1719 // Trusted set should include validators from intersection of lists
1720 ManifestCache manifests;
1721 auto trustedKeys = std::make_unique<ValidatorList>(
1722 manifests,
1723 manifests,
1724 env.timeKeeper(),
1725 app.config().legacy("database_path"),
1726 env.journal);
1727
1728 hash_set<NodeID> activeValidators;
1729 std::vector<Validator> valKeys;
1730 valKeys.reserve(maxKeys);
1731
1732 while (valKeys.size() != maxKeys)
1733 {
1734 valKeys.push_back(randomValidator());
1735 activeValidators.emplace(
1736 calcNodeID(valKeys.back().masterPublic));
1737 }
1738
1739 // locals[0]: from 0 to maxKeys - 4
1740 // locals[1]: from 1 to maxKeys - 2
1741 // locals[2]: from 2 to maxKeys
1742 // interesection of at least 2: same as locals[1]
1743 // intersection when 1 is dropped: from 2 to maxKeys - 4
1744 constexpr static int publishers = 3;
1745 std::array<
1746 std::pair<
1747 decltype(valKeys)::const_iterator,
1748 decltype(valKeys)::const_iterator>,
1749 publishers>
1750 locals = {
1751 std::make_pair(valKeys.cbegin(), valKeys.cend() - 4),
1752 std::make_pair(valKeys.cbegin() + 1, valKeys.cend() - 2),
1753 std::make_pair(valKeys.cbegin() + 2, valKeys.cend()),
1754 };
1755
1756 auto addPublishedList = [&, this](
1757 int i,
1758 NetClock::time_point& validUntil1,
1759 NetClock::time_point& validUntil2) {
1760 auto const publisherSecret = randomSecretKey();
1761 auto const publisherPublic =
1762 derivePublicKey(KeyType::ed25519, publisherSecret);
1763 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1764 auto const manifest = base64_encode(makeManifestString(
1765 publisherPublic,
1766 publisherSecret,
1767 pubSigningKeys.first,
1768 pubSigningKeys.second,
1769 1));
1770
1771 std::vector<std::string> cfgPublishers(
1772 {strHex(publisherPublic)});
1773 std::vector<std::string> emptyCfgKeys;
1774
1775 BEAST_EXPECT(
1776 trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
1777
1778 auto const version = 1;
1779 auto const sequence = 1;
1780 using namespace std::chrono_literals;
1781 // Want to drop 1 sooner
1782 NetClock::time_point const validUntil = env.timeKeeper().now() +
1783 (i == 2 ? 120s
1784 : i == 1 ? 60s
1785 : 3600s);
1786 if (i == 1)
1787 validUntil1 = validUntil;
1788 else if (i == 2)
1789 validUntil2 = validUntil;
1790 std::vector<Validator> localKeys{
1791 locals[i].first, locals[i].second};
1792 auto const blob = makeList(
1793 localKeys, sequence, validUntil.time_since_epoch().count());
1794 auto const sig = signList(blob, pubSigningKeys);
1795
1796 BEAST_EXPECT(
1797 ListDisposition::accepted ==
1798 trustedKeys
1799 ->applyLists(
1800 manifest, version, {{blob, sig, {}}}, siteUri)
1801 .bestDisposition());
1802 };
1803
1804 // Apply multiple published lists
1805 // validUntil1 is expiration time for locals[1]
1806 NetClock::time_point validUntil1, validUntil2;
1807 for (auto i = 0; i < publishers; ++i)
1808 addPublishedList(i, validUntil1, validUntil2);
1809 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
1810
1811 TrustChanges changes = trustedKeys->updateTrusted(
1812 activeValidators,
1813 env.timeKeeper().now(),
1814 env.app().getOPs(),
1815 env.app().overlay(),
1816 env.app().getHashRouter());
1817
1818 BEAST_EXPECT(
1819 trustedKeys->quorum() ==
1820 std::ceil((valKeys.size() - 3) * 0.8f));
1821
1822 for (auto const& val : valKeys)
1823 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
1824
1825 hash_set<NodeID> added;
1826 for (std::size_t i = 0; i < maxKeys; ++i)
1827 {
1828 auto const& val = valKeys[i];
1829 if (i >= 1 && i < maxKeys - 2)
1830 {
1831 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1832 added.insert(calcNodeID(val.masterPublic));
1833 }
1834 else
1835 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
1836 }
1837 BEAST_EXPECT(changes.added == added);
1838 BEAST_EXPECT(changes.removed.empty());
1839
1840 // Expire locals[1]
1841 env.timeKeeper().set(validUntil1);
1842 changes = trustedKeys->updateTrusted(
1843 activeValidators,
1844 env.timeKeeper().now(),
1845 env.app().getOPs(),
1846 env.app().overlay(),
1847 env.app().getHashRouter());
1848
1849 BEAST_EXPECT(
1850 trustedKeys->quorum() ==
1851 std::ceil((valKeys.size() - 6) * 0.8f));
1852
1853 for (auto const& val : valKeys)
1854 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
1855
1856 hash_set<NodeID> removed;
1857 for (std::size_t i = 0; i < maxKeys; ++i)
1858 {
1859 auto const& val = valKeys[i];
1860 if (i >= 2 && i < maxKeys - 4)
1861 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
1862 else
1863 {
1864 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
1865 if (i >= 1 && i < maxKeys - 2)
1866 removed.insert(calcNodeID(val.masterPublic));
1867 }
1868 }
1869
1870 BEAST_EXPECT(changes.added.empty());
1871 BEAST_EXPECT(changes.removed == removed);
1872
1873 // Expire locals[2], which removes all validators
1874 env.timeKeeper().set(validUntil2);
1875 changes = trustedKeys->updateTrusted(
1876 activeValidators,
1877 env.timeKeeper().now(),
1878 env.app().getOPs(),
1879 env.app().overlay(),
1880 env.app().getHashRouter());
1881
1882 BEAST_EXPECT(
1883 trustedKeys->quorum() ==
1885
1886 removed.clear();
1887 for (std::size_t i = 0; i < maxKeys; ++i)
1888 {
1889 auto const& val = valKeys[i];
1890 if (i < maxKeys - 4)
1891 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
1892 else
1893 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
1894
1895 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
1896 if (i >= 2 && i < maxKeys - 4)
1897 removed.insert(calcNodeID(val.masterPublic));
1898 }
1899
1900 BEAST_EXPECT(changes.added.empty());
1901 BEAST_EXPECT(changes.removed == removed);
1902 }
1903 }
1904
1905 void
1907 {
1908 testcase("Expires");
1909
1910 std::string const siteUri = "testExpires.test";
1911
1912 jtx::Env env(*this);
1913 auto& app = env.app();
1914
1915 auto toStr = [](PublicKey const& publicKey) {
1916 return toBase58(TokenType::NodePublic, publicKey);
1917 };
1918
1919 // Config listed keys
1920 {
1921 ManifestCache manifests;
1922 auto trustedKeys = std::make_unique<ValidatorList>(
1923 manifests,
1924 manifests,
1925 env.timeKeeper(),
1926 app.config().legacy("database_path"),
1927 env.journal);
1928
1929 // Empty list has no expiration
1930 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
1931
1932 // Config listed keys have maximum expiry
1933 PublicKey localCfgListed = randomNode();
1934 trustedKeys->load({}, {toStr(localCfgListed)}, {});
1935 BEAST_EXPECT(
1936 trustedKeys->expires() &&
1937 trustedKeys->expires().value() == NetClock::time_point::max());
1938 BEAST_EXPECT(trustedKeys->listed(localCfgListed));
1939 }
1940
1941 // Published keys with expirations
1942 {
1943 ManifestCache manifests;
1944 auto trustedKeys = std::make_unique<ValidatorList>(
1945 manifests,
1946 manifests,
1947 env.app().timeKeeper(),
1948 app.config().legacy("database_path"),
1949 env.journal);
1950
1951 std::vector<Validator> validators = {randomValidator()};
1952 hash_set<NodeID> activeValidators;
1953 for (Validator const& val : validators)
1954 activeValidators.insert(calcNodeID(val.masterPublic));
1955 // Store prepared list data to control when it is applied
1956 struct PreparedList
1957 {
1958 PublicKey publisherPublic;
1961 int version;
1963 };
1964
1965 using namespace std::chrono_literals;
1966 auto addPublishedList = [this, &env, &trustedKeys, &validators]() {
1967 auto const publisherSecret = randomSecretKey();
1968 auto const publisherPublic =
1969 derivePublicKey(KeyType::ed25519, publisherSecret);
1970 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
1971 auto const manifest = base64_encode(makeManifestString(
1972 publisherPublic,
1973 publisherSecret,
1974 pubSigningKeys.first,
1975 pubSigningKeys.second,
1976 1));
1977
1978 std::vector<std::string> cfgPublishers(
1979 {strHex(publisherPublic)});
1980 std::vector<std::string> emptyCfgKeys;
1981
1982 BEAST_EXPECT(
1983 trustedKeys->load({}, emptyCfgKeys, cfgPublishers));
1984
1985 auto const version = 2;
1986 auto const sequence1 = 1;
1987 NetClock::time_point const expiration1 =
1988 env.timeKeeper().now() + 1800s;
1989 auto const blob1 = makeList(
1990 validators,
1991 sequence1,
1992 expiration1.time_since_epoch().count());
1993 auto const sig1 = signList(blob1, pubSigningKeys);
1994
1995 NetClock::time_point const effective2 = expiration1 - 300s;
1996 NetClock::time_point const expiration2 = effective2 + 1800s;
1997 auto const sequence2 = 2;
1998 auto const blob2 = makeList(
1999 validators,
2000 sequence2,
2001 expiration2.time_since_epoch().count(),
2002 effective2.time_since_epoch().count());
2003 auto const sig2 = signList(blob2, pubSigningKeys);
2004
2005 return PreparedList{
2006 publisherPublic,
2007 manifest,
2008 {{blob1, sig1, {}}, {blob2, sig2, {}}},
2009 version,
2010 {expiration1, expiration2}};
2011 };
2012
2013 // Configure two publishers and prepare 2 lists
2014 PreparedList prep1 = addPublishedList();
2015 env.timeKeeper().set(env.timeKeeper().now() + 200s);
2016 PreparedList prep2 = addPublishedList();
2017
2018 // Initially, no list has been published, so no known expiration
2019 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
2020
2021 // Apply first list
2022 checkResult(
2023 trustedKeys->applyLists(
2024 prep1.manifest, prep1.version, prep1.blobs, siteUri),
2025 prep1.publisherPublic,
2026 ListDisposition::pending,
2027 ListDisposition::accepted);
2028
2029 // One list still hasn't published, so expiration is still
2030 // unknown
2031 BEAST_EXPECT(trustedKeys->expires() == std::nullopt);
2032
2033 // Apply second list
2034 checkResult(
2035 trustedKeys->applyLists(
2036 prep2.manifest, prep2.version, prep2.blobs, siteUri),
2037 prep2.publisherPublic,
2038 ListDisposition::pending,
2039 ListDisposition::accepted);
2040 // We now have loaded both lists, so expiration is known
2041 BEAST_EXPECT(
2042 trustedKeys->expires() &&
2043 trustedKeys->expires().value() == prep1.expirations.back());
2044
2045 // Advance past the first list's LAST validFrom date. It remains
2046 // the earliest validUntil, while rotating in the second list
2047 {
2048 env.timeKeeper().set(prep1.expirations.front() - 1s);
2049 auto changes = trustedKeys->updateTrusted(
2050 activeValidators,
2051 env.timeKeeper().now(),
2052 env.app().getOPs(),
2053 env.app().overlay(),
2054 env.app().getHashRouter());
2055 BEAST_EXPECT(
2056 trustedKeys->expires() &&
2057 trustedKeys->expires().value() == prep1.expirations.back());
2058 BEAST_EXPECT(!changes.added.empty());
2059 BEAST_EXPECT(changes.removed.empty());
2060 }
2061
2062 // Advance past the first list's LAST validUntil, but it remains
2063 // the earliest validUntil, while being invalidated
2064 {
2065 env.timeKeeper().set(prep1.expirations.back() + 1s);
2066 auto changes = trustedKeys->updateTrusted(
2067 activeValidators,
2068 env.timeKeeper().now(),
2069 env.app().getOPs(),
2070 env.app().overlay(),
2071 env.app().getHashRouter());
2072 BEAST_EXPECT(
2073 trustedKeys->expires() &&
2074 trustedKeys->expires().value() == prep1.expirations.back());
2075 BEAST_EXPECT(changes.added.empty());
2076 BEAST_EXPECT(changes.removed.empty());
2077 }
2078 }
2079 }
2080
2081 void
2083 {
2084 testcase("NegativeUNL");
2085 jtx::Env env(*this);
2086 ManifestCache manifests;
2087
2088 auto createValidatorList =
2089 [&](std::uint32_t vlSize,
2090 std::optional<std::size_t> minimumQuorum = {})
2092 auto trustedKeys = std::make_shared<ValidatorList>(
2093 manifests,
2094 manifests,
2095 env.timeKeeper(),
2096 env.app().config().legacy("database_path"),
2097 env.journal,
2098 minimumQuorum);
2099
2100 std::vector<std::string> cfgPublishers;
2102 hash_set<NodeID> activeValidators;
2103 cfgKeys.reserve(vlSize);
2104 while (cfgKeys.size() < cfgKeys.capacity())
2105 {
2106 auto const valKey = randomNode();
2107 cfgKeys.push_back(toBase58(TokenType::NodePublic, valKey));
2108 activeValidators.emplace(calcNodeID(valKey));
2109 }
2110 if (trustedKeys->load({}, cfgKeys, cfgPublishers))
2111 {
2112 trustedKeys->updateTrusted(
2113 activeValidators,
2114 env.timeKeeper().now(),
2115 env.app().getOPs(),
2116 env.app().overlay(),
2117 env.app().getHashRouter());
2118 if (minimumQuorum == trustedKeys->quorum() ||
2119 trustedKeys->quorum() == std::ceil(cfgKeys.size() * 0.8f))
2120 return trustedKeys;
2121 }
2122 return nullptr;
2123 };
2124
2125 /*
2126 * Test NegativeUNL
2127 * == Combinations ==
2128 * -- UNL size: 34, 35, 57
2129 * -- nUNL size: 0%, 20%, 30%, 50%
2130 *
2131 * == with UNL size 60
2132 * -- set == get,
2133 * -- check quorum, with nUNL size: 0, 12, 30, 18
2134 * -- nUNL overlap: |nUNL - UNL| = 5, with nUNL size: 18
2135 * -- with command line minimumQuorum = 50%,
2136 * seen_reliable affected by nUNL
2137 */
2138
2139 {
2140 hash_set<NodeID> activeValidators;
2141 //== Combinations ==
2142 std::array<std::uint32_t, 4> unlSizes = {34, 35, 39, 60};
2143 std::array<std::uint32_t, 4> nUnlPercent = {0, 20, 30, 50};
2144 for (auto us : unlSizes)
2145 {
2146 for (auto np : nUnlPercent)
2147 {
2148 auto validators = createValidatorList(us);
2149 BEAST_EXPECT(validators);
2150 if (validators)
2151 {
2152 std::uint32_t nUnlSize = us * np / 100;
2153 auto unl = validators->getTrustedMasterKeys();
2155 auto it = unl.begin();
2156 for (std::uint32_t i = 0; i < nUnlSize; ++i)
2157 {
2158 nUnl.insert(*it);
2159 ++it;
2160 }
2161 validators->setNegativeUNL(nUnl);
2162 validators->updateTrusted(
2163 activeValidators,
2164 env.timeKeeper().now(),
2165 env.app().getOPs(),
2166 env.app().overlay(),
2167 env.app().getHashRouter());
2168 BEAST_EXPECT(
2169 validators->quorum() ==
2170 static_cast<std::size_t>(std::ceil(
2171 std::max((us - nUnlSize) * 0.8f, us * 0.6f))));
2172 }
2173 }
2174 }
2175 }
2176
2177 {
2178 //== with UNL size 60
2179 auto validators = createValidatorList(60);
2180 BEAST_EXPECT(validators);
2181 if (validators)
2182 {
2183 hash_set<NodeID> activeValidators;
2184 auto unl = validators->getTrustedMasterKeys();
2185 BEAST_EXPECT(unl.size() == 60);
2186 {
2187 //-- set == get,
2188 //-- check quorum, with nUNL size: 0, 30, 18, 12
2189 auto nUnlChange = [&](std::uint32_t nUnlSize,
2190 std::uint32_t quorum) -> bool {
2192 auto it = unl.begin();
2193 for (std::uint32_t i = 0; i < nUnlSize; ++i)
2194 {
2195 nUnl.insert(*it);
2196 ++it;
2197 }
2198 validators->setNegativeUNL(nUnl);
2199 auto nUnl_temp = validators->getNegativeUNL();
2200 if (nUnl_temp.size() == nUnl.size())
2201 {
2202 for (auto& n : nUnl_temp)
2203 {
2204 if (nUnl.find(n) == nUnl.end())
2205 return false;
2206 }
2207 validators->updateTrusted(
2208 activeValidators,
2209 env.timeKeeper().now(),
2210 env.app().getOPs(),
2211 env.app().overlay(),
2212 env.app().getHashRouter());
2213 return validators->quorum() == quorum;
2214 }
2215 return false;
2216 };
2217 BEAST_EXPECT(nUnlChange(0, 48));
2218 BEAST_EXPECT(nUnlChange(30, 36));
2219 BEAST_EXPECT(nUnlChange(18, 36));
2220 BEAST_EXPECT(nUnlChange(12, 39));
2221 }
2222
2223 {
2224 // nUNL overlap: |nUNL - UNL| = 5, with nUNL size:
2225 // 18
2226 auto nUnl = validators->getNegativeUNL();
2227 BEAST_EXPECT(nUnl.size() == 12);
2228 std::size_t ss = 33;
2229 std::vector<uint8_t> data(ss, 0);
2230 data[0] = 0xED;
2231 for (int i = 0; i < 6; ++i)
2232 {
2233 Slice s(data.data(), ss);
2234 data[1]++;
2235 nUnl.emplace(s);
2236 }
2237 validators->setNegativeUNL(nUnl);
2238 validators->updateTrusted(
2239 activeValidators,
2240 env.timeKeeper().now(),
2241 env.app().getOPs(),
2242 env.app().overlay(),
2243 env.app().getHashRouter());
2244 BEAST_EXPECT(validators->quorum() == 39);
2245 }
2246 }
2247 }
2248
2249 {
2250 //== with UNL size 60
2251 //-- with command line minimumQuorum = 50%,
2252 // seen_reliable affected by nUNL
2253 auto validators = createValidatorList(60, 30);
2254 BEAST_EXPECT(validators);
2255 if (validators)
2256 {
2257 hash_set<NodeID> activeValidators;
2258 hash_set<PublicKey> unl = validators->getTrustedMasterKeys();
2259 auto it = unl.begin();
2260 for (std::uint32_t i = 0; i < 50; ++i)
2261 {
2262 activeValidators.insert(calcNodeID(*it));
2263 ++it;
2264 }
2265 validators->updateTrusted(
2266 activeValidators,
2267 env.timeKeeper().now(),
2268 env.app().getOPs(),
2269 env.app().overlay(),
2270 env.app().getHashRouter());
2271 BEAST_EXPECT(validators->quorum() == 30);
2273 it = unl.begin();
2274 for (std::uint32_t i = 0; i < 20; ++i)
2275 {
2276 nUnl.insert(*it);
2277 ++it;
2278 }
2279 validators->setNegativeUNL(nUnl);
2280 validators->updateTrusted(
2281 activeValidators,
2282 env.timeKeeper().now(),
2283 env.app().getOPs(),
2284 env.app().overlay(),
2285 env.app().getHashRouter());
2286 BEAST_EXPECT(validators->quorum() == 30);
2287 }
2288 }
2289 }
2290
2291 void
2293 {
2294 testcase("Sha512 hashing");
2295 // Tests that ValidatorList hash_append helpers with a single blob
2296 // returns the same result as ripple::Sha512Half used by the
2297 // TMValidatorList protocol message handler
2298 std::string const manifest = "This is not really a manifest";
2299 std::string const blob = "This is not really a blob";
2300 std::string const signature = "This is not really a signature";
2301 std::uint32_t const version = 1;
2302
2303 auto const global = sha512Half(manifest, blob, signature, version);
2304 BEAST_EXPECT(!!global);
2305
2306 std::vector<ValidatorBlobInfo> blobVector(1);
2307 blobVector[0].blob = blob;
2308 blobVector[0].signature = signature;
2309 BEAST_EXPECT(global == sha512Half(manifest, blobVector, version));
2310 BEAST_EXPECT(global != sha512Half(signature, blobVector, version));
2311
2312 {
2314 {99, blobVector[0]}};
2315 BEAST_EXPECT(global == sha512Half(manifest, blobMap, version));
2316 BEAST_EXPECT(global != sha512Half(blob, blobMap, version));
2317 }
2318
2319 {
2320 protocol::TMValidatorList msg1;
2321 msg1.set_manifest(manifest);
2322 msg1.set_blob(blob);
2323 msg1.set_signature(signature);
2324 msg1.set_version(version);
2325 BEAST_EXPECT(global == sha512Half(msg1));
2326 msg1.set_signature(blob);
2327 BEAST_EXPECT(global != sha512Half(msg1));
2328 }
2329
2330 {
2331 protocol::TMValidatorListCollection msg2;
2332 msg2.set_manifest(manifest);
2333 msg2.set_version(version);
2334 auto& bi = *msg2.add_blobs();
2335 bi.set_blob(blob);
2336 bi.set_signature(signature);
2337 BEAST_EXPECT(global == sha512Half(msg2));
2338 bi.set_manifest(manifest);
2339 BEAST_EXPECT(global != sha512Half(msg2));
2340 }
2341 }
2342
2343 void
2345 {
2346 testcase("Build and split messages");
2347
2348 std::uint32_t const manifestCutoff = 7;
2349 auto extractHeader = [this](Message& message) {
2350 auto const& buffer =
2351 message.getBuffer(compression::Compressed::Off);
2352
2353 boost::beast::multi_buffer buffers;
2354
2355 // simulate multi-buffer
2356 auto start = buffer.begin();
2357 auto end = buffer.end();
2358 std::vector<std::uint8_t> slice(start, end);
2359 buffers.commit(boost::asio::buffer_copy(
2360 buffers.prepare(slice.size()), boost::asio::buffer(slice)));
2361
2362 boost::system::error_code ec;
2363 auto header =
2364 detail::parseMessageHeader(ec, buffers.data(), buffers.size());
2365 BEAST_EXPECT(!ec);
2366 return std::make_pair(header, buffers);
2367 };
2368 auto extractProtocolMessage1 = [this,
2369 &extractHeader](Message& message) {
2370 auto [header, buffers] = extractHeader(message);
2371 if (BEAST_EXPECT(header) &&
2372 BEAST_EXPECT(header->message_type == protocol::mtVALIDATORLIST))
2373 {
2374 auto const msg =
2375 detail::parseMessageContent<protocol::TMValidatorList>(
2376 *header, buffers.data());
2377 BEAST_EXPECT(msg);
2378 return msg;
2379 }
2381 };
2382 auto extractProtocolMessage2 = [this,
2383 &extractHeader](Message& message) {
2384 auto [header, buffers] = extractHeader(message);
2385 if (BEAST_EXPECT(header) &&
2386 BEAST_EXPECT(
2387 header->message_type ==
2388 protocol::mtVALIDATORLISTCOLLECTION))
2389 {
2390 auto const msg = detail::parseMessageContent<
2391 protocol::TMValidatorListCollection>(
2392 *header, buffers.data());
2393 BEAST_EXPECT(msg);
2394 return msg;
2395 }
2397 };
2398 auto verifyMessage =
2399 [this,
2400 manifestCutoff,
2401 &extractProtocolMessage1,
2402 &extractProtocolMessage2](
2403 auto const version,
2404 auto const& manifest,
2405 auto const& blobInfos,
2406 auto const& messages,
2408 expectedInfo) {
2409 BEAST_EXPECT(messages.size() == expectedInfo.size());
2410 auto msgIter = expectedInfo.begin();
2411 for (auto const& messageWithHash : messages)
2412 {
2413 if (!BEAST_EXPECT(msgIter != expectedInfo.end()))
2414 break;
2415 if (!BEAST_EXPECT(messageWithHash.message))
2416 continue;
2417 auto const& expectedSeqs = msgIter->second;
2418 auto seqIter = expectedSeqs.begin();
2419 auto const size =
2420 messageWithHash.message
2421 ->getBuffer(compression::Compressed::Off)
2422 .size();
2423 // This size is arbitrary, but shouldn't change
2424 BEAST_EXPECT(size == msgIter->first);
2425 if (expectedSeqs.size() == 1)
2426 {
2427 auto const msg =
2428 extractProtocolMessage1(*messageWithHash.message);
2429 auto const expectedVersion = 1;
2430 if (BEAST_EXPECT(msg))
2431 {
2432 BEAST_EXPECT(msg->version() == expectedVersion);
2433 if (!BEAST_EXPECT(seqIter != expectedSeqs.end()))
2434 continue;
2435 auto const& expectedBlob = blobInfos.at(*seqIter);
2436 BEAST_EXPECT(
2437 (*seqIter < manifestCutoff) ==
2438 !!expectedBlob.manifest);
2439 auto const expectedManifest =
2440 *seqIter < manifestCutoff &&
2441 expectedBlob.manifest
2442 ? *expectedBlob.manifest
2443 : manifest;
2444 BEAST_EXPECT(msg->manifest() == expectedManifest);
2445 BEAST_EXPECT(msg->blob() == expectedBlob.blob);
2446 BEAST_EXPECT(
2447 msg->signature() == expectedBlob.signature);
2448 ++seqIter;
2449 BEAST_EXPECT(seqIter == expectedSeqs.end());
2450
2451 BEAST_EXPECT(
2452 messageWithHash.hash ==
2453 sha512Half(
2454 expectedManifest,
2455 expectedBlob.blob,
2456 expectedBlob.signature,
2457 expectedVersion));
2458 }
2459 }
2460 else
2461 {
2462 std::vector<ValidatorBlobInfo> hashingBlobs;
2463 hashingBlobs.reserve(msgIter->second.size());
2464
2465 auto const msg =
2466 extractProtocolMessage2(*messageWithHash.message);
2467 if (BEAST_EXPECT(msg))
2468 {
2469 BEAST_EXPECT(msg->version() == version);
2470 BEAST_EXPECT(msg->manifest() == manifest);
2471 for (auto const& blobInfo : msg->blobs())
2472 {
2473 if (!BEAST_EXPECT(
2474 seqIter != expectedSeqs.end()))
2475 break;
2476 auto const& expectedBlob =
2477 blobInfos.at(*seqIter);
2478 hashingBlobs.push_back(expectedBlob);
2479 BEAST_EXPECT(
2480 blobInfo.has_manifest() ==
2481 !!expectedBlob.manifest);
2482 BEAST_EXPECT(
2483 blobInfo.has_manifest() ==
2484 (*seqIter < manifestCutoff));
2485
2486 if (*seqIter < manifestCutoff)
2487 BEAST_EXPECT(
2488 blobInfo.manifest() ==
2489 *expectedBlob.manifest);
2490 BEAST_EXPECT(
2491 blobInfo.blob() == expectedBlob.blob);
2492 BEAST_EXPECT(
2493 blobInfo.signature() ==
2494 expectedBlob.signature);
2495 ++seqIter;
2496 }
2497 BEAST_EXPECT(seqIter == expectedSeqs.end());
2498 }
2499 BEAST_EXPECT(
2500 messageWithHash.hash ==
2501 sha512Half(manifest, hashingBlobs, version));
2502 }
2503 ++msgIter;
2504 }
2505 BEAST_EXPECT(msgIter == expectedInfo.end());
2506 };
2507 auto verifyBuildMessages =
2508 [this](
2510 std::size_t expectedSequence,
2511 std::size_t expectedSize) {
2512 BEAST_EXPECT(result.first == expectedSequence);
2513 BEAST_EXPECT(result.second == expectedSize);
2514 };
2515
2516 std::string const manifest = "This is not a manifest";
2517 std::uint32_t const version = 2;
2518 // Mutable so items can be removed in later tests.
2519 auto const blobInfos = [manifestCutoff = manifestCutoff]() {
2521
2522 for (auto seq : {5, 6, 7, 10, 12})
2523 {
2524 auto& b = bis[seq];
2526 s << "This is not a blob with sequence " << seq;
2527 b.blob = s.str();
2528 s.str(std::string());
2529 s << "This is not a signature for sequence " << seq;
2530 b.signature = s.str();
2531 if (seq < manifestCutoff)
2532 {
2533 // add a manifest for the "early" blobs
2534 s.str(std::string());
2535 s << "This is not manifest " << seq;
2536 b.manifest = s.str();
2537 }
2538 }
2539 return bis;
2540 }();
2541 auto const maxSequence = blobInfos.rbegin()->first;
2542 BEAST_EXPECT(maxSequence == 12);
2543
2545
2546 // Version 1
2547
2548 // This peer has a VL ahead of our "current"
2549 verifyBuildMessages(
2550 ValidatorList::buildValidatorListMessages(
2551 1, 8, maxSequence, version, manifest, blobInfos, messages),
2552 0,
2553 0);
2554 BEAST_EXPECT(messages.size() == 0);
2555
2556 // Don't repeat the work if messages is populated, even though the
2557 // peerSequence provided indicates it should. Note that this
2558 // situation is contrived for this test and should never happen in
2559 // real code.
2560 messages.emplace_back();
2561 verifyBuildMessages(
2562 ValidatorList::buildValidatorListMessages(
2563 1, 3, maxSequence, version, manifest, blobInfos, messages),
2564 5,
2565 0);
2566 BEAST_EXPECT(messages.size() == 1 && !messages.front().message);
2567
2568 // Generate a version 1 message
2569 messages.clear();
2570 verifyBuildMessages(
2571 ValidatorList::buildValidatorListMessages(
2572 1, 3, maxSequence, version, manifest, blobInfos, messages),
2573 5,
2574 1);
2575 if (BEAST_EXPECT(messages.size() == 1) &&
2576 BEAST_EXPECT(messages.front().message))
2577 {
2578 auto const& messageWithHash = messages.front();
2579 auto const msg = extractProtocolMessage1(*messageWithHash.message);
2580 auto const size =
2581 messageWithHash.message->getBuffer(compression::Compressed::Off)
2582 .size();
2583 // This size is arbitrary, but shouldn't change
2584 BEAST_EXPECT(size == 108);
2585 auto const& expected = blobInfos.at(5);
2586 if (BEAST_EXPECT(msg))
2587 {
2588 BEAST_EXPECT(msg->version() == 1);
2589 BEAST_EXPECT(msg->manifest() == *expected.manifest);
2590 BEAST_EXPECT(msg->blob() == expected.blob);
2591 BEAST_EXPECT(msg->signature() == expected.signature);
2592 }
2593 BEAST_EXPECT(
2594 messageWithHash.hash ==
2595 sha512Half(
2596 *expected.manifest, expected.blob, expected.signature, 1));
2597 }
2598
2599 // Version 2
2600
2601 messages.clear();
2602
2603 // This peer has a VL ahead of us.
2604 verifyBuildMessages(
2605 ValidatorList::buildValidatorListMessages(
2606 2,
2607 maxSequence * 2,
2608 maxSequence,
2609 version,
2610 manifest,
2611 blobInfos,
2612 messages),
2613 0,
2614 0);
2615 BEAST_EXPECT(messages.size() == 0);
2616
2617 // Don't repeat the work if messages is populated, even though the
2618 // peerSequence provided indicates it should. Note that this
2619 // situation is contrived for this test and should never happen in
2620 // real code.
2621 messages.emplace_back();
2622 verifyBuildMessages(
2623 ValidatorList::buildValidatorListMessages(
2624 2, 3, maxSequence, version, manifest, blobInfos, messages),
2625 maxSequence,
2626 0);
2627 BEAST_EXPECT(messages.size() == 1 && !messages.front().message);
2628
2629 // Generate a version 2 message. Don't send the current
2630 messages.clear();
2631 verifyBuildMessages(
2632 ValidatorList::buildValidatorListMessages(
2633 2, 5, maxSequence, version, manifest, blobInfos, messages),
2634 maxSequence,
2635 4);
2636 verifyMessage(
2637 version, manifest, blobInfos, messages, {{372, {6, 7, 10, 12}}});
2638
2639 // Test message splitting on size limits.
2640
2641 // Set a limit that should give two messages
2642 messages.clear();
2643 verifyBuildMessages(
2644 ValidatorList::buildValidatorListMessages(
2645 2, 5, maxSequence, version, manifest, blobInfos, messages, 300),
2646 maxSequence,
2647 4);
2648 verifyMessage(
2649 version,
2650 manifest,
2651 blobInfos,
2652 messages,
2653 {{212, {6, 7}}, {192, {10, 12}}});
2654
2655 // Set a limit between the size of the two earlier messages so one
2656 // will split and the other won't
2657 messages.clear();
2658 verifyBuildMessages(
2659 ValidatorList::buildValidatorListMessages(
2660 2, 5, maxSequence, version, manifest, blobInfos, messages, 200),
2661 maxSequence,
2662 4);
2663 verifyMessage(
2664 version,
2665 manifest,
2666 blobInfos,
2667 messages,
2668 {{108, {6}}, {108, {7}}, {192, {10, 12}}});
2669
2670 // Set a limit so that all the VLs are sent individually
2671 messages.clear();
2672 verifyBuildMessages(
2673 ValidatorList::buildValidatorListMessages(
2674 2, 5, maxSequence, version, manifest, blobInfos, messages, 150),
2675 maxSequence,
2676 4);
2677 verifyMessage(
2678 version,
2679 manifest,
2680 blobInfos,
2681 messages,
2682 {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}});
2683
2684 // Set a limit smaller than some of the messages. Because single
2685 // messages send regardless, they will all still be sent
2686 messages.clear();
2687 verifyBuildMessages(
2688 ValidatorList::buildValidatorListMessages(
2689 2, 5, maxSequence, version, manifest, blobInfos, messages, 108),
2690 maxSequence,
2691 4);
2692 verifyMessage(
2693 version,
2694 manifest,
2695 blobInfos,
2696 messages,
2697 {{108, {6}}, {108, {7}}, {110, {10}}, {110, {12}}});
2698 }
2699
2700 void
2702 {
2703 testcase("Test quorum disabled");
2704
2705 std::string const siteUri = "testQuorumDisabled.test";
2706 jtx::Env env(*this);
2707 auto& app = env.app();
2708
2709 constexpr std::size_t maxKeys = 20;
2710 hash_set<NodeID> activeValidators;
2711 std::vector<Validator> valKeys;
2712 while (valKeys.size() != maxKeys)
2713 {
2714 valKeys.push_back(randomValidator());
2715 activeValidators.emplace(calcNodeID(valKeys.back().masterPublic));
2716 }
2717
2718 struct Publisher
2719 {
2720 bool revoked;
2721 PublicKey pubKey;
2724 NetClock::time_point expiry = {};
2725 };
2726
2727 // Create ValidatorList with a set of countTotal publishers, of which
2728 // first countRevoked are revoked and the last one expires early
2729 auto makeValidatorList = [&, this](
2730 std::size_t countTotal,
2731 std::size_t countRevoked,
2732 std::size_t listThreshold,
2733 ManifestCache& pubManifests,
2734 ManifestCache& valManifests,
2736 std::vector<Publisher>& publishers // out
2738 auto result = std::make_unique<ValidatorList>(
2739 valManifests,
2740 pubManifests,
2741 env.timeKeeper(),
2742 app.config().legacy("database_path"),
2743 env.journal);
2744
2745 std::vector<std::string> cfgPublishers;
2746 for (std::size_t i = 0; i < countTotal; ++i)
2747 {
2748 auto const publisherSecret = randomSecretKey();
2749 auto const publisherPublic =
2750 derivePublicKey(KeyType::ed25519, publisherSecret);
2751 auto const pubSigningKeys = randomKeyPair(KeyType::secp256k1);
2752 cfgPublishers.push_back(strHex(publisherPublic));
2753
2754 constexpr auto revoked =
2756 auto const manifest = base64_encode(makeManifestString(
2757 publisherPublic,
2758 publisherSecret,
2759 pubSigningKeys.first,
2760 pubSigningKeys.second,
2761 i < countRevoked ? revoked : 1));
2762 publishers.push_back(Publisher{
2763 i < countRevoked,
2764 publisherPublic,
2765 pubSigningKeys,
2766 manifest});
2767 }
2768
2769 std::vector<std::string> const emptyCfgKeys;
2770 auto threshold =
2771 listThreshold > 0 ? std::optional(listThreshold) : std::nullopt;
2772 if (self)
2773 {
2774 valManifests.applyManifest(
2775 *deserializeManifest(base64_decode(self->manifest)));
2776 BEAST_EXPECT(result->load(
2777 self->signingPublic,
2778 emptyCfgKeys,
2779 cfgPublishers,
2780 threshold));
2781 }
2782 else
2783 {
2784 BEAST_EXPECT(
2785 result->load({}, emptyCfgKeys, cfgPublishers, threshold));
2786 }
2787
2788 for (std::size_t i = 0; i < countTotal; ++i)
2789 {
2790 using namespace std::chrono_literals;
2791 publishers[i].expiry = env.timeKeeper().now() +
2792 (i == countTotal - 1 ? 60s : 3600s);
2793 auto const blob = makeList(
2794 valKeys,
2795 1,
2796 publishers[i].expiry.time_since_epoch().count());
2797 auto const sig = signList(blob, publishers[i].signingKeys);
2798
2799 BEAST_EXPECT(
2800 result
2801 ->applyLists(
2802 publishers[i].manifest,
2803 1,
2804 {{blob, sig, {}}},
2805 siteUri)
2806 .bestDisposition() ==
2807 (publishers[i].revoked ? ListDisposition::untrusted
2808 : ListDisposition::accepted));
2809 }
2810
2811 return result;
2812 };
2813
2814 // Test cases use 5 publishers.
2815 constexpr auto quorumDisabled = std::numeric_limits<std::size_t>::max();
2816 {
2817 // List threshold = 5 (same as number of trusted publishers)
2818 ManifestCache pubManifests;
2819 ManifestCache valManifests;
2820 std::vector<Publisher> publishers;
2821 // Self is a random validator
2822 auto const self = randomValidator();
2823 auto const keysTotal = valKeys.size() + 1;
2824 auto trustedKeys = makeValidatorList(
2825 5, //
2826 0,
2827 5,
2828 pubManifests,
2829 valManifests,
2830 self,
2831 publishers);
2832 BEAST_EXPECT(trustedKeys->getListThreshold() == 5);
2833 for (auto const& p : publishers)
2834 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
2835
2836 TrustChanges changes = trustedKeys->updateTrusted(
2837 activeValidators,
2838 env.timeKeeper().now(),
2839 env.app().getOPs(),
2840 env.app().overlay(),
2841 env.app().getHashRouter());
2842 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
2843 BEAST_EXPECT(
2844 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
2845
2846 hash_set<NodeID> added;
2847 added.insert(calcNodeID(self.masterPublic));
2848 for (auto const& val : valKeys)
2849 {
2850 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
2851 added.insert(calcNodeID(val.masterPublic));
2852 }
2853 BEAST_EXPECT(changes.added == added);
2854 BEAST_EXPECT(changes.removed.empty());
2855
2856 // Expire one publisher - only trusted validator is self
2857 env.timeKeeper().set(publishers.back().expiry);
2858 changes = trustedKeys->updateTrusted(
2859 activeValidators,
2860 env.timeKeeper().now(),
2861 env.app().getOPs(),
2862 env.app().overlay(),
2863 env.app().getHashRouter());
2864 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
2865 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
2866
2867 hash_set<NodeID> removed;
2868 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
2869 for (auto const& val : valKeys)
2870 {
2871 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
2872 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
2873 removed.insert(calcNodeID(val.masterPublic));
2874 }
2875 BEAST_EXPECT(changes.added.empty());
2876 BEAST_EXPECT(changes.removed == removed);
2877 }
2878 {
2879 // List threshold = 5 (same as number of trusted publishers)
2880 ManifestCache pubManifests;
2881 ManifestCache valManifests;
2882 std::vector<Publisher> publishers;
2883 auto const keysTotal = valKeys.size();
2884 auto trustedKeys = makeValidatorList(
2885 5, //
2886 0,
2887 5,
2888 pubManifests,
2889 valManifests,
2890 {},
2891 publishers);
2892 BEAST_EXPECT(trustedKeys->getListThreshold() == 5);
2893 for (auto const& p : publishers)
2894 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
2895
2896 TrustChanges changes = trustedKeys->updateTrusted(
2897 activeValidators,
2898 env.timeKeeper().now(),
2899 env.app().getOPs(),
2900 env.app().overlay(),
2901 env.app().getHashRouter());
2902 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
2903 BEAST_EXPECT(
2904 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
2905
2906 hash_set<NodeID> added;
2907 for (auto const& val : valKeys)
2908 {
2909 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
2910 added.insert(calcNodeID(val.masterPublic));
2911 }
2912 BEAST_EXPECT(changes.added == added);
2913 BEAST_EXPECT(changes.removed.empty());
2914
2915 // Expire one publisher - no trusted validators
2916 env.timeKeeper().set(publishers.back().expiry);
2917 changes = trustedKeys->updateTrusted(
2918 activeValidators,
2919 env.timeKeeper().now(),
2920 env.app().getOPs(),
2921 env.app().overlay(),
2922 env.app().getHashRouter());
2923 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
2924 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
2925
2926 hash_set<NodeID> removed;
2927 for (auto const& val : valKeys)
2928 {
2929 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
2930 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
2931 removed.insert(calcNodeID(val.masterPublic));
2932 }
2933 BEAST_EXPECT(changes.added.empty());
2934 BEAST_EXPECT(changes.removed == removed);
2935 }
2936 {
2937 // List threshold = 4, 1 publisher is revoked
2938 ManifestCache pubManifests;
2939 ManifestCache valManifests;
2940 std::vector<Publisher> publishers;
2941 // Self is in UNL
2942 auto const self = valKeys[1];
2943 auto const keysTotal = valKeys.size();
2944 auto trustedKeys = makeValidatorList(
2945 5, //
2946 1,
2947 4,
2948 pubManifests,
2949 valManifests,
2950 self,
2951 publishers);
2952 BEAST_EXPECT(trustedKeys->getListThreshold() == 4);
2953 int untrustedCount = 0;
2954 for (auto const& p : publishers)
2955 {
2956 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
2957 BEAST_EXPECT(p.revoked ^ trusted);
2958 untrustedCount += trusted ? 0 : 1;
2959 }
2960 BEAST_EXPECT(untrustedCount == 1);
2961
2962 TrustChanges changes = trustedKeys->updateTrusted(
2963 activeValidators,
2964 env.timeKeeper().now(),
2965 env.app().getOPs(),
2966 env.app().overlay(),
2967 env.app().getHashRouter());
2968 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
2969 BEAST_EXPECT(
2970 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
2971
2972 hash_set<NodeID> added;
2973 for (auto const& val : valKeys)
2974 {
2975 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
2976 added.insert(calcNodeID(val.masterPublic));
2977 }
2978 BEAST_EXPECT(changes.added == added);
2979 BEAST_EXPECT(changes.removed.empty());
2980
2981 // Expire one publisher - only trusted validator is self
2982 env.timeKeeper().set(publishers.back().expiry);
2983 changes = trustedKeys->updateTrusted(
2984 activeValidators,
2985 env.timeKeeper().now(),
2986 env.app().getOPs(),
2987 env.app().overlay(),
2988 env.app().getHashRouter());
2989 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
2990 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
2991
2992 hash_set<NodeID> removed;
2993 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
2994 for (auto const& val : valKeys)
2995 {
2996 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
2997 if (val.masterPublic != self.masterPublic)
2998 {
2999 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3000 removed.insert(calcNodeID(val.masterPublic));
3001 }
3002 }
3003 BEAST_EXPECT(changes.added.empty());
3004 BEAST_EXPECT(changes.removed == removed);
3005 }
3006 {
3007 // List threshold = 3 (default), 2 publishers are revoked
3008 ManifestCache pubManifests;
3009 ManifestCache valManifests;
3010 std::vector<Publisher> publishers;
3011 // Self is a random validator
3012 auto const self = randomValidator();
3013 auto const keysTotal = valKeys.size() + 1;
3014 auto trustedKeys = makeValidatorList(
3015 5, //
3016 2,
3017 0,
3018 pubManifests,
3019 valManifests,
3020 self,
3021 publishers);
3022 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
3023 int untrustedCount = 0;
3024 for (auto const& p : publishers)
3025 {
3026 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3027 BEAST_EXPECT(p.revoked ^ trusted);
3028 untrustedCount += trusted ? 0 : 1;
3029 }
3030 BEAST_EXPECT(untrustedCount == 2);
3031
3032 TrustChanges changes = trustedKeys->updateTrusted(
3033 activeValidators,
3034 env.timeKeeper().now(),
3035 env.app().getOPs(),
3036 env.app().overlay(),
3037 env.app().getHashRouter());
3038 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3039 BEAST_EXPECT(
3040 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3041
3042 hash_set<NodeID> added;
3043 added.insert(calcNodeID(self.masterPublic));
3044 for (auto const& val : valKeys)
3045 {
3046 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3047 added.insert(calcNodeID(val.masterPublic));
3048 }
3049 BEAST_EXPECT(changes.added == added);
3050 BEAST_EXPECT(changes.removed.empty());
3051
3052 // Expire one publisher - no quorum, only trusted validator is self
3053 env.timeKeeper().set(publishers.back().expiry);
3054 changes = trustedKeys->updateTrusted(
3055 activeValidators,
3056 env.timeKeeper().now(),
3057 env.app().getOPs(),
3058 env.app().overlay(),
3059 env.app().getHashRouter());
3060 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3061 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3062
3063 hash_set<NodeID> removed;
3064 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3065 for (auto const& val : valKeys)
3066 {
3067 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3068 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3069 removed.insert(calcNodeID(val.masterPublic));
3070 }
3071 BEAST_EXPECT(changes.added.empty());
3072 BEAST_EXPECT(changes.removed == removed);
3073 }
3074 {
3075 // List threshold = 3 (default), 2 publishers are revoked
3076 ManifestCache pubManifests;
3077 ManifestCache valManifests;
3078 std::vector<Publisher> publishers;
3079 // Self is in UNL
3080 auto const self = valKeys[5];
3081 auto const keysTotal = valKeys.size();
3082 auto trustedKeys = makeValidatorList(
3083 5, //
3084 2,
3085 0,
3086 pubManifests,
3087 valManifests,
3088 self,
3089 publishers);
3090 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
3091 int untrustedCount = 0;
3092 for (auto const& p : publishers)
3093 {
3094 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3095 BEAST_EXPECT(p.revoked ^ trusted);
3096 untrustedCount += trusted ? 0 : 1;
3097 }
3098 BEAST_EXPECT(untrustedCount == 2);
3099
3100 TrustChanges changes = trustedKeys->updateTrusted(
3101 activeValidators,
3102 env.timeKeeper().now(),
3103 env.app().getOPs(),
3104 env.app().overlay(),
3105 env.app().getHashRouter());
3106 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3107 BEAST_EXPECT(
3108 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3109
3110 hash_set<NodeID> added;
3111 for (auto const& val : valKeys)
3112 {
3113 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3114 added.insert(calcNodeID(val.masterPublic));
3115 }
3116 BEAST_EXPECT(changes.added == added);
3117 BEAST_EXPECT(changes.removed.empty());
3118
3119 // Expire one publisher - no quorum, only trusted validator is self
3120 env.timeKeeper().set(publishers.back().expiry);
3121 changes = trustedKeys->updateTrusted(
3122 activeValidators,
3123 env.timeKeeper().now(),
3124 env.app().getOPs(),
3125 env.app().overlay(),
3126 env.app().getHashRouter());
3127 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3128 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3129
3130 hash_set<NodeID> removed;
3131 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3132 for (auto const& val : valKeys)
3133 {
3134 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3135 if (val.masterPublic != self.masterPublic)
3136 {
3137 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3138 removed.insert(calcNodeID(val.masterPublic));
3139 }
3140 }
3141 BEAST_EXPECT(changes.added.empty());
3142 BEAST_EXPECT(changes.removed == removed);
3143 }
3144 {
3145 // List threshold = 3 (default), 2 publishers are revoked
3146 ManifestCache pubManifests;
3147 ManifestCache valManifests;
3148 std::vector<Publisher> publishers;
3149 auto const keysTotal = valKeys.size();
3150 auto trustedKeys = makeValidatorList(
3151 5, //
3152 2,
3153 0,
3154 pubManifests,
3155 valManifests,
3156 {},
3157 publishers);
3158 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
3159 int untrustedCount = 0;
3160 for (auto const& p : publishers)
3161 {
3162 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3163 BEAST_EXPECT(p.revoked ^ trusted);
3164 untrustedCount += trusted ? 0 : 1;
3165 }
3166 BEAST_EXPECT(untrustedCount == 2);
3167
3168 TrustChanges changes = trustedKeys->updateTrusted(
3169 activeValidators,
3170 env.timeKeeper().now(),
3171 env.app().getOPs(),
3172 env.app().overlay(),
3173 env.app().getHashRouter());
3174 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3175 BEAST_EXPECT(
3176 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3177
3178 hash_set<NodeID> added;
3179 for (auto const& val : valKeys)
3180 {
3181 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3182 added.insert(calcNodeID(val.masterPublic));
3183 }
3184 BEAST_EXPECT(changes.added == added);
3185 BEAST_EXPECT(changes.removed.empty());
3186
3187 // Expire one publisher - no quorum, no trusted validators
3188 env.timeKeeper().set(publishers.back().expiry);
3189 changes = trustedKeys->updateTrusted(
3190 activeValidators,
3191 env.timeKeeper().now(),
3192 env.app().getOPs(),
3193 env.app().overlay(),
3194 env.app().getHashRouter());
3195 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3196 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
3197
3198 hash_set<NodeID> removed;
3199 for (auto const& val : valKeys)
3200 {
3201 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3202 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3203 removed.insert(calcNodeID(val.masterPublic));
3204 }
3205 BEAST_EXPECT(changes.added.empty());
3206 BEAST_EXPECT(changes.removed == removed);
3207 }
3208 {
3209 // List threshold = 2, 1 publisher is revoked
3210 ManifestCache pubManifests;
3211 ManifestCache valManifests;
3212 std::vector<Publisher> publishers;
3213 // Self is a random validator
3214 auto const self = randomValidator();
3215 auto const keysTotal = valKeys.size() + 1;
3216 auto trustedKeys = makeValidatorList(
3217 5, //
3218 1,
3219 2,
3220 pubManifests,
3221 valManifests,
3222 self,
3223 publishers);
3224 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
3225 int untrustedCount = 0;
3226 for (auto const& p : publishers)
3227 {
3228 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3229 BEAST_EXPECT(p.revoked ^ trusted);
3230 untrustedCount += trusted ? 0 : 1;
3231 }
3232 BEAST_EXPECT(untrustedCount == 1);
3233
3234 TrustChanges changes = trustedKeys->updateTrusted(
3235 activeValidators,
3236 env.timeKeeper().now(),
3237 env.app().getOPs(),
3238 env.app().overlay(),
3239 env.app().getHashRouter());
3240 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3241 BEAST_EXPECT(
3242 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3243
3244 hash_set<NodeID> added;
3245 added.insert(calcNodeID(self.masterPublic));
3246 for (auto const& val : valKeys)
3247 {
3248 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3249 added.insert(calcNodeID(val.masterPublic));
3250 }
3251 BEAST_EXPECT(changes.added == added);
3252 BEAST_EXPECT(changes.removed.empty());
3253
3254 // Expire one publisher - no quorum
3255 env.timeKeeper().set(publishers.back().expiry);
3256 changes = trustedKeys->updateTrusted(
3257 activeValidators,
3258 env.timeKeeper().now(),
3259 env.app().getOPs(),
3260 env.app().overlay(),
3261 env.app().getHashRouter());
3262 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3263 BEAST_EXPECT(
3264 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3265
3266 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3267 for (auto const& val : valKeys)
3268 {
3269 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3270 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3271 }
3272 BEAST_EXPECT(changes.added.empty());
3273 BEAST_EXPECT(changes.removed.empty());
3274 }
3275 {
3276 // List threshold = 1
3277 ManifestCache pubManifests;
3278 ManifestCache valManifests;
3279 std::vector<Publisher> publishers;
3280 // Self is a random validator
3281 auto const self = randomValidator();
3282 auto const keysTotal = valKeys.size() + 1;
3283 auto trustedKeys = makeValidatorList(
3284 5, //
3285 0,
3286 1,
3287 pubManifests,
3288 valManifests,
3289 self,
3290 publishers);
3291 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3292 for (auto const& p : publishers)
3293 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3294
3295 TrustChanges changes = trustedKeys->updateTrusted(
3296 activeValidators,
3297 env.timeKeeper().now(),
3298 env.app().getOPs(),
3299 env.app().overlay(),
3300 env.app().getHashRouter());
3301 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3302 BEAST_EXPECT(
3303 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3304
3305 hash_set<NodeID> added;
3306 added.insert(calcNodeID(self.masterPublic));
3307 for (auto const& val : valKeys)
3308 {
3309 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3310 added.insert(calcNodeID(val.masterPublic));
3311 }
3312 BEAST_EXPECT(changes.added == added);
3313 BEAST_EXPECT(changes.removed.empty());
3314
3315 // Expire one publisher - no quorum
3316 env.timeKeeper().set(publishers.back().expiry);
3317 changes = trustedKeys->updateTrusted(
3318 activeValidators,
3319 env.timeKeeper().now(),
3320 env.app().getOPs(),
3321 env.app().overlay(),
3322 env.app().getHashRouter());
3323 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3324 BEAST_EXPECT(
3325 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3326
3327 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3328 for (auto const& val : valKeys)
3329 {
3330 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3331 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3332 }
3333 BEAST_EXPECT(changes.added.empty());
3334 BEAST_EXPECT(changes.removed.empty());
3335 }
3336 {
3337 // List threshold = 1
3338 ManifestCache pubManifests;
3339 ManifestCache valManifests;
3340 std::vector<Publisher> publishers;
3341 // Self is in UNL
3342 auto const self = valKeys[7];
3343 auto const keysTotal = valKeys.size();
3344 auto trustedKeys = makeValidatorList(
3345 5, //
3346 0,
3347 1,
3348 pubManifests,
3349 valManifests,
3350 self,
3351 publishers);
3352 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3353 for (auto const& p : publishers)
3354 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3355
3356 TrustChanges changes = trustedKeys->updateTrusted(
3357 activeValidators,
3358 env.timeKeeper().now(),
3359 env.app().getOPs(),
3360 env.app().overlay(),
3361 env.app().getHashRouter());
3362 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3363 BEAST_EXPECT(
3364 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3365
3366 hash_set<NodeID> added;
3367 for (auto const& val : valKeys)
3368 {
3369 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3370 added.insert(calcNodeID(val.masterPublic));
3371 }
3372 BEAST_EXPECT(changes.added == added);
3373 BEAST_EXPECT(changes.removed.empty());
3374
3375 // Expire one publisher - no quorum
3376 env.timeKeeper().set(publishers.back().expiry);
3377 changes = trustedKeys->updateTrusted(
3378 activeValidators,
3379 env.timeKeeper().now(),
3380 env.app().getOPs(),
3381 env.app().overlay(),
3382 env.app().getHashRouter());
3383 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3384 BEAST_EXPECT(
3385 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3386
3387 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3388 for (auto const& val : valKeys)
3389 {
3390 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3391 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3392 }
3393 BEAST_EXPECT(changes.added.empty());
3394 BEAST_EXPECT(changes.removed.empty());
3395 }
3396 {
3397 // List threshold = 1
3398 ManifestCache pubManifests;
3399 ManifestCache valManifests;
3400 std::vector<Publisher> publishers;
3401 auto const keysTotal = valKeys.size();
3402 auto trustedKeys = makeValidatorList(
3403 5, //
3404 0,
3405 1,
3406 pubManifests,
3407 valManifests,
3408 {},
3409 publishers);
3410 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3411 for (auto const& p : publishers)
3412 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3413
3414 TrustChanges changes = trustedKeys->updateTrusted(
3415 activeValidators,
3416 env.timeKeeper().now(),
3417 env.app().getOPs(),
3418 env.app().overlay(),
3419 env.app().getHashRouter());
3420 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3421 BEAST_EXPECT(
3422 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3423
3424 hash_set<NodeID> added;
3425 for (auto const& val : valKeys)
3426 {
3427 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3428 added.insert(calcNodeID(val.masterPublic));
3429 }
3430 BEAST_EXPECT(changes.added == added);
3431 BEAST_EXPECT(changes.removed.empty());
3432
3433 // Expire one publisher - no quorum
3434 env.timeKeeper().set(publishers.back().expiry);
3435 changes = trustedKeys->updateTrusted(
3436 activeValidators,
3437 env.timeKeeper().now(),
3438 env.app().getOPs(),
3439 env.app().overlay(),
3440 env.app().getHashRouter());
3441 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3442 BEAST_EXPECT(
3443 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3444
3445 for (auto const& val : valKeys)
3446 {
3447 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3448 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3449 }
3450 BEAST_EXPECT(changes.added.empty());
3451 BEAST_EXPECT(changes.removed.empty());
3452 }
3453
3454 // Test cases use 2 publishers
3455 {
3456 // List threshold = 1, 1 publisher revoked
3457 ManifestCache pubManifests;
3458 ManifestCache valManifests;
3459 std::vector<Publisher> publishers;
3460 // Self is a random validator
3461 auto const self = randomValidator();
3462 auto const keysTotal = valKeys.size() + 1;
3463 auto trustedKeys = makeValidatorList(
3464 2, //
3465 1,
3466 1,
3467 pubManifests,
3468 valManifests,
3469 self,
3470 publishers);
3471 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3472 int untrustedCount = 0;
3473 for (auto const& p : publishers)
3474 {
3475 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3476 BEAST_EXPECT(p.revoked ^ trusted);
3477 untrustedCount += trusted ? 0 : 1;
3478 }
3479 BEAST_EXPECT(untrustedCount == 1);
3480
3481 TrustChanges changes = trustedKeys->updateTrusted(
3482 activeValidators,
3483 env.timeKeeper().now(),
3484 env.app().getOPs(),
3485 env.app().overlay(),
3486 env.app().getHashRouter());
3487 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3488 BEAST_EXPECT(
3489 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3490
3491 hash_set<NodeID> added;
3492 added.insert(calcNodeID(self.masterPublic));
3493 for (auto const& val : valKeys)
3494 {
3495 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3496 added.insert(calcNodeID(val.masterPublic));
3497 }
3498 BEAST_EXPECT(changes.added == added);
3499 BEAST_EXPECT(changes.removed.empty());
3500
3501 // Expire one publisher - no quorum, only trusted validator is self
3502 env.timeKeeper().set(publishers.back().expiry);
3503 changes = trustedKeys->updateTrusted(
3504 activeValidators,
3505 env.timeKeeper().now(),
3506 env.app().getOPs(),
3507 env.app().overlay(),
3508 env.app().getHashRouter());
3509 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3510 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3511
3512 hash_set<NodeID> removed;
3513 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3514 for (auto const& val : valKeys)
3515 {
3516 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
3517 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3518 removed.insert(calcNodeID(val.masterPublic));
3519 }
3520 BEAST_EXPECT(changes.added.empty());
3521 BEAST_EXPECT(changes.removed == removed);
3522 }
3523 {
3524 // List threshold = 1, 1 publisher revoked
3525 ManifestCache pubManifests;
3526 ManifestCache valManifests;
3527 std::vector<Publisher> publishers;
3528 // Self is in UNL
3529 auto const self = valKeys[5];
3530 auto const keysTotal = valKeys.size();
3531 auto trustedKeys = makeValidatorList(
3532 2, //
3533 1,
3534 1,
3535 pubManifests,
3536 valManifests,
3537 self,
3538 publishers);
3539 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3540 int untrustedCount = 0;
3541 for (auto const& p : publishers)
3542 {
3543 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3544 BEAST_EXPECT(p.revoked ^ trusted);
3545 untrustedCount += trusted ? 0 : 1;
3546 }
3547 BEAST_EXPECT(untrustedCount == 1);
3548
3549 TrustChanges changes = trustedKeys->updateTrusted(
3550 activeValidators,
3551 env.timeKeeper().now(),
3552 env.app().getOPs(),
3553 env.app().overlay(),
3554 env.app().getHashRouter());
3555 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3556 BEAST_EXPECT(
3557 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3558
3559 hash_set<NodeID> added;
3560 for (auto const& val : valKeys)
3561 {
3562 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3563 added.insert(calcNodeID(val.masterPublic));
3564 }
3565 BEAST_EXPECT(changes.added == added);
3566 BEAST_EXPECT(changes.removed.empty());
3567
3568 // Expire one publisher - no quorum, only trusted validator is self
3569 env.timeKeeper().set(publishers.back().expiry);
3570 changes = trustedKeys->updateTrusted(
3571 activeValidators,
3572 env.timeKeeper().now(),
3573 env.app().getOPs(),
3574 env.app().overlay(),
3575 env.app().getHashRouter());
3576 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3577 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3578
3579 hash_set<NodeID> removed;
3580 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3581 for (auto const& val : valKeys)
3582 {
3583 if (val.masterPublic != self.masterPublic)
3584 {
3585 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
3586 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3587 removed.insert(calcNodeID(val.masterPublic));
3588 }
3589 }
3590 BEAST_EXPECT(changes.added.empty());
3591 BEAST_EXPECT(changes.removed == removed);
3592 }
3593 {
3594 // List threshold = 1, 1 publisher revoked
3595 ManifestCache pubManifests;
3596 ManifestCache valManifests;
3597 std::vector<Publisher> publishers;
3598 auto const keysTotal = valKeys.size();
3599 auto trustedKeys = makeValidatorList(
3600 2, //
3601 1,
3602 1,
3603 pubManifests,
3604 valManifests,
3605 {},
3606 publishers);
3607 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3608 int untrustedCount = 0;
3609 for (auto const& p : publishers)
3610 {
3611 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
3612 BEAST_EXPECT(p.revoked ^ trusted);
3613 untrustedCount += trusted ? 0 : 1;
3614 }
3615 BEAST_EXPECT(untrustedCount == 1);
3616
3617 TrustChanges changes = trustedKeys->updateTrusted(
3618 activeValidators,
3619 env.timeKeeper().now(),
3620 env.app().getOPs(),
3621 env.app().overlay(),
3622 env.app().getHashRouter());
3623 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3624 BEAST_EXPECT(
3625 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3626
3627 hash_set<NodeID> added;
3628 for (auto const& val : valKeys)
3629 {
3630 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3631 added.insert(calcNodeID(val.masterPublic));
3632 }
3633 BEAST_EXPECT(changes.added == added);
3634 BEAST_EXPECT(changes.removed.empty());
3635
3636 // Expire one publisher - no quorum, no trusted validators
3637 env.timeKeeper().set(publishers.back().expiry);
3638 changes = trustedKeys->updateTrusted(
3639 activeValidators,
3640 env.timeKeeper().now(),
3641 env.app().getOPs(),
3642 env.app().overlay(),
3643 env.app().getHashRouter());
3644 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3645 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
3646
3647 hash_set<NodeID> removed;
3648 for (auto const& val : valKeys)
3649 {
3650 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
3651 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3652 removed.insert(calcNodeID(val.masterPublic));
3653 }
3654 BEAST_EXPECT(changes.added.empty());
3655 BEAST_EXPECT(changes.removed == removed);
3656 }
3657 {
3658 // List threshold = 2 (same as number of trusted publishers)
3659 ManifestCache pubManifests;
3660 ManifestCache valManifests;
3661 std::vector<Publisher> publishers;
3662 // Self is a random validator
3663 auto const self = randomValidator();
3664 auto const keysTotal = valKeys.size() + 1;
3665 auto trustedKeys = makeValidatorList(
3666 2, //
3667 0,
3668 2,
3669 pubManifests,
3670 valManifests,
3671 self,
3672 publishers);
3673 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
3674 for (auto const& p : publishers)
3675 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3676
3677 TrustChanges changes = trustedKeys->updateTrusted(
3678 activeValidators,
3679 env.timeKeeper().now(),
3680 env.app().getOPs(),
3681 env.app().overlay(),
3682 env.app().getHashRouter());
3683 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3684 BEAST_EXPECT(
3685 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3686
3687 hash_set<NodeID> added;
3688 added.insert(calcNodeID(self.masterPublic));
3689 for (auto const& val : valKeys)
3690 {
3691 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3692 added.insert(calcNodeID(val.masterPublic));
3693 }
3694 BEAST_EXPECT(changes.added == added);
3695 BEAST_EXPECT(changes.removed.empty());
3696
3697 // Expire one publisher - only trusted validator is self
3698 env.timeKeeper().set(publishers.back().expiry);
3699 changes = trustedKeys->updateTrusted(
3700 activeValidators,
3701 env.timeKeeper().now(),
3702 env.app().getOPs(),
3703 env.app().overlay(),
3704 env.app().getHashRouter());
3705 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3706 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3707
3708 hash_set<NodeID> removed;
3709 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3710 for (auto const& val : valKeys)
3711 {
3712 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3713 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3714 removed.insert(calcNodeID(val.masterPublic));
3715 }
3716 BEAST_EXPECT(changes.added.empty());
3717 BEAST_EXPECT(changes.removed == removed);
3718 }
3719 {
3720 // List threshold = 2 (same as number of trusted publishers)
3721 ManifestCache pubManifests;
3722 ManifestCache valManifests;
3723 std::vector<Publisher> publishers;
3724 // Self is in UNL
3725 auto const self = valKeys[5];
3726 auto const keysTotal = valKeys.size();
3727 auto trustedKeys = makeValidatorList(
3728 2, //
3729 0,
3730 2,
3731 pubManifests,
3732 valManifests,
3733 self,
3734 publishers);
3735 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
3736 for (auto const& p : publishers)
3737 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3738
3739 TrustChanges changes = trustedKeys->updateTrusted(
3740 activeValidators,
3741 env.timeKeeper().now(),
3742 env.app().getOPs(),
3743 env.app().overlay(),
3744 env.app().getHashRouter());
3745 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3746 BEAST_EXPECT(
3747 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3748
3749 hash_set<NodeID> added;
3750 added.insert(calcNodeID(self.masterPublic));
3751 for (auto const& val : valKeys)
3752 {
3753 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3754 added.insert(calcNodeID(val.masterPublic));
3755 }
3756 BEAST_EXPECT(changes.added == added);
3757 BEAST_EXPECT(changes.removed.empty());
3758
3759 // Expire one publisher - only trusted validator is self
3760 env.timeKeeper().set(publishers.back().expiry);
3761 changes = trustedKeys->updateTrusted(
3762 activeValidators,
3763 env.timeKeeper().now(),
3764 env.app().getOPs(),
3765 env.app().overlay(),
3766 env.app().getHashRouter());
3767 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3768 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3769
3770 hash_set<NodeID> removed;
3771 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3772 for (auto const& val : valKeys)
3773 {
3774 if (val.masterPublic != self.masterPublic)
3775 {
3776 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3777 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3778 removed.insert(calcNodeID(val.masterPublic));
3779 }
3780 }
3781 BEAST_EXPECT(changes.added.empty());
3782 BEAST_EXPECT(changes.removed == removed);
3783 }
3784 {
3785 // List threshold = 2 (same as number of trusted publishers)
3786 ManifestCache pubManifests;
3787 ManifestCache valManifests;
3788 std::vector<Publisher> publishers;
3789 auto const keysTotal = valKeys.size();
3790 auto trustedKeys = makeValidatorList(
3791 2, //
3792 0,
3793 2,
3794 pubManifests,
3795 valManifests,
3796 {},
3797 publishers);
3798 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
3799 for (auto const& p : publishers)
3800 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3801
3802 TrustChanges changes = trustedKeys->updateTrusted(
3803 activeValidators,
3804 env.timeKeeper().now(),
3805 env.app().getOPs(),
3806 env.app().overlay(),
3807 env.app().getHashRouter());
3808 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3809 BEAST_EXPECT(
3810 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3811
3812 hash_set<NodeID> added;
3813 for (auto const& val : valKeys)
3814 {
3815 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3816 added.insert(calcNodeID(val.masterPublic));
3817 }
3818 BEAST_EXPECT(changes.added == added);
3819 BEAST_EXPECT(changes.removed.empty());
3820
3821 // Expire one publisher - no trusted validators
3822 env.timeKeeper().set(publishers.back().expiry);
3823 changes = trustedKeys->updateTrusted(
3824 activeValidators,
3825 env.timeKeeper().now(),
3826 env.app().getOPs(),
3827 env.app().overlay(),
3828 env.app().getHashRouter());
3829 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3830 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 0);
3831
3832 hash_set<NodeID> removed;
3833 for (auto const& val : valKeys)
3834 {
3835 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
3836 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3837 removed.insert(calcNodeID(val.masterPublic));
3838 }
3839 BEAST_EXPECT(changes.added.empty());
3840 BEAST_EXPECT(changes.removed == removed);
3841 }
3842
3843 // Test case for 1 publisher
3844 {
3845 // List threshold = 1 (default), no publisher revoked
3846 ManifestCache pubManifests;
3847 ManifestCache valManifests;
3848 std::vector<Publisher> publishers;
3849 // Self is a random validator
3850 auto const self = randomValidator();
3851 auto const keysTotal = valKeys.size() + 1;
3852 auto trustedKeys = makeValidatorList(
3853 1, //
3854 0,
3855 0,
3856 pubManifests,
3857 valManifests,
3858 self,
3859 publishers);
3860 BEAST_EXPECT(trustedKeys->getListThreshold() == 1);
3861 for (auto const& p : publishers)
3862 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3863
3864 TrustChanges changes = trustedKeys->updateTrusted(
3865 activeValidators,
3866 env.timeKeeper().now(),
3867 env.app().getOPs(),
3868 env.app().overlay(),
3869 env.app().getHashRouter());
3870 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3871 BEAST_EXPECT(
3872 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3873
3874 hash_set<NodeID> added;
3875 added.insert(calcNodeID(self.masterPublic));
3876 for (auto const& val : valKeys)
3877 {
3878 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3879 added.insert(calcNodeID(val.masterPublic));
3880 }
3881 BEAST_EXPECT(changes.added == added);
3882 BEAST_EXPECT(changes.removed.empty());
3883
3884 // Expire one publisher - no quorum, only trusted validator is self
3885 env.timeKeeper().set(publishers.back().expiry);
3886 changes = trustedKeys->updateTrusted(
3887 activeValidators,
3888 env.timeKeeper().now(),
3889 env.app().getOPs(),
3890 env.app().overlay(),
3891 env.app().getHashRouter());
3892 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
3893 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
3894
3895 hash_set<NodeID> removed;
3896 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
3897 for (auto const& val : valKeys)
3898 {
3899 BEAST_EXPECT(!trustedKeys->listed(val.masterPublic));
3900 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
3901 removed.insert(calcNodeID(val.masterPublic));
3902 }
3903 BEAST_EXPECT(changes.added.empty());
3904 BEAST_EXPECT(changes.removed == removed);
3905 }
3906
3907 // Test case for 3 publishers (for 2 is a block above)
3908 {
3909 // List threshold = 2 (default), no publisher revoked
3910 ManifestCache pubManifests;
3911 ManifestCache valManifests;
3912 std::vector<Publisher> publishers;
3913 // Self is in UNL
3914 auto const self = valKeys[2];
3915 auto const keysTotal = valKeys.size();
3916 auto trustedKeys = makeValidatorList(
3917 3, //
3918 0,
3919 0,
3920 pubManifests,
3921 valManifests,
3922 self,
3923 publishers);
3924 BEAST_EXPECT(trustedKeys->getListThreshold() == 2);
3925 for (auto const& p : publishers)
3926 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3927
3928 TrustChanges changes = trustedKeys->updateTrusted(
3929 activeValidators,
3930 env.timeKeeper().now(),
3931 env.app().getOPs(),
3932 env.app().overlay(),
3933 env.app().getHashRouter());
3934 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3935 BEAST_EXPECT(
3936 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3937
3938 hash_set<NodeID> added;
3939 for (auto const& val : valKeys)
3940 {
3941 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3942 added.insert(calcNodeID(val.masterPublic));
3943 }
3944 BEAST_EXPECT(changes.added == added);
3945 BEAST_EXPECT(changes.removed.empty());
3946 }
3947
3948 // Test case for 4 publishers
3949 {
3950 // List threshold = 3 (default), no publisher revoked
3951 ManifestCache pubManifests;
3952 ManifestCache valManifests;
3953 std::vector<Publisher> publishers;
3954 auto const keysTotal = valKeys.size();
3955 auto trustedKeys = makeValidatorList(
3956 4, //
3957 0,
3958 0,
3959 pubManifests,
3960 valManifests,
3961 {},
3962 publishers);
3963 BEAST_EXPECT(trustedKeys->getListThreshold() == 3);
3964 for (auto const& p : publishers)
3965 BEAST_EXPECT(trustedKeys->trustedPublisher(p.pubKey));
3966
3967 TrustChanges changes = trustedKeys->updateTrusted(
3968 activeValidators,
3969 env.timeKeeper().now(),
3970 env.app().getOPs(),
3971 env.app().overlay(),
3972 env.app().getHashRouter());
3973 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
3974 BEAST_EXPECT(
3975 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
3976
3977 hash_set<NodeID> added;
3978 for (auto const& val : valKeys)
3979 {
3980 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
3981 added.insert(calcNodeID(val.masterPublic));
3982 }
3983 BEAST_EXPECT(changes.added == added);
3984 BEAST_EXPECT(changes.removed.empty());
3985 }
3986
3987 // Test case for 6 publishers (for 5 is a large block above)
3988 {
3989 // List threshold = 4 (default), 2 publishers revoked
3990 ManifestCache pubManifests;
3991 ManifestCache valManifests;
3992 std::vector<Publisher> publishers;
3993 // Self is a random validator
3994 auto const self = randomValidator();
3995 auto const keysTotal = valKeys.size() + 1;
3996 auto trustedKeys = makeValidatorList(
3997 6, //
3998 2,
3999 0,
4000 pubManifests,
4001 valManifests,
4002 self,
4003 publishers);
4004 BEAST_EXPECT(trustedKeys->getListThreshold() == 4);
4005 int untrustedCount = 0;
4006 for (auto const& p : publishers)
4007 {
4008 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
4009 BEAST_EXPECT(p.revoked ^ trusted);
4010 untrustedCount += trusted ? 0 : 1;
4011 }
4012 BEAST_EXPECT(untrustedCount == 2);
4013
4014 TrustChanges changes = trustedKeys->updateTrusted(
4015 activeValidators,
4016 env.timeKeeper().now(),
4017 env.app().getOPs(),
4018 env.app().overlay(),
4019 env.app().getHashRouter());
4020 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
4021 BEAST_EXPECT(
4022 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
4023
4024 hash_set<NodeID> added;
4025 added.insert(calcNodeID(self.masterPublic));
4026 for (auto const& val : valKeys)
4027 {
4028 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
4029 added.insert(calcNodeID(val.masterPublic));
4030 }
4031 BEAST_EXPECT(changes.added == added);
4032 BEAST_EXPECT(changes.removed.empty());
4033
4034 // Expire one publisher - no quorum, only trusted validator is self
4035 env.timeKeeper().set(publishers.back().expiry);
4036 changes = trustedKeys->updateTrusted(
4037 activeValidators,
4038 env.timeKeeper().now(),
4039 env.app().getOPs(),
4040 env.app().overlay(),
4041 env.app().getHashRouter());
4042 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
4043 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
4044
4045 hash_set<NodeID> removed;
4046 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
4047 for (auto const& val : valKeys)
4048 {
4049 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
4050 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
4051 removed.insert(calcNodeID(val.masterPublic));
4052 }
4053 BEAST_EXPECT(changes.added.empty());
4054 BEAST_EXPECT(changes.removed == removed);
4055 }
4056
4057 // Test case for 7 publishers
4058 {
4059 // List threshold = 4 (default), 3 publishers revoked
4060 ManifestCache pubManifests;
4061 ManifestCache valManifests;
4062 std::vector<Publisher> publishers;
4063 // Self is in UNL
4064 auto const self = valKeys[2];
4065 auto const keysTotal = valKeys.size();
4066 auto trustedKeys = makeValidatorList(
4067 7, //
4068 3,
4069 0,
4070 pubManifests,
4071 valManifests,
4072 self,
4073 publishers);
4074 BEAST_EXPECT(trustedKeys->getListThreshold() == 4);
4075 int untrustedCount = 0;
4076 for (auto const& p : publishers)
4077 {
4078 bool const trusted = trustedKeys->trustedPublisher(p.pubKey);
4079 BEAST_EXPECT(p.revoked ^ trusted);
4080 untrustedCount += trusted ? 0 : 1;
4081 }
4082 BEAST_EXPECT(untrustedCount == 3);
4083
4084 TrustChanges changes = trustedKeys->updateTrusted(
4085 activeValidators,
4086 env.timeKeeper().now(),
4087 env.app().getOPs(),
4088 env.app().overlay(),
4089 env.app().getHashRouter());
4090 BEAST_EXPECT(trustedKeys->quorum() == std::ceil(keysTotal * 0.8f));
4091 BEAST_EXPECT(
4092 trustedKeys->getTrustedMasterKeys().size() == keysTotal);
4093
4094 hash_set<NodeID> added;
4095 for (auto const& val : valKeys)
4096 {
4097 BEAST_EXPECT(trustedKeys->trusted(val.masterPublic));
4098 added.insert(calcNodeID(val.masterPublic));
4099 }
4100 BEAST_EXPECT(changes.added == added);
4101 BEAST_EXPECT(changes.removed.empty());
4102
4103 // Expire one publisher - only trusted validator is self
4104 env.timeKeeper().set(publishers.back().expiry);
4105 changes = trustedKeys->updateTrusted(
4106 activeValidators,
4107 env.timeKeeper().now(),
4108 env.app().getOPs(),
4109 env.app().overlay(),
4110 env.app().getHashRouter());
4111 BEAST_EXPECT(trustedKeys->quorum() == quorumDisabled);
4112 BEAST_EXPECT(trustedKeys->getTrustedMasterKeys().size() == 1);
4113
4114 hash_set<NodeID> removed;
4115 BEAST_EXPECT(trustedKeys->trusted(self.masterPublic));
4116 for (auto const& val : valKeys)
4117 {
4118 if (val.masterPublic != self.masterPublic)
4119 {
4120 BEAST_EXPECT(trustedKeys->listed(val.masterPublic));
4121 BEAST_EXPECT(!trustedKeys->trusted(val.masterPublic));
4122 removed.insert(calcNodeID(val.masterPublic));
4123 }
4124 }
4125 BEAST_EXPECT(changes.added.empty());
4126 BEAST_EXPECT(changes.removed == removed);
4127 }
4128 }
4129
4130public:
4131 void
4132 run() override
4133 {
4134 testGenesisQuorum();
4135 testConfigLoad();
4136 testApplyLists();
4137 testGetAvailable();
4138 testUpdateTrusted();
4139 testExpires();
4140 testNegativeUNL();
4141 testSha512Hash();
4142 testBuildMessages();
4143 testQuorumDisabled();
4144 }
4145}; // namespace test
4146
4147BEAST_DEFINE_TESTSUITE(ValidatorList, app, ripple);
4148
4149} // namespace test
4150} // namespace ripple
T at(T... args)
T back(T... args)
T cbegin(T... args)
T capacity(T... args)
T ceil(T... args)
A testsuite class.
Definition: suite.h:53
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:153
virtual Config & config()=0
virtual Overlay & overlay()=0
virtual TimeKeeper & timeKeeper()=0
virtual NetworkOPs & getOPs()=0
virtual HashRouter & getHashRouter()=0
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
Remembers manifests with the highest sequence number.
Definition: Manifest.h:256
std::optional< PublicKey > getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
A public key.
Definition: PublicKey.h:62
void add(Serializer &s) const override
Definition: STObject.cpp:111
A secret key.
Definition: SecretKey.h:37
std::size_t size() const noexcept
Definition: Serializer.h:72
void const * data() const noexcept
Definition: Serializer.h:78
An immutable linear range of bytes.
Definition: Slice.h:45
time_point now() const override
Returns the current time.
void run() override
Runs the suite.
static hash_set< NodeID > asNodeIDs(std::initializer_list< PublicKey > const &pks)
void checkResult(ValidatorList::PublisherListStats const &result, PublicKey pubKey, ListDisposition expectedWorst, ListDisposition expectedBest)
static std::string makeRevocationString(PublicKey const &pk, SecretKey const &sk)
std::string makeList(std::vector< Validator > const &validators, std::size_t sequence, std::size_t validUntil, std::optional< std::size_t > validFrom={})
static std::string makeManifestString(PublicKey const &pk, SecretKey const &sk, PublicKey const &spk, SecretKey const &ssk, int seq)
std::string signList(std::string const &blob, std::pair< PublicKey, SecretKey > const &keys)
A transaction testing environment.
Definition: Env.h:117
Application & app()
Definition: Env.h:255
beast::Journal const journal
Definition: Env.h:158
ManualTimeKeeper & timeKeeper()
Definition: Env.h:267
Set the regular signature on a JTx.
Definition: sig.h:35
T clear(T... args)
T emplace(T... args)
T cend(T... args)
T find(T... args)
T insert(T... args)
T make_pair(T... args)
T max(T... args)
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:54
void sign(Json::Value &jv, Account const &account)
Sign automatically.
Definition: utility.cpp:46
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:106
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
std::string base64_decode(std::string_view data)
Definition: base64.cpp:245
SField const sfGeneric
@ accepted
List is valid.
@ same_sequence
Same sequence as current list.
@ expired
List is expired, but has the largest non-pending sequence seen so far.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:313
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:207
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
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:243
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:281
std::string base64_encode(std::uint8_t const *data, std::size_t len)
Definition: base64.cpp:236
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:303
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
@ manifest
Manifest.
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:223
T push_back(T... args)
T rbegin(T... args)
T reserve(T... args)
T str(T... args)
Changes in trusted nodes after updating validator list.
hash_set< NodeID > added
hash_set< NodeID > removed
Describes the result of processing a Validator List (UNL), including some of the information from the...
std::optional< PublicKey > publisherKey
Set the sequence number on a JTx.
Definition: seq.h:34
T time_since_epoch(T... args)
T to_string(T... args)