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>
48 return "Revocation Manifest " + mk;
120 domain.
assign(
reinterpret_cast<char const*
>(d.data()), d.size());
143 if (!hasEphemeralKey)
146 if (!hasEphemeralSig)
149 auto const spk = st.
getFieldVL(sfSigningPubKey);
157 if (*signingKey == masterKey)
164 return Manifest(serialized, masterKey, signingKey, seq, domain);
168 JLOG(journal.
error()) <<
"Exception in " << __func__ <<
": " << ex.
what();
173template <
class Stream>
182template <
class Stream>
192 <<
";OldSeq: " << oldSeq <<
";";
249 if (!
get(st, sfSignature))
277 for (
auto const& line : blob)
285 if (r.
parse(tokenStr, token))
290 if (m.isString() && k.isString())
292 auto const key =
strUnHex(k.asString());
294 if (key && key->size() == 32)
297 .manifest = m.asString(), .validationSecret =
makeSlice(*key)};
306 JLOG(journal.
error()) <<
"Exception in " << __func__ <<
": " << ex.
what();
315 auto const iter =
map_.find(pk);
317 if (iter !=
map_.end() && !iter->second.revoked())
318 return iter->second.signingKey;
338 auto const iter =
map_.find(pk);
340 if (iter !=
map_.end() && !iter->second.revoked())
341 return iter->second.sequence;
350 auto const iter =
map_.find(pk);
352 if (iter !=
map_.end() && !iter->second.revoked())
353 return iter->second.domain;
362 auto const iter =
map_.find(pk);
364 if (iter !=
map_.end() && !iter->second.revoked())
365 return iter->second.serialized;
374 auto const iter =
map_.find(pk);
376 if (iter !=
map_.end())
377 return iter->second.revoked();
390 bool checkSignature =
true;
394 auto prewriteCheck = [
this, &m, &checkSignature](
397 XRPL_ASSERT(lock.owns_lock(),
"xrpl::ManifestCache::applyManifest::prewriteCheck : locked");
400 if (iter !=
map_.end() && m.
sequence <= iter->second.sequence)
406 if (
auto stream =
j_.debug())
413 checkSignature =
false;
416 if (
auto stream =
j_.warn())
431 if (
auto stream =
j_.warn(); stream &&
revoked)
438 JLOG(
j_.warn()) <<
to_string(m) <<
": Master key already used as ephemeral key for "
449 <<
": is not revoked and the manifest has no "
450 "signing key. Hence, the manifest is "
461 <<
": Ephemeral key already used as ephemeral key for "
469 JLOG(
j_.warn()) <<
to_string(m) <<
": Ephemeral key used as master key for "
483 auto atUntrustedCap = [
this, &m, uncapped](
auto const& iter,
auto const& lock) {
485 lock.owns_lock(),
"xrpl::ManifestCache::applyManifest::atUntrustedCap : locked");
492 if (
auto stream =
j_.debug())
497 JLOG(
j_.warn()) <<
"Untrusted manifest cap reached; " << n
498 <<
" manifests rejected so far";
509 if (atUntrustedCap(iter, sl))
512 if (
auto d = prewriteCheck(iter, sl); d.has_value())
521 if (atUntrustedCap(iter, sl))
533 if (
auto d = prewriteCheck(iter, sl); d.has_value())
539 if (iter ==
map_.end())
541 if (
auto stream =
j_.info())
558 map_.emplace(std::move(masterKey), std::move(m));
568 if (
auto stream =
j_.info())
577 *iter->second.signingKey);
587 iter->second = std::move(m);
619 load(dbCon, dbTable);
621 if (!configManifest.
empty())
626 JLOG(
j_.error()) <<
"Malformed validator_token in config";
632 JLOG(
j_.warn()) <<
"Configured manifest revokes public key";
638 JLOG(
j_.error()) <<
"Manifest in config was rejected";
643 if (!configRevocation.
empty())
648 configRevocation.
cbegin(),
649 configRevocation.
cend(),
653 for (
auto const& line : configRevocation)
658 if (!mo || !mo->revoked() ||
662 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()
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.
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.
static constexpr std::uint64_t kUntrustedRejectCount
Number of cap rejections between summary warnings.
hash_set< PublicKey > untrustedKeys_
Master keys of cached manifests for validators this node does not list.
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.
hash_map< PublicKey, PublicKey > signingToMasterKeys_
Master public keys stored by current ephemeral public key.
std::optional< std::string > getManifest(PublicKey const &pk) const
Returns manifest corresponding to a given public key.
hash_map< PublicKey, Manifest > map_
Active manifests stored by master 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)
uint256 getHash(HashPrefix prefix) const
bool isFieldPresent(SField const &field) const
void set(SOTemplate 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, hash_map< 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.
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.
uint256 hash() const
Returns hash of serialized manifest data.
bool verify() const
Returns true if manifest signature is valid.