xrpld
Loading...
Searching...
No Matches
AccountRootHelpers.cpp
1#include <xrpl/ledger/helpers/AccountRootHelpers.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/basics/contract.h>
6#include <xrpl/beast/utility/Journal.h>
7#include <xrpl/beast/utility/Zero.h>
8#include <xrpl/beast/utility/instrumentation.h>
9#include <xrpl/ledger/ApplyView.h>
10#include <xrpl/ledger/ReadView.h>
11#include <xrpl/protocol/AccountID.h>
12#include <xrpl/protocol/Feature.h>
13#include <xrpl/protocol/Indexes.h>
14#include <xrpl/protocol/LedgerFormats.h>
15#include <xrpl/protocol/Rate.h>
16#include <xrpl/protocol/SField.h>
17#include <xrpl/protocol/STLedgerEntry.h>
18#include <xrpl/protocol/TER.h>
19#include <xrpl/protocol/XRPAmount.h>
20#include <xrpl/protocol/digest.h>
21
22#include <algorithm>
23#include <cstdint>
24#include <expected>
25#include <limits>
26#include <memory>
27#include <optional>
28#include <set>
29#include <stdexcept>
30#include <vector>
31
32namespace xrpl {
33
34bool
35isGlobalFrozen(ReadView const& view, AccountID const& issuer)
36{
37 if (isXRP(issuer))
38 return false;
39 if (auto const sle = view.read(keylet::account(issuer)))
40 return sle->isFlag(lsfGlobalFreeze);
41 return false;
42}
43
44// An owner count cannot be negative. If adjustment would cause a negative
45// owner count, clamp the owner count at 0. Similarly for overflow. This
46// adjustment allows the ownerCount to be adjusted up or down in multiple steps.
47// If id != std::nullopt, then do error reporting.
48//
49// Returns adjusted owner count.
50static std::uint32_t
52 std::uint32_t current,
53 std::int32_t adjustment,
54 std::optional<AccountID> const& id = std::nullopt,
56{
57 std::uint32_t adjusted{current + adjustment};
58 if (adjustment > 0)
59 {
60 // Overflow is well defined on unsigned
61 if (adjusted < current)
62 {
63 if (id)
64 {
65 JLOG(j.fatal()) << "Account " << *id << " owner count exceeds max!";
66 }
68 }
69 }
70 else
71 {
72 // Underflow is well defined on unsigned
73 if (adjusted > current)
74 {
75 if (id)
76 {
77 JLOG(j.fatal()) << "Account " << *id << " owner count set below 0!";
78 }
79 adjusted = 0;
80 XRPL_ASSERT(!id, "xrpl::confineOwnerCount : id is not set");
81 }
82 }
83 return adjusted;
84}
85
87xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j)
88{
89 auto const sle = view.read(keylet::account(id));
90 if (sle == nullptr)
91 return beast::kZero;
92
93 // Return balance minus reserve
94 std::uint32_t const ownerCount =
95 confineOwnerCount(view.ownerCountHook(id, sle->getFieldU32(sfOwnerCount)), ownerCountAdj);
96
97 // Pseudo-accounts have no reserve requirement
98 auto const reserve =
99 isPseudoAccount(sle) ? XRPAmount{0} : view.fees().accountReserve(ownerCount);
100
101 auto const fullBalance = sle->getFieldAmount(sfBalance);
102
103 auto const balance = view.balanceHookIOU(id, xrpAccount(), fullBalance);
104
105 STAmount const amount = (balance < reserve) ? STAmount{0} : balance - reserve;
106
107 JLOG(j.trace()) << "accountHolds:" << " account=" << to_string(id)
108 << " amount=" << amount.getFullText()
109 << " fullBalance=" << fullBalance.getFullText()
110 << " balance=" << balance.getFullText() << " reserve=" << reserve
111 << " ownerCount=" << ownerCount << " ownerCountAdj=" << ownerCountAdj;
112
113 return amount.xrp();
114}
115
116Rate
117transferRate(ReadView const& view, AccountID const& issuer)
118{
119 auto const sle = view.read(keylet::account(issuer));
120
121 if (sle && sle->isFieldPresent(sfTransferRate))
122 return Rate{sle->getFieldU32(sfTransferRate)};
123
124 return kParityRate;
125}
126
127void
129{
130 if (!sle)
131 return;
132 XRPL_ASSERT(amount, "xrpl::adjustOwnerCount : nonzero amount input");
133 std::uint32_t const current{sle->getFieldU32(sfOwnerCount)};
134 AccountID const id = (*sle)[sfAccount];
135 std::uint32_t const adjusted = confineOwnerCount(current, amount, id, j);
136 view.adjustOwnerCountHook(id, current, adjusted);
137 sle->at(sfOwnerCount) = adjusted;
138 view.update(sle);
139}
140
142pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey)
143{
144 // This number must not be changed without an amendment
145 static constexpr std::uint16_t kMaxAccountAttempts = 256;
146 for (std::uint16_t i = 0; i < kMaxAccountAttempts; ++i)
147 {
148 RipeshaHasher rsh;
149 auto const hash = sha512Half(i, view.header().parentHash, pseudoOwnerKey);
150 rsh(hash.data(), hash.size());
151 AccountID const ret = AccountID::fromRaw(static_cast<RipeshaHasher::result_type>(rsh));
152 if (!view.read(keylet::account(ret)))
153 return ret;
154 }
155 return beast::kZero;
156}
157
158// Pseudo-account designator fields MUST be maintained by including the
159// SField::sMD_PseudoAccount flag in the SField definition. (Don't forget to
160// "| SField::sMD_Default"!) The fields do NOT need to be amendment-gated,
161// since a non-active amendment will not set any field, by definition.
162// Specific properties of a pseudo-account are NOT checked here, that's what
163// InvariantCheck is for.
164[[nodiscard]] std::vector<SField const*> const&
166{
167 static std::vector<SField const*> const kPseudoFields = []() {
168 auto const ar = LedgerFormats::getInstance().findByType(ltACCOUNT_ROOT);
169 if (!ar)
170 {
171 // LCOV_EXCL_START
173 "xrpl::getPseudoAccountFields : unable to find account root "
174 "ledger format");
175 // LCOV_EXCL_STOP
176 }
177 auto const& soTemplate = ar->getSOTemplate();
178
179 std::vector<SField const*> pseudoFields;
180 for (auto const& field : soTemplate)
181 {
182 if (field.sField().shouldMeta(SField::kSmdPseudoAccount))
183 pseudoFields.emplace_back(&field.sField());
184 }
185 return pseudoFields;
186 }();
187 return kPseudoFields;
188}
189
190[[nodiscard]] bool
192{
193 auto const& fields = getPseudoAccountFields();
194
195 // Intentionally use defensive coding here because it's cheap and makes the
196 // semantics of true return value clean.
197 return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT &&
199 fields.begin(), fields.end(), [&sleAcct, &pseudoFieldFilter](SField const* sf) -> bool {
200 return sleAcct->isFieldPresent(*sf) &&
201 (pseudoFieldFilter.empty() || pseudoFieldFilter.contains(sf));
202 }) > 0;
203}
204
205std::expected<SLE::pointer, TER>
206createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField)
207{
208 [[maybe_unused]]
209 auto const& fields = getPseudoAccountFields();
210 XRPL_ASSERT(
212 fields.begin(),
213 fields.end(),
214 [&ownerField](SField const* sf) -> bool { return *sf == ownerField; }) == 1,
215 "xrpl::createPseudoAccount : valid owner field");
216
217 auto const accountId = pseudoAccountAddress(view, pseudoOwnerKey);
218 if (accountId == beast::kZero)
220
221 // Create pseudo-account.
222 auto account = std::make_shared<SLE>(keylet::account(accountId));
223 account->setAccountID(sfAccount, accountId);
224 account->setFieldAmount(sfBalance, STAmount{});
225
226 // Pseudo-accounts can't submit transactions, so set the sequence number
227 // to 0 to make them easier to spot and verify, and add an extra level
228 // of protection.
229 std::uint32_t const seqno = //
230 view.rules().enabled(featureSingleAssetVault) || //
231 view.rules().enabled(featureLendingProtocol) //
232 ? 0 //
233 : view.seq();
234 account->setFieldU32(sfSequence, seqno);
235 // Ignore reserves requirement, disable the master key, allow default
236 // rippling, and enable deposit authorization to prevent payments into
237 // pseudo-account.
238 account->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth);
239 // Link the pseudo-account with its owner object.
240 account->setFieldH256(ownerField, pseudoOwnerKey);
241
242 view.insert(account);
243
244 return account;
245}
246
247[[nodiscard]] TER
248checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag)
249{
250 if (toSle == nullptr)
251 return tecNO_DST;
252
253 // The tag is basically account-specific information we don't
254 // understand, but we can require someone to fill it in.
255 if (toSle->isFlag(lsfRequireDestTag) && !hasDestinationTag)
256 return tecDST_TAG_NEEDED; // Cannot send without a tag
257
258 return tesSUCCESS;
259}
260
261} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
static Sink & getNullSink()
Returns a Sink which does nothing.
Stream trace() const
Severity stream access functions.
Definition Journal.h:291
Writeable view to a ledger, for applying a transaction.
Definition ApplyView.h:118
virtual void insert(SLE::ref sle)=0
Insert a new state SLE.
virtual void adjustOwnerCountHook(AccountID const &account, std::uint32_t cur, std::uint32_t next)
Definition ApplyView.h:278
virtual void update(SLE::ref sle)=0
Indicate changes to a peeked SLE.
static BaseUInt fromRaw(Container const &c)
Definition base_uint.h:294
Item const * findByType(KeyType type) const
Retrieve a format based on its type.
static LedgerFormats const & getInstance()
A view into a ledger.
Definition ReadView.h:31
virtual Rules const & rules() const =0
Returns the tx processing rules.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
virtual LedgerHeader const & header() const =0
Returns information about the ledger.
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition ReadView.h:97
virtual std::uint32_t ownerCountHook(AccountID const &account, std::uint32_t count) const
Definition ReadView.h:186
virtual STAmount balanceHookIOU(AccountID const &account, AccountID const &issuer, STAmount const &amount) const
Definition ReadView.h:155
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:171
Identifies fields.
Definition SField.h:130
static constexpr auto kSmdPseudoAccount
Definition SField.h:139
std::string getFullText() const override
Definition STAmount.cpp:636
XRPAmount xrp() const
Definition STAmount.cpp:271
std::shared_ptr< STLedgerEntry > const & ref
std::shared_ptr< STLedgerEntry const > const & const_ref
std::shared_ptr< STLedgerEntry const > const_pointer
T count_if(T... args)
T emplace_back(T... args)
T make_shared(T... args)
T max(T... args)
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
std::vector< SField const * > const & getPseudoAccountFields()
Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account if set.
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
AccountID pseudoAccountAddress(ReadView const &view, uint256 const &pseudoOwnerKey)
Generate a pseudo-account address from a pseudo owner key.
bool isXRP(AccountID const &c)
Definition AccountID.h:70
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition digest.h:204
std::expected< SLE::pointer, TER > createPseudoAccount(ApplyView &view, uint256 const &pseudoOwnerKey, SField const &ownerField)
Create pseudo-account, storing pseudoOwnerKey into ownerField.
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
static std::uint32_t confineOwnerCount(std::uint32_t current, std::int32_t adjustment, std::optional< AccountID > const &id=std::nullopt, beast::Journal j=beast::Journal{beast::Journal::getNullSink()})
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
Check if the issuer has the global freeze flag set.
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Rate const kParityRate
A transfer rate signifying a 1:1 exchange.
void adjustOwnerCount(ApplyView &view, SLE::ref sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:28
TERSubset< CanCvtToTER > TER
Definition TER.h:634
AccountID const & xrpAccount()
Compute AccountID from public key.
@ tecDST_TAG_NEEDED
Definition TER.h:307
@ tecDUPLICATE
Definition TER.h:313
@ tecNO_DST
Definition TER.h:288
bool isPseudoAccount(SLE::const_pointer sleAcct, std::set< SField const * > const &pseudoFieldFilter={})
Returns true if and only if sleAcct is a pseudo-account or specific pseudo-accounts in pseudoFieldFil...
TER checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag)
Checks the destination and tag.
BaseUInt< 256 > uint256
Definition base_uint.h:562
@ tesSUCCESS
Definition TER.h:240
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:49
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
Represents a transfer rate.
Definition Rate.h:20
Returns the RIPEMD-160 digest of the SHA256 hash of the message.
Definition digest.h:116
std::array< std::uint8_t, 20 > result_type
Definition digest.h:123
T unexpected(T... args)