xrpld
Loading...
Searching...
No Matches
CredentialCreate.cpp
1#include <xrpl/tx/transactors/credentials/CredentialCreate.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/core/ServiceRegistry.h>
6#include <xrpl/ledger/ApplyView.h>
7#include <xrpl/ledger/helpers/AccountRootHelpers.h>
8#include <xrpl/ledger/helpers/CredentialHelpers.h> // IWYU pragma: keep
9#include <xrpl/ledger/helpers/DirectoryHelpers.h>
10#include <xrpl/ledger/helpers/SponsorHelpers.h>
11#include <xrpl/protocol/Feature.h>
12#include <xrpl/protocol/Indexes.h>
13#include <xrpl/protocol/Keylet.h>
14#include <xrpl/protocol/LedgerFormats.h>
15#include <xrpl/protocol/Protocol.h>
16#include <xrpl/protocol/SField.h>
17#include <xrpl/protocol/STLedgerEntry.h>
18#include <xrpl/protocol/STTx.h>
19#include <xrpl/protocol/TER.h>
20#include <xrpl/protocol/TxFlags.h>
21#include <xrpl/protocol/XRPAmount.h>
22#include <xrpl/tx/Transactor.h>
23
24#include <chrono>
25#include <cstdint>
26#include <memory>
27
28namespace xrpl {
29
30/*
31 Credentials
32 ======
33
34 A verifiable credentials (VC
35 https://en.wikipedia.org/wiki/Verifiable_credentials), as defined by the W3C
36 specification (https://www.w3.org/TR/vc-data-model-2.0/), is a
37 secure and tamper-evident way to represent information about a subject, such
38 as an individual, organization, or even an IoT device. These credentials are
39 issued by a trusted entity and can be verified by third parties without
40 directly involving the issuer at all.
41*/
42
43using namespace credentials;
44
45std::uint32_t
47{
48 // 0 means "Allow any flags"
49 return ctx.rules.enabled(fixInvalidTxFlags) ? tfUniversalMask : 0;
50}
51
54{
55 auto const& tx = ctx.tx;
56 auto& j = ctx.j;
57
58 if (!tx[sfSubject])
59 {
60 JLOG(j.trace()) << "Malformed transaction: Invalid Subject";
61 return temMALFORMED;
62 }
63
64 auto const uri = tx[~sfURI];
65 if (uri && (uri->empty() || (uri->size() > kMaxCredentialUriLength)))
66 {
67 JLOG(j.trace()) << "Malformed transaction: invalid size of URI.";
68 return temMALFORMED;
69 }
70
71 auto const credType = tx[sfCredentialType];
72 if (credType.empty() || (credType.size() > kMaxCredentialTypeLength))
73 {
74 JLOG(j.trace()) << "Malformed transaction: invalid size of CredentialType.";
75 return temMALFORMED;
76 }
77
78 return tesSUCCESS;
79}
80
81TER
83{
84 auto const credType(ctx.tx[sfCredentialType]);
85 auto const subject = ctx.tx[sfSubject];
86
87 auto const subjectSle = ctx.view.read(keylet::account(subject));
88
89 if (!subjectSle)
90 {
91 JLOG(ctx.j.trace()) << "Subject doesn't exist.";
92 return tecNO_TARGET;
93 }
94
95 if (ctx.view.exists(keylet::credential(subject, ctx.tx[sfAccount], credType)))
96 {
97 JLOG(ctx.j.trace()) << "Credential already exists.";
98 return tecDUPLICATE;
99 }
100
101 if (ctx.view.rules().enabled(fixCleanup3_3_0) && isPseudoAccount(subjectSle))
102 {
103 JLOG(ctx.j.trace()) << "Subject is a pseudo-account.";
104 return tecPSEUDO_ACCOUNT;
105 }
106
107 return tesSUCCESS;
108}
109
110TER
112{
113 auto const subject = ctx_.tx[sfSubject];
114 auto const credType(ctx_.tx[sfCredentialType]);
115 Keylet const credentialKey = keylet::credential(subject, accountID_, credType);
116
117 auto const sleCred = std::make_shared<SLE>(credentialKey);
118 if (!sleCred)
119 return tefINTERNAL; // LCOV_EXCL_LINE
120
121 auto const optExp = ctx_.tx[~sfExpiration];
122 if (optExp)
123 {
124 std::uint32_t const closeTime =
125 ctx_.view().header().parentCloseTime.time_since_epoch().count();
126
127 if (closeTime > *optExp)
128 {
129 JLOG(j_.trace()) << "Malformed transaction: "
130 "Expiration time is in the past.";
131 return tecEXPIRED;
132 }
133
134 sleCred->setFieldU32(sfExpiration, *optExp);
135 }
136
137 auto const sleIssuer = view().peek(keylet::account(accountID_));
138 if (!sleIssuer)
139 return tefINTERNAL; // LCOV_EXCL_LINE
140
141 if (auto const ret = checkReserve(
142 ctx_.getApplyViewContext(), sleIssuer, preFeeBalance_, {.ownerCountDelta = 1}, j_);
143 !isTesSuccess(ret))
144 return ret;
145
146 sleCred->setAccountID(sfSubject, subject);
147 sleCred->setAccountID(sfIssuer, accountID_);
148 sleCred->setFieldVL(sfCredentialType, credType);
149
150 if (ctx_.tx.isFieldPresent(sfURI))
151 sleCred->setFieldVL(sfURI, ctx_.tx.getFieldVL(sfURI));
152
153 {
154 auto const page = view().dirInsert(
156 JLOG(j_.trace()) << "Adding Credential to owner directory " << to_string(credentialKey.key)
157 << ": " << (page ? "success" : "failure");
158 if (!page)
159 return tecDIR_FULL;
160 sleCred->setFieldU64(sfIssuerNode, *page);
161
162 increaseOwnerCount(ctx_.getApplyViewContext(), sleIssuer, 1, j_);
163 addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCred);
164 }
165
166 if (subject == accountID_)
167 {
168 sleCred->setFieldU32(sfFlags, lsfAccepted);
169 }
170 else
171 {
172 // Added to both dirs, owned only by issuer. CredentialAccept will transfer ownership to
173 // subject. CredentialDelete will remove from both dirs and decrement 1 ownerCount.
174 auto const page =
175 view().dirInsert(keylet::ownerDir(subject), credentialKey, describeOwnerDir(subject));
176 JLOG(j_.trace()) << "Adding Credential to subject directory "
177 << to_string(credentialKey.key) << ": " << (page ? "success" : "failure");
178 if (!page)
179 return tecDIR_FULL;
180 sleCred->setFieldU64(sfSubjectNode, *page);
181 }
182
183 view().insert(sleCred);
184
185 return tesSUCCESS;
186}
187
188void
190{
191 // No transaction-specific invariants yet (future work).
192}
193
194bool
196 STTx const&,
197 TER,
198 XRPAmount,
199 ReadView const&,
200 beast::Journal const&)
201{
202 // No transaction-specific invariants yet (future work).
203 return true;
204}
205} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:44
Stream trace() const
Severity stream access functions.
Definition Journal.h:338
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void insert(SLE::ref sle)=0
Insert a new state SLE.
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(SLE::ref)> const &describe)
Insert an entry to a directory.
Definition ApplyView.h:366
static std::uint32_t getFlagsMask(PreflightContext const &ctx)
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
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.
static NotTEC preflight(PreflightContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
A view into a ledger.
Definition ReadView.h:41
virtual Rules const & rules() const =0
Returns the tx processing rules.
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 enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:180
std::shared_ptr< STLedgerEntry const > const & const_ref
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 make_shared(T... args)
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:373
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:198
Keylet credential(AccountID const &subject, AccountID const &issuer, Slice const &credType) noexcept
Definition Indexes.cpp:555
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
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 kMaxCredentialTypeLength
The maximum length of a CredentialType inside a Credential.
Definition Protocol.h:275
@ tefINTERNAL
Definition TER.h:165
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
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.
constexpr std::size_t kMaxCredentialUriLength
The maximum length of a URI inside a Credential.
Definition Protocol.h:270
@ 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_TARGET
Definition TER.h:307
@ tecEXPIRED
Definition TER.h:317
@ tecDUPLICATE
Definition TER.h:318
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...
constexpr FlagValue tfUniversalMask
Definition TxFlags.h:46
@ tesSUCCESS
Definition TER.h:245
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:20
uint256 key
Definition Keylet.h:21
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:83
ReadView const & view
Definition Transactor.h:86
beast::Journal const j
Definition Transactor.h:91
State information when preflighting a tx.
Definition Transactor.h:38
beast::Journal const j
Definition Transactor.h:45