xrpld
Loading...
Searching...
No Matches
PermissionedDomainInvariant.cpp
1#include <xrpl/tx/invariants/PermissionedDomainInvariant.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/beast/utility/Journal.h>
5#include <xrpl/ledger/ReadView.h>
6#include <xrpl/ledger/helpers/CredentialHelpers.h>
7#include <xrpl/protocol/Feature.h>
8#include <xrpl/protocol/LedgerFormats.h>
9#include <xrpl/protocol/Protocol.h>
10#include <xrpl/protocol/SField.h>
11#include <xrpl/protocol/STAccount.h> // IWYU pragma: keep
12#include <xrpl/protocol/STArray.h>
13#include <xrpl/protocol/STLedgerEntry.h>
14#include <xrpl/protocol/STTx.h>
15#include <xrpl/protocol/TER.h>
16#include <xrpl/protocol/TxFormats.h>
17#include <xrpl/protocol/XRPAmount.h>
18
19#include <vector>
20
21namespace xrpl {
22
23void
25{
26 if (before && before->getType() != ltPERMISSIONED_DOMAIN)
27 return;
28 if (after && after->getType() != ltPERMISSIONED_DOMAIN)
29 return;
30
31 auto check = [isDel](std::vector<SleStatus>& sleStatus, SLE::const_ref sle) {
32 auto const& credentials = sle->getFieldArray(sfAcceptedCredentials);
33 auto const sorted = credentials::makeSorted(credentials);
34
35 SleStatus ss{
36 .credentialsSize = credentials.size(),
37 .isSorted = false,
38 .isUnique = !sorted.empty(),
39 .isDelete = isDel};
40
41 // If array have duplicates then all the other checks are invalid
42 if (ss.isUnique)
43 {
44 unsigned i = 0;
45 for (auto const& cred : sorted)
46 {
47 auto const& credTx = credentials[i++];
48 ss.isSorted =
49 (cred.first == credTx[sfIssuer]) && (cred.second == credTx[sfCredentialType]);
50 if (!ss.isSorted)
51 break;
52 }
53 }
54 sleStatus.emplace_back(ss);
55 };
56
57 if (after)
58 check(sleStatus_, after);
59}
60
61bool
63 STTx const& tx,
64 TER const result,
65 XRPAmount const,
66 ReadView const& view,
67 beast::Journal const& j)
68{
69 auto check = [](SleStatus const& sleStatus, beast::Journal const& j) {
70 if (!sleStatus.credentialsSize)
71 {
72 JLOG(j.fatal()) << "Invariant failed: permissioned domain with "
73 "no rules.";
74 return false;
75 }
76
78 {
79 JLOG(j.fatal()) << "Invariant failed: permissioned domain bad "
80 "credentials size "
81 << sleStatus.credentialsSize;
82 return false;
83 }
84
85 if (!sleStatus.isUnique)
86 {
87 JLOG(j.fatal()) << "Invariant failed: permissioned domain credentials "
88 "aren't unique";
89 return false;
90 }
91
92 if (!sleStatus.isSorted)
93 {
94 JLOG(j.fatal()) << "Invariant failed: permissioned domain credentials "
95 "aren't sorted";
96 return false;
97 }
98
99 return true;
100 };
101
102 if (view.rules().enabled(fixCleanup3_1_3))
103 {
104 // No permissioned domains should be affected if the transaction failed
105 if (!isTesSuccess(result))
106 {
107 // If nothing changed, all is good. If there were changes, that's bad.
108 return sleStatus_.empty();
109 }
110
111 if (sleStatus_.size() > 1)
112 {
113 JLOG(j.fatal()) << "Invariant failed: transaction affected more "
114 "than 1 permissioned domain entry.";
115 return false;
116 }
117
118 switch (tx.getTxnType())
119 {
120 case ttPERMISSIONED_DOMAIN_SET: {
121 if (sleStatus_.empty())
122 {
123 JLOG(j.fatal()) << "Invariant failed: no domain objects affected by "
124 "PermissionedDomainSet";
125 return false;
126 }
127
128 auto const& sleStatus = sleStatus_[0];
129 if (sleStatus.isDelete)
130 {
131 JLOG(j.fatal()) << "Invariant failed: domain object "
132 "deleted by PermissionedDomainSet";
133 return false;
134 }
135 return check(sleStatus, j);
136 }
137 case ttPERMISSIONED_DOMAIN_DELETE: {
138 if (sleStatus_.empty())
139 {
140 JLOG(j.fatal()) << "Invariant failed: no domain objects affected by "
141 "PermissionedDomainDelete";
142 return false;
143 }
144
145 if (!sleStatus_[0].isDelete)
146 {
147 JLOG(j.fatal()) << "Invariant failed: domain object "
148 "modified, but not deleted by "
149 "PermissionedDomainDelete";
150 return false;
151 }
152 return true;
153 }
154 default: {
155 if (!sleStatus_.empty())
156 {
157 JLOG(j.fatal()) << "Invariant failed: " << sleStatus_.size()
158 << " domain object(s) affected by an "
159 "unauthorized transaction. "
160 << tx.getTxnType();
161 return false;
162 }
163 return true;
164 }
165 }
166 }
167 else
168 {
169 if (tx.getTxnType() != ttPERMISSIONED_DOMAIN_SET || !isTesSuccess(result) ||
170 sleStatus_.empty())
171 return true;
172 return check(sleStatus_[0], j);
173 }
174}
175
176} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:44
Stream fatal() const
Definition Journal.h:368
A view into a ledger.
Definition ReadView.h:41
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:180
std::shared_ptr< STLedgerEntry const > const & const_ref
TxType getTxnType() const
Definition STTx.h:226
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
void visitEntry(bool, SLE::const_ref, SLE::const_ref)
T emplace_back(T... args)
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:572
bool isTesSuccess(TER x) noexcept
Definition TER.h:676
TERSubset< CanCvtToTER > TER
Definition TER.h:647
constexpr std::size_t kMaxPermissionedDomainCredentialsArraySize
The maximum number of credentials can be passed in array for permissioned domain.
Definition Protocol.h:286