-
Notifications
You must be signed in to change notification settings - Fork 79
feat: Add delegate filter param's to account_tx RPC #2827
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 21 commits
7a58d95
141aa14
18bcdf3
55f5961
300219a
eb83ca3
7ee435e
d8ffa5d
efe8a49
fbdef94
902668e
595e1b9
5553eee
2f4987e
909573d
541c0a0
bfc6675
d5846f6
42c4721
5d9a924
9e8da15
533c924
983768c
223c8ed
6c09975
73a70c3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,9 +14,9 @@ | |
|
|
||
| #include <cstdint> | ||
| #include <expected> | ||
| #include <optional> | ||
| #include <string> | ||
| #include <utility> | ||
| #include <variant> | ||
|
|
||
| namespace etl { | ||
| class LoadBalancer; | ||
|
|
@@ -175,6 +175,25 @@ struct AccountCursor { | |
| } | ||
| }; | ||
|
|
||
| /** | ||
| * @brief A delegate object used filter account_tx by specific delegate accounts | ||
| */ | ||
| struct DelegateFilter { | ||
| /** | ||
| * @brief A delegate type used in delegate filter | ||
| */ | ||
| enum class Role { | ||
|
PeterChen13579 marked this conversation as resolved.
Outdated
|
||
| Actor, /**< This account is the *active* sender, acting on behalf of another party. | ||
| * e.g., Account A in "A sends payment to B on behalf of C." */ | ||
|
|
||
| Authorizer /**< This account is the *passive* party whose funds are being moved from. | ||
| * e.g., Account C in "A sends payment to B on behalf of C." */ | ||
| }; | ||
|
|
||
| Role delegateType = Role::Actor; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need do add a default value here?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is needed as otherwise clang-tidy complains; Role is an enum class with no default initialization |
||
| std::optional<std::string> counterParty; | ||
| }; | ||
|
|
||
| /** | ||
| * @brief Convert an empty output to a JSON object | ||
| * | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| #pragma once | ||
|
|
||
| #include "data/Types.hpp" | ||
|
|
||
| #include <xrpl/protocol/AccountID.h> | ||
|
|
||
| #include <optional> | ||
|
|
||
| namespace rpc { | ||
|
|
||
| /** | ||
| * @brief Result of a filter check. | ||
| */ | ||
| struct FilterResult { | ||
| bool shouldInclude = false; | ||
| std::optional<xrpl::AccountID> relevantAccount; | ||
|
PeterChen13579 marked this conversation as resolved.
Outdated
|
||
| }; | ||
|
|
||
| /** | ||
| * @brief Interface for filtering transactions. | ||
| */ | ||
| class TransactionFilter { | ||
| public: | ||
| virtual ~TransactionFilter() = default; | ||
|
|
||
| /** | ||
| * @brief Check if a transaction blob matches the filter criteria. | ||
| * @param txnPlusMeta The transaction and metadata blob from the backend. | ||
| * @return FilterResult indicating if the txn should be included in the output Json or not | ||
| */ | ||
| [[nodiscard]] virtual FilterResult | ||
| check(data::TransactionAndMetadata const& txnPlusMeta) const = 0; | ||
| }; | ||
|
|
||
| } // namespace rpc | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| #include "rpc/filters/impl/DelegateTransactionsFilter.hpp" | ||
|
|
||
| #include "data/Types.hpp" | ||
| #include "rpc/common/Types.hpp" | ||
| #include "rpc/filters/TransactionFilter.hpp" | ||
|
|
||
| #include <xrpl/protocol/AccountID.h> | ||
| #include <xrpl/protocol/SField.h> | ||
| #include <xrpl/protocol/STTx.h> | ||
| #include <xrpl/protocol/Serializer.h> | ||
|
|
||
| #include <optional> | ||
| #include <utility> | ||
|
|
||
| namespace rpc { | ||
|
|
||
| DelegateTransactionFilter::DelegateTransactionFilter( | ||
| rpc::DelegateFilter filter, | ||
| xrpl::AccountID queriedAccount | ||
| ) | ||
| : delegateFilter_(std::move(filter)), queriedAccount_(queriedAccount) | ||
| { | ||
| if (delegateFilter_.counterParty) | ||
| counterparty_ = xrpl::parseBase58<xrpl::AccountID>(*delegateFilter_.counterParty); | ||
| } | ||
|
|
||
| FilterResult | ||
| DelegateTransactionFilter::check(data::TransactionAndMetadata const& txnPlusMeta) const | ||
| { | ||
| xrpl::SerialIter sit{txnPlusMeta.transaction.data(), txnPlusMeta.transaction.size()}; | ||
| xrpl::STTx const sttx{sit}; | ||
|
|
||
| // The account is always the owner whose funds move; when sfDelegate is present, sfAccount is | ||
| // the "authorizer" and sfDelegate is the "actor" that signed on its behalf. | ||
| auto const txAccount = sttx.getAccountID(xrpl::sfAccount); | ||
|
|
||
| std::optional<xrpl::AccountID> txDelegate; | ||
| if (sttx.isFieldPresent(xrpl::sfDelegate)) | ||
| txDelegate = sttx.getAccountID(xrpl::sfDelegate); | ||
|
|
||
| // Transactions without an sfDelegate field are not delegated; exclude them immediately. | ||
| if (not txDelegate.has_value()) | ||
| return {.shouldInclude = false, .relevantAccount = std::nullopt}; | ||
|
|
||
| // Filter by "authorizer" ie. the queried account is the actor (signer) and the user wants to | ||
| // find the authorizer (owner) it acted for. | ||
| if (delegateFilter_.delegateType == rpc::DelegateFilter::Role::Authorizer) { | ||
| if (*txDelegate == queriedAccount_) { | ||
| if (!counterparty_ || *counterparty_ == txAccount) | ||
| return {.shouldInclude = true, .relevantAccount = txAccount}; | ||
| } | ||
| } | ||
|
|
||
|
PeterChen13579 marked this conversation as resolved.
|
||
| // Filter by "actor" ie. the queried account is the authorizer (owner) and the user wants to | ||
| // find the actor (signer) that acted on its behalf. | ||
| else if (delegateFilter_.delegateType == rpc::DelegateFilter::Role::Actor) { | ||
| if (txAccount == queriedAccount_) { | ||
| if (!counterparty_ || *counterparty_ == *txDelegate) | ||
| return {.shouldInclude = true, .relevantAccount = txDelegate}; | ||
| } | ||
| } | ||
|
|
||
| return {.shouldInclude = false, .relevantAccount = std::nullopt}; | ||
| } | ||
|
|
||
| } // namespace rpc | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| #pragma once | ||
|
|
||
| #include "data/Types.hpp" | ||
| #include "rpc/common/Types.hpp" | ||
| #include "rpc/filters/TransactionFilter.hpp" | ||
|
|
||
| #include <xrpl/protocol/AccountID.h> | ||
|
|
||
| #include <optional> | ||
|
|
||
| namespace rpc { | ||
|
|
||
| /** | ||
| * @brief Delegate transaction filter to filter txn based on permission delegate | ||
| */ | ||
| class DelegateTransactionFilter : public TransactionFilter { | ||
| public: | ||
| /** | ||
| * @brief Construct a new delegate transaction filter | ||
| * @param filter The filter parameters from the JSON request (role, counterparty string) | ||
| * @param queriedAccount The account currently being queried in account_tx (input from | ||
| * account_tx handler) | ||
| */ | ||
| DelegateTransactionFilter(rpc::DelegateFilter filter, xrpl::AccountID queriedAccount); | ||
|
|
||
| [[nodiscard]] FilterResult | ||
| check(data::TransactionAndMetadata const& txnPlusMeta) const override; | ||
|
|
||
| private: | ||
| rpc::DelegateFilter delegateFilter_; | ||
| xrpl::AccountID queriedAccount_; | ||
| std::optional<xrpl::AccountID> counterparty_; | ||
| }; | ||
|
|
||
| } // namespace rpc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::expected<DelegateFilter::Role, void> better shows what you're trying to achieve.
Below as well
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just realized the
voidinstd::expected<DelegateFilter::Role, void>is not valid code. I'd probably leave it as is ascustomValidatorchecks for if parsing failed or not (has_value())