1#include <test/jtx/Env.h>
2#include <test/unit_test/utils.h>
4#include <xrpld/app/misc/ValidatorList.h>
6#include <xrpl/basics/Slice.h>
7#include <xrpl/basics/base64.h>
8#include <xrpl/basics/contract.h>
9#include <xrpl/basics/strHex.h>
10#include <xrpl/beast/unit_test/suite.h>
11#include <xrpl/config/Constants.h>
12#include <xrpl/protocol/HashPrefix.h>
13#include <xrpl/protocol/KeyType.h>
14#include <xrpl/protocol/PublicKey.h>
15#include <xrpl/protocol/SField.h>
16#include <xrpl/protocol/STObject.h>
17#include <xrpl/protocol/SecretKey.h>
18#include <xrpl/protocol/Seed.h>
19#include <xrpl/protocol/Serializer.h>
20#include <xrpl/protocol/Sign.h>
21#include <xrpl/protocol/tokens.h>
22#include <xrpl/server/Manifest.h>
23#include <xrpl/server/Wallet.h>
25#include <boost/filesystem/operations.hpp>
26#include <boost/filesystem/path.hpp>
61 using namespace boost::filesystem;
62 if (!exists(dbPath) || !is_directory(dbPath) || !is_empty(dbPath))
70 using namespace boost::filesystem;
73 create_directory(dbPath);
77 if (!is_directory(dbPath))
83 static boost::filesystem::path
86 return boost::filesystem::current_path() /
"manifest_test_databases";
120 st[sfSequence] = seq;
121 st[sfPublicKey] = pk;
122 st[sfSigningPubKey] = spk;
143 st[sfPublicKey] = pk;
162 st[sfPublicKey] = pk;
173 return std::move(*r);
185 bool invalidSig =
false)
191 st[sfSequence] = seq;
192 st[sfPublicKey] = pk;
193 st[sfSigningPubKey] = spk;
207 return std::move(*r);
233 auto getPopulatedManifests =
237 cache.forEachManifest([&result](
Manifest const& man) { result.
push_back(&man); });
248 auto& app = env.
app();
255 m.
save(*dbCon,
"ValidatorManifests", [&unl](
PublicKey const& pubKey) {
256 return unl->listed(pubKey);
261 loaded.
load(*dbCon,
"ValidatorManifests");
265 sort(getPopulatedManifests(loaded)));
267 for (
auto const& man : loadedManifests)
268 BEAST_EXPECT(man->revoked());
276 for (
auto const& man : inManifests)
278 unl->load({}, s1, keys);
280 m.
save(*dbCon,
"ValidatorManifests", [&unl](
PublicKey const& pubKey) {
281 return unl->listed(pubKey);
284 loaded.
load(*dbCon,
"ValidatorManifests");
288 sort(getPopulatedManifests(loaded)));
290 if (inManifests.size() == loadedManifests.
size())
310 !loaded.
load(*dbCon,
"ValidatorManifests", badManifest, emptyRevocation));
319 loaded.
load(*dbCon,
"ValidatorManifests", cfgManifest, emptyRevocation));
328 !loaded.
load(*dbCon,
"ValidatorManifests", emptyManifest, badRevocation));
338 !loaded.
load(*dbCon,
"ValidatorManifests", emptyManifest, nonRevocation));
339 BEAST_EXPECT(!loaded.
revoked(pk));
344 !loaded.
load(*dbCon,
"ValidatorManifests", emptyManifest, badSigRevocation));
345 BEAST_EXPECT(!loaded.
revoked(pk));
349 loaded.
load(*dbCon,
"ValidatorManifests", emptyManifest, cfgRevocation));
351 BEAST_EXPECT(loaded.
revoked(pk));
354 boost::filesystem::remove(
getDatabasePath() / boost::filesystem::path(dbName));
368 st[sfPublicKey] = pk;
369 st[sfSigningPubKey] = kp.first;
376 strHex(*m.getSignature()));
379 BEAST_EXPECT(
strHex(masterSig) ==
strHex(m.getMasterSignature()));
417 BEAST_EXPECT(cache.
getMasterKey(kp0.first) == kp0.first);
427 BEAST_EXPECT(cache.
getMasterKey(kp0.first) == kp0.first);
435 BEAST_EXPECT(cache.
revoked(pk));
437 BEAST_EXPECT(cache.
getMasterKey(kp0.first) == kp0.first);
438 BEAST_EXPECT(cache.
getMasterKey(kp1.first) == kp1.first);
452 " eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n",
453 " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl \n",
454 "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE\n",
455 "\t hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\t \t\n",
456 "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2\n",
457 "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1\n",
458 "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj\n",
459 "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n",
462 auto const manifest =
463 "JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/"
464 "vCxHXXLplc2GnMhAkE1agqXxBwD"
465 "wDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQIhAOngu9sAKqXYouJ+l2V0W+"
467 "+ZRS6PShlJAfUsXfAiBsVJGesaadOJc/"
468 "aAZokS1vymGmVrlHPKWX3Yywu6in8HASQKPu"
469 "gBD67kMaRFGvmpATHlGKJdvDFlWPYy5AqDedFv5TJa2w0i21eq3MYywLVJZnFO"
478 BEAST_EXPECT(
token->manifest == manifest);
500 st[sfPublicKey] = pk;
501 st[sfSigningPubKey] = spk;
504 st[sfVersion] = version;
532 0x99, 0x30, 0xE7, 0xFC, 0x9D, 0x56, 0xBB, 0x25, 0xD6, 0x89, 0x3B,
533 0xA3, 0xF3, 0x17, 0xAE, 0x5B, 0xCF, 0x33, 0xB3, 0x29, 0x1B, 0xD6,
534 0x3D, 0xB3, 0x26, 0x54, 0xA3, 0x13, 0x22, 0x2F, 0x7F, 0xD0, 0x20};
555 auto toString = [](
STObject const& st) {
562 for (
auto const keyType : keyTypes)
567 for (
auto const sKeyType : keyTypes)
574 bool noSigningPublic =
false,
575 bool noSignature =
false) {
577 st[sfSequence] = seq;
578 st[sfPublicKey] = pk;
583 if (!noSigningPublic)
584 st[sfSigningPubKey] = spk;
599 auto const st = buildManifestObject(++sequence, std::nullopt);
601 auto const m = toString(st);
604 BEAST_EXPECT(manifest);
606 BEAST_EXPECT(manifest->masterKey == pk);
607 BEAST_EXPECT(manifest->signingKey == spk);
608 BEAST_EXPECT(manifest->sequence == sequence);
609 BEAST_EXPECT(manifest->serialized == m);
610 BEAST_EXPECT(manifest->domain.empty());
611 BEAST_EXPECT(manifest->verify());
616 auto const st = buildManifestObject(++sequence,
std::string{});
622 auto const st = buildManifestObject(++sequence,
std::string{
"a.b"});
627 auto const st = buildManifestObject(++sequence, s +
".example.com");
632 auto const st = buildManifestObject(++sequence, s +
".example.com");
636 auto const st = buildManifestObject(++sequence,
std::string{
"example.com"});
640 auto const m = toString(st);
643 BEAST_EXPECT(manifest);
645 BEAST_EXPECT(manifest->masterKey == pk);
646 BEAST_EXPECT(manifest->signingKey == spk);
647 BEAST_EXPECT(manifest->sequence == sequence);
648 BEAST_EXPECT(manifest->serialized == m);
649 BEAST_EXPECT(manifest->domain ==
"example.com");
650 BEAST_EXPECT(manifest->verify());
656 badSigSt[sfSequence] = sequence + 1;
658 auto const m = toString(badSigSt);
661 BEAST_EXPECT(manifest);
663 BEAST_EXPECT(manifest->masterKey == pk);
664 BEAST_EXPECT(manifest->signingKey == spk);
665 BEAST_EXPECT(manifest->sequence == sequence + 1);
666 BEAST_EXPECT(manifest->serialized == m);
667 BEAST_EXPECT(manifest->domain ==
"example.com");
668 BEAST_EXPECT(!manifest->verify());
674 BEAST_EXPECT(badSt.delField(sfSequence));
680 BEAST_EXPECT(badSt.delField(sfPublicKey));
692 badSt[sfPublicKey] =
makeSlice(shortKey);
698 BEAST_EXPECT(badSt.delField(sfSigningPubKey));
704 badSt[sfSigningPubKey] =
makeSlice(badKey);
710 badSt[sfSigningPubKey] =
makeSlice(shortKey);
716 BEAST_EXPECT(badSt.delField(sfMasterSignature));
722 BEAST_EXPECT(badSt.delField(sfSignature));
728 st[sfSequence] = 314159;
729 st[sfPublicKey] = pk;
730 st[sfSigningPubKey] = pk;
746 auto const st = buildManifestObject(
749 auto const m = toString(st);
752 BEAST_EXPECT(manifest);
754 BEAST_EXPECT(manifest->masterKey == pk);
757 BEAST_EXPECT(!manifest->signingKey);
758 BEAST_EXPECT(manifest->revoked());
759 BEAST_EXPECT(manifest->domain.empty());
760 BEAST_EXPECT(manifest->serialized == m);
761 BEAST_EXPECT(manifest->verify());
766 auto const st = buildManifestObject(
772 auto const st = buildManifestObject(
778 auto const st = buildManifestObject(
802 st[sfPublicKey] = pk1;
804 st[sfSigningPubKey] = pk2;
815 BEAST_EXPECT(
test(
"example.com"));
816 BEAST_EXPECT(
test(
"test.example.com"));
817 BEAST_EXPECT(
test(
"example-domain.com"));
818 BEAST_EXPECT(
test(
"xn--mxavchb.gr"));
819 BEAST_EXPECT(
test(
"test.xn--mxavchb.gr"));
820 BEAST_EXPECT(
test(
"123.gr"));
821 BEAST_EXPECT(
test(
"x.yz"));
826 BEAST_EXPECT(!
test(
"example"));
829 BEAST_EXPECT(!
test(
".com"));
830 BEAST_EXPECT(!
test(
".example.com"));
833 BEAST_EXPECT(!
test(
"example.com."));
836 BEAST_EXPECT(!
test(
"-example.com"));
837 BEAST_EXPECT(!
test(
"example-.com"));
840 BEAST_EXPECT(!
test(
"double..periods.example.com"));
843 BEAST_EXPECT(!
test(
"example.x"));
847 BEAST_EXPECT(!
test(
"example.com-org"));
848 BEAST_EXPECT(!
test(
"bang!.com"));
849 BEAST_EXPECT(!
test(
"bang!.example.com"));
852 BEAST_EXPECT(!
test(
"a.b"));
900 auto const fake = sB2.serialized +
'\0';
906 BEAST_EXPECT(cache.
sequence() > seq0);
910 BEAST_EXPECT(cache.
sequence() == seq1);
920 BEAST_EXPECT(!cache.
revoked(pkA));
921 BEAST_EXPECT(sAMax.revoked());
926 BEAST_EXPECT(cache.
revoked(pkA));
void fail(String const &reason, char const *file, int line)
Record a failure.
TestcaseT testcase
Memberspace for declaring test cases.
Remembers manifests with the highest sequence number.
bool load(DatabaseCon &dbCon, std::string const &dbTable, std::string const &configManifest, std::vector< std::string > const &configRevocation)
Populate manifest cache with manifests in database and config.
std::optional< PublicKey > getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
std::uint32_t sequence() const
A monotonically increasing number used to detect new manifests.
void save(DatabaseCon &dbCon, std::string const &dbTable, std::function< bool(PublicKey const &)> const &isTrusted)
Save cached manifests to database.
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
void addWithoutSigningFields(Serializer &s) const
void add(Serializer &s) const override
Slice slice() const noexcept
std::size_t size() const noexcept
void const * data() const noexcept
static Manifest clone(Manifest const &m)
void testManifestDeserialization()
void testLoadStore(ManifestCache &m)
static PublicKey randomMasterKey()
void run() override
Runs the suite.
static std::string makeManifestString(PublicKey const &pk, SecretKey const &sk, PublicKey const &spk, SecretKey const &ssk, int seq)
void testValidatorToken()
~Manifest_test() override
void testManifestDomainNames()
std::string makeRevocationString(SecretKey const &sk, KeyType type, bool invalidSig=false)
static void setupDatabaseDir(boost::filesystem::path const &dbPath)
static void cleanupDatabaseDir(boost::filesystem::path const &dbPath)
Manifest makeManifest(SecretKey const &sk, KeyType type, SecretKey const &ssk, KeyType stype, int seq, bool invalidSig=false)
static PublicKey randomNode()
static boost::filesystem::path getDatabasePath()
void testManifestVersioning()
Manifest makeRevocation(SecretKey const &sk, KeyType type, bool invalidSig=false)
A transaction testing environment.
ManualTimeKeeper & timeKeeper()
beast::Journal const journal
void sign(json::Value &jv, Account const &account, json::Value &sigObject)
Sign automatically into a specific Json field of the jv object.
bool equal(STAmount const &sa1, STAmount const &sa2)
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
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.
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
Seed randomSeed()
Create a seed using secure random numbers.
std::string strHex(FwdIt begin, FwdIt end)
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig) noexcept
Verify a signature on a message.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
std::string to_string(BaseUInt< Bits, Tag > const &a)
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.
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
std::string base64Encode(std::uint8_t const *data, std::size_t len)
std::unique_ptr< DatabaseCon > makeTestWalletDB(DatabaseCon::Setup const &setup, std::string const &dbname, beast::Journal j)
makeTestWalletDB Opens a test wallet database with an arbitrary name.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
std::enable_if_t< std::is_same_v< T, char >||std::is_same_v< T, unsigned char >, Slice > makeSlice(std::array< T, N > const &a)
std::optional< ValidatorToken > loadValidatorToken(std::vector< std::string > const &blob, beast::Journal journal=beast::Journal(beast::Journal::getNullSink()))
@ BadMasterKey
The master key is not acceptable to us.
@ Accepted
Manifest is valid.
@ Invalid
Timely, but invalid signature.
@ BadEphemeralKey
The ephemeral key is not acceptable to us.
@ Stale
Sequence is too old.
boost::filesystem::path dataDir
PublicKey masterKey
The master key associated with this manifest.
std::string serialized
The manifest in serialized form.
std::string domain
The domain, if one was specified in the manifest; empty otherwise.
std::optional< PublicKey > signingKey
The ephemeral key associated with this manifest.
std::uint32_t sequence
The sequence number of this manifest.
static constexpr auto kDatabasePath