xrpld
Loading...
Searching...
No Matches
DelegateSet.cpp
1#include <xrpl/tx/transactors/delegate/DelegateSet.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/beast/utility/Journal.h>
5#include <xrpl/core/ServiceRegistry.h>
6#include <xrpl/ledger/helpers/AccountRootHelpers.h>
7#include <xrpl/ledger/helpers/DirectoryHelpers.h>
8#include <xrpl/ledger/helpers/SponsorHelpers.h>
9#include <xrpl/protocol/Indexes.h>
10#include <xrpl/protocol/Protocol.h>
11#include <xrpl/protocol/SField.h>
12#include <xrpl/protocol/STLedgerEntry.h>
13#include <xrpl/protocol/STTx.h>
14#include <xrpl/protocol/TER.h>
15#include <xrpl/protocol/XRPAmount.h>
16#include <xrpl/tx/Transactor.h>
17
18#include <cstdint>
19#include <memory>
20#include <unordered_set>
21
22namespace xrpl {
23
26{
27 auto const& permissions = ctx.tx.getFieldArray(sfPermissions);
28 if (permissions.size() > kPermissionMaxSize)
29 return temARRAY_TOO_LARGE;
30
31 // can not authorize self
32 if (ctx.tx[sfAccount] == ctx.tx[sfAuthorize])
33 return temMALFORMED;
34
36
37 for (auto const& permission : permissions)
38 {
39 if (!permissionSet.insert(permission[sfPermissionValue]).second)
40 return temMALFORMED;
41
42 if (!Permission::getInstance().isDelegable(permission[sfPermissionValue], ctx.rules))
43 return temMALFORMED;
44 }
45
46 return tesSUCCESS;
47}
48
49TER
51{
52 if (!ctx.view.exists(keylet::account(ctx.tx[sfAccount])))
53 return terNO_ACCOUNT; // LCOV_EXCL_LINE
54
55 auto const sleAuthorize = ctx.view.read(keylet::account(ctx.tx[sfAuthorize]));
56 if (!sleAuthorize)
57 return tecNO_TARGET;
58
59 if (isPseudoAccount(sleAuthorize))
60 return tecPSEUDO_ACCOUNT;
61
62 // Deleting the delegate object is invalid if it doesn’t exist.
63 if (ctx.tx.getFieldArray(sfPermissions).empty() &&
64 !ctx.view.exists(keylet::delegate(ctx.tx[sfAccount], ctx.tx[sfAuthorize])))
65 {
66 return tecNO_ENTRY;
67 }
68
69 return tesSUCCESS;
70}
71
72TER
74{
75 auto const sleOwner = ctx_.view().peek(keylet::account(accountID_));
76 if (!sleOwner)
77 return tefINTERNAL; // LCOV_EXCL_LINE
78
79 auto const& authAccount = ctx_.tx[sfAuthorize];
80 auto const delegateKey = keylet::delegate(accountID_, authAccount);
81
82 auto sle = ctx_.view().peek(delegateKey);
83 if (sle)
84 {
85 auto const& permissions = ctx_.tx.getFieldArray(sfPermissions);
86 if (permissions.empty())
87 {
88 // if permissions array is empty, delete the ledger object.
89 return deleteDelegate(view(), sle, j_);
90 }
91
92 sle->setFieldArray(sfPermissions, permissions);
93 ctx_.view().update(sle);
94 return tesSUCCESS;
95 }
96
97 auto const& permissions = ctx_.tx.getFieldArray(sfPermissions);
98 if (permissions.empty())
99 return tecINTERNAL; // LCOV_EXCL_LINE
100
101 if (auto const ret = checkReserve(
102 ctx_.getApplyViewContext(),
103 sleOwner,
105 {.ownerCountDelta = 1},
106 ctx_.journal);
107 !isTesSuccess(ret))
108 return ret;
109
110 sle = std::make_shared<SLE>(delegateKey);
111 sle->setAccountID(sfAccount, accountID_);
112 sle->setAccountID(sfAuthorize, authAccount);
113
114 sle->setFieldArray(sfPermissions, permissions);
115
116 // Add to delegating account's owner directory
117 auto const page = ctx_.view().dirInsert(
119
120 if (!page)
121 return tecDIR_FULL; // LCOV_EXCL_LINE
122
123 (*sle)[sfOwnerNode] = *page;
124
125 // Add to authorized account's owner directory so AccountDelete can find
126 // and clean up inbound delegations when the authorized account is deleted.
127 auto const destPage = ctx_.view().dirInsert(
128 keylet::ownerDir(authAccount), delegateKey, describeOwnerDir(authAccount));
129
130 if (!destPage)
131 return tecDIR_FULL; // LCOV_EXCL_LINE
132
133 (*sle)[sfDestinationNode] = *destPage;
134
135 ctx_.view().insert(sle);
136 increaseOwnerCount(ctx_.getApplyViewContext(), sleOwner, 1, ctx_.journal);
137 addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sle);
138
139 return tesSUCCESS;
140}
141
142TER
144{
145 if (!sle)
146 return tecINTERNAL; // LCOV_EXCL_LINE
147
148 auto const delegator = (*sle)[sfAccount];
149 auto const delegatee = (*sle)[sfAuthorize];
150
151 // Remove from delegating account's owner directory
152 if (!view.dirRemove(keylet::ownerDir(delegator), (*sle)[sfOwnerNode], sle->key(), false))
153 {
154 // LCOV_EXCL_START
155 JLOG(j.fatal()) << "Unable to delete Delegate from owner.";
156 return tefBAD_LEDGER;
157 // LCOV_EXCL_STOP
158 }
159
160 // Remove from authorized account's owner directory, if present
161 if (auto const optPage = (*sle)[~sfDestinationNode])
162 {
163 if (!view.dirRemove(keylet::ownerDir(delegatee), *optPage, sle->key(), false))
164 {
165 // LCOV_EXCL_START
166 JLOG(j.fatal()) << "Unable to delete Delegate from authorized account.";
167 return tefBAD_LEDGER;
168 // LCOV_EXCL_STOP
169 }
170 }
171
172 // Only the delegating account's owner count was incremented on creation
173 auto const sleOwner = view.peek(keylet::account(delegator));
174 if (!sleOwner)
175 return tecINTERNAL; // LCOV_EXCL_LINE
176
177 decreaseOwnerCountForObject(view, sleOwner, sle, 1, j);
178
179 view.erase(sle);
180
181 return tesSUCCESS;
182}
183
184void
186{
187 // No transaction-specific invariants yet (future work).
188}
189
190bool
192{
193 // No transaction-specific invariants yet (future work).
194 return true;
195}
196
197} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:44
Stream fatal() const
Definition Journal.h:368
Writeable view to a ledger, for applying a transaction.
Definition ApplyView.h:134
static TER deleteDelegate(ApplyView &view, SLE::ref sle, beast::Journal j)
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
static NotTEC preflight(PreflightContext const &ctx)
bool finalizeInvariants(STTx const &tx, TER result, XRPAmount fee, ReadView const &view, beast::Journal const &j) override
Check transaction-specific post-conditions after all entries have been visited.
TER doApply() override
static TER preclaim(PreclaimContext const &ctx)
static Permission const & getInstance()
A view into a ledger.
Definition ReadView.h:41
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
bool empty() const
Definition STArray.h:254
std::shared_ptr< STLedgerEntry > const & ref
std::shared_ptr< STLedgerEntry const > const & const_ref
STArray const & getFieldArray(SField const &field) const
Definition STObject.cpp:688
beast::Journal const j_
Definition Transactor.h:155
ApplyView & view()
Definition Transactor.h:175
AccountID const accountID_
Definition Transactor.h:157
XRPAmount preFeeBalance_
Definition Transactor.h:158
ApplyContext & ctx_
Definition Transactor.h:153
T insert(T... args)
T make_shared(T... args)
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:373
Keylet delegate(AccountID const &account, AccountID const &authorizedAccount) noexcept
A keylet for Delegate object.
Definition Indexes.cpp:481
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:198
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ terNO_ACCOUNT
Definition TER.h:213
void decreaseOwnerCountForObject(ApplyView &view, SLE::ref accountSle, SLE::ref objectSle, std::uint32_t count, beast::Journal j)
Decrease owner-count fields for an existing ledger object.
void increaseOwnerCount(ApplyView &view, SLE::ref accountSle, SLE::ref sponsorSle, std::uint32_t count, beast::Journal j)
Increase owner-count fields when the caller supplies the sponsor.
constexpr std::size_t kPermissionMaxSize
The maximum number of delegate permissions an account can grant.
Definition Protocol.h:438
@ tefBAD_LEDGER
Definition TER.h:162
@ tefINTERNAL
Definition TER.h:165
void addSponsorToLedgerEntry(SLE::ref sle, SLE::const_ref sponsorSle, SF_ACCOUNT const &field=sfSponsor)
Stamp a reserve sponsor onto a ledger entry using an explicit sponsor SLE.
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:607
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Returns a function that sets the owner on a directory SLE.
TER checkReserve(ApplyViewContext ctx, SLE::const_ref accSle, XRPAmount accBalance, SLE::const_ref sponsorSle, Adjustment adj, beast::Journal j, TER insufReserveCode=tecINSUFFICIENT_RESERVE)
Check if an account has sufficient reserve.
@ temARRAY_TOO_LARGE
Definition TER.h:129
@ temMALFORMED
Definition TER.h:75
bool isTesSuccess(TER x) noexcept
Definition TER.h:676
TERSubset< CanCvtToTER > TER
Definition TER.h:647
@ tecDIR_FULL
Definition TER.h:290
@ tecPSEUDO_ACCOUNT
Definition TER.h:365
@ tecNO_ENTRY
Definition TER.h:309
@ tecNO_TARGET
Definition TER.h:307
@ tecINTERNAL
Definition TER.h:313
bool isPseudoAccount(SLE::const_pointer sleAcct, std::set< SField const * > const &pseudoFieldFilter={})
Returns true if and only if sleAcct is a pseudo-account or specific pseudo-accounts in pseudoFieldFil...
@ tesSUCCESS
Definition TER.h:245
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:83
ReadView const & view
Definition Transactor.h:86
State information when preflighting a tx.
Definition Transactor.h:38