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