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