20 #include <ripple/basics/Log.h>
21 #include <ripple/basics/chrono.h>
22 #include <ripple/basics/contract.h>
23 #include <ripple/ledger/ReadView.h>
24 #include <ripple/ledger/View.h>
25 #include <ripple/protocol/Feature.h>
26 #include <ripple/protocol/Protocol.h>
27 #include <ripple/protocol/Quality.h>
28 #include <ripple/protocol/st.h>
40 std::is_same_v<std::remove_cv_t<N>,
SLE> &&
41 std::is_base_of_v<ReadView, V>>>
50 auto const& svIndexes = page->getFieldV256(
sfIndexes);
51 assert(index <= svIndexes.size());
53 if (index >= svIndexes.size())
63 if constexpr (std::is_const_v<N>)
78 entry = svIndexes[index++];
86 std::is_same_v<std::remove_cv_t<N>,
SLE> &&
87 std::is_base_of_v<ReadView, V>>>
96 if constexpr (std::is_const_v<N>)
189 if (issuer != account)
214 if (issuer != account)
244 amount.
clear({currency, issuer});
248 isFrozen(view, account, currency, issuer))
255 if (account > issuer)
262 JLOG(j.
trace()) <<
"accountHolds:"
318 if (adjusted < current)
323 <<
"Account " << *
id <<
" owner count exceeds max!";
331 if (adjusted > current)
336 <<
"Account " << *
id <<
" owner count set below 0!";
361 auto const reserve = sle->isFieldPresent(
sfAMMID)
365 auto const fullBalance = sle->getFieldAmount(
sfBalance);
370 (balance < reserve) ?
STAmount{0} : balance - reserve;
372 JLOG(j.
trace()) <<
"accountHolds:"
375 <<
" fullBalance=" << fullBalance.getFullText()
376 <<
" balance=" << balance.getFullText()
377 <<
" reserve=" << reserve <<
" ownerCount=" << ownerCount
378 <<
" ownerCountAdj=" << ownerCountAdj;
398 auto sle = view.
read(pos);
401 for (
auto const& key : sle->getFieldV256(
sfIndexes))
424 auto currentIndex =
root;
427 if (
after.isNonZero())
431 if (
auto hintDir = view.
read(hintIndex))
433 for (
auto const& key : hintDir->getFieldV256(
sfIndexes))
438 currentIndex = hintIndex;
447 auto const ownerDir = view.
read(currentIndex);
450 for (
auto const& key : ownerDir->getFieldV256(
sfIndexes))
463 auto const uNodeNext = ownerDir->getFieldU64(
sfIndexNext);
473 auto const ownerDir = view.
read(currentIndex);
476 for (
auto const& key : ownerDir->getFieldV256(
sfIndexes))
479 auto const uNodeNext = ownerDir->getFieldU64(
sfIndexNext);
514 if (hash && (*hash != validLedger.
info().
hash))
516 JLOG(s) << reason <<
" incompatible with valid ledger";
518 JLOG(s) <<
"Hash(VSeq): " <<
to_string(*hash);
530 if (hash && (*hash != testLedger.
info().
hash))
532 JLOG(s) << reason <<
" incompatible preceding ledger";
534 JLOG(s) <<
"Hash(NSeq): " <<
to_string(*hash);
544 JLOG(s) << reason <<
" incompatible ledger";
551 JLOG(s) <<
"Val: " << validLedger.
info().
seq <<
" "
554 JLOG(s) <<
"New: " << testLedger.
info().
seq <<
" "
571 if (testLedger.
info().
seq > validIndex)
578 if (hash && (*hash != validHash))
580 JLOG(s) << reason <<
" incompatible following ledger";
581 JLOG(s) <<
"Hash(VSeq): " <<
to_string(*hash);
587 (validIndex == testLedger.
info().
seq) &&
588 (testLedger.
info().
hash != validHash))
590 JLOG(s) << reason <<
" incompatible ledger";
597 JLOG(s) <<
"Val: " << validIndex <<
" " <<
to_string(validHash);
599 JLOG(s) <<
"New: " << testLedger.
info().
seq <<
" "
609 auto const sleNode = view.
read(k);
612 if (!sleNode->getFieldV256(
sfIndexes).empty())
630 amendments.insert(v.begin(), v.end());
647 using d = tp::duration;
649 auto const majorities = sle->getFieldArray(
sfMajorities);
651 for (
auto const& m : majorities)
664 if (seq > ledger.
seq())
667 <<
"Can't get seq " << seq <<
" from " << ledger.
seq() <<
" future";
670 if (seq == ledger.
seq())
672 if (seq == (ledger.
seq() - 1))
675 if (
int diff = ledger.
seq() - seq; diff <= 256)
685 if (vec.
size() >= diff)
686 return vec[vec.
size() - diff];
688 <<
"Ledger " << ledger.
seq() <<
" missing hash for " << seq
689 <<
" (" << vec.
size() <<
"," << diff <<
")";
694 <<
"Ledger " << ledger.
seq() <<
":" << ledger.
info().
hash
695 <<
" missing normal list";
699 if ((seq & 0xff) != 0)
701 JLOG(journal.
debug())
702 <<
"Can't get seq " << seq <<
" from " << ledger.
seq() <<
" past";
711 assert(lastSeq >= seq);
712 assert((lastSeq & 0xff) == 0);
713 auto const diff = (lastSeq - seq) >> 8;
715 if (vec.
size() > diff)
716 return vec[vec.
size() - diff - 1];
718 JLOG(journal.
warn()) <<
"Can't get seq " << seq <<
" from " << ledger.
seq()
764 const bool bNoRipple,
774 JLOG(j.
trace()) <<
"trustCreate: " <<
to_string(uSrcAccountID) <<
", "
778 auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID;
779 auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID;
781 auto const sleRippleState = std::make_shared<SLE>(
ltRIPPLE_STATE, uIndex);
782 view.
insert(sleRippleState);
786 sleRippleState->
key(),
794 sleRippleState->
key(),
800 const bool bSetDst = saLimit.
getIssuer() == uDstAccountID;
801 const bool bSetHigh = bSrcHigh ^ bSetDst;
809 (bSetHigh ? uHighAccountID : uLowAccountID));
816 sleRippleState->setFieldU64(
sfLowNode, *lowNode);
817 sleRippleState->setFieldU64(
sfHighNode, *highNode);
819 sleRippleState->setFieldAmount(
821 sleRippleState->setFieldAmount(
825 bSetDst ? uSrcAccountID : uDstAccountID}));
828 sleRippleState->setFieldU32(
832 sleRippleState->setFieldU32(
856 sleRippleState->setFieldU32(
sfFlags, uFlags);
860 sleRippleState->setFieldAmount(
861 sfBalance, bSetHigh ? -saBalance : saBalance);
864 uSrcAccountID, uDstAccountID, saBalance, saBalance.zeroed());
881 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: low";
886 sleRippleState->
key(),
892 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: high";
897 sleRippleState->
key(),
903 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: state";
904 view.
erase(sleRippleState);
914 auto offerIndex = sle->
key();
962 assert(!bCheckIssuer || uSenderID == issuer || uReceiverID == issuer);
966 assert(uSenderID != uReceiverID);
968 bool const bSenderHigh = uSenderID > uReceiverID;
969 auto const index =
keylet::line(uSenderID, uReceiverID, currency);
975 if (
auto const sleRippleState = view.
peek(index))
982 view.
creditHook(uSenderID, uReceiverID, saAmount, saBalance);
984 STAmount const saBefore = saBalance;
986 saBalance -= saAmount;
988 JLOG(j.
trace()) <<
"rippleCredit: " <<
to_string(uSenderID) <<
" -> "
995 bool bDelete =
false;
999 if (saBefore > beast::zero
1001 && saBalance <= beast::zero
1012 !sleRippleState->getFieldAmount(
1015 && !sleRippleState->getFieldU32(
1018 && !sleRippleState->getFieldU32(
1027 sleRippleState->setFieldU32(
1032 bDelete = !saBalance
1041 sleRippleState->setFieldAmount(
sfBalance, saBalance);
1049 bSenderHigh ? uReceiverID : uSenderID,
1050 !bSenderHigh ? uReceiverID : uSenderID,
1054 view.
update(sleRippleState);
1058 STAmount const saReceiverLimit({currency, uReceiverID});
1063 JLOG(j.
debug()) <<
"rippleCredit: "
1104 auto const issuer = saAmount.
getIssuer();
1106 assert(!
isXRP(uSenderID) && !
isXRP(uReceiverID));
1107 assert(uSenderID != uReceiverID);
1109 if (uSenderID == issuer || uReceiverID == issuer || issuer ==
noAccount())
1113 rippleCredit(view, uSenderID, uReceiverID, saAmount,
false, j);
1116 saActual = saAmount;
1128 JLOG(j.
debug()) <<
"rippleSend> " <<
to_string(uSenderID) <<
" - > "
1133 TER terResult =
rippleCredit(view, issuer, uReceiverID, saAmount,
true, j);
1136 terResult =
rippleCredit(view, uSenderID, issuer, saActual,
true, j);
1150 assert(saAmount >= beast::zero);
1155 if (!saAmount || (uSenderID == uReceiverID))
1162 JLOG(j.
trace()) <<
"accountSend: " <<
to_string(uSenderID) <<
" -> "
1167 view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee);
1184 if (
auto stream = j.
trace())
1195 stream <<
"accountSend> " <<
to_string(uSenderID) <<
" (" << sender_bal
1196 <<
") -> " <<
to_string(uReceiverID) <<
" (" << receiver_bal
1230 if (
auto stream = j.
trace())
1241 stream <<
"accountSend< " <<
to_string(uSenderID) <<
" (" << sender_bal
1242 <<
") -> " <<
to_string(uReceiverID) <<
" (" << receiver_bal
1268 if (before > beast::zero
1270 &&
after <= beast::zero
1274 &&
static_cast<bool>(
1313 assert(issue == amount.
issue());
1316 assert(issue.
account != account);
1321 bool bSenderHigh = issue.
account > account;
1325 if (
auto state = view.
peek(index))
1332 STAmount const start_balance = final_balance;
1334 final_balance -= amount;
1353 state->setFieldAmount(
sfBalance, final_balance);
1358 bSenderHigh ? account : issue.
account,
1359 bSenderHigh ? issue.
account : account,
1376 if (!receiverAccount)
1409 assert(issue == amount.
issue());
1412 assert(issue.
account != account);
1417 bool bSenderHigh = account > issue.
account;
1427 STAmount const start_balance = final_balance;
1429 final_balance -= amount;
1432 view, state, bSenderHigh, account, start_balance, final_balance, j);
1442 state->setFieldAmount(
sfBalance, final_balance);
1449 bSenderHigh ? issue.
account : account,
1450 bSenderHigh ? account : issue.
account,
1463 <<
" but no trust line exists!";
1476 assert(from != beast::zero);
1477 assert(to != beast::zero);
1483 if (!sender || !receiver)
1518 if (
auto const trustLine =
1520 return ((*trustLine)[
sfFlags] &
1533 Keylet const& ownerDirKeylet,
1540 unsigned int uDirEntry{0};
1541 uint256 dirEntry{beast::zero};
1544 if (view.
exists(ownerDirKeylet) &&
1545 dirFirst(view, ownerDirKeylet.
key, sleDirNode, uDirEntry, dirEntry))
1549 if (maxNodesToDelete && ++deleted > *maxNodesToDelete)
1558 <<
"DeleteAccount: Directory node in ledger " << view.
seq()
1559 <<
" has index to object that is missing: "
1569 auto const [ter, skipEntry] = deleter(nodeType, dirEntry, sleItem);
1589 assert(uDirEntry >= 1);
1593 <<
"DeleteAccount iterator re-validation failed.";
1600 dirNext(view, ownerDirKeylet.
key, sleDirNode, uDirEntry, dirEntry));
1621 if (!sleLow || !sleHigh)
1623 bool const ammLow = sleLow->isFieldPresent(
sfAMMID);
1624 bool const ammHigh = sleHigh->isFieldPresent(
sfAMMID);
1627 if (ammLow && ammHigh)
1631 if (!ammLow && !ammHigh)
1638 if (
auto const ter =
trustDelete(view, sleState, low, high, j);
1642 <<
"deleteAMMTrustLine: failed to delete the trustline.";
1647 if (!(sleState->
getFlags() & uFlags))
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
const SF_UINT64 sfIndexNext
const SF_UINT32 sfHighQualityIn
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
const SF_UINT32 sfOwnerCount
Rate transferRate(ReadView const &view, AccountID const &issuer)
bool cdirNext(ReadView const &view, uint256 const &root, std::shared_ptr< SLE const > &page, unsigned int &index, uint256 &entry)
Returns the next entry in the directory, advancing the index.
bool dirNext(ApplyView &view, uint256 const &root, std::shared_ptr< SLE > &page, unsigned int &index, uint256 &entry)
uint256 const & key() const
Returns the 'key' (or 'index') of this item.
majorityAmendments_t getMajorityAmendments(ReadView const &view)
A pair of SHAMap key and LedgerEntryType.
std::set< uint256 > getEnabledAmendments(ReadView const &view)
A currency issued by an account.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Keylet const & amendments() noexcept
The index of the amendment table.
bool forEachItemAfter(ReadView const &view, Keylet const &root, uint256 const &after, std::uint64_t const hint, unsigned int limit, std::function< bool(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items after an item in the given directory.
const SF_UINT64 sfOwnerNode
Represents a transfer rate.
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Stream trace() const
Severity stream access functions.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
Issue const & issue() const
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
std::uint64_t getFieldU64(SField const &field) const
bool internalDirNext(V &view, uint256 const &root, std::shared_ptr< N > &page, unsigned int &index, uint256 &entry)
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
const SF_UINT256 sfBookDirectory
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
virtual void creditHook(AccountID const &from, AccountID const &to, STAmount const &amount, STAmount const &preCreditBalance)
Keylet const & skip() noexcept
The index of the "short" skip list.
Keylet child(uint256 const &key) noexcept
Any item that can be in an owner dir.
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
virtual STAmount balanceHook(AccountID const &account, AccountID const &issuer, STAmount const &amount) const
TER deleteAMMTrustLine(ApplyView &view, std::shared_ptr< SLE > sleState, std::optional< AccountID > const &ammAccountID, beast::Journal j)
Delete trustline to AMM.
const SF_UINT32 sfCloseTime
void setIssuer(AccountID const &uIssuer)
NetClock::time_point parentCloseTime() const
Returns the close time of the previous ledger.
FreezeHandling
Controls the treatment of frozen account balances.
static Sink & getNullSink()
Returns a Sink which does nothing.
const Rate parityRate(QUALITY_ONE)
A transfer rate signifying a 1:1 exchange.
AccountID ammAccountID(std::uint16_t prefix, uint256 const &parentHash, uint256 const &ammID)
Calculate AMM account ID.
Writeable view to a ledger, for applying a transaction.
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account requires authorization.
@ ltDIR_NODE
A ledger object which contains a list of object identifiers.
AccountID const & getIssuer() const
const uint256 featureDeletableAccounts
const SF_VECTOR256 sfIndexes
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
const SF_UINT64 sfLowNode
const SF_UINT32 sfLowQualityOut
std::string getFullText() const override
const SF_AMOUNT sfLowLimit
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
std::map< uint256, NetClock::time_point > majorityAmendments_t
Keylet account(AccountID const &id) noexcept
AccountID root.
void setFieldAmount(SField const &field, STAmount const &)
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
AccountID getAccountID(SField const &field) const
Keylet page(uint256 const &key, std::uint64_t index) noexcept
A page in a directory.
const SF_UINT64 sfBookNode
const SF_UINT32 sfLowQualityIn
TERSubset< CanCvtToTER > TER
AccountID const & xrpAccount()
Compute AccountID from public key.
Provide a light-weight way to check active() before string formatting.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
std::uint32_t getFlags() const
std::optional< uint256 > hashOfSeq(ReadView const &ledger, LedgerIndex seq, beast::Journal journal)
Return the hash of a ledger by sequence.
const SF_UINT32 sfTransferRate
bool isXRP(AccountID const &c)
@ current
This was a new validation and was added.
A generic endpoint for log messages.
const SF_AMOUNT sfHighLimit
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
virtual void adjustOwnerCountHook(AccountID const &account, std::uint32_t cur, std::uint32_t next)
TER trustDelete(ApplyView &view, std::shared_ptr< SLE > const &sleRippleState, AccountID const &uLowAccountID, AccountID const &uHighAccountID, beast::Journal j)
LedgerEntryType getType() const
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
TER cleanupOnAccountDelete(ApplyView &view, Keylet const &ownerDirKeylet, EntryDeleter const &deleter, beast::Journal j, std::optional< uint16_t > maxNodesToDelete)
bool areCompatible(ReadView const &validLedger, ReadView const &testLedger, beast::Journal::Stream &s, const char *reason)
Return false if the test ledger is provably incompatible with the valid ledger, that is,...
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
TER transferXRP(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &amount, beast::Journal j)
STAmount multiply(STAmount const &amount, Rate const &rate)
const SF_VECTOR256 sfHashes
TER issueIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
bool native() const noexcept
bool dirIsEmpty(ReadView const &view, Keylet const &k)
Returns true if the directory is empty.
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool dirFirst(ApplyView &view, uint256 const &root, std::shared_ptr< SLE > &page, unsigned int &index, uint256 &entry)
bool isIndividualFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
TER trustCreate(ApplyView &view, const bool bSrcHigh, AccountID const &uSrcAccountID, AccountID const &uDstAccountID, uint256 const &uIndex, SLE::ref sleAccount, const bool bAuth, const bool bNoRipple, const bool bFreeze, STAmount const &saBalance, STAmount const &saLimit, std::uint32_t uQualityIn, std::uint32_t uQualityOut, beast::Journal j)
Create a trust line.
const SF_UINT16 sfLedgerEntryType
LedgerEntryType
Identifiers for on-ledger objects.
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
LedgerIndex seq() const
Returns the sequence number of the base ledger.
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
virtual Rules const & rules() const =0
Returns the tx processing rules.
virtual std::uint32_t ownerCountHook(AccountID const &account, std::uint32_t count) const
const SF_AMOUNT sfBalance
bool internalDirFirst(V &view, uint256 const &root, std::shared_ptr< N > &page, unsigned int &index, uint256 &entry)
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()})
const SF_UINT32 sfHighQualityOut
void forEachItem(ReadView const &view, Keylet const &root, std::function< void(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items in the given directory.
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
const SF_ACCOUNT sfAccount
@ ltRIPPLE_STATE
A ledger object which describes a bidirectional trust line.
std::chrono::duration< rep, period > duration
std::uint32_t getFieldU32(SField const &field) const
static bool updateTrustLine(ApplyView &view, SLE::pointer state, bool bSenderHigh, AccountID const &sender, STAmount const &before, STAmount const &after, beast::Journal j)
static TER rippleSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, STAmount &saActual, beast::Journal j, WaiveTransferFee waiveFee)
const SF_UINT32 sfLastLedgerSequence
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(std::shared_ptr< SLE > const &)> const &describe)
Insert an entry to a directory.
const SF_UINT256 sfAmendment
bool cdirFirst(ReadView const &view, uint256 const &root, std::shared_ptr< SLE const > &page, unsigned int &index, uint256 &entry)
Returns the first entry in the directory, advancing the index.
const std::shared_ptr< STLedgerEntry > & ref
const SField sfMajorities
virtual bool open() const =0
Returns true if this reflects an open ledger.
std::chrono::time_point< NetClock > time_point
void setFieldU32(SField const &field, std::uint32_t)
Currency const & getCurrency() const
const SF_UINT64 sfHighNode
bool isFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
STAmount const & getFieldAmount(SField const &field) const
AccountID const & noAccount()
A placeholder for empty accounts.
std::shared_ptr< STLedgerEntry > pointer
const SF_VECTOR256 sfAmendments
uint256 getFieldH256(SField const &field) const
Number root(Number f, unsigned d)