1#include <xrpl/server/Manifest.h>
3#include <xrpl/basics/Blob.h>
4#include <xrpl/basics/Log.h>
5#include <xrpl/basics/Slice.h>
6#include <xrpl/basics/StringUtilities.h>
7#include <xrpl/basics/base64.h>
8#include <xrpl/basics/base_uint.h>
9#include <xrpl/basics/contract.h>
10#include <xrpl/beast/utility/Journal.h>
11#include <xrpl/beast/utility/instrumentation.h>
12#include <xrpl/json/json_reader.h>
13#include <xrpl/json/json_value.h>
14#include <xrpl/protocol/HashPrefix.h>
15#include <xrpl/protocol/PublicKey.h>
16#include <xrpl/protocol/SField.h>
17#include <xrpl/protocol/SOTemplate.h>
18#include <xrpl/protocol/STExchange.h>
19#include <xrpl/protocol/STObject.h>
20#include <xrpl/protocol/Serializer.h>
21#include <xrpl/protocol/Sign.h>
22#include <xrpl/protocol/tokens.h>
23#include <xrpl/rdb/DatabaseCon.h>
24#include <xrpl/server/Wallet.h>
49 return "Revocation Manifest " + mk;
121 domain.
assign(
reinterpret_cast<char const*
>(d.data()), d.size());
144 if (!hasEphemeralKey)
147 if (!hasEphemeralSig)
150 auto const spk = st.
getFieldVL(sfSigningPubKey);
158 if (*signingKey == masterKey)
165 return Manifest(serialized, masterKey, signingKey, seq, domain);
169 JLOG(journal.
error()) <<
"Exception in " << __func__ <<
": " << ex.
what();
174template <
class Stream>
183template <
class Stream>
193 <<
";OldSeq: " << oldSeq <<
";";
250 if (!
get(st, sfSignature))
278 for (
auto const& line : blob)
286 if (r.
parse(tokenStr, token))
291 if (m.isString() && k.isString())
293 auto const key =
strUnHex(k.asString());
295 if (key && key->size() == 32)
298 .manifest = m.asString(), .validationSecret =
makeSlice(*key)};
307 JLOG(journal.
error()) <<
"Exception in " << __func__ <<
": " << ex.
what();
316 auto const iter =
map_.find(pk);
318 if (iter !=
map_.end() && !iter->second.revoked())
319 return iter->second.signingKey;
339 auto const iter =
map_.find(pk);
341 if (iter !=
map_.end() && !iter->second.revoked())
342 return iter->second.sequence;
351 auto const iter =
map_.find(pk);
353 if (iter !=
map_.end() && !iter->second.revoked())
354 return iter->second.domain;
363 auto const iter =
map_.find(pk);
365 if (iter !=
map_.end() && !iter->second.revoked())
366 return iter->second.serialized;
375 auto const iter =
map_.find(pk);
377 if (iter !=
map_.end())
378 return iter->second.revoked();
391 bool checkSignature =
true;
395 auto prewriteCheck = [
this, &m, &checkSignature](
398 XRPL_ASSERT(lock.owns_lock(),
"xrpl::ManifestCache::applyManifest::prewriteCheck : locked");
401 if (iter !=
map_.end() && m.
sequence <= iter->second.sequence)
407 if (
auto stream =
j_.debug())
414 checkSignature =
false;
417 if (
auto stream =
j_.warn())
432 if (
auto stream =
j_.warn(); stream &&
revoked)
439 JLOG(
j_.warn()) <<
to_string(m) <<
": Master key already used as ephemeral key for "
450 <<
": is not revoked and the manifest has no "
451 "signing key. Hence, the manifest is "
462 <<
": Ephemeral key already used as ephemeral key for "
470 JLOG(
j_.warn()) <<
to_string(m) <<
": Ephemeral key used as master key for "
484 auto atUntrustedCap = [
this, &m, uncapped](
auto const& iter,
auto const& lock) {
486 lock.owns_lock(),
"xrpl::ManifestCache::applyManifest::atUntrustedCap : locked");
493 if (
auto stream =
j_.debug())
498 JLOG(
j_.warn()) <<
"Untrusted manifest cap reached; " << n
499 <<
" manifests rejected so far";
510 if (atUntrustedCap(iter, sl))
513 if (
auto d = prewriteCheck(iter, sl); d.has_value())
522 if (atUntrustedCap(iter, sl))
534 if (
auto d = prewriteCheck(iter, sl); d.has_value())
540 if (iter ==
map_.end())
542 if (
auto stream =
j_.info())
559 map_.emplace(std::move(masterKey), std::move(m));
569 if (
auto stream =
j_.info())
578 *iter->second.signingKey);
588 iter->second = std::move(m);
620 load(dbCon, dbTable);
622 if (!configManifest.
empty())
627 JLOG(
j_.error()) <<
"Malformed validator_token in config";
633 JLOG(
j_.warn()) <<
"Configured manifest revokes public key";
639 JLOG(
j_.error()) <<
"Manifest in config was rejected";
644 if (!configRevocation.
empty())
649 configRevocation.
cbegin(),
650 configRevocation.
cend(),
654 for (
auto const& line : configRevocation)
659 if (!mo || !mo->revoked() ||
663 JLOG(
j_.error()) <<
"Invalid validator key revocation in config";
A generic endpoint for log messages.
Unserialize a JSON document into a Value.
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Value get(UInt index, Value const &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
LockedSociSession checkoutDb()
HashMap< PublicKey, Manifest > map_
Active manifests stored by master public key.
std::size_t const maxUntrustedCount_
Maximum number of untrusted master keys kept in the cache.
std::atomic< std::uint32_t > seq_
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.
HashMap< PublicKey, PublicKey > signingToMasterKeys_
Master public keys stored by current ephemeral public key.
std::optional< PublicKey > getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
HashSet< PublicKey > untrustedKeys_
Master keys of cached manifests for validators this node does not list.
ManifestDisposition applyManifest(Manifest m, ManifestRateLimitCapPolicy cap)
Add manifest to cache.
static constexpr std::uint64_t kUntrustedRejectCount
Number of cap rejections between summary warnings.
std::optional< std::string > getDomain(PublicKey const &pk) const
Returns domain claimed by a given public key.
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
std::optional< std::string > getManifest(PublicKey const &pk) const
Returns manifest corresponding to a given public key.
std::optional< std::uint32_t > getSequence(PublicKey const &pk) const
Returns master key's current manifest sequence.
void save(DatabaseCon &dbCon, std::string const &dbTable, std::function< bool(PublicKey const &)> const &isTrusted)
Save cached manifests to database.
std::atomic< std::uint64_t > untrustedRejectCount_
Running count of manifests rejected because the untrusted cap was full.
void promoteToTrusted(PublicKey const &pk)
Stop counting a master key against the untrusted cap.
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
Defines the fields and their attributes within a STObject.
Blob getFieldVL(SField const &field) const
std::uint32_t getFieldU32(SField const &field) const
void applyTemplate(SOTemplate const &type)
bool isFieldPresent(SField const &field) const
void set(SOTemplate const &)
UInt256 getHash(HashPrefix prefix) const
std::uint16_t getFieldU16(SField const &field) const
An immutable linear range of bytes.
bool empty() const noexcept
Return true if the byte range is empty.
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Stream & logMftAct(Stream &s, std::string const &action, PublicKey const &pk, std::uint32_t seq)
std::string base64Decode(std::string_view data)
void saveManifests(soci::session &session, std::string const &dbTable, std::function< bool(PublicKey const &)> const &isTrusted, HashMap< PublicKey, Manifest > const &map, beast::Journal j)
saveManifests Saves all given manifests to the database.
bool isProperlyFormedTomlDomain(std::string_view domain)
Determines if the given string looks like a TOML-file hosting domain.
T get(Section const §ion, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
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.
constexpr std::size_t kMaxManifestBytes
Largest a valid manifest can be, in decoded bytes.
std::string trimWhitespace(std::string str)
Remove leading and trailing ASCII whitespace.
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.
ManifestRateLimitCapPolicy
Whether a manifest counts against the 'untrusted' cache cap.
@ Uncapped
Bypasses the cap (listed/trusted or config manifests).
Slice makeSlice(std::array< T, N > const &a)
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
void getManifests(soci::session &session, std::string const &dbTable, ManifestCache &cache, beast::Journal j)
getManifests Loads a manifest from the wallet database and stores it in the cache.
std::vector< unsigned char > Blob
Storage for linear binary data.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
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.
@ UntrustedCapacity
Unlisted and limit reached.
static bool revoked(std::uint32_t sequence)
Returns true if manifest revokes master key.
PublicKey masterKey
The master key associated with this manifest.
std::string serialized
The manifest in serialized form.
Blob getMasterSignature() const
Returns manifest master key signature.
std::optional< Blob > getSignature() const
Returns manifest signature.
UInt256 hash() const
Returns hash of serialized manifest data.
std::optional< PublicKey > signingKey
The ephemeral key associated with this manifest.
std::uint32_t sequence
The sequence number of this manifest.
bool revoked() const
Returns true if manifest revokes master key.
bool verify() const
Returns true if manifest signature is valid.