Merge remote-tracking branch 'XRPLF/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2

* XRPLF/ximinez/online-delete-gaps:
  ci: Run full matrix only on `Ready to merge` or `Full CI build` labeled PRs (7689)
  fix: Strengthen Clawback invariant checks for MPT balances (7285)
  test: Add unit tests for IP address related functions (7744)
  ci: Add Rust to Nix docker image (7571)
  docs: Add more information about pre-commit hooks and how to set them up (7802)
  test: Add JSON array size tests (7592)
  chore: Enable most readability checks (7772)
  ci: Do not run conflict checker when label is applied (7774)
  chore: Run clang_tidy_check with `pass_filenames: false` from pre-commit (7800)
  feat: Add delegate filter param for account_tx RPC (6126)
  refactor: Move `jss.h` `include` out of `Indexes.h` (7799)
This commit is contained in:
Ed Hennis
2026-07-14 20:21:59 -04:00
85 changed files with 2381 additions and 1052 deletions

View File

@@ -358,12 +358,13 @@ template <class = void>
bool
tokenInList(boost::string_ref const& value, boost::string_ref const& token)
{
for (auto const& item : makeList(value))
{
if (ciEqual(item, token))
return true;
}
return false;
auto const list = makeList(value);
// ListIterator is not default-constructible, so it does not model a std::ranges
// sentinel/range; the classic std::any_of (which only needs an input iterator)
// is used instead.
// NOLINTNEXTLINE(modernize-use-ranges)
return std::any_of(
list.begin(), list.end(), [&token](auto const& item) { return ciEqual(item, token); });
}
template <bool IsRequest, class Body, class Fields>

View File

@@ -13,7 +13,6 @@
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/STXChainBridge.h>
#include <xrpl/protocol/UintTypes.h>
#include <xrpl/protocol/jss.h>
#include <array>
#include <cstdint>
@@ -423,21 +422,8 @@ struct KeyletDesc
bool includeInTests{};
};
// This list should include all of the keylet functions that take a single
// AccountID parameter.
std::array<KeyletDesc<AccountID const&>, 6> const kDirectAccountKeylets{
{{.function = &keylet::account, .expectedLEName = jss::AccountRoot, .includeInTests = false},
{.function = &keylet::ownerDir, .expectedLEName = jss::DirectoryNode, .includeInTests = true},
{.function = &keylet::signerList, .expectedLEName = jss::SignerList, .includeInTests = true},
// It's normally impossible to create an item at nftpage_min, but
// test it anyway, since the invariant checks for it.
{.function = &keylet::nftokenPageMin,
.expectedLEName = jss::NFTokenPage,
.includeInTests = true},
{.function = &keylet::nftokenPageMax,
.expectedLEName = jss::NFTokenPage,
.includeInTests = true},
{.function = &keylet::did, .expectedLEName = jss::DID, .includeInTests = true}}};
// This list should include all of the keylet functions that take a single AccountID parameter.
extern std::array<KeyletDesc<AccountID const&>, 6> const kDirectAccountKeylets;
MPTID
makeMptID(std::uint32_t sequence, AccountID const& account);

View File

@@ -110,6 +110,7 @@ JSS(accounts); // in: LedgerEntry, Subscribe, handlers/Ledger
JSS(accounts_proposed); // in: Subscribe, Unsubscribe
JSS(action); //
JSS(active); // out: OverlayImpl
JSS(actor); // in/out: AccountTx
JSS(acquiring); // out: LedgerRequest
JSS(address); // out: PeerImp
JSS(affected); // out: AcceptedLedgerTx
@@ -133,6 +134,7 @@ JSS(attestation_reward_account); //
JSS(auction_slot); // out: amm_info
JSS(authorized); // out: AccountLines
JSS(authorize); // out: delegate
JSS(authorizer); // in/out: AccountTx
JSS(authorized_credentials); // in: ledger_entry DepositPreauth
JSS(auth_accounts); // out: amm_info
JSS(auth_change); // out: AccountInfo
@@ -191,6 +193,7 @@ JSS(converge_time); // out: NetworkOPs
JSS(converge_time_s); // out: NetworkOPs
JSS(cookie); // out: NetworkOPs
JSS(count); // in: AccountTx*, ValidatorList
JSS(counter_party); // in/out: AccountTx
JSS(counters); // in/out: retrieve counters
JSS(credentials); // in: deposit_authorized
JSS(credential_type); // in: LedgerEntry DepositPreauth
@@ -270,6 +273,7 @@ JSS(freeze); // out: AccountLines
JSS(freeze_peer); // out: AccountLines
JSS(deep_freeze); // out: AccountLines
JSS(deep_freeze_peer); // out: AccountLines
JSS(delegate_filter); // in/out: AccountTx
JSS(frozen_balances); // out: GatewayBalances
JSS(full); // in: LedgerClearer, handlers/Ledger
JSS(full_reply); // out: PathFind

View File

@@ -46,6 +46,22 @@ struct LedgerRange
uint32_t max;
};
/**
* @brief Enumeration of possible delegate types that can occur during filtering in account_tx
*/
enum class DelegateType {
Actor, ///< Another account signed and submitted transactions on behalf of this account (this
///< account is the owner/delegator).
Authorizer ///< This account signed and submitted transactions on behalf of another account
///< (this account is the signer/delegatee).
};
struct DelegateFilter
{
DelegateType type = DelegateType::Actor;
std::optional<AccountID> counterparty;
};
class RelationalDatabase
{
public:
@@ -82,6 +98,7 @@ public:
std::optional<AccountTxMarker> marker;
std::uint32_t limit = 0;
bool bAdmin = false;
std::optional<DelegateFilter> delegate;
};
using AccountTx = std::pair<std::shared_ptr<Transaction>, std::shared_ptr<TxMeta>>;
@@ -101,6 +118,7 @@ public:
bool forward = false;
uint32_t limit = 0;
std::optional<AccountTxMarker> marker;
std::optional<DelegateFilter> delegate;
};
struct AccountTxResult
@@ -109,6 +127,7 @@ public:
LedgerRange ledgerRange{};
uint32_t limit = 0;
std::optional<AccountTxMarker> marker;
std::optional<DelegateFilter> delegate;
};
virtual ~RelationalDatabase() = default;

View File

@@ -13,7 +13,7 @@
#include <soci/session.h>
#include <memory>
#if defined(__clang__)
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
#endif
@@ -120,6 +120,6 @@ makeCheckpointer(std::uintptr_t id, std::weak_ptr<soci::session>, JobQueue&, Ser
} // namespace xrpl
#if defined(__clang__)
#ifdef __clang__
#pragma clang diagnostic pop
#endif

View File

@@ -316,17 +316,26 @@ public:
};
/**
* @brief Invariant: Token holder's trustline balance cannot be negative after
* Clawback.
* @brief Invariant: Token holder's trustline/MPT balance cannot be invalid
* after Clawback.
*
* We iterate all the trust lines affected by this transaction and ensure
* that no more than one trustline is modified, and also holder's balance is
* non-negative.
* non-negative. When featureMPTokensV2 is enabled, also verify the holder's
* raw trustline/MPToken balance decreased by the clawed amount.
*/
class ValidClawback
{
struct EntryChange
{
SLE::const_pointer before;
SLE::const_pointer after;
};
std::uint32_t trustlinesChanged_ = 0;
std::uint32_t mptokensChanged_ = 0;
EntryChange iou_;
EntryChange mpt_;
public:
void
@@ -440,7 +449,7 @@ using InvariantChecks = std::tuple<
ValidLoan,
ValidVault,
ValidConfidentialMPToken,
ValidMPTPayment,
ValidMPTBalanceChanges,
ValidAmounts,
ValidMPTTransfer,
ObjectHasPseudoAccount,

View File

@@ -87,7 +87,7 @@ public:
* OutstandingAmount after application equals OutstandingAmount before
* application plus the net holder balance delta.
*/
class ValidMPTPayment
class ValidMPTBalanceChanges
{
enum class Order { Before = 0, After = 1 };
struct MPTData