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 = ctx.view().fees().accountReserve((*sleAccount)[sfOwnerCount] + 1);
76
77 if (balance < reserve)
79 }
80
81 // Add ledger object to ledger
82 ctx.view().insert(sle);
83
84 // Add ledger object to owner's page
85 {
86 auto page =
87 ctx.view().dirInsert(keylet::ownerDir(owner), sle->key(), describeOwnerDir(owner));
88 if (!page)
89 return tecDIR_FULL; // LCOV_EXCL_LINE
90 (*sle)[sfOwnerNode] = *page;
91 }
92 adjustOwnerCount(ctx.view(), sleAccount, 1, ctx.journal);
93 ctx.view().update(sleAccount);
94
95 return tesSUCCESS;
96}
97
98TER
100{
101 // Edit ledger object if it already exists
102 Keylet const didKeylet = keylet::did(accountID_);
103 if (auto const sleDID = ctx_.view().peek(didKeylet))
104 {
105 auto update = [&](auto const& sField) {
106 if (auto const field = ctx_.tx[~sField])
107 {
108 if (field->empty())
109 {
110 sleDID->makeFieldAbsent(sField);
111 }
112 else
113 {
114 (*sleDID)[sField] = *field;
115 }
116 }
117 };
118 update(sfURI);
119 update(sfDIDDocument);
120 update(sfData);
121
122 if (!sleDID->isFieldPresent(sfURI) && !sleDID->isFieldPresent(sfDIDDocument) &&
123 !sleDID->isFieldPresent(sfData))
124 {
125 return tecEMPTY_DID;
126 }
127 ctx_.view().update(sleDID);
128 return tesSUCCESS;
129 }
130
131 // Create new ledger object otherwise
132 auto const sleDID = std::make_shared<SLE>(didKeylet);
133 (*sleDID)[sfAccount] = accountID_;
134
135 auto set = [&](auto const& sField) {
136 if (auto const field = ctx_.tx[~sField]; field && !field->empty())
137 (*sleDID)[sField] = *field;
138 };
139
140 set(sfURI);
141 set(sfDIDDocument);
142 set(sfData);
143 if (ctx_.view().rules().enabled(fixEmptyDID) && !sleDID->isFieldPresent(sfURI) &&
144 !sleDID->isFieldPresent(sfDIDDocument) && !sleDID->isFieldPresent(sfData))
145 {
146 return tecEMPTY_DID;
147 }
148
149 return addSLE(ctx_, sleDID, accountID_);
150}
151
152void
154{
155 // No transaction-specific invariants yet (future work).
156}
157
158bool
160{
161 // No transaction-specific invariants yet (future work).
162 return true;
163}
164
165} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
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:340
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:159
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:153
TER doApply() override
Definition DIDSet.cpp:99
static NotTEC preflight(PreflightContext const &ctx)
Definition DIDSet.cpp:41
A view into a ledger.
Definition ReadView.h:31
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
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:967
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:454
AccountID const accountID_
Definition Transactor.h:120
ApplyContext & ctx_
Definition Transactor.h:116
T make_shared(T... args)
Keylet did(AccountID const &account) noexcept
Definition Indexes.cpp:509
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:357
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:186
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,...
@ tefINTERNAL
Definition TER.h:163
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:216
constexpr std::size_t kMaxDidUriLength
The maximum length of a URI inside a DID.
Definition Protocol.h:213
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:594
constexpr std::size_t kMaxDidDocumentLength
The maximum length of a Data element inside a DID.
Definition Protocol.h:210
void adjustOwnerCount(ApplyView &view, SLE::ref sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
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:28
@ temEMPTY_DID
Definition TER.h:124
@ temMALFORMED
Definition TER.h:73
TERSubset< CanCvtToTER > TER
Definition TER.h:634
@ tecDIR_FULL
Definition TER.h:285
@ tecEMPTY_DID
Definition TER.h:351
@ tecINSUFFICIENT_RESERVE
Definition TER.h:305
@ tesSUCCESS
Definition TER.h:240
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:19
State information when preflighting a tx.
Definition Transactor.h:18