Merge remote-tracking branch 'origin/develop' into tapanito/invariant-improvement

This commit is contained in:
Vito
2026-06-24 14:27:39 +02:00
293 changed files with 6682 additions and 5907 deletions

View File

@@ -1,248 +0,0 @@
#pragma once
#include <xrpl/basics/contract.h>
#include <boost/outcome.hpp>
#include <stdexcept>
namespace xrpl {
/** Expected is an approximation of std::expected (hoped for in C++23)
See: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html
The implementation is entirely based on boost::outcome_v2::result.
*/
// Exception thrown by an invalid access to Expected.
struct BadExpectedAccess : public std::runtime_error
{
BadExpectedAccess() : runtime_error("bad expected access")
{
}
};
namespace detail {
// Custom policy for Expected. Always throw on an invalid access.
struct ThrowPolicy : public boost::outcome_v2::policy::base
{
template <class Impl>
static constexpr void
// NOLINTNEXTLINE(readability-identifier-naming)
wide_value_check(Impl&& self)
{
if (!base::_has_value(std::forward<Impl>(self)))
Throw<BadExpectedAccess>();
}
template <class Impl>
static constexpr void
// NOLINTNEXTLINE(readability-identifier-naming)
wide_error_check(Impl&& self)
{
if (!base::_has_error(std::forward<Impl>(self)))
Throw<BadExpectedAccess>();
}
template <class Impl>
static constexpr void
// NOLINTNEXTLINE(readability-identifier-naming)
wide_exception_check(Impl&& self)
{
if (!base::_has_exception(std::forward<Impl>(self)))
Throw<BadExpectedAccess>();
}
};
} // namespace detail
// Definition of Unexpected, which is used to construct the unexpected
// return type of an Expected.
template <class E>
class Unexpected
{
public:
static_assert(!std::is_same_v<E, void>, "E must not be void");
Unexpected() = delete;
constexpr explicit Unexpected(E const& e) : val_(e)
{
}
constexpr explicit Unexpected(E&& e) : val_(std::move(e))
{
}
[[nodiscard]] constexpr E const&
value() const&
{
return val_;
}
constexpr E&
value() &
{
return val_;
}
constexpr E&&
value() &&
{
return std::move(val_);
}
[[nodiscard]] constexpr E const&&
value() const&&
{
return std::move(val_);
}
private:
E val_;
};
// Unexpected deduction guide that converts array to const*.
template <typename E, std::size_t N>
Unexpected(E (&)[N]) -> Unexpected<E const*>;
// Definition of Expected. All of the machinery comes from boost::result.
template <class T, class E>
class [[nodiscard]] Expected : private boost::outcome_v2::result<T, E, detail::ThrowPolicy>
{
using Base = boost::outcome_v2::result<T, E, detail::ThrowPolicy>;
public:
template <typename U>
requires std::convertible_to<U, T>
constexpr Expected(U&& r) : Base(boost::outcome_v2::in_place_type_t<T>{}, std::forward<U>(r))
{
}
template <typename U>
requires std::convertible_to<U, E> && (!std::is_reference_v<U>)
constexpr Expected(Unexpected<U> e)
: Base(boost::outcome_v2::in_place_type_t<E>{}, std::move(e.value()))
{
}
[[nodiscard]] constexpr bool
// NOLINTNEXTLINE(readability-identifier-naming)
has_value() const
{
return Base::has_value();
}
[[nodiscard]] constexpr T const&
value() const
{
return Base::value();
}
constexpr T&
value()
{
return Base::value();
}
[[nodiscard]] constexpr E const&
error() const&
{
return Base::error();
}
[[nodiscard]] constexpr E&
error() &
{
return Base::error();
}
[[nodiscard]] constexpr E&&
error() &&
{
return std::move(Base::error());
}
constexpr explicit
operator bool() const
{
return has_value();
}
// Add operator* and operator-> so the Expected API looks a bit more like
// what std::expected is likely to look like. See:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html
[[nodiscard]] constexpr T&
operator*()
{
return this->value();
}
[[nodiscard]] constexpr T const&
operator*() const
{
return this->value();
}
[[nodiscard]] constexpr T*
operator->()
{
return &this->value();
}
[[nodiscard]] constexpr T const*
operator->() const
{
return &this->value();
}
};
// Specialization of Expected<void, E>. Allows returning either success
// (without a value) or the reason for the failure.
template <class E>
class [[nodiscard]]
Expected<void, E> : private boost::outcome_v2::result<void, E, detail::ThrowPolicy>
{
using Base = boost::outcome_v2::result<void, E, detail::ThrowPolicy>;
public:
// The default constructor makes a successful Expected<void, E>.
// This aligns with std::expected behavior proposed in P0323R10.
constexpr Expected() : Base(boost::outcome_v2::success())
{
}
template <typename U>
requires std::convertible_to<U, E> && (!std::is_reference_v<U>)
constexpr Expected(Unexpected<U> e) : Base(E(std::move(e.value())))
{
}
[[nodiscard]] constexpr E const&
error() const&
{
return Base::error();
}
[[nodiscard]] constexpr E&
error() &
{
return Base::error();
}
[[nodiscard]] constexpr E&&
error() &&
{
return std::move(Base::error());
}
constexpr explicit
operator bool() const
{
return Base::has_value();
}
};
} // namespace xrpl

View File

@@ -408,33 +408,40 @@ public:
}
friend constexpr bool
operator<(Number const& x, Number const& y) noexcept
operator<(Number const& l, Number const& r) noexcept
{
bool const lneg = l.negative_;
bool const rneg = r.negative_;
// If the two amounts have different signs (zero is treated as positive)
// then the comparison is true iff the left is negative.
bool const lneg = x.negative_;
bool const rneg = y.negative_;
if (lneg != rneg)
return lneg;
// Both have same sign and the left is zero: the right must be
// greater than 0.
if (x.mantissa_ == 0)
return y.mantissa_ > 0;
// Both have same sign and the left is zero: both must be non-negative.
// If the right is greater than 0, then it is larger, so the comparison is true.
if (l.mantissa_ == 0)
return r.mantissa_ > 0;
// Both have same sign, the right is zero and the left is non-zero.
if (y.mantissa_ == 0)
// Both have same sign, the right is zero and the left is non-zero, so the left must be
// positive, and thus is larger, so the comparison is false.
if (r.mantissa_ == 0)
return false;
// Both have the same sign, compare by exponents:
if (x.exponent_ > y.exponent_)
if (l.exponent_ > r.exponent_)
return lneg;
if (x.exponent_ < y.exponent_)
if (l.exponent_ < r.exponent_)
return !lneg;
// If equal exponents, compare mantissas
return x.mantissa_ < y.mantissa_;
// If equal signs and exponents, compare mantissas.
if (lneg)
{
// If negative, the operator is reversed.
return l.mantissa_ > r.mantissa_;
}
return l.mantissa_ < r.mantissa_;
}
/** Return the sign of the amount */

View File

@@ -11,6 +11,7 @@
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
namespace xrpl {
@@ -95,13 +96,7 @@ strUnHex(std::size_t strSize, Iterator begin, Iterator end)
}
inline std::optional<Blob>
strUnHex(std::string const& strSrc)
{
return strUnHex(strSrc.size(), strSrc.cbegin(), strSrc.cend());
}
inline std::optional<Blob>
strViewUnHex(std::string_view strSrc)
strUnHex(std::string_view strSrc)
{
return strUnHex(strSrc.size(), strSrc.cbegin(), strSrc.cend());
}

View File

@@ -36,6 +36,7 @@
#include <cstdint>
#include <string>
#include <string_view>
namespace xrpl {
@@ -43,7 +44,7 @@ std::string
base64Encode(std::uint8_t const* data, std::size_t len);
inline std::string
base64Encode(std::string const& s)
base64Encode(std::string_view s)
{
return base64Encode(reinterpret_cast<std::uint8_t const*>(s.data()), s.size());
}

View File

@@ -5,7 +5,6 @@
#pragma once
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/contract.h>
#include <xrpl/basics/hardened_hash.h>
@@ -20,6 +19,7 @@
#include <algorithm>
#include <array>
#include <cstring>
#include <expected>
#include <type_traits>
namespace xrpl {
@@ -177,7 +177,7 @@ private:
BadChar,
};
constexpr Expected<decltype(data_), ParseResult>
constexpr std::expected<decltype(data_), ParseResult>
parseFromStringView(std::string_view sv) noexcept
{
// Local lambda that converts a single hex char to four bits and
@@ -216,7 +216,7 @@ private:
}
if (sv.size() != size() * 2)
return Unexpected(ParseResult::BadLength);
return std::unexpected(ParseResult::BadLength);
std::size_t i = 0u;
auto in = sv.begin();
@@ -227,7 +227,7 @@ private:
{
if (auto const result = hexCharToUInt(*in++, shift, accum);
result != ParseResult::Okay)
return Unexpected(result);
return std::unexpected(result);
}
ret[i++] = accum;
}

View File

@@ -1,12 +1,13 @@
#pragma once
#include <string>
#include <string_view>
namespace xrpl {
template <class Stream, class Iter>
Stream&
join(Stream& s, Iter iter, Iter end, std::string const& delimiter)
join(Stream& s, Iter iter, Iter end, std::string_view delimiter)
{
if (iter == end)
return s;

View File

@@ -1,29 +0,0 @@
#pragma once
#if XRPL_ROCKSDB_AVAILABLE
// #include <rocksdb2/port/port_posix.h>
#include <rocksdb/cache.h>
#include <rocksdb/compaction_filter.h>
#include <rocksdb/comparator.h>
#include <rocksdb/convenience.h>
#include <rocksdb/db.h>
#include <rocksdb/env.h>
#include <rocksdb/filter_policy.h>
#include <rocksdb/flush_block_policy.h>
#include <rocksdb/iterator.h>
#include <rocksdb/memtablerep.h>
#include <rocksdb/merge_operator.h>
#include <rocksdb/options.h>
#include <rocksdb/perf_context.h>
#include <rocksdb/slice.h>
#include <rocksdb/slice_transform.h>
#include <rocksdb/statistics.h>
#include <rocksdb/status.h>
#include <rocksdb/table.h>
#include <rocksdb/table_properties.h>
#include <rocksdb/transaction_log.h>
#include <rocksdb/types.h>
#include <rocksdb/universal_compaction.h>
#include <rocksdb/write_batch.h>
#endif

View File

@@ -4,7 +4,7 @@
/*
ASAN flags some false positives with sudden jumps in control flow, like
exceptions, or when encountering coroutine stack switches. This macro can be used to disable ASAN
intrumentation for specific functions.
instrumentation for specific functions.
*/
#if defined(__GNUC__) || defined(__clang__)
#define XRPL_NO_SANITIZE_ADDRESS __attribute__((no_sanitize("address", "hwaddress")))

View File

@@ -7,8 +7,11 @@
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <new>
#include <optional>
#include <span>
#include <type_traits>
namespace beast {

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/insight/CounterImpl.h>
#include <memory>
#include <utility>
namespace beast::insight {
@@ -29,7 +30,7 @@ public:
factory function in the Collector interface.
@see Collector.
*/
explicit Counter(std::shared_ptr<CounterImpl> const& impl) : impl_(impl)
explicit Counter(std::shared_ptr<CounterImpl> impl) : impl_(std::move(impl))
{
}

View File

@@ -4,6 +4,7 @@
#include <chrono>
#include <memory>
#include <utility>
namespace beast::insight {
@@ -31,7 +32,7 @@ public:
factory function in the Collector interface.
@see Collector.
*/
explicit Event(std::shared_ptr<EventImpl> const& impl) : impl_(impl)
explicit Event(std::shared_ptr<EventImpl> impl) : impl_(std::move(impl))
{
}

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/insight/GaugeImpl.h>
#include <memory>
#include <utility>
namespace beast::insight {
@@ -31,7 +32,7 @@ public:
factory function in the Collector interface.
@see Collector.
*/
explicit Gauge(std::shared_ptr<GaugeImpl> const& impl) : impl_(impl)
explicit Gauge(std::shared_ptr<GaugeImpl> impl) : impl_(std::move(impl))
{
}

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/insight/HookImpl.h>
#include <memory>
#include <utility>
namespace beast::insight {
@@ -20,7 +21,7 @@ public:
factory function in the Collector interface.
@see Collector.
*/
explicit Hook(std::shared_ptr<HookImpl> const& impl) : impl_(impl)
explicit Hook(std::shared_ptr<HookImpl> impl) : impl_(std::move(impl))
{
}

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/insight/MeterImpl.h>
#include <memory>
#include <utility>
namespace beast::insight {
@@ -28,7 +29,7 @@ public:
factory function in the Collector interface.
@see Collector.
*/
explicit Meter(std::shared_ptr<MeterImpl> const& impl) : impl_(impl)
explicit Meter(std::shared_ptr<MeterImpl> impl) : impl_(std::move(impl))
{
}

View File

@@ -41,7 +41,7 @@ private:
public:
template <class = void>
explicit Selector(ModeT mode, std::string const& pattern = "");
explicit Selector(ModeT mode, std::string pattern = "");
template <class = void>
bool
@@ -51,9 +51,9 @@ public:
//------------------------------------------------------------------------------
template <class>
Selector::Selector(ModeT mode, std::string const& pattern) : mode_(mode), pat_(pattern)
Selector::Selector(ModeT mode, std::string pattern) : mode_(mode), pat_(std::move(pattern))
{
if (mode_ == ModeT::Automatch && pattern.empty())
if (mode_ == ModeT::Automatch && pat_.empty())
mode_ = ModeT::All;
}

View File

@@ -11,6 +11,8 @@
// Macros below are copied from antithesis_sdk.h and slightly simplified
// The duplication is because Visual Studio 2019 cannot compile that header
// even with the option -Zc:__cplusplus added.
// NOTE: cond must not contain bare commas outside () or []. Commas inside {}
// are not protected by the preprocessor and would be parsed as extra arguments.
#define ALWAYS(cond, message, ...) assert((message) && (cond))
#define ALWAYS_OR_UNREACHABLE(cond, message) assert((message) && (cond))
#define SOMETIMES(cond, message, ...)
@@ -22,6 +24,8 @@
#define XRPL_ASSERT_PARTS(cond, function, description, ...) \
XRPL_ASSERT(cond, function " : " description)
#define XRPL_ASSERT_IF(guard, cond, message) XRPL_ASSERT(!(guard) || (cond), message)
// How to use the instrumentation macros:
//
// * XRPL_ASSERT if cond must be true but the line might not be reached during
@@ -29,6 +33,14 @@
// * XRPL_ASSERT_PARTS is for convenience, and works like XRPL_ASSERT, but
// splits the message param into "function" and "description", then joins
// them with " : " before passing to XRPL_ASSERT.
// * XRPL_ASSERT_IF(guard, cond, message) asserts the implication
// `guard => cond`: it can only fail when guard is true (e.g. an amendment
// is enabled) and cond is false. Unlike `if (guard) XRPL_ASSERT(...)`, the
// assertion site is always evaluated, so the fuzzer registers it
// unconditionally; cond itself is short-circuited and only evaluated when
// guard is true. NOTE: do not rely on side effects in guard — in release
// builds the assertion body is stripped, and the compiler may optimize away
// a side-effect-free guard entirely.
// * ALWAYS if cond must be true _and_ the line must be reached during fuzzing.
// Same like `assert` in normal use.
// * REACHABLE if the line must be reached during fuzzing

View File

@@ -0,0 +1,180 @@
#pragma once
namespace xrpl {
struct Sections
{
static constexpr auto kAmendments = "amendments";
static constexpr auto kAmendmentMajorityTime = "amendment_majority_time";
static constexpr auto kBetaRpcApi = "beta_rpc_api";
static constexpr auto kClusterNodes = "cluster_nodes";
static constexpr auto kCompression = "compression";
static constexpr auto kCrawl = "crawl";
static constexpr auto kDatabasePath = "database_path";
static constexpr auto kDebugLogfile = "debug_logfile";
static constexpr auto kElbSupport = "elb_support";
static constexpr auto kFeatures = "features";
static constexpr auto kFeeDefault = "fee_default";
static constexpr auto kFetchDepth = "fetch_depth";
static constexpr auto kHashrouter = "hashrouter";
static constexpr auto kImportNodeDatabase = "import_db";
static constexpr auto kInsight = "insight";
static constexpr auto kIoWorkers = "io_workers";
static constexpr auto kIps = "ips";
static constexpr auto kIpsFixed = "ips_fixed";
static constexpr auto kLedgerHistory = "ledger_history";
static constexpr auto kLedgerReplay = "ledger_replay";
static constexpr auto kLedgerTxTables = "ledger_tx_tables";
static constexpr auto kMaxTransactions = "max_transactions";
static constexpr auto kNetworkId = "network_id";
static constexpr auto kNetworkQuorum = "network_quorum";
static constexpr auto kNodeDatabase = "node_db";
static constexpr auto kNodeSeed = "node_seed";
static constexpr auto kNodeSize = "node_size";
static constexpr auto kOverlay = "overlay";
static constexpr auto kPathSearch = "path_search";
static constexpr auto kPathSearchFast = "path_search_fast";
static constexpr auto kPathSearchMax = "path_search_max";
static constexpr auto kPathSearchOld = "path_search_old";
static constexpr auto kPeerPrivate = "peer_private";
static constexpr auto kPeersInMax = "peers_in_max";
static constexpr auto kPeersMax = "peers_max";
static constexpr auto kPeersOutMax = "peers_out_max";
static constexpr auto kPerf = "perf";
static constexpr auto kPortGrpc = "port_grpc";
static constexpr auto kPortPeer = "port_peer";
static constexpr auto kPortRpc = "port_rpc";
static constexpr auto kPortWs = "port_ws";
static constexpr auto kPortWssAdmin = "port_wss_admin";
static constexpr auto kPrefetchWorkers = "prefetch_workers";
static constexpr auto kReduceRelay = "reduce_relay";
static constexpr auto kRelationalDb = "relational_db";
static constexpr auto kRelayProposals = "relay_proposals";
static constexpr auto kRelayValidations = "relay_validations";
static constexpr auto kRpcStartup = "rpc_startup";
static constexpr auto kServer = "server";
static constexpr auto kServerDomain = "server_domain";
static constexpr auto kSigningSupport = "signing_support";
static constexpr auto kSntp = "sntp_servers";
static constexpr auto kSqdb = "sqdb";
static constexpr auto kSqlite = "sqlite";
static constexpr auto kSslVerify = "ssl_verify";
static constexpr auto kSslVerifyDir = "ssl_verify_dir";
static constexpr auto kSslVerifyFile = "ssl_verify_file";
static constexpr auto kSweepInterval = "sweep_interval";
static constexpr auto kTransactionQueue = "transaction_queue";
static constexpr auto kValidationSeed = "validation_seed";
static constexpr auto kValidatorKeys = "validator_keys";
static constexpr auto kValidatorKeyRevocation = "validator_key_revocation";
static constexpr auto kValidatorListKeys = "validator_list_keys";
static constexpr auto kValidatorListSites = "validator_list_sites";
static constexpr auto kValidatorListThreshold = "validator_list_threshold";
static constexpr auto kValidatorToken = "validator_token";
static constexpr auto kValidators = "validators";
static constexpr auto kValidatorsFile = "validators_file";
static constexpr auto kVetoAmendments = "veto_amendments";
static constexpr auto kVl = "vl";
static constexpr auto kVoting = "voting";
static constexpr auto kWorkers = "workers";
};
struct Keys
{
static constexpr auto kAccountReserve = "account_reserve";
static constexpr auto kAddress = "address";
static constexpr auto kAdmin = "admin";
static constexpr auto kAdminPassword = "admin_password";
static constexpr auto kAdminUser = "admin_user";
static constexpr auto kAdvisoryDelete = "advisory_delete";
static constexpr auto kAgeThresholdSeconds = "age_threshold_seconds";
static constexpr auto kBackOff = "backOff";
static constexpr auto kBackOffMilliseconds = "back_off_milliseconds";
static constexpr auto kBackend = "backend";
static constexpr auto kBbtOptions = "bbt_options";
static constexpr auto kBgThreads = "bg_threads";
static constexpr auto kBlockSize = "block_size";
static constexpr auto kCacheAge = "cache_age";
static constexpr auto kCacheMb = "cache_mb";
static constexpr auto kCacheSize = "cache_size";
static constexpr auto kClientMaxWindowBits = "client_max_window_bits";
static constexpr auto kClientNoContextTakeover = "client_no_context_takeover";
static constexpr auto kCompressLevel = "compress_level";
static constexpr auto kCounts = "counts";
static constexpr auto kDeleteBatch = "delete_batch";
static constexpr auto kEarliestSeq = "earliest_seq";
static constexpr auto kFastLoad = "fast_load";
static constexpr auto kFileSizeMb = "file_size_mb";
static constexpr auto kFileSizeMult = "file_size_mult";
static constexpr auto kFilterBits = "filter_bits";
static constexpr auto kFilterFull = "filter_full";
static constexpr auto kHardSet = "hard_set";
static constexpr auto kHighThreads = "high_threads";
static constexpr auto kHoldTime = "hold_time";
static constexpr auto kIp = "ip";
static constexpr auto kJournalMode = "journal_mode";
static constexpr auto kJournalSizeLimit = "journal_size_limit";
static constexpr auto kLedgersInQueue = "ledgers_in_queue";
static constexpr auto kLimit = "limit";
static constexpr auto kLogInterval = "log_interval";
static constexpr auto kMaxDivergedTime = "max_diverged_time";
static constexpr auto kMaxLedgerCountsToStore = "max_ledger_counts_to_store";
static constexpr auto kMaxUnknownTime = "max_unknown_time";
static constexpr auto kMaximumTxnInLedger = "maximum_txn_in_ledger";
static constexpr auto kMaximumTxnPerAccount = "maximum_txn_per_account";
static constexpr auto kMemoryLevel = "memory_level";
static constexpr auto kMinLedgersToComputeSizeLimit = "min_ledgers_to_compute_size_limit";
static constexpr auto kMinimumEscalationMultiplier = "minimum_escalation_multiplier";
static constexpr auto kMinimumLastLedgerBuffer = "minimum_last_ledger_buffer";
static constexpr auto kMinimumQueueSize = "minimum_queue_size";
static constexpr auto kMinimumTxnInLedger = "minimum_txn_in_ledger";
static constexpr auto kMinimumTxnInLedgerStandalone = "minimum_txn_in_ledger_standalone";
static constexpr auto kNormalConsensusIncreasePercent = "normal_consensus_increase_percent";
static constexpr auto kNudbBlockSize = "nudb_block_size";
static constexpr auto kOnlineDelete = "online_delete";
static constexpr auto kOpenFiles = "open_files";
static constexpr auto kOptions = "options";
static constexpr auto kOverlay = "overlay";
static constexpr auto kOwnerReserve = "owner_reserve";
static constexpr auto kPageSize = "page_size";
static constexpr auto kPassword = "password";
static constexpr auto kPath = "path";
static constexpr auto kPermessageDeflate = "permessage_deflate";
static constexpr auto kPort = "port";
static constexpr auto kPrefix = "prefix";
static constexpr auto kProtocol = "protocol";
static constexpr auto kRecoveryWaitSeconds = "recovery_wait_seconds";
static constexpr auto kReferenceFee = "reference_fee";
static constexpr auto kRelayTime = "relay_time";
static constexpr auto kRetrySequencePercent = "retry_sequence_percent";
static constexpr auto kRqBundle = "rq_bundle";
static constexpr auto kSafetyLevel = "safety_level";
static constexpr auto kSecureGateway = "secure_gateway";
static constexpr auto kSendQueueLimit = "send_queue_limit";
static constexpr auto kServer = "server";
static constexpr auto kServerMaxWindowBits = "server_max_window_bits";
static constexpr auto kServerNoContextTakeover = "server_no_context_takeover";
static constexpr auto kSlowConsensusDecreasePercent = "slow_consensus_decrease_percent";
static constexpr auto kSslCert = "ssl_cert";
static constexpr auto kSslCertChain = "ssl_cert_chain";
static constexpr auto kSslChain = "ssl_chain";
static constexpr auto kSslCiphers = "ssl_ciphers";
static constexpr auto kSslClientCa = "ssl_client_ca";
static constexpr auto kSslKey = "ssl_key";
static constexpr auto kSynchronous = "synchronous";
static constexpr auto kTargetTxnInLedger = "target_txn_in_ledger";
static constexpr auto kTempStore = "temp_store";
static constexpr auto kTxEnable = "tx_enable";
static constexpr auto kTxMetrics = "tx_metrics";
static constexpr auto kTxMinPeers = "tx_min_peers";
static constexpr auto kTxRelayPercentage = "tx_relay_percentage";
static constexpr auto kType = "type";
static constexpr auto kUniversalCompaction = "universal_compaction";
static constexpr auto kUnl = "unl";
static constexpr auto kUseTxTables = "use_tx_tables";
static constexpr auto kUser = "user";
static constexpr auto kVpBaseSquelchEnable = "vp_base_squelch_enable";
static constexpr auto kVpBaseSquelchMaxSelectedPeers = "vp_base_squelch_max_selected_peers";
static constexpr auto kVpEnable = "vp_enable";
};
} // namespace xrpl

View File

@@ -1,6 +1,5 @@
#pragma once
#include <xrpl/basics/BasicConfig.h>
#include <xrpl/core/JobTypes.h>
#include <xrpl/json/json_value.h>
@@ -18,6 +17,7 @@ class Journal;
namespace xrpl {
class Application;
class Section;
namespace perf {
/**

View File

@@ -1,6 +1,7 @@
#pragma once
#include <string>
#include <string_view>
#include <vector>
namespace xrpl {
@@ -34,7 +35,7 @@ private:
static void
standard(std::string& strWord);
static int
wsrch(std::string const& strWord, int iMin, int iMax);
wsrch(std::string_view strWord, int iMin, int iMax);
static int
etob(std::string& strData, std::vector<std::string> vsHuman);

View File

@@ -1,49 +0,0 @@
#pragma once
#include <xrpl/protocol/MultiApiJson.h>
#include <xrpl/server/InfoSub.h>
#include <memory>
#include <mutex>
namespace xrpl {
/** Listen to public/subscribe messages from a book. */
class BookListeners
{
public:
using pointer = std::shared_ptr<BookListeners>;
BookListeners() = default;
/** Add a new subscription for this book
*/
void
addSubscriber(InfoSub::ref sub);
/** Stop publishing to a subscriber
*/
void
removeSubscriber(std::uint64_t sub);
/** Publish a transaction to subscribers
Publish a transaction to clients subscribed to changes on this book.
Uses havePublished to prevent sending duplicate transactions to clients
that have subscribed to multiple books.
@param jvObj JSON transaction data to publish
@param havePublished InfoSub sequence numbers that have already
published this transaction.
*/
void
publish(MultiApiJson const& jvObj, hash_set<std::uint64_t>& havePublished);
private:
std::recursive_mutex lock_;
hash_map<std::uint64_t, InfoSub::wptr> listeners_;
};
} // namespace xrpl

View File

@@ -93,7 +93,7 @@ public:
}
void
insert(std::shared_ptr<STTx const> const& txn);
insert(std::shared_ptr<STTx const> txn);
// Pops the next transaction on account that follows seqProx in the
// sort order. Normally called when a transaction is successfully

View File

@@ -1,11 +1,11 @@
#pragma once
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/AcceptedLedgerTx.h>
#include <xrpl/ledger/BookListeners.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Book.h>
#include <xrpl/protocol/MultiApiJson.h>
#include <xrpl/protocol/UintTypes.h>
#include <memory>
@@ -77,34 +77,24 @@ public:
*/
virtual bool
isBookToXRP(Asset const& asset, std::optional<Domain> const& domain = std::nullopt) = 0;
/**
* Process a transaction for order book tracking.
* @param ledger The ledger the transaction was applied to
* @param alTx The transaction to process
* @param jvObj The JSON object of the transaction
*/
virtual void
processTxn(
std::shared_ptr<ReadView const> const& ledger,
AcceptedLedgerTx const& alTx,
MultiApiJson const& jvObj) = 0;
/**
* Get the book listeners for a book.
* @param book The book to get the listeners for
* @return The book listeners for the book
*/
virtual BookListeners::pointer
getBookListeners(Book const&) = 0;
/**
* Create a new book listeners for a book.
* @param book The book to create the listeners for
* @return The new book listeners for the book
*/
virtual BookListeners::pointer
makeBookListeners(Book const&) = 0;
};
/** Extract the set of books affected by a transaction.
*
* Walks the transaction's metadata nodes and collects every order book
* whose offers were created, modified, or deleted. Used by NetworkOPs to
* fan transaction notifications out to book subscribers.
*
* @param alTx The accepted ledger transaction to inspect.
* @param j Journal used to log per-node parsing failures. Inspecting an
* offer node can throw if a required field is missing; in that
* case the bad node is skipped and a warn-level message is
* emitted via @p j. Other affected books in the same transaction
* are still returned.
* @return The set of books whose offers were created, modified, or
* deleted. May be empty for non-offer transactions.
*/
hash_set<Book>
affectedBooks(AcceptedLedgerTx const& alTx, beast::Journal const& j);
} // namespace xrpl

View File

@@ -1,6 +1,5 @@
#pragma once
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/Log.h>
#include <xrpl/basics/Number.h>
#include <xrpl/beast/utility/Journal.h>
@@ -18,6 +17,8 @@
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <expected>
namespace xrpl {
namespace detail {
@@ -36,6 +37,8 @@ reduceOffer(auto const& amount)
enum class IsDeposit : bool { No = false, Yes = true };
inline Number const kAMMInvariantRelativeTolerance{1, -11};
/** Calculate LP Tokens given AMM pool reserves.
* @param asset1 AMM one side of the pool reserve
* @param asset2 AMM another side of the pool reserve
@@ -737,11 +740,35 @@ ammPoolHolds(
AuthHandling authHandling,
beast::Journal const j);
/** Check AMM pool product invariant after an AMM operation that changes LP tokens
* (deposit/withdraw/clawback) from an already calculated pool product mean.
* Returns tecPRECISION_LOSS if poolProductMean < newLPTokenBalance beyond the
* invariant tolerance,
* tesSUCCESS otherwise. Skips check when newLPTokenBalance is zero (last withdrawal).
*/
TER
checkAMMPrecisionLoss(Number const& poolProductMean, STAmount const& newLPTokenBalance);
/** Check AMM pool product invariant after an AMM operation that changes LP tokens
* (deposit/withdraw/clawback).
* Returns tecPRECISION_LOSS if sqrt(asset1 * asset2) < newLPTokenBalance beyond
* the invariant tolerance,
* tesSUCCESS otherwise. Skips check when newLPTokenBalance is zero (last withdrawal).
*/
TER
checkAMMPrecisionLoss(
ReadView const& view,
AccountID const& ammAccountID,
Asset const& asset1,
Asset const& asset2,
STAmount const& newLPTokenBalance,
beast::Journal const j);
/** Get AMM pool and LP token balances. If both optIssue are
* provided then they are used as the AMM token pair issues.
* Otherwise the missing issues are fetched from ammSle.
*/
Expected<std::tuple<STAmount, STAmount, STAmount>, TER>
std::expected<std::tuple<STAmount, STAmount, STAmount>, TER>
ammHolds(
ReadView const& view,
SLE const& ammSle,
@@ -801,14 +828,14 @@ initializeFeeAuctionVote(
* otherwise. Return tecINTERNAL if encountered an unexpected condition,
* for instance Liquidity Provider has more than one LPToken trustline.
*/
Expected<bool, TER>
std::expected<bool, TER>
isOnlyLiquidityProvider(ReadView const& view, Issue const& ammIssue, AccountID const& lpAccount);
/** Due to rounding, the LPTokenBalance of the last LP might
* not match the LP's trustline balance. If it's within the tolerance,
* update LPTokenBalance to match the LP's trustline balance.
*/
Expected<bool, TER>
std::expected<bool, TER>
verifyAndAdjustLPTokenBalance(
Sandbox& sb,
STAmount const& lpTokens,

View File

@@ -1,6 +1,5 @@
#pragma once
#include <xrpl/basics/Expected.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
@@ -9,6 +8,7 @@
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>
#include <expected>
#include <set>
#include <vector>
@@ -91,7 +91,7 @@ isPseudoAccount(
* before using a field. The amendment check is **not** performed in
* createPseudoAccount.
*/
[[nodiscard]] Expected<SLE::pointer, TER>
[[nodiscard]] std::expected<SLE::pointer, TER>
createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField);
/** Checks the destination and tag.

View File

@@ -36,13 +36,13 @@ checkFields(STTx const& tx, beast::Journal j);
TER
valid(STTx const& tx, ReadView const& view, AccountID const& src, beast::Journal j);
// Check if subject has any credential maching the given domain. If you call it
// Check if subject has any credential matching the given domain. If you call it
// in preclaim and it returns tecEXPIRED, you should call verifyValidDomain in
// doApply. This will ensure that expired credentials are deleted.
TER
validDomain(ReadView const& view, uint256 domainID, AccountID const& subject);
// This function is only called when we about to return tecNO_PERMISSION
// This function is only called when we are about to return tecNO_PERMISSION
// because all the checks for the DepositPreauth authorization failed.
TER
authorizedDepositPreauth(ReadView const& view, STVector256 const& ctx, AccountID const& dst);
@@ -58,7 +58,7 @@ checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j);
} // namespace credentials
// Check expired credentials and for credentials maching DomainID of the ledger
// Check expired credentials and for credentials matching DomainID of the ledger
// object
TER
verifyValidDomain(ApplyView& view, AccountID const& account, uint256 domainID, beast::Journal j);

View File

@@ -23,13 +23,9 @@ checkTxPermission(SLE::const_ref delegate, STTx const& tx);
* @param delegate The delegate account.
* @param type Used to determine which granted granular permissions to load,
* based on the transaction type.
* @param granularPermissions Granted granular permissions tied to the
* transaction type.
* @return the granted granular permissions tied to the transaction type.
*/
void
loadGranularPermission(
SLE::const_ref delegate,
TxType const& type,
std::unordered_set<GranularPermissionType>& granularPermissions);
std::unordered_set<GranularPermissionType>
getGranularPermission(SLE::const_ref delegate, TxType const& type);
} // namespace xrpl

View File

@@ -4,6 +4,7 @@
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/st.h>
#include <expected>
#include <string_view>
namespace xrpl {
@@ -397,7 +398,7 @@ struct LoanStateDeltas
nonNegative();
};
Expected<std::pair<LoanPaymentParts, LoanProperties>, TER>
std::expected<std::pair<LoanPaymentParts, LoanProperties>, TER>
tryOverpayment(
Rules const& rules,
Asset const& asset,
@@ -523,7 +524,7 @@ isRounded(Asset const& asset, Number const& value, std::int32_t scale);
// potential extra work at the end.
enum class LoanPaymentType { Regular = 0, Late, Full, Overpayment };
Expected<LoanPaymentParts, TER>
std::expected<LoanPaymentParts, TER>
loanMakePayment(
Asset const& asset,
ApplyView& view,

View File

@@ -5,9 +5,45 @@
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/UintTypes.h>
#include <cstdint>
#include <memory>
#include <optional>
namespace xrpl {
/** Close a payment channel and return its remaining funds to the channel owner.
*
* @param slep The SLE for the PayChannel object to close.
* @param view The apply view in which ledger state modifications are made.
* @param key The ledger key identifying the PayChannel entry.
* @param j Journal used for fatal-level diagnostic messages.
* @return tesSUCCESS on success; tefBAD_LEDGER if a directory removal
* fails; tefINTERNAL if the source account SLE cannot be found.
*/
TER
closeChannel(SLE::ref slep, ApplyView& view, uint256 const& key, beast::Journal j);
/** Add two uint32_t values with saturation at UINT32_MAX.
*
* @param rules The current ledger rules used to check amendment status.
* @param lhs Left-hand operand.
* @param rhs Right-hand operand.
* @return @p lhs + @p rhs, saturated at UINT32_MAX when the amendment
* is active.
*/
uint32_t
saturatingAdd(Rules const& rules, uint32_t const lhs, uint32_t const rhs);
/** Determine whether a payment channel time field represents an expired time.
*
* @param view The apply view providing the parent close time and rules.
* @param timeField The optional expiry timestamp (seconds since the XRP
* Ledger epoch). If empty, the function returns false.
* @return @c true if @p timeField is set and the indicated time is
* in the past relative to the view's parent close time;
* @c false otherwise.
*/
bool
isChannelExpired(ApplyView const& view, std::optional<std::uint32_t> timeField);
} // namespace xrpl

View File

@@ -1,6 +1,5 @@
#pragma once
#include <xrpl/basics/BasicConfig.h>
#include <xrpl/basics/Log.h>
#include <xrpl/basics/TaggedCache.ipp>
#include <xrpl/nodestore/Backend.h>
@@ -10,6 +9,10 @@
#include <condition_variable>
namespace xrpl {
class Section;
} // namespace xrpl
namespace xrpl::NodeStore {
/** Persistency layer for NodeObject

View File

@@ -1,12 +1,15 @@
#pragma once
#include <xrpl/basics/BasicConfig.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/nodestore/Backend.h>
#include <xrpl/nodestore/Scheduler.h>
#include <nudb/store.hpp>
namespace xrpl {
class Section;
} // namespace xrpl
namespace xrpl::NodeStore {
/** Base class for backend factories. */

View File

@@ -2,6 +2,8 @@
#include <xrpl/basics/TaggedCache.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/config/BasicConfig.h>
#include <xrpl/config/Constants.h>
#include <xrpl/nodestore/Database.h>
namespace xrpl::NodeStore {
@@ -24,16 +26,16 @@ public:
{
std::optional<int> cacheSize, cacheAge;
if (config.exists("cache_size"))
if (config.exists(Keys::kCacheSize))
{
cacheSize = get<int>(config, "cache_size");
cacheSize = get<int>(config, Keys::kCacheSize);
if (cacheSize.value() < 0)
Throw<std::runtime_error>("Specified negative value for cache_size");
}
if (config.exists("cache_age"))
if (config.exists(Keys::kCacheAge))
{
cacheAge = get<int>(config, "cache_age");
cacheAge = get<int>(config, Keys::kCacheAge);
if (cacheAge.value() < 0)
Throw<std::runtime_error>("Specified negative value for cache_age");
}

View File

@@ -65,7 +65,7 @@ invalidAMMAssetPair(
std::optional<std::uint8_t>
ammAuctionTimeSlot(std::uint64_t current, STObject const& auctionSlot);
/** Return true if required AMM amendments are enabled
/** Return true if required AMM amendment is enabled
*/
bool
ammEnabled(Rules const&);

View File

@@ -102,25 +102,32 @@ getAPIVersionNumber(json::Value const& jv, bool betaEnabled)
json::Value const maxVersion(
betaEnabled ? RPC::kApiBetaVersion : RPC::kApiMaximumSupportedVersion);
if (jv.isObject())
if (!jv.isObject() || !jv.isMember(jss::api_version))
return RPC::kApiVersionIfUnspecified;
try
{
if (jv.isMember(jss::api_version))
auto const& rawVersion = jv[jss::api_version];
switch (rawVersion.type())
{
auto const specifiedVersion = jv[jss::api_version];
if (!specifiedVersion.isInt() && !specifiedVersion.isUInt())
{
return RPC::kApiInvalidVersion;
case json::ValueType::Int:
if (rawVersion.asInt() < 0)
return RPC::kApiInvalidVersion;
[[fallthrough]];
case json::ValueType::UInt: {
auto const apiVersion = rawVersion.asUInt();
if (apiVersion < kMinVersion || apiVersion > maxVersion)
return RPC::kApiInvalidVersion;
return apiVersion;
}
auto const specifiedVersionInt = specifiedVersion.asInt();
if (specifiedVersionInt < kMinVersion || specifiedVersionInt > maxVersion)
{
default:
return RPC::kApiInvalidVersion;
}
return specifiedVersionInt;
}
}
return RPC::kApiVersionIfUnspecified;
catch (...)
{
return RPC::kApiInvalidVersion;
}
}
} // namespace RPC

View File

@@ -1,6 +1,5 @@
#pragma once
#include <xrpl/basics/LocalValue.h>
#include <xrpl/basics/Number.h>
#include <xrpl/beast/utility/Zero.h>
@@ -179,36 +178,4 @@ to_string(IOUAmount const& amount);
IOUAmount
mulRatio(IOUAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundUp);
// Since many uses of the number class do not have access to a ledger,
// getSTNumberSwitchover needs to be globally accessible.
bool
getSTNumberSwitchover();
void
setSTNumberSwitchover(bool v);
/** RAII class to set and restore the Number switchover.
*/
class NumberSO
{
bool saved_;
public:
~NumberSO()
{
setSTNumberSwitchover(saved_);
}
NumberSO(NumberSO const&) = delete;
NumberSO&
operator=(NumberSO const&) = delete;
explicit NumberSO(bool v) : saved_(getSTNumberSwitchover())
{
setSTNumberSwitchover(v);
}
};
} // namespace xrpl

View File

@@ -180,12 +180,12 @@ enum LedgerEntryType : std::uint16_t {
LSF_FLAG(lsfMPTCanClawback, 0x00000040)) \
\
LEDGER_OBJECT(MPTokenIssuanceMutable, \
LSF_FLAG(lsmfMPTCanMutateCanLock, 0x00000002) \
LSF_FLAG(lsmfMPTCanMutateRequireAuth, 0x00000004) \
LSF_FLAG(lsmfMPTCanMutateCanEscrow, 0x00000008) \
LSF_FLAG(lsmfMPTCanMutateCanTrade, 0x00000010) \
LSF_FLAG(lsmfMPTCanMutateCanTransfer, 0x00000020) \
LSF_FLAG(lsmfMPTCanMutateCanClawback, 0x00000040) \
LSF_FLAG(lsmfMPTCanEnableCanLock, 0x00000002) \
LSF_FLAG(lsmfMPTCanEnableRequireAuth, 0x00000004) \
LSF_FLAG(lsmfMPTCanEnableCanEscrow, 0x00000008) \
LSF_FLAG(lsmfMPTCanEnableCanTrade, 0x00000010) \
LSF_FLAG(lsmfMPTCanEnableCanTransfer, 0x00000020) \
LSF_FLAG(lsmfMPTCanEnableCanClawback, 0x00000040) \
LSF_FLAG(lsmfMPTCanMutateMetadata, 0x00010000) \
LSF_FLAG(lsmfMPTCanMutateTransferFee, 0x00020000)) \
\

View File

@@ -7,8 +7,13 @@
#include <optional>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace xrpl {
class STTx;
/**
* We have both transaction type permissions and granular type permissions.
* Since we will reuse the TransactionFormats to parse the Transaction
@@ -19,15 +24,15 @@ namespace xrpl {
// Macro-generated, complex
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum GranularPermissionType : std::uint32_t {
#pragma push_macro("PERMISSION")
#undef PERMISSION
#pragma push_macro("GRANULAR_PERMISSION")
#undef GRANULAR_PERMISSION
#define PERMISSION(type, txType, value) type = (value),
#define GRANULAR_PERMISSION(name, txType, value, ...) name = (value),
#include <xrpl/protocol/detail/permissions.macro>
#undef PERMISSION
#pragma pop_macro("PERMISSION")
#undef GRANULAR_PERMISSION
#pragma pop_macro("GRANULAR_PERMISSION")
};
// Injected bare enumerators (xrpl::delegable / xrpl::notDelegable) are required by preprocessor
@@ -40,15 +45,30 @@ class Permission
private:
Permission();
std::unordered_map<std::uint16_t, uint256> txFeatureMap_;
struct GranularPermissionEntry
{
std::string name;
TxType txType;
std::uint32_t permittedFlags;
SOTemplate permittedFields;
std::unordered_map<std::uint16_t, Delegation> delegableTx_;
GranularPermissionEntry(
std::string name,
TxType txType,
std::uint32_t permittedFlags,
std::vector<SOElement> fields);
};
std::unordered_map<std::string, GranularPermissionType> granularPermissionMap_;
struct TxDelegationEntry
{
uint256 amendment;
Delegation delegable{NotDelegable};
};
std::unordered_map<GranularPermissionType, std::string> granularNameMap_;
std::unordered_map<GranularPermissionType, TxType> granularTxTypeMap_;
std::unordered_set<TxType> granularTxTypes_;
std::unordered_map<TxType, TxDelegationEntry> txDelegationMap_;
std::unordered_map<std::string, GranularPermissionType> granularPermissionsByName_;
std::unordered_map<GranularPermissionType, GranularPermissionEntry> granularPermissions_;
public:
static Permission const&
@@ -59,30 +79,52 @@ public:
operator=(Permission const&) = delete;
[[nodiscard]] std::optional<std::string>
getPermissionName(std::uint32_t const value) const;
getPermissionName(std::uint32_t value) const;
[[nodiscard]] std::optional<std::uint32_t>
getGranularValue(std::string const& name) const;
[[nodiscard]] std::optional<std::string>
getGranularName(GranularPermissionType const& value) const;
getGranularName(GranularPermissionType value) const;
[[nodiscard]] std::optional<TxType>
getGranularTxType(GranularPermissionType const& gpType) const;
getGranularTxType(GranularPermissionType gpType) const;
// Returns a reference to avoid copying uint256 - 32 bytes. std::optional
// cannot hold references directly, so std::reference_wrapper is used.
[[nodiscard]] std::optional<std::reference_wrapper<uint256 const>>
getTxFeature(TxType txType) const;
[[nodiscard]] bool
isDelegable(std::uint32_t const& permissionValue, Rules const& rules) const;
isDelegable(std::uint32_t permissionValue, Rules const& rules) const;
[[nodiscard]] bool
hasGranularPermissions(TxType txType) const;
// for tx level permission, permission value is equal to tx type plus one
static uint32_t
txToPermissionType(TxType const& type);
[[nodiscard]] static uint32_t
txToPermissionType(TxType type);
// tx type value is permission value minus one
static TxType
permissionToTxType(uint32_t const& value);
[[nodiscard]] static TxType
permissionToTxType(std::uint32_t value);
/**
* @brief Verifies a delegated transaction against its granular permission template.
*
* @note WARNING: Do not move this check before standard transaction-level
* format checks, which is in preclaim. This function assumes the transaction's
* base structural integrity (fees, sequence, signatures) has already been
* validated.
*
* @param tx The transaction to verify.
* @param heldPermissions The granular permissions that the sender hold.
* @return true if the transaction fields and flags comply with the granular template.
*/
[[nodiscard]] bool
checkGranularSandbox(
STTx const& tx,
std::unordered_set<GranularPermissionType> const& heldPermissions) const;
};
} // namespace xrpl

View File

@@ -122,7 +122,6 @@ private:
std::optional<Rules> saved_;
};
class NumberSO;
class NumberMantissaScaleGuard;
bool
@@ -131,7 +130,6 @@ useRulesGuards(Rules const& rules);
void
createGuards(
Rules const& rules,
std::optional<NumberSO>& stNumberSO,
std::optional<CurrentTransactionRulesGuard>& rulesGuard,
std::optional<NumberMantissaScaleGuard>& mantissaScaleGuard);

View File

@@ -1,6 +1,5 @@
#pragma once
#include <xrpl/basics/Expected.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/PublicKey.h>
#include <xrpl/protocol/Rules.h>
@@ -11,6 +10,7 @@
#include <boost/container/flat_set.hpp>
#include <expected>
#include <functional>
namespace xrpl {
@@ -108,10 +108,10 @@ public:
@param rules The current ledger rules.
@return `true` if valid signature. If invalid, the error message string.
*/
Expected<void, std::string>
std::expected<void, std::string>
checkSign(Rules const& rules) const;
Expected<void, std::string>
std::expected<void, std::string>
checkBatchSign(Rules const& rules) const;
// SQL Functions with metadata.
@@ -138,19 +138,19 @@ private:
Will be *this more often than not.
@return `true` if valid signature. If invalid, the error message string.
*/
Expected<void, std::string>
std::expected<void, std::string>
checkSign(Rules const& rules, STObject const& sigObject) const;
Expected<void, std::string>
std::expected<void, std::string>
checkSingleSign(STObject const& sigObject) const;
Expected<void, std::string>
std::expected<void, std::string>
checkMultiSign(Rules const& rules, STObject const& sigObject) const;
Expected<void, std::string>
std::expected<void, std::string>
checkBatchSingleSign(STObject const& batchSigner) const;
Expected<void, std::string>
std::expected<void, std::string>
checkBatchMultiSign(STObject const& batchSigner, Rules const& rules) const;
STBase*

View File

@@ -17,8 +17,8 @@ public:
STVector256() = default;
explicit STVector256(SField const& n);
explicit STVector256(std::vector<uint256> const& vector);
STVector256(SField const& n, std::vector<uint256> const& vector);
explicit STVector256(std::vector<uint256> vector);
STVector256(SField const& n, std::vector<uint256> vector);
STVector256(SerialIter& sit, SField const& name);
[[nodiscard]] SerializedTypeID
@@ -103,12 +103,12 @@ inline STVector256::STVector256(SField const& n) : STBase(n)
{
}
inline STVector256::STVector256(std::vector<uint256> const& vector) : value_(vector)
inline STVector256::STVector256(std::vector<uint256> vector) : value_(std::move(vector))
{
}
inline STVector256::STVector256(SField const& n, std::vector<uint256> const& vector)
: STBase(n), value_(vector)
inline STVector256::STVector256(SField const& n, std::vector<uint256> vector)
: STBase(n), value_(std::move(vector))
{
}

View File

@@ -341,38 +341,32 @@ inline constexpr FlagValue tfTrustSetPermissionMask =
// MPTokenIssuanceCreate MutableFlags:
// Indicating specific fields or flags may be changed after issuance.
inline constexpr FlagValue tmfMPTCanMutateCanLock = lsmfMPTCanMutateCanLock;
inline constexpr FlagValue tmfMPTCanMutateRequireAuth = lsmfMPTCanMutateRequireAuth;
inline constexpr FlagValue tmfMPTCanMutateCanEscrow = lsmfMPTCanMutateCanEscrow;
inline constexpr FlagValue tmfMPTCanMutateCanTrade = lsmfMPTCanMutateCanTrade;
inline constexpr FlagValue tmfMPTCanMutateCanTransfer = lsmfMPTCanMutateCanTransfer;
inline constexpr FlagValue tmfMPTCanMutateCanClawback = lsmfMPTCanMutateCanClawback;
inline constexpr FlagValue tmfMPTCanEnableCanLock = lsmfMPTCanEnableCanLock;
inline constexpr FlagValue tmfMPTCanEnableRequireAuth = lsmfMPTCanEnableRequireAuth;
inline constexpr FlagValue tmfMPTCanEnableCanEscrow = lsmfMPTCanEnableCanEscrow;
inline constexpr FlagValue tmfMPTCanEnableCanTrade = lsmfMPTCanEnableCanTrade;
inline constexpr FlagValue tmfMPTCanEnableCanTransfer = lsmfMPTCanEnableCanTransfer;
inline constexpr FlagValue tmfMPTCanEnableCanClawback = lsmfMPTCanEnableCanClawback;
inline constexpr FlagValue tmfMPTCanMutateMetadata = lsmfMPTCanMutateMetadata;
inline constexpr FlagValue tmfMPTCanMutateTransferFee = lsmfMPTCanMutateTransferFee;
inline constexpr FlagValue tmfMPTokenIssuanceCreateMutableMask =
~(tmfMPTCanMutateCanLock | tmfMPTCanMutateRequireAuth | tmfMPTCanMutateCanEscrow |
tmfMPTCanMutateCanTrade | tmfMPTCanMutateCanTransfer | tmfMPTCanMutateCanClawback |
~(tmfMPTCanEnableCanLock | tmfMPTCanEnableRequireAuth | tmfMPTCanEnableCanEscrow |
tmfMPTCanEnableCanTrade | tmfMPTCanEnableCanTransfer | tmfMPTCanEnableCanClawback |
tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee);
// MPTokenIssuanceSet MutableFlags:
// Set or Clear flags.
// Enable mutable capability flags. These flags are one-way: once enabled,
// the corresponding capability cannot be disabled by MPTokenIssuanceSet.
inline constexpr FlagValue tmfMPTSetCanLock = 0x00000001;
inline constexpr FlagValue tmfMPTClearCanLock = 0x00000002;
inline constexpr FlagValue tmfMPTSetRequireAuth = 0x00000004;
inline constexpr FlagValue tmfMPTClearRequireAuth = 0x00000008;
inline constexpr FlagValue tmfMPTSetCanEscrow = 0x00000010;
inline constexpr FlagValue tmfMPTClearCanEscrow = 0x00000020;
inline constexpr FlagValue tmfMPTSetCanTrade = 0x00000040;
inline constexpr FlagValue tmfMPTClearCanTrade = 0x00000080;
inline constexpr FlagValue tmfMPTSetCanTransfer = 0x00000100;
inline constexpr FlagValue tmfMPTClearCanTransfer = 0x00000200;
inline constexpr FlagValue tmfMPTSetCanClawback = 0x00000400;
inline constexpr FlagValue tmfMPTClearCanClawback = 0x00000800;
inline constexpr FlagValue tmfMPTokenIssuanceSetMutableMask = ~(
tmfMPTSetCanLock | tmfMPTClearCanLock | tmfMPTSetRequireAuth | tmfMPTClearRequireAuth |
tmfMPTSetCanEscrow | tmfMPTClearCanEscrow | tmfMPTSetCanTrade | tmfMPTClearCanTrade |
tmfMPTSetCanTransfer | tmfMPTClearCanTransfer | tmfMPTSetCanClawback | tmfMPTClearCanClawback);
inline constexpr FlagValue tmfMPTSetRequireAuth = 0x00000002;
inline constexpr FlagValue tmfMPTSetCanEscrow = 0x00000004;
inline constexpr FlagValue tmfMPTSetCanTrade = 0x00000008;
inline constexpr FlagValue tmfMPTSetCanTransfer = 0x00000010;
inline constexpr FlagValue tmfMPTSetCanClawback = 0x00000020;
inline constexpr FlagValue tmfMPTokenIssuanceSetMutableMask =
~(tmfMPTSetCanLock | tmfMPTSetRequireAuth | tmfMPTSetCanEscrow | tmfMPTSetCanTrade |
tmfMPTSetCanTransfer | tmfMPTSetCanClawback);
// Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between accounts allowed a
// TrustLine to be added to the issuer of that token without explicit permission from that issuer.

View File

@@ -1,7 +1,6 @@
#pragma once
#include <xrpl/basics/Buffer.h>
#include <xrpl/basics/Expected.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/PublicKey.h>
@@ -15,6 +14,7 @@
#include <boost/container/vector.hpp>
#include <cstddef>
#include <expected>
#include <utility>
#include <vector>

View File

@@ -37,7 +37,7 @@ private:
// The largest "small object" we can accommodate
static constexpr std::size_t kMaxSize = 72;
std::aligned_storage<kMaxSize>::type d_ = {};
alignas(std::max_align_t) std::byte d_[kMaxSize] = {};
STBase* p_ = nullptr;
public:

View File

@@ -15,15 +15,16 @@
// Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order.
XRPL_FIX (Cleanup3_3_0, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (Cleanup3_2_0, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(MPTokensV2, Supported::No, VoteBehavior::DefaultNo)
XRPL_FIX (Cleanup3_1_3, Supported::Yes, VoteBehavior::DefaultYes)
XRPL_FIX (BatchInnerSigs, Supported::No, VoteBehavior::DefaultNo)
XRPL_FEATURE(LendingProtocol, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(PermissionDelegationV1_1, Supported::No, VoteBehavior::DefaultNo)
XRPL_FEATURE(PermissionDelegationV1_1, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (DirectoryLimit, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (IncludeKeyletFields, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(DynamicMPT, Supported::No, VoteBehavior::DefaultNo)
XRPL_FEATURE(DynamicMPT, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (TokenEscrowV1, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (PriceOracleOrder, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (MPTDeliveredAmount, Supported::Yes, VoteBehavior::DefaultNo)
@@ -64,7 +65,6 @@ XRPL_FIX (DisallowIncomingV1, Supported::Yes, VoteBehavior::DefaultNo
XRPL_FEATURE(XChainBridge, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(AMM, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(Clawback, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (UniversalNumber, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(XRPFees, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::Yes, VoteBehavior::DefaultYes)
@@ -112,6 +112,7 @@ XRPL_RETIRE_FIX(RmSmallIncreasedQOffers)
XRPL_RETIRE_FIX(STAmountCanonicalize)
XRPL_RETIRE_FIX(TakerDryOfferRemoval)
XRPL_RETIRE_FIX(TrustLinesToSelf)
XRPL_RETIRE_FIX(UniversalNumber)
XRPL_RETIRE_FEATURE(Checks)
XRPL_RETIRE_FEATURE(CheckCashMakesTrustLine)

View File

@@ -1,49 +1,74 @@
#if !defined(PERMISSION)
#error "undefined macro: PERMISSION"
#if !defined(GRANULAR_PERMISSION)
#error "undefined macro: GRANULAR_PERMISSION"
#endif
/**
* PERMISSION(name, type, txType, value)
* GRANULAR_PERMISSION(name, txType, value, allowedFlags, allowedFields)
*
* This macro defines a permission:
* name: the name of the permission.
* type: the GranularPermissionType enum.
* txType: the corresponding TxType for this permission.
* value: the uint32 numeric value for the enum type.
* Defines a granular permission:
* name: the granular permission name.
* txType: the corresponding TxType for this permission.
* value: the uint32 numeric value for the enum type.
* allowedFlags: transaction flags permitted under this permission.
* allowedFields: transaction fields permitted under this permission.
*/
/** This permission grants the delegated account the ability to authorize a trustline. */
PERMISSION(TrustlineAuthorize, ttTRUST_SET, 65537)
/** Grants the ability to authorize a trustline. */
GRANULAR_PERMISSION(TrustlineAuthorize, ttTRUST_SET, 65537, tfUniversal | tfSetfAuth,
({{sfLimitAmount, SoeRequired}}))
/** This permission grants the delegated account the ability to freeze a trustline. */
PERMISSION(TrustlineFreeze, ttTRUST_SET, 65538)
/** Grants the ability to freeze a trustline. */
GRANULAR_PERMISSION(TrustlineFreeze, ttTRUST_SET, 65538, tfUniversal | tfSetFreeze,
({{sfLimitAmount, SoeRequired}}))
/** This permission grants the delegated account the ability to unfreeze a trustline. */
PERMISSION(TrustlineUnfreeze, ttTRUST_SET, 65539)
/** Grants the ability to unfreeze a trustline. */
GRANULAR_PERMISSION(TrustlineUnfreeze, ttTRUST_SET, 65539, tfUniversal | tfClearFreeze,
({{sfLimitAmount, SoeRequired}}))
/** This permission grants the delegated account the ability to set Domain. */
PERMISSION(AccountDomainSet, ttACCOUNT_SET, 65540)
/** Grants the ability to set Domain. */
GRANULAR_PERMISSION(AccountDomainSet, ttACCOUNT_SET, 65540, tfUniversal,
({{sfDomain, SoeOptional}}))
/** This permission grants the delegated account the ability to set EmailHashSet. */
PERMISSION(AccountEmailHashSet, ttACCOUNT_SET, 65541)
/** Grants the ability to set EmailHash. */
GRANULAR_PERMISSION(AccountEmailHashSet, ttACCOUNT_SET, 65541, tfUniversal,
({{sfEmailHash, SoeOptional}}))
/** This permission grants the delegated account the ability to set MessageKey. */
PERMISSION(AccountMessageKeySet, ttACCOUNT_SET, 65542)
/** Grants the ability to set MessageKey. */
GRANULAR_PERMISSION(AccountMessageKeySet, ttACCOUNT_SET, 65542, tfUniversal,
({{sfMessageKey, SoeOptional}}))
/** This permission grants the delegated account the ability to set TransferRate. */
PERMISSION(AccountTransferRateSet, ttACCOUNT_SET, 65543)
/** Grants the ability to set TransferRate. */
GRANULAR_PERMISSION(AccountTransferRateSet, ttACCOUNT_SET, 65543, tfUniversal,
({{sfTransferRate, SoeOptional}}))
/** This permission grants the delegated account the ability to set TickSize. */
PERMISSION(AccountTickSizeSet, ttACCOUNT_SET, 65544)
/** Grants the ability to set TickSize. */
GRANULAR_PERMISSION(AccountTickSizeSet, ttACCOUNT_SET, 65544, tfUniversal,
({{sfTickSize, SoeOptional}}))
/** This permission grants the delegated account the ability to mint payment, which means sending a payment for a currency where the sending account is the issuer. */
PERMISSION(PaymentMint, ttPAYMENT, 65545)
/** Grants the ability to mint payment (sending account is the issuer). Cross-currency payments are disallowed. */
GRANULAR_PERMISSION(PaymentMint, ttPAYMENT, 65545, tfUniversal,
({{sfDestination, SoeRequired},
{sfAmount, SoeRequired},
{sfSendMax, SoeOptional},
{sfInvoiceID, SoeOptional},
{sfDestinationTag, SoeOptional},
{sfCredentialIDs, SoeOptional}}))
/** This permission grants the delegated account the ability to burn payment, which means sending a payment for a currency where the destination account is the issuer */
PERMISSION(PaymentBurn, ttPAYMENT, 65546)
/** Grants the ability to burn payment (destination account is the issuer). Cross-currency payments are disallowed. */
GRANULAR_PERMISSION(PaymentBurn, ttPAYMENT, 65546, tfUniversal,
({{sfDestination, SoeRequired},
{sfAmount, SoeRequired},
{sfSendMax, SoeOptional},
{sfInvoiceID, SoeOptional},
{sfDestinationTag, SoeOptional},
{sfCredentialIDs, SoeOptional}}))
/** This permission grants the delegated account the ability to lock MPToken. */
PERMISSION(MPTokenIssuanceLock, ttMPTOKEN_ISSUANCE_SET, 65547)
/** Grants the ability to lock an MPToken. */
GRANULAR_PERMISSION(MPTokenIssuanceLock, ttMPTOKEN_ISSUANCE_SET, 65547, tfUniversal | tfMPTLock,
({{sfMPTokenIssuanceID, SoeRequired},
{sfHolder, SoeOptional}}))
/** This permission grants the delegated account the ability to unlock MPToken. */
PERMISSION(MPTokenIssuanceUnlock, ttMPTOKEN_ISSUANCE_SET, 65548)
/** Grants the ability to unlock an MPToken. */
GRANULAR_PERMISSION(MPTokenIssuanceUnlock, ttMPTOKEN_ISSUANCE_SET, 65548, tfUniversal | tfMPTUnlock,
({{sfMPTokenIssuanceID, SoeRequired},
{sfHolder, SoeOptional}}))

View File

@@ -1,10 +1,10 @@
#pragma once
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/contract.h>
#include <xrpl/protocol/detail/token_errors.h>
#include <cstdint>
#include <expected>
#include <optional>
#include <span>
#include <string>
@@ -13,7 +13,7 @@
namespace xrpl {
template <class T>
using B58Result = Expected<T, std::error_code>;
using B58Result = std::expected<T, std::error_code>;
enum class TokenType : std::uint8_t {
None = 1, // unused

View File

@@ -1,6 +1,7 @@
#pragma once
#include <xrpl/basics/CountedObject.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/Book.h>
#include <xrpl/protocol/ErrorCodes.h>
@@ -26,6 +27,19 @@ public:
};
/** Manages a client's subscription to data feeds.
*
* An InfoSub holds a non-owning reference to its `Source` (typically the
* process-wide `NetworkOPsImp`). The destructor reaches back into the
* `Source` to remove this subscriber from every server-side subscription
* map.
*
* @note Lifetime contract: every `InfoSub` instance MUST be destroyed
* before the backing `Source`. NetworkOPsImp shutdown drops all
* subscriber strong refs before its own teardown to satisfy this.
* @note Thread-safety: per-instance state is guarded by `lock_`. The
* destructor reads tracking sets without taking `lock_` because
* the strong-pointer ref-count is zero at destruction time, so
* no other thread can be calling the public mutators.
*/
class InfoSub : public CountedObject<InfoSub>
{
@@ -117,8 +131,43 @@ public:
virtual bool
subBook(ref ispListener, Book const&) = 0;
/**
* Remove a book subscription for a live subscriber.
*
* Clears the book from the subscriber's own tracking set
* (InfoSub::bookSubscriptions_) and then removes the server-side
* entry from subBook_. Call this from RPC unsubscribe handlers.
*
* @param ispListener The subscriber requesting removal.
* @param book The order book to unsubscribe from.
* @return true if the entry was present and removed, false if the
* subscriber was not subscribed to @p book.
*
* @note Thread-safety: acquires subLock_ internally.
* @note Do NOT call from ~InfoSub(). Use unsubBookInternal instead
* to avoid a redundant write-back to bookSubscriptions_ on a
* partially-destroyed object.
*/
virtual bool
unsubBook(std::uint64_t uListener, Book const&) = 0;
unsubBook(ref ispListener, Book const&) = 0;
/**
* Remove a book subscription during InfoSub teardown.
*
* Removes only the server-side entry from subBook_. Does NOT touch
* InfoSub::bookSubscriptions_ because the InfoSub is being destroyed.
* Called by ~InfoSub() for each book in bookSubscriptions_.
*
* @param uListener The sequence number of the subscriber being torn down.
* @param book The order book entry to remove.
* @return true if the entry was present and removed, false otherwise
* (e.g., already removed by a concurrent RPC unsubscribe).
*
* @note Thread-safety: acquires subLock_ internally.
*/
virtual bool
unsubBookInternal(std::uint64_t uListener, Book const&) = 0;
virtual bool
subTransactions(ref ispListener) = 0;
@@ -158,6 +207,13 @@ public:
addRpcSub(std::string const& strUrl, ref rspEntry) = 0;
virtual bool
tryRemoveRpcSub(std::string const& strUrl) = 0;
/** Journal used by InfoSub for diagnostics that occur after the
* owning subsystem (e.g. application-level Logs) is the only
* surviving sink — primarily destructor-time cleanup failures.
*/
[[nodiscard]] virtual beast::Journal const&
journal() const = 0;
};
public:
@@ -184,6 +240,31 @@ public:
void
deleteSubAccountInfo(AccountID const& account, bool rt);
/** Record that this subscriber is following @p book.
*
* Called by NetworkOPsImp::subBook so that ~InfoSub() can issue a
* matching unsubBook for every book this subscriber is tracking,
* keeping per-subscriber state symmetric with the server-side map.
*
* @param book The order book this subscriber has just subscribed to.
* @note Idempotent: re-inserting an already-tracked book is a no-op.
* @note Thread-safe: takes InfoSub::lock_.
*/
void
insertBookSubscription(Book const& book);
/** Stop tracking @p book for this subscriber.
*
* Called by the unsubscribe RPC handler so that the book is not
* re-unsubscribed by ~InfoSub(). Pairs with insertBookSubscription.
*
* @param book The order book to forget.
* @note No-op if @p book was not previously inserted.
* @note Thread-safe: takes InfoSub::lock_.
*/
void
deleteBookSubscription(Book const& book);
// return false if already subscribed to this account
bool
insertSubAccountHistory(AccountID const& account);
@@ -217,6 +298,7 @@ private:
std::shared_ptr<InfoSubRequest> request_;
std::uint64_t seq_;
hash_set<AccountID> accountHistorySubscriptions_;
hash_set<Book> bookSubscriptions_;
unsigned int apiVersion_ = 0;
static int

View File

@@ -249,6 +249,19 @@ public:
virtual void
stateAccounting(json::Value& obj) = 0;
/** Total number of (book, subscriber) entries currently tracked.
*
* Counts every weak_ptr stored across every book in subBook_, NOT the
* number of distinct subscribers and NOT the number of distinct
* books: a single subscriber following N books contributes N entries.
*
* @note Diagnostic accessor; intended for tests and operator visibility
* into per-book subscription state. The returned value is a
* snapshot under the subscription lock.
*/
virtual std::size_t
getBookSubscribersCount() = 0;
};
} // namespace xrpl

View File

@@ -1,6 +1,5 @@
#pragma once
#include <xrpl/basics/BasicConfig.h>
#include <xrpl/beast/net/IPEndpoint.h>
#include <boost/asio/ip/address.hpp>
@@ -14,6 +13,7 @@
#include <optional>
#include <set>
#include <string>
#include <vector>
namespace boost::asio::ssl {
class context; // NOLINT(readability-identifier-naming) -- external library name
@@ -21,6 +21,8 @@ class context; // NOLINT(readability-identifier-naming) -- external library nam
namespace xrpl {
class Section;
/** Configuration information for a Server listening port. */
struct Port
{

View File

@@ -10,6 +10,7 @@
#include <functional>
#include <memory>
#include <ostream>
#include <string_view>
#include <vector>
namespace xrpl {
@@ -53,10 +54,10 @@ public:
/** Send a copy of data asynchronously. */
/** @{ */
void
write(std::string const& s)
write(std::string_view s)
{
if (!s.empty())
write(&s[0], std::distance(s.begin(), s.end()));
write(s.data(), s.size());
}
template <typename BufferSequence>

View File

@@ -5,6 +5,7 @@
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
namespace xrpl {
@@ -127,7 +128,7 @@ operator<<(std::ostream& out, SHAMapNodeID const& node)
deserializeSHAMapNodeID(void const* data, std::size_t size);
[[nodiscard]] inline std::optional<SHAMapNodeID>
deserializeSHAMapNodeID(std::string const& s)
deserializeSHAMapNodeID(std::string_view s)
{
return deserializeSHAMapNodeID(s.data(), s.size());
}

View File

@@ -1,11 +1,11 @@
#pragma once
#include <xrpl/basics/Expected.h> //
#include <xrpl/beast/utility/Journal.h> // beast::Journal
#include <xrpl/protocol/TER.h> // temMALFORMED
#include <xrpl/protocol/UintTypes.h> // AccountID
#include <xrpl/tx/Transactor.h> // NotTEC
#include <expected>
#include <optional>
#include <string_view>
@@ -60,7 +60,7 @@ public:
// obj Contains a SignerEntries field that is an STArray.
// journal For reporting error conditions.
// annotation Source of SignerEntries, like "ledger" or "transaction".
static Expected<std::vector<SignerEntry>, NotTEC>
static std::expected<std::vector<SignerEntry>, NotTEC>
deserialize(STObject const& obj, beast::Journal journal, std::string_view annotation);
};

View File

@@ -8,6 +8,7 @@
#include <xrpl/tx/applySteps.h>
#include <xrpl/tx/invariants/CheckInvariants.h>
#include <tuple>
#include <utility>
namespace xrpl {
@@ -234,8 +235,63 @@ public:
return tesSUCCESS;
}
/**
* This function can be overridden to introduce additional semantic constraints beyond the
* granular template validation for granular permissions. It is called by the base
* invokeCheckPermission method only after the transaction has successfully passed
* checkGranularSandbox.
*/
static NotTEC
checkPermission(ReadView const& view, STTx const& tx);
checkGranularSemantics(
ReadView const& view,
STTx const& tx,
std::unordered_set<GranularPermissionType> const& heldGranularPermissions)
{
return tesSUCCESS;
}
/**
* Checks whether the transaction is authorized to be executed by the delegated account.
* This function enforces the strict permission check hierarchy. It is explicitly
* designed NOT to be overridden. Derived transactors must instead implement
* checkGranularSemantics to add custom validation logic for granular permissions.
*
* The evaluation proceeds as follows:
* - If transaction-level permission is granted, the function immediately returns tesSUCCESS.
* - If transaction-level permission is not granted, the function checks whether the transaction
* matches the granular permission template defined in permissions.macro. If it does, it then
* calls checkGranularSemantics to perform any additional, fine-grained validation.
*
*/
template <class T>
static NotTEC
invokeCheckPermission(ReadView const& view, STTx const& tx)
{
// heldGranularPermissions is passed by reference into checkPermission.
// It is populated with the senders granular permissions only when the sender
// lacks tx-level permission but has granular permissions that satisfy the
// granular permission template.
//
// - result is terNO_DELEGATE_PERMISSION: return immediately.
// - result is tesSUCCESS and heldGranularPermissions is empty: tx-level permission was
// granted, so we returned success before populating it.
// - result is tesSUCCESS and heldGranularPermissions is not empty: tx-level permission was
// not granted, but the held granular permissions passed checkGranularSandbox, so we proceed
// to checkGranularSemantics.
//
// WARNING: Do not simplify checkPermission to return only
// heldGranularPermissions or the ter code. Both the result and the
// populated set are required to enforce the strict permission hierarchy
// described above.
std::unordered_set<GranularPermissionType> heldGranularPermissions;
if (NotTEC const result = checkPermission(view, tx, heldGranularPermissions);
!isTesSuccess(result) || heldGranularPermissions.empty())
{
return result;
}
return T::checkGranularSemantics(view, tx, heldGranularPermissions);
}
/////////////////////////////////////////////////////
// Interface used by AccountDelete
@@ -365,13 +421,24 @@ protected:
unit::ValueUnit<Unit, T> min = unit::ValueUnit<Unit, T>{});
private:
static NotTEC
checkPermission(
ReadView const& view,
STTx const& tx,
std::unordered_set<GranularPermissionType>& heldGranularPermissions);
std::pair<TER, XRPAmount>
reset(XRPAmount fee);
TER
consumeSeqProxy(SLE::pointer const& sleAccount);
TER
payFee();
std::tuple<TER, XRPAmount, bool>
processPersistentChanges(TER result, XRPAmount fee);
static NotTEC
checkSingleSign(
ReadView const& view,
@@ -379,6 +446,7 @@ private:
AccountID const& idAccount,
SLE::const_pointer sleAccount,
beast::Journal const j);
static NotTEC
checkMultiSign(
ReadView const& view,

View File

@@ -15,7 +15,9 @@ class ValidAMM
std::optional<AccountID> ammAccount_;
std::optional<STAmount> lptAMMBalanceAfter_;
std::optional<STAmount> lptAMMBalanceBefore_;
std::optional<STAmount> lptAMMBalanceBeforeDeletion_;
bool ammPoolChanged_{false};
bool ammDeleted_{false};
public:
enum class ZeroAllowed : bool { No = false, Yes = true };
@@ -35,12 +37,17 @@ private:
[[nodiscard]] bool
finalizeCreate(STTx const&, ReadView const&, bool enforce, beast::Journal const&) const;
[[nodiscard]] bool
finalizeDelete(bool enforce, TER res, beast::Journal const&) const;
finalizeDelete(bool enforce, bool enforceAMMDelete, TER res, beast::Journal const&) const;
[[nodiscard]] bool
finalizeDeposit(STTx const&, ReadView const&, bool enforce, beast::Journal const&) const;
// Includes clawback
[[nodiscard]] bool
finalizeWithdraw(STTx const&, ReadView const&, bool enforce, beast::Journal const&) const;
finalizeWithdraw(
STTx const&,
ReadView const&,
bool enforce,
bool enforceAMMDelete,
beast::Journal const&) const;
[[nodiscard]] bool
finalizeDEX(bool enforce, beast::Journal const&) const;
[[nodiscard]] bool

View File

@@ -23,9 +23,6 @@ public:
static NotTEC
preflight(PreflightContext const& ctx);
static NotTEC
checkPermission(ReadView const& view, STTx const& tx);
static TER
preclaim(PreclaimContext const& ctx);

View File

@@ -32,7 +32,10 @@ public:
preflight(PreflightContext const& ctx);
static NotTEC
checkPermission(ReadView const& view, STTx const& tx);
checkGranularSemantics(
ReadView const& view,
STTx const& tx,
std::unordered_set<GranularPermissionType> const& heldGranularPermissions);
static TER
preclaim(PreclaimContext const& ctx);

View File

@@ -1,9 +1,10 @@
#pragma once
#include <xrpl/basics/Expected.h>
#include <xrpl/protocol/UintTypes.h>
#include <xrpl/tx/Transactor.h>
#include <expected>
namespace xrpl {
// NOLINTBEGIN(readability-redundant-member-init)
@@ -61,7 +62,7 @@ public:
ReadView const& view,
beast::Journal const& j) override;
static Expected<MPTID, TER>
static std::expected<MPTID, TER>
create(ApplyView& view, beast::Journal journal, MPTCreateArgs const& args);
};

View File

@@ -22,9 +22,6 @@ public:
static NotTEC
preflight(PreflightContext const& ctx);
static NotTEC
checkPermission(ReadView const& view, STTx const& tx);
static TER
preclaim(PreclaimContext const& ctx);

View File

@@ -21,7 +21,10 @@ public:
preflight(PreflightContext const& ctx);
static NotTEC
checkPermission(ReadView const& view, STTx const& tx);
checkGranularSemantics(
ReadView const& view,
STTx const& tx,
std::unordered_set<GranularPermissionType> const& heldGranularPermissions);
static TER
preclaim(PreclaimContext const& ctx);

View File

@@ -2,6 +2,8 @@
#include <xrpl/tx/Transactor.h>
#include <expected>
namespace xrpl {
class VaultClawback : public Transactor
@@ -34,7 +36,7 @@ public:
beast::Journal const& j) override;
private:
Expected<std::pair<STAmount, STAmount>, TER>
std::expected<std::pair<STAmount, STAmount>, TER>
assetsToClawback(
SLE::ref vault,
SLE::const_ref sleShareIssuance,