xrpld
Loading...
Searching...
No Matches
LedgerStateFix.cpp
1#include <xrpl/tx/transactors/system/LedgerStateFix.h>
2
3#include <xrpl/beast/utility/Journal.h>
4#include <xrpl/ledger/ReadView.h>
5#include <xrpl/ledger/helpers/NFTokenHelpers.h>
6#include <xrpl/protocol/AccountID.h>
7#include <xrpl/protocol/Feature.h>
8#include <xrpl/protocol/Indexes.h>
9#include <xrpl/protocol/LedgerFormats.h>
10#include <xrpl/protocol/SField.h>
11#include <xrpl/protocol/STLedgerEntry.h>
12#include <xrpl/protocol/STTx.h>
13#include <xrpl/protocol/TER.h>
14#include <xrpl/protocol/XRPAmount.h>
15#include <xrpl/tx/Transactor.h>
16
17#include <algorithm>
18#include <array>
19#include <utility>
20
21namespace xrpl {
22
23namespace {
24
25using FixType = LedgerStateFix::FixType;
26
27std::array<std::pair<FixType, SField const*>, 2> const kLedgerFixFields = {{
28 {FixType::NfTokenPageLink, &sfOwner},
29 {FixType::BookExchangeRate, &sfBookDirectory},
30}};
31
32[[nodiscard]] SField const*
33fixField(FixType const fixType)
34{
35 auto const iter = std::ranges::find_if(
36 kLedgerFixFields, [fixType](auto const& entry) { return entry.first == fixType; });
37
38 if (iter == kLedgerFixFields.end())
39 return nullptr; // LCOV_EXCL_LINE
40
41 return iter->second;
42}
43
44[[nodiscard]] bool
45hasUnexpectedFixField(STTx const& tx, SField const& expected)
46{
47 return std::ranges::any_of(kLedgerFixFields, [&tx, &expected](auto const& entry) {
48 auto const field = entry.second;
49 return field != &expected && tx.isFieldPresent(*field);
50 });
51}
52
53} // namespace
54
57{
58 auto const fixType = static_cast<FixType>(ctx.tx[sfLedgerFixType]);
59
60 switch (fixType)
61 {
63 break;
64
66 if (!ctx.rules.enabled(fixCleanup3_2_0))
67 return temDISABLED;
68 break;
69
70 default:
72 }
73
74 auto const expectedField = fixField(fixType);
75 if (expectedField == nullptr)
76 return tefINVALID_LEDGER_FIX_TYPE; // LCOV_EXCL_LINE
77
78 // Each fix type allows exactly one fix-specific field.
79 if (!ctx.tx.isFieldPresent(*expectedField) || hasUnexpectedFixField(ctx.tx, *expectedField))
80 return temINVALID;
81
82 return tesSUCCESS;
83}
84
87{
88 // The fee required for LedgerStateFix is one owner reserve, just like
89 // the fee for AccountDelete.
91}
92
93TER
95{
96 if (static_cast<FixType>(ctx.tx[sfLedgerFixType]) == FixType::NfTokenPageLink)
97 {
98 AccountID const owner{ctx.tx[sfOwner]};
99 if (!ctx.view.read(keylet::account(owner)))
100 return tecOBJECT_NOT_FOUND;
101
102 return tesSUCCESS;
103 }
104
105 if (static_cast<FixType>(ctx.tx[sfLedgerFixType]) == FixType::BookExchangeRate)
106 {
107 auto const dirKey = ctx.tx.getFieldH256(sfBookDirectory);
108 auto const sle = ctx.view.read(Keylet(ltDIR_NODE, dirKey));
109 if (!sle)
110 return tecOBJECT_NOT_FOUND;
111
112 // Must be the first page of a book directory (has sfExchangeRate).
113 if (!sle->isFieldPresent(sfExchangeRate))
114 return tecNO_PERMISSION;
115
116 // ExchangeRate is already correct, nothing to fix.
117 if (getQuality(sle->key()) == sle->getFieldU64(sfExchangeRate))
118 return tecNO_PERMISSION;
119
120 return tesSUCCESS;
121 }
122
123 // preflight is supposed to verify that only valid FixTypes get to preclaim.
124 return tecINTERNAL; // LCOV_EXCL_LINE
125}
126
127TER
129{
130 if (static_cast<FixType>(ctx_.tx[sfLedgerFixType]) == FixType::NfTokenPageLink)
131 {
132 if (!nft::repairNFTokenDirectoryLinks(view(), ctx_.tx[sfOwner]))
134
135 return tesSUCCESS;
136 }
137
138 if (static_cast<FixType>(ctx_.tx[sfLedgerFixType]) == FixType::BookExchangeRate)
139 {
140 auto const dirKey = ctx_.tx.getFieldH256(sfBookDirectory);
141 auto sle = view().peek(Keylet(ltDIR_NODE, dirKey));
142 if (!sle)
143 return tecINTERNAL; // LCOV_EXCL_LINE
144
145 sle->setFieldU64(sfExchangeRate, getQuality(sle->key()));
146 view().update(sle);
147 return tesSUCCESS;
148 }
149
150 // preflight is supposed to verify that only valid FixTypes get to doApply.
151 return tecINTERNAL; // LCOV_EXCL_LINE
152}
153
154void
156{
157 // No transaction-specific invariants yet (future work).
158}
159
160bool
162 STTx const&,
163 TER,
164 XRPAmount,
165 ReadView const&,
166 beast::Journal const&)
167{
168 // No transaction-specific invariants yet (future work).
169 return true;
170}
171
172} // namespace xrpl
T any_of(T... args)
A generic endpoint for log messages.
Definition Journal.h:38
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
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.
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
static NotTEC preflight(PreflightContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
A view into a ledger.
Definition ReadView.h:31
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:171
Identifies fields.
Definition SField.h:130
std::shared_ptr< STLedgerEntry const > const & const_ref
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:454
uint256 getFieldH256(SField const &field) const
Definition STObject.cpp:621
static XRPAmount calculateOwnerReserveFee(ReadView const &view, STTx const &tx)
ApplyView & view()
Definition Transactor.h:136
ApplyContext & ctx_
Definition Transactor.h:116
T end(T... args)
T find_if(T... args)
FieldT< CharT, Traits, Allocator > field(std::basic_string< CharT, Traits, Allocator > const &text, int width=8, int pad=0, bool right=false)
Definition iosformat.h:133
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:186
bool repairNFTokenDirectoryLinks(ApplyView &view, AccountID const &owner)
Repairs the links in an NFTokenPage directory.
json::Value entry(jtx::Env &env, jtx::Account const &account, jtx::Account const &authorize)
Definition delegate.cpp:41
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ tefINVALID_LEDGER_FIX_TYPE
Definition TER.h:177
std::uint64_t getQuality(uint256 const &uBase)
Definition Indexes.cpp:152
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:594
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:28
@ temINVALID
Definition TER.h:96
@ temDISABLED
Definition TER.h:100
TERSubset< CanCvtToTER > TER
Definition TER.h:634
@ tecOBJECT_NOT_FOUND
Definition TER.h:324
@ tecINTERNAL
Definition TER.h:308
@ tecFAILED_PROCESSING
Definition TER.h:284
@ tecNO_PERMISSION
Definition TER.h:303
@ tesSUCCESS
Definition TER.h:240
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:19
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:61
ReadView const & view
Definition Transactor.h:64
State information when preflighting a tx.
Definition Transactor.h:18