rippled
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 <ripple/app/tx/impl/DID.h>
21 
22 #include <ripple/basics/Log.h>
23 #include <ripple/ledger/ApplyView.h>
24 #include <ripple/ledger/View.h>
25 #include <ripple/protocol/Feature.h>
26 #include <ripple/protocol/Indexes.h>
27 #include <ripple/protocol/TxFlags.h>
28 #include <ripple/protocol/st.h>
29 
30 namespace 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 
46 NotTEC
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) &&
60  return temEMPTY_DID;
61 
62  if (ctx.tx.isFieldPresent(sfURI) && ctx.tx[sfURI].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 
81 TER
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 
118 TER
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);
163  set(sfData);
164 
165  return addSLE(ctx_, sleDID, account_);
166 }
167 
168 NotTEC
170 {
171  if (!ctx.rules.enabled(featureDID))
172  return temDISABLED;
173 
174  if (ctx.tx.getFlags() & tfUniversalMask)
175  return temINVALID_FLAG;
176 
177  if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
178  return ret;
179 
180  return preflight2(ctx);
181 }
182 
183 TER
184 DIDDelete::deleteSLE(ApplyContext& ctx, Keylet sleKeylet, AccountID const owner)
185 {
186  auto const sle = ctx.view().peek(sleKeylet);
187  if (!sle)
188  return tecNO_ENTRY;
189 
190  return DIDDelete::deleteSLE(ctx.view(), sle, owner, ctx.journal);
191 }
192 
193 TER
195  ApplyView& view,
197  AccountID const owner,
198  beast::Journal j)
199 {
200  // Remove object from owner directory
201  if (!view.dirRemove(
202  keylet::ownerDir(owner), (*sle)[sfOwnerNode], sle->key(), true))
203  {
204  JLOG(j.fatal()) << "Unable to delete DID Token from owner.";
205  return tefBAD_LEDGER;
206  }
207 
208  auto const sleOwner = view.peek(keylet::account(owner));
209  if (!sleOwner)
210  return tecINTERNAL;
211 
212  adjustOwnerCount(view, sleOwner, -1, j);
213  view.update(sleOwner);
214 
215  // Remove object from ledger
216  view.erase(sle);
217  return tesSUCCESS;
218 }
219 
220 TER
222 {
224 }
225 
226 } // namespace ripple
ripple::addSLE
TER addSLE(ApplyContext &ctx, std::shared_ptr< SLE > const &sle, AccountID const &owner)
Definition: DID.cpp:82
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:338
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:312
ripple::sfOwnerCount
const SF_UINT32 sfOwnerCount
ripple::STLedgerEntry::key
uint256 const & key() const
Returns the 'key' (or 'index') of this item.
Definition: STLedgerEntry.h:113
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:133
ripple::Keylet
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:38
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:167
ripple::Rules::enabled
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:94
std::shared_ptr
STL class.
ripple::sfOwnerNode
const SF_UINT64 sfOwnerNode
ripple::ApplyView::peek
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
ripple::featureDID
const uint256 featureDID
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:748
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:636
ripple::DIDDelete::preflight
static NotTEC preflight(PreflightContext const &ctx)
Definition: DID.cpp:169
ripple::ApplyView::erase
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
ripple::ReadView::fees
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
ripple::maxDIDURILength
constexpr std::size_t maxDIDURILength
The maximum length of a URI inside a DID.
Definition: Protocol.h:90
ripple::STObject::empty
bool empty() const
Definition: STObject.h:875
ripple::keylet::did
Keylet did(AccountID const &account) noexcept
Definition: Indexes.cpp:442
ripple::ApplyView::update
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
ripple::ApplyContext::journal
const beast::Journal journal
Definition: ApplyContext.h:51
ripple::temEMPTY_DID
@ temEMPTY_DID
Definition: TER.h:137
ripple::DIDSet::preflight
static NotTEC preflight(PreflightContext const &ctx)
Definition: DID.cpp:47
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:345
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:81
ripple::ApplyView
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:134
ripple::ApplyView::dirRemove
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
Definition: ApplyView.cpp:189
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:82
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:110
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:164
ripple::adjustOwnerCount
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:730
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:142
ripple::DIDDelete::deleteSLE
static TER deleteSLE(ApplyContext &ctx, Keylet sleKeylet, AccountID const owner)
Definition: DID.cpp:184
ripple::TERSubset< CanCvtToTER >
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:607
ripple::set
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:313
ripple::STAmount
Definition: STAmount.h:46
ripple::tecINTERNAL
@ tecINTERNAL
Definition: TER.h:290
ripple::STObject::getFlags
std::uint32_t getFlags() const
Definition: STObject.cpp:481
ripple::maxDIDDocumentLength
constexpr std::size_t maxDIDDocumentLength
The maximum length of a Data element inside a DID.
Definition: Protocol.h:87
ripple::ApplyContext
State information when applying a tx.
Definition: ApplyContext.h:35
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::ApplyContext::view
ApplyView & view()
Definition: ApplyContext.h:54
ripple::tecDIR_FULL
@ tecDIR_FULL
Definition: TER.h:267
ripple::sfURI
const SF_VL sfURI
ripple::ApplyView::insert
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::sfDIDDocument
const SF_VL sfDIDDocument
ripple::Transactor::view
ApplyView & view()
Definition: Transactor.h:107
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:113
ripple::Fees::accountReserve
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
Definition: protocol/Fees.h:49
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:428
ripple::tecEMPTY_DID
@ tecEMPTY_DID
Definition: TER.h:333
ripple::sfData
const SF_VL sfData
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:287
ripple::DIDSet::doApply
TER doApply() override
Definition: DID.cpp:119
ripple::maxDIDAttestationLength
constexpr std::size_t maxDIDAttestationLength
The maximum length of an Attestation inside a DID.
Definition: Protocol.h:93
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:88
std::size_t
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:286
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:86
ripple::PreflightContext::tx
STTx const & tx
Definition: Transactor.h:35
ripple::PreflightContext
State information when preflighting a tx.
Definition: Transactor.h:31
ripple::ApplyView::dirInsert
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:306
ripple::PreflightContext::rules
const Rules rules
Definition: Transactor.h:36
ripple::tfUniversalMask
constexpr std::uint32_t tfUniversalMask
Definition: TxFlags.h:60
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:235
ripple::Transactor::account_
const AccountID account_
Definition: Transactor.h:91
ripple::DIDDelete::doApply
TER doApply() override
Definition: DID.cpp:221
ripple::ApplyContext::tx
STTx const & tx
Definition: ApplyContext.h:48
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:567