xrpld
Loading...
Searching...
No Matches
VaultSet.cpp
1#include <xrpl/tx/transactors/vault/VaultSet.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/beast/utility/Zero.h>
5#include <xrpl/protocol/Feature.h>
6#include <xrpl/protocol/Indexes.h>
7#include <xrpl/protocol/LedgerFormats.h>
8#include <xrpl/protocol/Protocol.h>
9#include <xrpl/protocol/SField.h>
10#include <xrpl/protocol/STLedgerEntry.h>
11#include <xrpl/protocol/STNumber.h> // IWYU pragma: keep
12#include <xrpl/protocol/STTakesAsset.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
18namespace xrpl {
19
20bool
22{
23 return !ctx.tx.isFieldPresent(sfDomainID) || ctx.rules.enabled(featurePermissionedDomains);
24}
25
28{
29 if (ctx.tx[sfVaultID] == beast::kZero)
30 {
31 JLOG(ctx.j.debug()) << "VaultSet: zero/empty vault ID.";
32 return temMALFORMED;
33 }
34
35 if (auto const data = ctx.tx[~sfData])
36 {
37 if (data->empty() || data->length() > kMaxDataPayloadLength)
38 {
39 JLOG(ctx.j.debug()) << "VaultSet: invalid data payload size.";
40 return temMALFORMED;
41 }
42 }
43
44 if (auto const assetMax = ctx.tx[~sfAssetsMaximum])
45 {
46 if (*assetMax < beast::kZero)
47 {
48 JLOG(ctx.j.debug()) << "VaultSet: invalid max assets.";
49 return temMALFORMED;
50 }
51 }
52
53 if (!ctx.tx.isFieldPresent(sfDomainID) && !ctx.tx.isFieldPresent(sfAssetsMaximum) &&
54 !ctx.tx.isFieldPresent(sfData))
55 {
56 JLOG(ctx.j.debug()) << "VaultSet: nothing is being updated.";
57 return temMALFORMED;
58 }
59
60 return tesSUCCESS;
61}
62
63TER
65{
66 auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
67 if (!vault)
68 return tecNO_ENTRY;
69
70 // Assert that submitter is the Owner.
71 if (ctx.tx[sfAccount] != vault->at(sfOwner))
72 {
73 JLOG(ctx.j.debug()) << "VaultSet: account is not an owner.";
74 return tecNO_PERMISSION;
75 }
76
77 auto const mptIssuanceID = (*vault)[sfShareMPTID];
78 auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
79 if (!sleIssuance)
80 {
81 // LCOV_EXCL_START
82 JLOG(ctx.j.error()) << "VaultSet: missing issuance of vault shares.";
83 return tefINTERNAL;
84 // LCOV_EXCL_STOP
85 }
86
87 if (auto const domain = ctx.tx[~sfDomainID])
88 {
89 // We can only set domain if private flag was originally set
90 if (!vault->isFlag(lsfVaultPrivate))
91 {
92 JLOG(ctx.j.debug()) << "VaultSet: vault is not private";
93 return tecNO_PERMISSION;
94 }
95
96 if (*domain != beast::kZero)
97 {
98 auto const sleDomain = ctx.view.read(keylet::permissionedDomain(*domain));
99 if (!sleDomain)
100 return tecOBJECT_NOT_FOUND;
101 }
102
103 // Sanity check only, this should be enforced by VaultCreate
104 if (!sleIssuance->isFlag(lsfMPTRequireAuth))
105 {
106 // LCOV_EXCL_START
107 JLOG(ctx.j.error()) << "VaultSet: issuance of vault shares is not private.";
108 return tefINTERNAL;
109 // LCOV_EXCL_STOP
110 }
111 }
112
113 return tesSUCCESS;
114}
115
116TER
118{
119 // All return codes in `doApply` must be `tec`, `ter`, or `tes`.
120 // As we move checks into `preflight` and `preclaim`,
121 // we can consider downgrading them to `tef` or `tem`.
122
123 auto const& tx = ctx_.tx;
124
125 // Update existing object.
126 auto vault = view().peek(keylet::vault(tx[sfVaultID]));
127 if (!vault)
128 return tefINTERNAL; // LCOV_EXCL_LINE
129
130 auto const vaultAsset = vault->at(sfAsset);
131
132 auto const mptIssuanceID = (*vault)[sfShareMPTID];
133 auto const sleIssuance = view().peek(keylet::mptokenIssuance(mptIssuanceID));
134 if (!sleIssuance)
135 {
136 // LCOV_EXCL_START
137 JLOG(j_.error()) << "VaultSet: missing issuance of vault shares.";
138 return tefINTERNAL;
139 // LCOV_EXCL_STOP
140 }
141
142 // Update mutable flags and fields if given.
143 if (tx.isFieldPresent(sfData))
144 vault->at(sfData) = tx[sfData];
145 if (tx.isFieldPresent(sfAssetsMaximum))
146 {
147 if (tx[sfAssetsMaximum] != 0 && tx[sfAssetsMaximum] < *vault->at(sfAssetsTotal))
148 return tecLIMIT_EXCEEDED;
149 vault->at(sfAssetsMaximum) = tx[sfAssetsMaximum];
150 }
151
152 if (auto const domainId = tx[~sfDomainID]; domainId)
153 {
154 if (*domainId != beast::kZero)
155 {
156 // In VaultSet::preclaim we enforce that lsfVaultPrivate must have
157 // been set in the vault. We currently do not support making such a
158 // vault public (i.e. removal of lsfVaultPrivate flag). The
159 // sfDomainID flag must be set in the MPTokenIssuance object and can
160 // be freely updated.
161 sleIssuance->setFieldH256(sfDomainID, *domainId);
162 }
163 else if (sleIssuance->isFieldPresent(sfDomainID))
164 {
165 sleIssuance->makeFieldAbsent(sfDomainID);
166 }
167 view().update(sleIssuance);
168 }
169
170 // Note, we must update Vault object even if only DomainID is being updated
171 // in Issuance object. Otherwise it's really difficult for Vault invariants
172 // to verify the operation.
173 view().update(vault);
174
175 associateAsset(*vault, vaultAsset);
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 error() const
Definition Journal.h:315
Stream debug() const
Definition Journal.h:297
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void update(SLE::ref sle)=0
Indicate changes to a peeked SLE.
A view into a ledger.
Definition ReadView.h:31
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:171
std::shared_ptr< STLedgerEntry const > const & const_ref
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:454
beast::Journal const j_
Definition Transactor.h:118
ApplyView & view()
Definition Transactor.h:136
ApplyContext & ctx_
Definition Transactor.h:116
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.
Definition VaultSet.cpp:187
static bool checkExtraFeatures(PreflightContext const &ctx)
Definition VaultSet.cpp:21
static TER preclaim(PreclaimContext const &ctx)
Definition VaultSet.cpp:64
TER doApply() override
Definition VaultSet.cpp:117
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
Definition VaultSet.cpp:181
static NotTEC preflight(PreflightContext const &ctx)
Definition VaultSet.cpp:27
Keylet mptokenIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:521
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:551
Keylet permissionedDomain(AccountID const &account, std::uint32_t seq) noexcept
Definition Indexes.cpp:569
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ tefINTERNAL
Definition TER.h:163
constexpr std::size_t kMaxDataPayloadLength
The maximum length of Data payload.
Definition Protocol.h:242
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:594
@ temMALFORMED
Definition TER.h:73
TERSubset< CanCvtToTER > TER
Definition TER.h:634
@ tecNO_ENTRY
Definition TER.h:304
@ tecOBJECT_NOT_FOUND
Definition TER.h:324
@ tecLIMIT_EXCEEDED
Definition TER.h:359
@ tecNO_PERMISSION
Definition TER.h:303
void associateAsset(STLedgerEntry &sle, Asset const &asset)
Associate an Asset with all sMD_NeedsAsset fields in a ledger entry.
@ 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
beast::Journal const j
Definition Transactor.h:69
State information when preflighting a tx.
Definition Transactor.h:18
beast::Journal const j
Definition Transactor.h:25