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