rippled
Loading...
Searching...
No Matches
DID.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2023 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/tx/detail/DID.h>
21
22#include <xrpld/ledger/ApplyView.h>
23#include <xrpld/ledger/View.h>
24#include <xrpl/basics/Log.h>
25#include <xrpl/protocol/Feature.h>
26#include <xrpl/protocol/Indexes.h>
27#include <xrpl/protocol/TxFlags.h>
28#include <xrpl/protocol/st.h>
29
30namespace ripple {
31
32/*
33 DID
34 ======
35
36 Decentralized Identifiers (DIDs) are a new type of identifier that enable
37 verifiable, self-sovereign digital identity and are designed to be
38 compatible with any distributed ledger or network. This implementation
39 conforms to the requirements specified in the DID v1.0 specification
40 currently recommended by the W3C Credentials Community Group
41 (https://www.w3.org/TR/did-core/).
42*/
43
44//------------------------------------------------------------------------------
45
48{
49 if (!ctx.rules.enabled(featureDID))
50 return temDISABLED;
51
52 if (ctx.tx.getFlags() & tfUniversalMask)
53 return temINVALID_FLAG;
54
55 if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
56 return ret;
57
58 if (!ctx.tx.isFieldPresent(sfURI) &&
59 !ctx.tx.isFieldPresent(sfDIDDocument) && !ctx.tx.isFieldPresent(sfData))
60 return temEMPTY_DID;
61
62 if (ctx.tx.isFieldPresent(sfURI) && ctx.tx[sfURI].empty() &&
63 ctx.tx.isFieldPresent(sfDIDDocument) && ctx.tx[sfDIDDocument].empty() &&
64 ctx.tx.isFieldPresent(sfData) && ctx.tx[sfData].empty())
65 return temEMPTY_DID;
66
67 auto isTooLong = [&](auto const& sField, std::size_t length) -> bool {
68 if (auto field = ctx.tx[~sField])
69 return field->length() > length;
70 return false;
71 };
72
73 if (isTooLong(sfURI, maxDIDURILength) ||
74 isTooLong(sfDIDDocument, maxDIDDocumentLength) ||
75 isTooLong(sfData, maxDIDAttestationLength))
76 return temMALFORMED;
77
78 return preflight2(ctx);
79}
80
81TER
83 ApplyContext& ctx,
84 std::shared_ptr<SLE> const& sle,
85 AccountID const& owner)
86{
87 auto const sleAccount = ctx.view().peek(keylet::account(owner));
88 if (!sleAccount)
89 return tefINTERNAL;
90
91 // Check reserve availability for new object creation
92 {
93 auto const balance = STAmount((*sleAccount)[sfBalance]).xrp();
94 auto const reserve =
95 ctx.view().fees().accountReserve((*sleAccount)[sfOwnerCount] + 1);
96
97 if (balance < reserve)
99 }
100
101 // Add ledger object to ledger
102 ctx.view().insert(sle);
103
104 // Add ledger object to owner's page
105 {
106 auto page = ctx.view().dirInsert(
107 keylet::ownerDir(owner), sle->key(), describeOwnerDir(owner));
108 if (!page)
109 return tecDIR_FULL;
110 (*sle)[sfOwnerNode] = *page;
111 }
112 adjustOwnerCount(ctx.view(), sleAccount, 1, ctx.journal);
113 ctx.view().update(sleAccount);
114
115 return tesSUCCESS;
116}
117
118TER
120{
121 // Edit ledger object if it already exists
122 Keylet const didKeylet = keylet::did(account_);
123 if (auto const sleDID = ctx_.view().peek(didKeylet))
124 {
125 auto update = [&](auto const& sField) {
126 if (auto const field = ctx_.tx[~sField])
127 {
128 if (field->empty())
129 {
130 sleDID->makeFieldAbsent(sField);
131 }
132 else
133 {
134 (*sleDID)[sField] = *field;
135 }
136 }
137 };
138 update(sfURI);
139 update(sfDIDDocument);
140 update(sfData);
141
142 if (!sleDID->isFieldPresent(sfURI) &&
143 !sleDID->isFieldPresent(sfDIDDocument) &&
144 !sleDID->isFieldPresent(sfData))
145 {
146 return tecEMPTY_DID;
147 }
148 ctx_.view().update(sleDID);
149 return tesSUCCESS;
150 }
151
152 // Create new ledger object otherwise
153 auto const sleDID = std::make_shared<SLE>(didKeylet);
154 (*sleDID)[sfAccount] = account_;
155
156 auto set = [&](auto const& sField) {
157 if (auto const field = ctx_.tx[~sField]; field && !field->empty())
158 (*sleDID)[sField] = *field;
159 };
160
161 set(sfURI);
162 set(sfDIDDocument);
163 set(sfData);
164 if (ctx_.view().rules().enabled(fixEmptyDID) &&
165 !sleDID->isFieldPresent(sfURI) &&
166 !sleDID->isFieldPresent(sfDIDDocument) &&
167 !sleDID->isFieldPresent(sfData))
168 {
169 return tecEMPTY_DID;
170 }
171
172 return addSLE(ctx_, sleDID, account_);
173}
174
175NotTEC
177{
178 if (!ctx.rules.enabled(featureDID))
179 return temDISABLED;
180
181 if (ctx.tx.getFlags() & tfUniversalMask)
182 return temINVALID_FLAG;
183
184 if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
185 return ret;
186
187 return preflight2(ctx);
188}
189
190TER
192{
193 auto const sle = ctx.view().peek(sleKeylet);
194 if (!sle)
195 return tecNO_ENTRY;
196
197 return DIDDelete::deleteSLE(ctx.view(), sle, owner, ctx.journal);
198}
199
200TER
202 ApplyView& view,
204 AccountID const owner,
206{
207 // Remove object from owner directory
208 if (!view.dirRemove(
209 keylet::ownerDir(owner), (*sle)[sfOwnerNode], sle->key(), true))
210 {
211 JLOG(j.fatal()) << "Unable to delete DID Token from owner.";
212 return tefBAD_LEDGER;
213 }
214
215 auto const sleOwner = view.peek(keylet::account(owner));
216 if (!sleOwner)
217 return tecINTERNAL;
218
219 adjustOwnerCount(view, sleOwner, -1, j);
220 view.update(sleOwner);
221
222 // Remove object from ledger
223 view.erase(sle);
224 return tesSUCCESS;
225}
226
227TER
229{
231}
232
233} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:59
Stream fatal() const
Definition: Journal.h:341
State information when applying a tx.
Definition: ApplyContext.h:36
ApplyView & view()
Definition: ApplyContext.h:54
beast::Journal const journal
Definition: ApplyContext.h:51
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:140
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
Definition: ApplyView.cpp:189
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(std::shared_ptr< SLE > const &)> const &describe)
Insert an entry to a directory.
Definition: ApplyView.h:314
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
static NotTEC preflight(PreflightContext const &ctx)
Definition: DID.cpp:176
static TER deleteSLE(ApplyContext &ctx, Keylet sleKeylet, AccountID const owner)
Definition: DID.cpp:191
TER doApply() override
Definition: DID.cpp:228
static NotTEC preflight(PreflightContext const &ctx)
Definition: DID.cpp:47
TER doApply() override
Definition: DID.cpp:119
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
virtual Rules const & rules() const =0
Returns the tx processing rules.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:122
XRPAmount xrp() const
Definition: STAmount.cpp:273
bool empty() const
Definition: STObject.h:923
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:454
std::uint32_t getFlags() const
Definition: STObject.cpp:507
AccountID const account_
Definition: Transactor.h:91
ApplyView & view()
Definition: Transactor.h:107
ApplyContext & ctx_
Definition: Transactor.h:88
Keylet did(AccountID const &account) noexcept
Definition: Indexes.cpp:482
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:160
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:350
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::size_t constexpr maxDIDURILength
The maximum length of a URI inside a DID.
Definition: Protocol.h:91
std::size_t constexpr maxDIDAttestationLength
The maximum length of an Attestation inside a DID.
Definition: Protocol.h:94
TER addSLE(ApplyContext &ctx, std::shared_ptr< SLE > const &sle, AccountID const &owner)
Definition: DID.cpp:82
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:316
std::size_t constexpr maxDIDDocumentLength
The maximum length of a Data element inside a DID.
Definition: Protocol.h:88
bool isTesSuccess(TER x)
Definition: TER.h:656
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:925
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
@ tefBAD_LEDGER
Definition: TER.h:170
@ tefINTERNAL
Definition: TER.h:173
static bool adjustOwnerCount(ApplyContext &ctx, int count)
Definition: SetOracle.cpp:186
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:134
@ tecNO_ENTRY
Definition: TER.h:293
@ tecDIR_FULL
Definition: TER.h:274
@ tecINTERNAL
Definition: TER.h:297
@ tecEMPTY_DID
Definition: TER.h:340
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:294
@ tesSUCCESS
Definition: TER.h:242
constexpr std::uint32_t tfUniversalMask
Definition: TxFlags.h:62
TERSubset< CanCvtToTER > TER
Definition: TER.h:627
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:587
@ temMALFORMED
Definition: TER.h:87
@ temINVALID_FLAG
Definition: TER.h:111
@ temDISABLED
Definition: TER.h:114
@ temEMPTY_DID
Definition: TER.h:138
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
Definition: protocol/Fees.h:49
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:39
State information when preflighting a tx.
Definition: Transactor.h:32