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/protocol/Indexes.h>
9#include <xrpl/protocol/Protocol.h>
10#include <xrpl/protocol/SField.h>
11#include <xrpl/protocol/STAmount.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 tecNO_PERMISSION;
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 STAmount const reserve{
102 ctx_.view().fees().accountReserve(sleOwner->getFieldU32(sfOwnerCount) + 1)};
103
104 if (preFeeBalance_ < reserve)
106
107 sle = std::make_shared<SLE>(delegateKey);
108 sle->setAccountID(sfAccount, accountID_);
109 sle->setAccountID(sfAuthorize, authAccount);
110
111 sle->setFieldArray(sfPermissions, permissions);
112
113 // Add to delegating account's owner directory
114 auto const page = ctx_.view().dirInsert(
116
117 if (!page)
118 return tecDIR_FULL; // LCOV_EXCL_LINE
119
120 (*sle)[sfOwnerNode] = *page;
121
122 // Add to authorized account's owner directory so AccountDelete can find
123 // and clean up inbound delegations when the authorized account is deleted.
124 auto const destPage = ctx_.view().dirInsert(
125 keylet::ownerDir(authAccount), delegateKey, describeOwnerDir(authAccount));
126
127 if (!destPage)
128 return tecDIR_FULL; // LCOV_EXCL_LINE
129
130 (*sle)[sfDestinationNode] = *destPage;
131
132 ctx_.view().insert(sle);
133 adjustOwnerCount(ctx_.view(), sleOwner, 1, ctx_.journal);
134
135 return tesSUCCESS;
136}
137
138TER
140{
141 if (!sle)
142 return tecINTERNAL; // LCOV_EXCL_LINE
143
144 auto const delegator = (*sle)[sfAccount];
145 auto const delegatee = (*sle)[sfAuthorize];
146
147 // Remove from delegating account's owner directory
148 if (!view.dirRemove(keylet::ownerDir(delegator), (*sle)[sfOwnerNode], sle->key(), false))
149 {
150 // LCOV_EXCL_START
151 JLOG(j.fatal()) << "Unable to delete Delegate from owner.";
152 return tefBAD_LEDGER;
153 // LCOV_EXCL_STOP
154 }
155
156 // Remove from authorized account's owner directory, if present
157 if (auto const optPage = (*sle)[~sfDestinationNode])
158 {
159 if (!view.dirRemove(keylet::ownerDir(delegatee), *optPage, sle->key(), false))
160 {
161 // LCOV_EXCL_START
162 JLOG(j.fatal()) << "Unable to delete Delegate from authorized account.";
163 return tefBAD_LEDGER;
164 // LCOV_EXCL_STOP
165 }
166 }
167
168 // Only the delegating account's owner count was incremented on creation
169 auto const sleOwner = view.peek(keylet::account(delegator));
170 if (!sleOwner)
171 return tecINTERNAL; // LCOV_EXCL_LINE
172
173 adjustOwnerCount(view, sleOwner, -1, j);
174
175 view.erase(sle);
176
177 return tesSUCCESS;
178}
179
180void
182{
183 // No transaction-specific invariants yet (future work).
184}
185
186bool
188{
189 // No transaction-specific invariants yet (future work).
190 return true;
191}
192
193} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
Stream fatal() const
Definition Journal.h:321
Writeable view to a ledger, for applying a transaction.
Definition ApplyView.h:118
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:31
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:246
std::shared_ptr< STLedgerEntry > const & ref
std::shared_ptr< STLedgerEntry const > const & const_ref
STArray const & getFieldArray(SField const &field) const
Definition STObject.cpp:678
beast::Journal const j_
Definition Transactor.h:118
ApplyView & view()
Definition Transactor.h:136
AccountID const accountID_
Definition Transactor.h:120
XRPAmount preFeeBalance_
Definition Transactor.h:121
ApplyContext & ctx_
Definition Transactor.h:116
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:357
Keylet delegate(AccountID const &account, AccountID const &authorizedAccount) noexcept
A keylet for Delegate object.
Definition Indexes.cpp:465
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:186
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ terNO_ACCOUNT
Definition TER.h:209
constexpr std::size_t kPermissionMaxSize
The maximum number of delegate permissions an account can grant.
Definition Protocol.h:309
@ tefBAD_LEDGER
Definition TER.h:160
@ tefINTERNAL
Definition TER.h:163
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:594
void adjustOwnerCount(ApplyView &view, SLE::ref sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Returns a function that sets the owner on a directory SLE.
@ temARRAY_TOO_LARGE
Definition TER.h:127
@ temMALFORMED
Definition TER.h:73
TERSubset< CanCvtToTER > TER
Definition TER.h:634
@ tecDIR_FULL
Definition TER.h:285
@ tecNO_ENTRY
Definition TER.h:304
@ tecNO_TARGET
Definition TER.h:302
@ tecINTERNAL
Definition TER.h:308
@ tecINSUFFICIENT_RESERVE
Definition TER.h:305
@ tecNO_PERMISSION
Definition TER.h:303
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:240
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:61
ReadView const & view
Definition Transactor.h:64
State information when preflighting a tx.
Definition Transactor.h:18