xrpld
Loading...
Searching...
No Matches
DIDSet.cpp
1#include <xrpl/tx/transactors/did/DIDSet.h>
2
3#include <xrpl/core/ServiceRegistry.h>
4#include <xrpl/ledger/ApplyView.h>
5#include <xrpl/ledger/ReadView.h>
6#include <xrpl/ledger/helpers/AccountRootHelpers.h>
7#include <xrpl/ledger/helpers/DirectoryHelpers.h>
8#include <xrpl/protocol/AccountID.h>
9#include <xrpl/protocol/Feature.h>
10#include <xrpl/protocol/Indexes.h>
11#include <xrpl/protocol/Keylet.h>
12#include <xrpl/protocol/Protocol.h>
13#include <xrpl/protocol/SField.h>
14#include <xrpl/protocol/STLedgerEntry.h>
15#include <xrpl/protocol/STTx.h>
16#include <xrpl/protocol/TER.h>
17#include <xrpl/protocol/XRPAmount.h>
18#include <xrpl/tx/ApplyContext.h>
19#include <xrpl/tx/Transactor.h>
20
21#include <cstddef>
22#include <memory>
23
24namespace xrpl {
25
26/*
27 DID
28 ======
29
30 Decentralized Identifiers (DIDs) are a new type of identifier that enable
31 verifiable, self-sovereign digital identity and are designed to be
32 compatible with any distributed ledger or network. This implementation
33 conforms to the requirements specified in the DID v1.0 specification
34 currently recommended by the W3C Credentials Community Group
35 (https://www.w3.org/TR/did-core/).
36*/
37
38//------------------------------------------------------------------------------
39
42{
43 if (!ctx.tx.isFieldPresent(sfURI) && !ctx.tx.isFieldPresent(sfDIDDocument) &&
44 !ctx.tx.isFieldPresent(sfData))
45 return temEMPTY_DID;
46
47 if (ctx.tx.isFieldPresent(sfURI) && ctx.tx[sfURI].empty() &&
48 ctx.tx.isFieldPresent(sfDIDDocument) && ctx.tx[sfDIDDocument].empty() &&
49 ctx.tx.isFieldPresent(sfData) && ctx.tx[sfData].empty())
50 return temEMPTY_DID;
51
52 auto isTooLong = [&](auto const& sField, std::size_t length) -> bool {
53 if (auto field = ctx.tx[~sField])
54 return field->length() > length;
55 return false;
56 };
57
58 if (isTooLong(sfURI, kMaxDidUriLength) || isTooLong(sfDIDDocument, kMaxDidDocumentLength) ||
59 isTooLong(sfData, kMaxDidDataLength))
60 return temMALFORMED;
61
62 return tesSUCCESS;
63}
64
65static TER
66addSLE(ApplyContext& ctx, SLE::ref sle, AccountID const& owner)
67{
68 auto const sleAccount = ctx.view().peek(keylet::account(owner));
69 if (!sleAccount)
70 return tefINTERNAL; // LCOV_EXCL_LINE
71
72 // Check reserve availability for new object creation
73 {
74 auto const balance = STAmount((*sleAccount)[sfBalance]).xrp();
75 auto const reserve =
76 accountReserve(ctx.view(), sleAccount, ctx.journal, {.ownerCountDelta = 1});
77
78 if (balance < reserve)
80 }
81
82 // Add ledger object to ledger
83 ctx.view().insert(sle);
84
85 // Add ledger object to owner's page
86 {
87 auto page =
88 ctx.view().dirInsert(keylet::ownerDir(owner), sle->key(), describeOwnerDir(owner));
89 if (!page)
90 return tecDIR_FULL; // LCOV_EXCL_LINE
91 (*sle)[sfOwnerNode] = *page;
92 }
93 increaseOwnerCount(ctx.view(), sleAccount, {}, 1, ctx.journal);
94 ctx.view().update(sleAccount);
95
96 return tesSUCCESS;
97}
98
99TER
101{
102 // Edit ledger object if it already exists
103 Keylet const didKeylet = keylet::did(accountID_);
104 if (auto const sleDID = ctx_.view().peek(didKeylet))
105 {
106 auto update = [&](auto const& sField) {
107 if (auto const field = ctx_.tx[~sField])
108 {
109 if (field->empty())
110 {
111 sleDID->makeFieldAbsent(sField);
112 }
113 else
114 {
115 (*sleDID)[sField] = *field;
116 }
117 }
118 };
119 update(sfURI);
120 update(sfDIDDocument);
121 update(sfData);
122
123 if (!sleDID->isFieldPresent(sfURI) && !sleDID->isFieldPresent(sfDIDDocument) &&
124 !sleDID->isFieldPresent(sfData))
125 {
126 return tecEMPTY_DID;
127 }
128 ctx_.view().update(sleDID);
129 return tesSUCCESS;
130 }
131
132 // Create new ledger object otherwise
133 auto const sleDID = std::make_shared<SLE>(didKeylet);
134 (*sleDID)[sfAccount] = accountID_;
135
136 auto set = [&](auto const& sField) {
137 if (auto const field = ctx_.tx[~sField]; field && !field->empty())
138 (*sleDID)[sField] = *field;
139 };
140
141 set(sfURI);
142 set(sfDIDDocument);
143 set(sfData);
144 if (ctx_.view().rules().enabled(fixEmptyDID) && !sleDID->isFieldPresent(sfURI) &&
145 !sleDID->isFieldPresent(sfDIDDocument) && !sleDID->isFieldPresent(sfData))
146 {
147 return tecEMPTY_DID;
148 }
149
150 return addSLE(ctx_, sleDID, accountID_);
151}
152
153void
155{
156 // No transaction-specific invariants yet (future work).
157}
158
159bool
161{
162 // No transaction-specific invariants yet (future work).
163 return true;
164}
165
166} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:44
State information when applying a tx.
beast::Journal const journal
ApplyView & view()
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
virtual void update(SLE::ref sle)=0
Indicate changes to a peeked SLE.
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.
Definition DIDSet.cpp:160
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
Definition DIDSet.cpp:154
TER doApply() override
Definition DIDSet.cpp:100
static NotTEC preflight(PreflightContext const &ctx)
Definition DIDSet.cpp:41
A view into a ledger.
Definition ReadView.h:41
XRPAmount xrp() const
Definition STAmount.cpp:271
std::shared_ptr< STLedgerEntry > const & ref
std::shared_ptr< STLedgerEntry const > const & const_ref
bool empty() const
Definition STObject.h:976
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:464
AccountID const accountID_
Definition Transactor.h:157
ApplyContext & ctx_
Definition Transactor.h:153
T make_shared(T... args)
Keylet did(AccountID const &account) noexcept
Definition Indexes.cpp:525
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
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
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,...
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.
@ tefINTERNAL
Definition TER.h:165
static TER addSLE(ApplyContext &ctx, SLE::ref sle, AccountID const &owner)
Definition DIDSet.cpp:66
constexpr std::size_t kMaxDidDataLength
The maximum length of an Attestation inside a DID.
Definition Protocol.h:260
constexpr std::size_t kMaxDidUriLength
The maximum length of a URI inside a DID.
Definition Protocol.h:255
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:607
constexpr std::size_t kMaxDidDocumentLength
The maximum length of a Data element inside a DID.
Definition Protocol.h:250
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Returns a function that sets the owner on a directory SLE.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:34
@ temEMPTY_DID
Definition TER.h:126
@ temMALFORMED
Definition TER.h:75
TERSubset< CanCvtToTER > TER
Definition TER.h:647
@ tecDIR_FULL
Definition TER.h:290
@ tecEMPTY_DID
Definition TER.h:356
@ tecINSUFFICIENT_RESERVE
Definition TER.h:310
XRPAmount accountReserve(ReadView const &view, SLE::const_ref sle, beast::Journal j, Adjustment adj={})
Returns the account reserve, in drops.
@ tesSUCCESS
Definition TER.h:245
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:20
State information when preflighting a tx.
Definition Transactor.h:38