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:373
static std::uint32_t getFlagsMask(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.
void visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override
Inspect a single ledger entry modified by this transaction.
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:182
std::shared_ptr< STLedgerEntry const > const & ConstRef
beast::Journal const j_
Definition Transactor.h:164
ApplyView & view()
Definition Transactor.h:184
AccountID const accountID_
Definition Transactor.h:166
XRPAmount preFeeBalance_
Definition Transactor.h:167
ApplyContext & ctx_
Definition Transactor.h:162
T make_shared(T... args)
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:403
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:220
Keylet credential(AccountID const &subject, AccountID const &issuer, Slice const &credType) noexcept
Definition Indexes.cpp:585
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
constexpr std::size_t kMaxCredentialTypeLength
The maximum length of a CredentialType inside a Credential.
Definition Protocol.h:276
@ tefINTERNAL
Definition TER.h:168
TER checkReserve(ApplyViewContext ctx, SLE::ConstRef accSle, XRPAmount accBalance, SLE::ConstRef sponsorSle, Adjustment adj, beast::Journal j, TER insufReserveCode=tecINSUFFICIENT_RESERVE)
Check if an account has sufficient reserve.
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.
void addSponsorToLedgerEntry(SLE::Ref sle, SLE::ConstRef sponsorSle, SF_ACCOUNT const &field=sfSponsor)
Stamp a reserve sponsor onto a ledger entry using an explicit sponsor SLE.
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:657
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:614
bool isPseudoAccount(SLE::const_pointer sleAcct)
Returns true if and only if sleAcct is a pseudo-account of any kind (i.e.
constexpr std::size_t kMaxCredentialUriLength
The maximum length of a URI inside a Credential.
Definition Protocol.h:271
@ temMALFORMED
Definition TER.h:75
bool isTesSuccess(TER x) noexcept
Definition TER.h:683
TERSubset< CanCvtToTER > TER
Definition TER.h:654
@ tecDIR_FULL
Definition TER.h:295
@ tecPSEUDO_ACCOUNT
Definition TER.h:370
@ tecNO_TARGET
Definition TER.h:312
@ tecEXPIRED
Definition TER.h:322
@ tecDUPLICATE
Definition TER.h:323
std::function< void(SLE::Ref)> describeOwnerDir(AccountID const &account)
Returns a function that sets the owner on a directory SLE.
constexpr FlagValue tfUniversalMask
Definition TxFlags.h:46
@ tesSUCCESS
Definition TER.h:250
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:92
ReadView const & view
Definition Transactor.h:95
beast::Journal const j
Definition Transactor.h:100
State information when preflighting a tx.
Definition Transactor.h:39
beast::Journal const j
Definition Transactor.h:46