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 <xrpl/basics/Log.h>
23#include <xrpl/ledger/ApplyView.h>
24#include <xrpl/ledger/View.h>
25#include <xrpl/protocol/Feature.h>
26#include <xrpl/protocol/Indexes.h>
27#include <xrpl/protocol/TxFlags.h>
28
29namespace ripple {
30
31/*
32 DID
33 ======
34
35 Decentralized Identifiers (DIDs) are a new type of identifier that enable
36 verifiable, self-sovereign digital identity and are designed to be
37 compatible with any distributed ledger or network. This implementation
38 conforms to the requirements specified in the DID v1.0 specification
39 currently recommended by the W3C Credentials Community Group
40 (https://www.w3.org/TR/did-core/).
41*/
42
43//------------------------------------------------------------------------------
44
47{
48 if (!ctx.tx.isFieldPresent(sfURI) &&
49 !ctx.tx.isFieldPresent(sfDIDDocument) && !ctx.tx.isFieldPresent(sfData))
50 return temEMPTY_DID;
51
52 if (ctx.tx.isFieldPresent(sfURI) && ctx.tx[sfURI].empty() &&
53 ctx.tx.isFieldPresent(sfDIDDocument) && ctx.tx[sfDIDDocument].empty() &&
54 ctx.tx.isFieldPresent(sfData) && ctx.tx[sfData].empty())
55 return temEMPTY_DID;
56
57 auto isTooLong = [&](auto const& sField, std::size_t length) -> bool {
58 if (auto field = ctx.tx[~sField])
59 return field->length() > length;
60 return false;
61 };
62
63 if (isTooLong(sfURI, maxDIDURILength) ||
64 isTooLong(sfDIDDocument, maxDIDDocumentLength) ||
65 isTooLong(sfData, maxDIDAttestationLength))
66 return temMALFORMED;
67
68 return tesSUCCESS;
69}
70
71TER
73 ApplyContext& ctx,
74 std::shared_ptr<SLE> const& sle,
75 AccountID const& owner)
76{
77 auto const sleAccount = ctx.view().peek(keylet::account(owner));
78 if (!sleAccount)
79 return tefINTERNAL; // LCOV_EXCL_LINE
80
81 // Check reserve availability for new object creation
82 {
83 auto const balance = STAmount((*sleAccount)[sfBalance]).xrp();
84 auto const reserve =
85 ctx.view().fees().accountReserve((*sleAccount)[sfOwnerCount] + 1);
86
87 if (balance < reserve)
89 }
90
91 // Add ledger object to ledger
92 ctx.view().insert(sle);
93
94 // Add ledger object to owner's page
95 {
96 auto page = ctx.view().dirInsert(
97 keylet::ownerDir(owner), sle->key(), describeOwnerDir(owner));
98 if (!page)
99 return tecDIR_FULL; // LCOV_EXCL_LINE
100 (*sle)[sfOwnerNode] = *page;
101 }
102 adjustOwnerCount(ctx.view(), sleAccount, 1, ctx.journal);
103 ctx.view().update(sleAccount);
104
105 return tesSUCCESS;
106}
107
108TER
110{
111 // Edit ledger object if it already exists
112 Keylet const didKeylet = keylet::did(account_);
113 if (auto const sleDID = ctx_.view().peek(didKeylet))
114 {
115 auto update = [&](auto const& sField) {
116 if (auto const field = ctx_.tx[~sField])
117 {
118 if (field->empty())
119 {
120 sleDID->makeFieldAbsent(sField);
121 }
122 else
123 {
124 (*sleDID)[sField] = *field;
125 }
126 }
127 };
128 update(sfURI);
129 update(sfDIDDocument);
130 update(sfData);
131
132 if (!sleDID->isFieldPresent(sfURI) &&
133 !sleDID->isFieldPresent(sfDIDDocument) &&
134 !sleDID->isFieldPresent(sfData))
135 {
136 return tecEMPTY_DID;
137 }
138 ctx_.view().update(sleDID);
139 return tesSUCCESS;
140 }
141
142 // Create new ledger object otherwise
143 auto const sleDID = std::make_shared<SLE>(didKeylet);
144 (*sleDID)[sfAccount] = account_;
145
146 auto set = [&](auto const& sField) {
147 if (auto const field = ctx_.tx[~sField]; field && !field->empty())
148 (*sleDID)[sField] = *field;
149 };
150
151 set(sfURI);
152 set(sfDIDDocument);
153 set(sfData);
154 if (ctx_.view().rules().enabled(fixEmptyDID) &&
155 !sleDID->isFieldPresent(sfURI) &&
156 !sleDID->isFieldPresent(sfDIDDocument) &&
157 !sleDID->isFieldPresent(sfData))
158 {
159 return tecEMPTY_DID;
160 }
161
162 return addSLE(ctx_, sleDID, account_);
163}
164
165NotTEC
167{
168 return tesSUCCESS;
169}
170
171TER
173{
174 auto const sle = ctx.view().peek(sleKeylet);
175 if (!sle)
176 return tecNO_ENTRY;
177
178 return DIDDelete::deleteSLE(ctx.view(), sle, owner, ctx.journal);
179}
180
181TER
183 ApplyView& view,
185 AccountID const owner,
187{
188 // Remove object from owner directory
189 if (!view.dirRemove(
190 keylet::ownerDir(owner), (*sle)[sfOwnerNode], sle->key(), true))
191 {
192 // LCOV_EXCL_START
193 JLOG(j.fatal()) << "Unable to delete DID Token from owner.";
194 return tefBAD_LEDGER;
195 // LCOV_EXCL_STOP
196 }
197
198 auto const sleOwner = view.peek(keylet::account(owner));
199 if (!sleOwner)
200 return tecINTERNAL; // LCOV_EXCL_LINE
201
202 adjustOwnerCount(view, sleOwner, -1, j);
203 view.update(sleOwner);
204
205 // Remove object from ledger
206 view.erase(sle);
207 return tesSUCCESS;
208}
209
210TER
215
216} // namespace ripple
A generic endpoint for log messages.
Definition Journal.h:60
Stream fatal() const
Definition Journal.h:352
State information when applying a tx.
ApplyView & view()
beast::Journal const journal
Writeable view to a ledger, for applying a transaction.
Definition ApplyView.h:143
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.
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:319
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:166
static TER deleteSLE(ApplyContext &ctx, Keylet sleKeylet, AccountID const owner)
Definition DID.cpp:172
TER doApply() override
Definition DID.cpp:211
static NotTEC preflight(PreflightContext const &ctx)
Definition DID.cpp:46
TER doApply() override
Definition DID.cpp:109
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:130
XRPAmount xrp() const
Definition STAmount.cpp:283
bool empty() const
Definition STObject.h:945
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:484
AccountID const account_
Definition Transactor.h:147
ApplyView & view()
Definition Transactor.h:163
ApplyContext & ctx_
Definition Transactor.h:143
T is_same_v
Keylet did(AccountID const &account) noexcept
Definition Indexes.cpp:514
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:184
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:374
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
std::size_t constexpr maxDIDURILength
The maximum length of a URI inside a DID.
Definition Protocol.h:94
std::size_t constexpr maxDIDAttestationLength
The maximum length of an Attestation inside a DID.
Definition Protocol.h:97
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
Definition View.cpp:1032
TER addSLE(ApplyContext &ctx, std::shared_ptr< SLE > const &sle, AccountID const &owner)
Definition DID.cpp:72
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,...
std::size_t constexpr maxDIDDocumentLength
The maximum length of a Data element inside a DID.
Definition Protocol.h:91
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition View.cpp:1050
@ tefBAD_LEDGER
Definition TER.h:170
@ tefINTERNAL
Definition TER.h:173
@ tecNO_ENTRY
Definition TER.h:307
@ tecDIR_FULL
Definition TER.h:288
@ tecINTERNAL
Definition TER.h:311
@ tecEMPTY_DID
Definition TER.h:354
@ tecINSUFFICIENT_RESERVE
Definition TER.h:308
@ tesSUCCESS
Definition TER.h:245
TERSubset< CanCvtToTER > TER
Definition TER.h:649
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:609
@ temMALFORMED
Definition TER.h:87
@ temEMPTY_DID
Definition TER.h:138
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:39
State information when preflighting a tx.
Definition Transactor.h:35