diff --git a/AMMBid_8cpp_source.html b/AMMBid_8cpp_source.html index b8a876a40b..cfb3ae4031 100644 --- a/AMMBid_8cpp_source.html +++ b/AMMBid_8cpp_source.html @@ -492,7 +492,7 @@ $(function() {
ripple::TOTAL_TIME_SLOT_SECS
std::uint32_t constexpr TOTAL_TIME_SLOT_SECS
Definition: AMMCore.h:34
ripple::AUCTION_SLOT_TIME_INTERVALS
std::uint16_t constexpr AUCTION_SLOT_TIME_INTERVALS
Definition: AMMCore.h:35
ripple::ammAuctionTimeSlot
std::optional< std::uint8_t > ammAuctionTimeSlot(std::uint64_t current, STObject const &auctionSlot)
Get time slot of the auction slot.
Definition: AMMCore.cpp:107
-
ripple::redeemIOU
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
Definition: View.cpp:1699
+
ripple::redeemIOU
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
Definition: View.cpp:1745
ripple::toSTAmount
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
Definition: AmountConversions.h:32
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
ripple::ammEnabled
bool ammEnabled(Rules const &)
Return true if required AMM amendments are enabled.
Definition: AMMCore.cpp:128
@@ -515,7 +515,7 @@ $(function() {
ripple::terNO_AMM
@ terNO_AMM
Definition: TER.h:227
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:627
ripple::AUCTION_SLOT_MAX_AUTH_ACCOUNTS
std::uint16_t constexpr AUCTION_SLOT_MAX_AUTH_ACCOUNTS
Definition: AMMCore.h:36
-
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
Definition: View.cpp:1526
+
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
Definition: View.cpp:1571
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:587
ripple::AUCTION_SLOT_DISCOUNTED_FEE_FRACTION
std::uint32_t constexpr AUCTION_SLOT_DISCOUNTED_FEE_FRACTION
Definition: AMMCore.h:38
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:87
diff --git a/AMMClawback_8cpp_source.html b/AMMClawback_8cpp_source.html index efd455acd4..9125825b14 100644 --- a/AMMClawback_8cpp_source.html +++ b/AMMClawback_8cpp_source.html @@ -414,10 +414,10 @@ $(function() {
ripple::lsfAllowTrustLineClawback
@ lsfAllowTrustLineClawback
Definition: LedgerFormats.h:149
ripple::lsfNoFreeze
@ lsfNoFreeze
Definition: LedgerFormats.h:132
ripple::toSTAmount
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
Definition: AmountConversions.h:32
-
ripple::tfClawTwoAssets
constexpr std::uint32_t tfClawTwoAssets
Definition: TxFlags.h:219
+
ripple::tfClawTwoAssets
constexpr std::uint32_t tfClawTwoAssets
Definition: TxFlags.h:221
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
-
ripple::tfAMMClawbackMask
constexpr std::uint32_t tfAMMClawbackMask
Definition: TxFlags.h:220
+
ripple::tfAMMClawbackMask
constexpr std::uint32_t tfAMMClawbackMask
Definition: TxFlags.h:222
ripple::ammLPHolds
STAmount ammLPHolds(ReadView const &view, Currency const &cur1, Currency const &cur2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
Definition: AMMUtils.cpp:111
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:134
ripple::tecINTERNAL
@ tecINTERNAL
Definition: TER.h:297
@@ -426,7 +426,7 @@ $(function() {
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
ripple::ammHolds
Expected< std::tuple< STAmount, STAmount, STAmount >, TER > ammHolds(ReadView const &view, SLE const &ammSle, std::optional< Issue > const &optIssue1, std::optional< Issue > const &optIssue2, FreezeHandling freezeHandling, beast::Journal const j)
Get AMM pool and LP token balances.
Definition: AMMUtils.cpp:45
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
-
ripple::rippleCredit
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
Definition: View.cpp:2015
+
ripple::rippleCredit
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
Definition: View.cpp:2061
ripple::terNO_ACCOUNT
@ terNO_ACCOUNT
Definition: TER.h:217
ripple::terNO_AMM
@ terNO_AMM
Definition: TER.h:227
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:587
diff --git a/AMMClawback__test_8cpp_source.html b/AMMClawback__test_8cpp_source.html index fa85ccd51a..5b50dcb51f 100644 --- a/AMMClawback__test_8cpp_source.html +++ b/AMMClawback__test_8cpp_source.html @@ -1923,12 +1923,12 @@ $(function() {
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::asfGlobalFreeze
constexpr std::uint32_t asfGlobalFreeze
Definition: TxFlags.h:82
-
ripple::tfClawTwoAssets
constexpr std::uint32_t tfClawTwoAssets
Definition: TxFlags.h:219
+
ripple::tfClawTwoAssets
constexpr std::uint32_t tfClawTwoAssets
Definition: TxFlags.h:221
ripple::TxSearched::all
@ all
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:292
ripple::tecAMM_BALANCE
@ tecAMM_BALANCE
Definition: TER.h:316
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
-
ripple::tfTwoAssetIfEmpty
constexpr std::uint32_t tfTwoAssetIfEmpty
Definition: TxFlags.h:208
+
ripple::tfTwoAssetIfEmpty
constexpr std::uint32_t tfTwoAssetIfEmpty
Definition: TxFlags.h:210
ripple::asfAllowTrustLineClawback
constexpr std::uint32_t asfAllowTrustLineClawback
Definition: TxFlags.h:93
ripple::terNO_ACCOUNT
@ terNO_ACCOUNT
Definition: TER.h:217
ripple::terNO_AMM
@ terNO_AMM
Definition: TER.h:227
diff --git a/AMMCreate_8cpp_source.html b/AMMCreate_8cpp_source.html index a35700ab17..efaad5c41d 100644 --- a/AMMCreate_8cpp_source.html +++ b/AMMCreate_8cpp_source.html @@ -519,14 +519,14 @@ $(function() {
ripple::invalidAMMAmount
NotTEC invalidAMMAmount(STAmount const &amount, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt, bool validZero=false)
Validate the amount.
Definition: AMMCore.cpp:94
ripple::fhZERO_IF_FROZEN
@ fhZERO_IF_FROZEN
Definition: View.h:80
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
-
ripple::requireAuth
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account lacks required authorization.
Definition: View.cpp:1815
+
ripple::requireAuth
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account lacks required authorization.
Definition: View.cpp:1861
ripple::lsfDefaultRipple
@ lsfDefaultRipple
Definition: LedgerFormats.h:134
ripple::lsfAllowTrustLineClawback
@ lsfAllowTrustLineClawback
Definition: LedgerFormats.h:149
ripple::lsfDisableMaster
@ lsfDisableMaster
Definition: LedgerFormats.h:131
ripple::lsfDepositAuth
@ lsfDepositAuth
Definition: LedgerFormats.h:136
-
ripple::lsfAMMNode
@ lsfAMMNode
Definition: LedgerFormats.h:165
+
ripple::lsfAMMNode
@ lsfAMMNode
Definition: LedgerFormats.h:167
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
-
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:848
+
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:887
ripple::ammEnabled
bool ammEnabled(Rules const &)
Return true if required AMM amendments are enabled.
Definition: AMMCore.cpp:128
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
ripple::ammLPTIssue
Issue ammLPTIssue(Currency const &cur1, Currency const &cur2, AccountID const &ammAccountID)
Calculate LPT Issue from AMM asset pair.
Definition: AMMCore.cpp:56
@@ -546,15 +546,15 @@ $(function() {
ripple::tecUNFUNDED_AMM
@ tecUNFUNDED_AMM
Definition: TER.h:315
ripple::tecAMM_INVALID_TOKENS
@ tecAMM_INVALID_TOKENS
Definition: TER.h:318
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
-
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:271
+
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:297
ripple::ammLPTokens
STAmount ammLPTokens(STAmount const &asset1, STAmount const &asset2, Issue const &lptIssue)
Calculate LP Tokens given AMM pool reserves.
Definition: AMMHelpers.cpp:25
ripple::tfUniversalMask
constexpr std::uint32_t tfUniversalMask
Definition: TxFlags.h:62
ripple::terNO_RIPPLE
@ terNO_RIPPLE
Definition: TER.h:224
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:627
ripple::TRADING_FEE_THRESHOLD
std::uint16_t constexpr TRADING_FEE_THRESHOLD
Definition: AMMCore.h:31
-
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
Definition: View.cpp:1526
+
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
Definition: View.cpp:1571
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:587
-
ripple::xrpLiquid
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
Definition: View.cpp:430
+
ripple::xrpLiquid
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
Definition: View.cpp:469
ripple::temBAD_FEE
@ temBAD_FEE
Definition: TER.h:92
ripple::temBAD_AMM_TOKENS
@ temBAD_AMM_TOKENS
Definition: TER.h:129
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:111
diff --git a/AMMDeposit_8cpp_source.html b/AMMDeposit_8cpp_source.html index 2063da263c..b7aef0ff9c 100644 --- a/AMMDeposit_8cpp_source.html +++ b/AMMDeposit_8cpp_source.html @@ -995,7 +995,7 @@ $(function() {
ripple::keylet::amm
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Definition: Indexes.cpp:422
ripple::keylet::line
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:220
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
-
ripple::tfSingleAsset
constexpr std::uint32_t tfSingleAsset
Definition: TxFlags.h:204
+
ripple::tfSingleAsset
constexpr std::uint32_t tfSingleAsset
Definition: TxFlags.h:206
ripple::invalidAMMAmount
NotTEC invalidAMMAmount(STAmount const &amount, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt, bool validZero=false)
Validate the amount.
Definition: AMMCore.cpp:94
ripple::divide
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:87
ripple::lpTokensIn
STAmount lpTokensIn(STAmount const &asset1Balance, STAmount const &asset1Deposit, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's deposit amount.
Definition: AMMHelpers.cpp:41
@@ -1005,23 +1005,23 @@ $(function() {
ripple::isIndividualFrozen
bool isIndividualFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition: View.cpp:204
ripple::getTradingFee
std::uint16_t getTradingFee(ReadView const &view, SLE const &ammSle, AccountID const &account)
Get AMM trading fee for the given account.
Definition: AMMUtils.cpp:145
ripple::solveQuadraticEq
Number solveQuadraticEq(Number const &a, Number const &b, Number const &c)
Positive solution for quadratic equation: x = (-b + sqrt(b**2 + 4*a*c))/(2*a)
Definition: AMMHelpers.cpp:220
-
ripple::requireAuth
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account lacks required authorization.
Definition: View.cpp:1815
+
ripple::requireAuth
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account lacks required authorization.
Definition: View.cpp:1861
ripple::toSTAmount
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
Definition: AmountConversions.h:32
-
ripple::tfLimitLPToken
constexpr std::uint32_t tfLimitLPToken
Definition: TxFlags.h:207
+
ripple::tfLimitLPToken
constexpr std::uint32_t tfLimitLPToken
Definition: TxFlags.h:209
ripple::ammAssetIn
STAmount ammAssetIn(STAmount const &asset1Balance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Calculate asset deposit given LP Tokens.
Definition: AMMHelpers.cpp:67
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:47
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
ripple::ammEnabled
bool ammEnabled(Rules const &)
Return true if required AMM amendments are enabled.
Definition: AMMCore.cpp:128
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
ripple::adjustAmountsByLPTokens
std::tuple< STAmount, std::optional< STAmount >, STAmount > adjustAmountsByLPTokens(STAmount const &amountBalance, STAmount const &amount, std::optional< STAmount > const &amount2, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee, bool isDeposit)
Calls adjustLPTokens() and adjusts deposit or withdraw amounts if the adjusted LP tokens are less tha...
Definition: AMMHelpers.cpp:147
-
ripple::tfOneAssetLPToken
constexpr std::uint32_t tfOneAssetLPToken
Definition: TxFlags.h:206
+
ripple::tfOneAssetLPToken
constexpr std::uint32_t tfOneAssetLPToken
Definition: TxFlags.h:208
ripple::isFrozen
bool isFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition: View.cpp:238
ripple::ammAccountID
AccountID ammAccountID(std::uint16_t prefix, uint256 const &parentHash, uint256 const &ammID)
Calculate AMM account ID.
Definition: AMMCore.cpp:30
ripple::feeMult
Number feeMult(std::uint16_t tfee)
Get fee multiplier (1 - tfee) @tfee trading fee in basis points.
Definition: AMMCore.h:118
ripple::initializeFeeAuctionVote
void initializeFeeAuctionVote(ApplyView &view, std::shared_ptr< SLE > &ammSle, AccountID const &account, Issue const &lptIssue, std::uint16_t tfee)
Initialize Auction and Voting slots and set the trading/discounted fee.
Definition: AMMUtils.cpp:306
-
ripple::tfTwoAsset
constexpr std::uint32_t tfTwoAsset
Definition: TxFlags.h:205
+
ripple::tfTwoAsset
constexpr std::uint32_t tfTwoAsset
Definition: TxFlags.h:207
ripple::ammLPHolds
STAmount ammLPHolds(ReadView const &view, Currency const &cur1, Currency const &cur2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
Definition: AMMUtils.cpp:111
-
ripple::tfDepositSubTx
constexpr std::uint32_t tfDepositSubTx
Definition: TxFlags.h:212
+
ripple::tfDepositSubTx
constexpr std::uint32_t tfDepositSubTx
Definition: TxFlags.h:214
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:134
ripple::WaiveTransferFee::Yes
@ Yes
ripple::tecINSUF_RESERVE_LINE
@ tecINSUF_RESERVE_LINE
Definition: TER.h:275
@@ -1032,22 +1032,22 @@ $(function() {
ripple::tecUNFUNDED_AMM
@ tecUNFUNDED_AMM
Definition: TER.h:315
ripple::tecAMM_FAILED
@ tecAMM_FAILED
Definition: TER.h:317
ripple::tecAMM_INVALID_TOKENS
@ tecAMM_INVALID_TOKENS
Definition: TER.h:318
-
ripple::tfLPToken
constexpr std::uint32_t tfLPToken
Definition: TxFlags.h:201
+
ripple::tfLPToken
constexpr std::uint32_t tfLPToken
Definition: TxFlags.h:203
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
ripple::invalidAMMAssetPair
NotTEC invalidAMMAssetPair(Issue const &issue1, Issue const &issue2, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt)
Definition: AMMCore.cpp:79
-
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:271
-
ripple::tfDepositMask
constexpr std::uint32_t tfDepositMask
Definition: TxFlags.h:216
+
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:297
+
ripple::tfDepositMask
constexpr std::uint32_t tfDepositMask
Definition: TxFlags.h:218
ripple::ammHolds
Expected< std::tuple< STAmount, STAmount, STAmount >, TER > ammHolds(ReadView const &view, SLE const &ammSle, std::optional< Issue > const &optIssue1, std::optional< Issue > const &optIssue2, FreezeHandling freezeHandling, beast::Journal const j)
Get AMM pool and LP token balances.
Definition: AMMUtils.cpp:45
ripple::ammLPTokens
STAmount ammLPTokens(STAmount const &asset1, STAmount const &asset2, Issue const &lptIssue)
Calculate LP Tokens given AMM pool reserves.
Definition: AMMHelpers.cpp:25
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
-
ripple::tfTwoAssetIfEmpty
constexpr std::uint32_t tfTwoAssetIfEmpty
Definition: TxFlags.h:208
+
ripple::tfTwoAssetIfEmpty
constexpr std::uint32_t tfTwoAssetIfEmpty
Definition: TxFlags.h:210
ripple::feeMultHalf
Number feeMultHalf(std::uint16_t tfee)
Get fee multiplier (1 - tfee / 2) @tfee trading fee in basis points.
Definition: AMMCore.h:127
ripple::terNO_AMM
@ terNO_AMM
Definition: TER.h:227
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:627
ripple::TRADING_FEE_THRESHOLD
std::uint16_t constexpr TRADING_FEE_THRESHOLD
Definition: AMMCore.h:31
-
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
Definition: View.cpp:1526
+
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
Definition: View.cpp:1571
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:587
-
ripple::xrpLiquid
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
Definition: View.cpp:430
+
ripple::xrpLiquid
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
Definition: View.cpp:469
ripple::temBAD_AMOUNT
@ temBAD_AMOUNT
Definition: TER.h:89
ripple::temBAD_FEE
@ temBAD_FEE
Definition: TER.h:92
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:87
diff --git a/AMMExtended__test_8cpp_source.html b/AMMExtended__test_8cpp_source.html index 8400039ade..2a050dfcbc 100644 --- a/AMMExtended__test_8cpp_source.html +++ b/AMMExtended__test_8cpp_source.html @@ -4389,7 +4389,7 @@ $(function() {
ripple::flow
StrandResult< TInAmt, TOutAmt > flow(PaymentSandbox const &baseView, Strand const &strand, std::optional< TInAmt > const &maxIn, TOutAmt const &out, beast::Journal j)
Request out amount from a strand.
Definition: StrandFlow.h:106
ripple::tfPassive
constexpr std::uint32_t tfPassive
Definition: TxFlags.h:96
ripple::tfImmediateOrCancel
constexpr std::uint32_t tfImmediateOrCancel
Definition: TxFlags.h:97
-
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1010
+
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1054
ripple::asfDisableMaster
constexpr std::uint32_t asfDisableMaster
Definition: TxFlags.h:79
ripple::no
@ no
Definition: Steps.h:42
ripple::tfPartialPayment
constexpr std::uint32_t tfPartialPayment
Definition: TxFlags.h:105
diff --git a/AMMOffer_8h_source.html b/AMMOffer_8h_source.html index 6a3b9ae7d1..3ee38875dd 100644 --- a/AMMOffer_8h_source.html +++ b/AMMOffer_8h_source.html @@ -240,7 +240,7 @@ $(function() {
std::uint32_t
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::WaiveTransferFee::Yes
@ Yes
-
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
Definition: View.cpp:1526
+
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
Definition: View.cpp:1571
std::optional
std::pair
diff --git a/AMMUtils_8cpp_source.html b/AMMUtils_8cpp_source.html index 40f78b90d0..384dc377df 100644 --- a/AMMUtils_8cpp_source.html +++ b/AMMUtils_8cpp_source.html @@ -561,7 +561,7 @@ $(function() {
ripple::fhZERO_IF_FROZEN
@ fhZERO_IF_FROZEN
Definition: View.h:80
ripple::TOTAL_TIME_SLOT_SECS
std::uint32_t constexpr TOTAL_TIME_SLOT_SECS
Definition: AMMCore.h:34
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
-
ripple::deleteAMMTrustLine
TER deleteAMMTrustLine(ApplyView &view, std::shared_ptr< SLE > sleState, std::optional< AccountID > const &ammAccountID, beast::Journal j)
Delete trustline to AMM.
Definition: View.cpp:1966
+
ripple::deleteAMMTrustLine
TER deleteAMMTrustLine(ApplyView &view, std::shared_ptr< SLE > sleState, std::optional< AccountID > const &ammAccountID, beast::Journal j)
Delete trustline to AMM.
Definition: View.cpp:2012
ripple::ammLPTCurrency
Currency ammLPTCurrency(Currency const &cur1, Currency const &cur2)
Calculate Liquidity Provider Token (LPT) Currency.
Definition: AMMCore.cpp:42
ripple::getTradingFee
std::uint16_t getTradingFee(ReadView const &view, SLE const &ammSle, AccountID const &account)
Get AMM trading fee for the given account.
Definition: AMMUtils.cpp:145
ripple::deleteAMMAccount
TER deleteAMMAccount(Sandbox &view, Issue const &asset, Issue const &asset2, beast::Journal j)
Delete trustlines to AMM.
Definition: AMMUtils.cpp:249
@@ -580,11 +580,11 @@ $(function() {
ripple::VOTE_WEIGHT_SCALE_FACTOR
std::uint32_t constexpr VOTE_WEIGHT_SCALE_FACTOR
Definition: AMMCore.h:45
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
ripple::invalidAMMAssetPair
NotTEC invalidAMMAssetPair(Issue const &issue1, Issue const &issue2, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt)
Definition: AMMCore.cpp:79
-
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:271
+
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:297
ripple::ammHolds
Expected< std::tuple< STAmount, STAmount, STAmount >, TER > ammHolds(ReadView const &view, SLE const &ammSle, std::optional< Issue > const &optIssue1, std::optional< Issue > const &optIssue2, FreezeHandling freezeHandling, beast::Journal const j)
Get AMM pool and LP token balances.
Definition: AMMUtils.cpp:45
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::LedgerEntryType
LedgerEntryType
Identifiers for on-ledger objects.
Definition: LedgerFormats.h:54
-
ripple::cleanupOnAccountDelete
TER cleanupOnAccountDelete(ApplyView &view, Keylet const &ownerDirKeylet, EntryDeleter const &deleter, beast::Journal j, std::optional< uint16_t > maxNodesToDelete)
Definition: View.cpp:1888
+
ripple::cleanupOnAccountDelete
TER cleanupOnAccountDelete(ApplyView &view, Keylet const &ownerDirKeylet, EntryDeleter const &deleter, beast::Journal j, std::optional< uint16_t > maxNodesToDelete)
Definition: View.cpp:1934
ripple::ammAccountHolds
STAmount ammAccountHolds(ReadView const &view, AccountID const &ammAccountID, Issue const &issue)
Returns total amount held by AMM for the given token.
Definition: AMMUtils.cpp:177
ripple::root
Number root(Number f, unsigned d)
Definition: Number.cpp:630
ripple::maxDeletableAMMTrustLines
std::uint16_t constexpr maxDeletableAMMTrustLines
The maximum number of trustlines to delete as part of AMM account deletion cleanup.
Definition: Protocol.h:130
diff --git a/AMMWithdraw_8cpp_source.html b/AMMWithdraw_8cpp_source.html index fe5d97239b..060cc6f544 100644 --- a/AMMWithdraw_8cpp_source.html +++ b/AMMWithdraw_8cpp_source.html @@ -1114,10 +1114,10 @@ $(function() {
ripple::keylet::line
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:220
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:160
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
-
ripple::tfSingleAsset
constexpr std::uint32_t tfSingleAsset
Definition: TxFlags.h:204
+
ripple::tfSingleAsset
constexpr std::uint32_t tfSingleAsset
Definition: TxFlags.h:206
ripple::invalidAMMAmount
NotTEC invalidAMMAmount(STAmount const &amount, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt, bool validZero=false)
Validate the amount.
Definition: AMMCore.cpp:94
ripple::divide
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:87
-
ripple::tfOneAssetWithdrawAll
constexpr std::uint32_t tfOneAssetWithdrawAll
Definition: TxFlags.h:203
+
ripple::tfOneAssetWithdrawAll
constexpr std::uint32_t tfOneAssetWithdrawAll
Definition: TxFlags.h:205
ripple::WithdrawAll
WithdrawAll
AMMWithdraw implements AMM withdraw Transactor.
Definition: AMMWithdraw.h:67
ripple::WithdrawAll::Yes
@ Yes
ripple::WithdrawAll::No
@ No
@@ -1127,26 +1127,26 @@ $(function() {
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
ripple::isIndividualFrozen
bool isIndividualFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition: View.cpp:204
ripple::getTradingFee
std::uint16_t getTradingFee(ReadView const &view, SLE const &ammSle, AccountID const &account)
Get AMM trading fee for the given account.
Definition: AMMUtils.cpp:145
-
ripple::tfWithdrawMask
constexpr std::uint32_t tfWithdrawMask
Definition: TxFlags.h:215
+
ripple::tfWithdrawMask
constexpr std::uint32_t tfWithdrawMask
Definition: TxFlags.h:217
ripple::deleteAMMAccount
TER deleteAMMAccount(Sandbox &view, Issue const &asset, Issue const &asset2, beast::Journal j)
Delete trustlines to AMM.
Definition: AMMUtils.cpp:249
-
ripple::requireAuth
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account lacks required authorization.
Definition: View.cpp:1815
-
ripple::redeemIOU
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
Definition: View.cpp:1699
+
ripple::requireAuth
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account lacks required authorization.
Definition: View.cpp:1861
+
ripple::redeemIOU
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
Definition: View.cpp:1745
ripple::toSTAmount
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
Definition: AmountConversions.h:32
ripple::lpTokensOut
STAmount lpTokensOut(STAmount const &asset1Balance, STAmount const &asset1Withdraw, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's withdraw amount.
Definition: AMMHelpers.cpp:90
-
ripple::tfLimitLPToken
constexpr std::uint32_t tfLimitLPToken
Definition: TxFlags.h:207
+
ripple::tfLimitLPToken
constexpr std::uint32_t tfLimitLPToken
Definition: TxFlags.h:209
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:47
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
ripple::ammEnabled
bool ammEnabled(Rules const &)
Return true if required AMM amendments are enabled.
Definition: AMMCore.cpp:128
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
ripple::adjustAmountsByLPTokens
std::tuple< STAmount, std::optional< STAmount >, STAmount > adjustAmountsByLPTokens(STAmount const &amountBalance, STAmount const &amount, std::optional< STAmount > const &amount2, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee, bool isDeposit)
Calls adjustLPTokens() and adjusts deposit or withdraw amounts if the adjusted LP tokens are less tha...
Definition: AMMHelpers.cpp:147
-
ripple::tfOneAssetLPToken
constexpr std::uint32_t tfOneAssetLPToken
Definition: TxFlags.h:206
+
ripple::tfOneAssetLPToken
constexpr std::uint32_t tfOneAssetLPToken
Definition: TxFlags.h:208
ripple::isOnlyLiquidityProvider
Expected< bool, TER > isOnlyLiquidityProvider(ReadView const &view, Issue const &ammIssue, AccountID const &lpAccount)
Return true if the Liquidity Provider is the only AMM provider, false otherwise.
Definition: AMMUtils.cpp:353
ripple::tokensWithdraw
static std::optional< STAmount > tokensWithdraw(STAmount const &lpTokens, std::optional< STAmount > const &tokensIn, std::uint32_t flags)
Definition: AMMWithdraw.cpp:160
ripple::isFrozen
bool isFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition: View.cpp:238
ripple::ammAccountID
AccountID ammAccountID(std::uint16_t prefix, uint256 const &parentHash, uint256 const &ammID)
Calculate AMM account ID.
Definition: AMMCore.cpp:30
-
ripple::tfTwoAsset
constexpr std::uint32_t tfTwoAsset
Definition: TxFlags.h:205
+
ripple::tfTwoAsset
constexpr std::uint32_t tfTwoAsset
Definition: TxFlags.h:207
ripple::ammLPHolds
STAmount ammLPHolds(ReadView const &view, Currency const &cur1, Currency const &cur2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
Definition: AMMUtils.cpp:111
-
ripple::tfWithdrawAll
constexpr std::uint32_t tfWithdrawAll
Definition: TxFlags.h:202
+
ripple::tfWithdrawAll
constexpr std::uint32_t tfWithdrawAll
Definition: TxFlags.h:204
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:134
ripple::WaiveTransferFee::Yes
@ Yes
ripple::noIssue
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
Definition: Issue.h:126
@@ -1158,18 +1158,18 @@ $(function() {
ripple::tecAMM_INVALID_TOKENS
@ tecAMM_INVALID_TOKENS
Definition: TER.h:318
ripple::tecAMM_BALANCE
@ tecAMM_BALANCE
Definition: TER.h:316
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:294
-
ripple::tfLPToken
constexpr std::uint32_t tfLPToken
Definition: TxFlags.h:201
+
ripple::tfLPToken
constexpr std::uint32_t tfLPToken
Definition: TxFlags.h:203
ripple::getFee
Number getFee(std::uint16_t tfee)
Convert to the fee from the basis points.
Definition: AMMCore.h:109
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
ripple::invalidAMMAssetPair
NotTEC invalidAMMAssetPair(Issue const &issue1, Issue const &issue2, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt)
Definition: AMMCore.cpp:79
ripple::ammHolds
Expected< std::tuple< STAmount, STAmount, STAmount >, TER > ammHolds(ReadView const &view, SLE const &ammSle, std::optional< Issue > const &optIssue1, std::optional< Issue > const &optIssue2, FreezeHandling freezeHandling, beast::Journal const j)
Get AMM pool and LP token balances.
Definition: AMMUtils.cpp:45
-
ripple::tfWithdrawSubTx
constexpr std::uint32_t tfWithdrawSubTx
Definition: TxFlags.h:209
+
ripple::tfWithdrawSubTx
constexpr std::uint32_t tfWithdrawSubTx
Definition: TxFlags.h:211
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::terNO_AMM
@ terNO_AMM
Definition: TER.h:227
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:627
ripple::withdrawByTokens
STAmount withdrawByTokens(STAmount const &assetBalance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Calculate asset withdrawal by tokens.
Definition: AMMHelpers.cpp:114
ripple::withinRelativeDistance
bool withinRelativeDistance(Quality const &calcQuality, Quality const &reqQuality, Number const &dist)
Check if the relative distance between the qualities is within the requested distance.
Definition: AMMHelpers.h:130
-
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
Definition: View.cpp:1526
+
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
Definition: View.cpp:1571
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:587
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:87
ripple::temBAD_AMM_TOKENS
@ temBAD_AMM_TOKENS
Definition: TER.h:129
diff --git a/AMM_8cpp_source.html b/AMM_8cpp_source.html index 449ea93ac9..33696529bc 100644 --- a/AMM_8cpp_source.html +++ b/AMM_8cpp_source.html @@ -1011,27 +1011,27 @@ $(function() {
ripple::test::jtx::initialTokens
static IOUAmount initialTokens(STAmount const &asset1, STAmount const &asset2)
Definition: AMM.cpp:42
ripple::test::jtx::create
Json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount, NetClock::duration const &settleDelay, PublicKey const &pk, std::optional< NetClock::time_point > const &cancelAfter, std::optional< std::uint32_t > const &dstTag)
Definition: TestHelpers.cpp:256
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
-
ripple::tfSingleAsset
constexpr std::uint32_t tfSingleAsset
Definition: TxFlags.h:204
+
ripple::tfSingleAsset
constexpr std::uint32_t tfSingleAsset
Definition: TxFlags.h:206
ripple::fhZERO_IF_FROZEN
@ fhZERO_IF_FROZEN
Definition: View.h:80
ripple::fhIGNORE_FREEZE
@ fhIGNORE_FREEZE
Definition: View.h:80
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
ripple::ammAuctionTimeSlot
std::optional< std::uint8_t > ammAuctionTimeSlot(std::uint64_t current, STObject const &auctionSlot)
Get time slot of the auction slot.
Definition: AMMCore.cpp:107
ripple::toSTAmount
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
Definition: AmountConversions.h:32
-
ripple::tfLimitLPToken
constexpr std::uint32_t tfLimitLPToken
Definition: TxFlags.h:207
+
ripple::tfLimitLPToken
constexpr std::uint32_t tfLimitLPToken
Definition: TxFlags.h:209
ripple::ammLPTIssue
Issue ammLPTIssue(Currency const &cur1, Currency const &cur2, AccountID const &ammAccountID)
Calculate LPT Issue from AMM asset pair.
Definition: AMMCore.cpp:56
-
ripple::tfOneAssetLPToken
constexpr std::uint32_t tfOneAssetLPToken
Definition: TxFlags.h:206
+
ripple::tfOneAssetLPToken
constexpr std::uint32_t tfOneAssetLPToken
Definition: TxFlags.h:208
ripple::ammAccountID
AccountID ammAccountID(std::uint16_t prefix, uint256 const &parentHash, uint256 const &ammID)
Calculate AMM account ID.
Definition: AMMCore.cpp:30
-
ripple::tfTwoAsset
constexpr std::uint32_t tfTwoAsset
Definition: TxFlags.h:205
+
ripple::tfTwoAsset
constexpr std::uint32_t tfTwoAsset
Definition: TxFlags.h:207
ripple::ammLPHolds
STAmount ammLPHolds(ReadView const &view, Currency const &cur1, Currency const &cur2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
Definition: AMMUtils.cpp:111
ripple::to_json
Json::Value to_json(Asset const &asset)
Definition: Asset.cpp:74
-
ripple::tfDepositSubTx
constexpr std::uint32_t tfDepositSubTx
Definition: TxFlags.h:212
+
ripple::tfDepositSubTx
constexpr std::uint32_t tfDepositSubTx
Definition: TxFlags.h:214
ripple::ammPoolHolds
std::pair< STAmount, STAmount > ammPoolHolds(ReadView const &view, AccountID const &ammAccountID, Issue const &issue1, Issue const &issue2, FreezeHandling freezeHandling, beast::Journal const j)
Get AMM pool balances.
Definition: AMMUtils.cpp:29
-
ripple::tfLPToken
constexpr std::uint32_t tfLPToken
Definition: TxFlags.h:201
+
ripple::tfLPToken
constexpr std::uint32_t tfLPToken
Definition: TxFlags.h:203
ripple::tfUniversal
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:61
ripple::amountFromJsonNoThrow
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
Definition: STAmount.cpp:1029
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
-
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:271
-
ripple::tfWithdrawSubTx
constexpr std::uint32_t tfWithdrawSubTx
Definition: TxFlags.h:209
+
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:297
+
ripple::tfWithdrawSubTx
constexpr std::uint32_t tfWithdrawSubTx
Definition: TxFlags.h:211
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::root2
Number root2(Number f)
Definition: Number.cpp:695
std
STL namespace.
diff --git a/AMM_8h_source.html b/AMM_8h_source.html index 1ad31abc11..8a625c1a13 100644 --- a/AMM_8h_source.html +++ b/AMM_8h_source.html @@ -588,8 +588,8 @@ $(function() {
ripple::test::jtx::amm::ammClawback
Json::Value ammClawback(Account const &issuer, Account const &holder, Issue const &asset, Issue const &asset2, std::optional< STAmount > const &amount)
Definition: AMM.cpp:828
ripple::test::jtx::amm::pay
Json::Value pay(Account const &account, AccountID const &to, STAmount const &amount)
Definition: AMM.cpp:816
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
-
ripple::tfOneAssetWithdrawAll
constexpr std::uint32_t tfOneAssetWithdrawAll
Definition: TxFlags.h:203
-
ripple::tfWithdrawAll
constexpr std::uint32_t tfWithdrawAll
Definition: TxFlags.h:202
+
ripple::tfOneAssetWithdrawAll
constexpr std::uint32_t tfOneAssetWithdrawAll
Definition: TxFlags.h:205
+
ripple::tfWithdrawAll
constexpr std::uint32_t tfWithdrawAll
Definition: TxFlags.h:204
std::optional
std::pair
ripple::test::jtx::BidArg
Definition: AMM.h:110
diff --git a/AMM__test_8cpp_source.html b/AMM__test_8cpp_source.html index cdc75cfa32..62a89b892d 100644 --- a/AMM__test_8cpp_source.html +++ b/AMM__test_8cpp_source.html @@ -7355,9 +7355,9 @@ $(function() {
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::xrpIssue
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:118
ripple::amountFromString
STAmount amountFromString(Asset const &issue, std::string const &amount)
Definition: STAmount.cpp:834
-
ripple::tfSingleAsset
constexpr std::uint32_t tfSingleAsset
Definition: TxFlags.h:204
+
ripple::tfSingleAsset
constexpr std::uint32_t tfSingleAsset
Definition: TxFlags.h:206
ripple::asfGlobalFreeze
constexpr std::uint32_t asfGlobalFreeze
Definition: TxFlags.h:82
-
ripple::tfOneAssetWithdrawAll
constexpr std::uint32_t tfOneAssetWithdrawAll
Definition: TxFlags.h:203
+
ripple::tfOneAssetWithdrawAll
constexpr std::uint32_t tfOneAssetWithdrawAll
Definition: TxFlags.h:205
ripple::TOTAL_TIME_SLOT_SECS
std::uint32_t constexpr TOTAL_TIME_SLOT_SECS
Definition: AMMCore.h:34
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
ripple::LedgerNameSpace::AMM
@ AMM
@@ -7370,16 +7370,16 @@ $(function() {
ripple::lsfDefaultRipple
@ lsfDefaultRipple
Definition: LedgerFormats.h:134
ripple::lsfDisableMaster
@ lsfDisableMaster
Definition: LedgerFormats.h:131
ripple::lsfDepositAuth
@ lsfDepositAuth
Definition: LedgerFormats.h:136
-
ripple::tfLimitLPToken
constexpr std::uint32_t tfLimitLPToken
Definition: TxFlags.h:207
-
ripple::tfBurnable
constexpr std::uint32_t const tfBurnable
Definition: TxFlags.h:131
+
ripple::tfLimitLPToken
constexpr std::uint32_t tfLimitLPToken
Definition: TxFlags.h:209
+
ripple::tfBurnable
constexpr std::uint32_t const tfBurnable
Definition: TxFlags.h:133
ripple::tfPassive
constexpr std::uint32_t tfPassive
Definition: TxFlags.h:96
-
ripple::tfOneAssetLPToken
constexpr std::uint32_t tfOneAssetLPToken
Definition: TxFlags.h:206
+
ripple::tfOneAssetLPToken
constexpr std::uint32_t tfOneAssetLPToken
Definition: TxFlags.h:208
ripple::isOnlyLiquidityProvider
Expected< bool, TER > isOnlyLiquidityProvider(ReadView const &view, Issue const &ammIssue, AccountID const &lpAccount)
Return true if the Liquidity Provider is the only AMM provider, false otherwise.
Definition: AMMUtils.cpp:353
ripple::tefEXCEPTION
@ tefEXCEPTION
Definition: TER.h:172
-
ripple::tfTwoAsset
constexpr std::uint32_t tfTwoAsset
Definition: TxFlags.h:205
+
ripple::tfTwoAsset
constexpr std::uint32_t tfTwoAsset
Definition: TxFlags.h:207
ripple::tfPartialPayment
constexpr std::uint32_t tfPartialPayment
Definition: TxFlags.h:105
ripple::TxSearched::all
@ all
-
ripple::tfWithdrawAll
constexpr std::uint32_t tfWithdrawAll
Definition: TxFlags.h:202
+
ripple::tfWithdrawAll
constexpr std::uint32_t tfWithdrawAll
Definition: TxFlags.h:204
ripple::Currency
base_uint< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
Definition: UintTypes.h:56
ripple::changeSpotPriceQuality
std::optional< TAmounts< TIn, TOut > > changeSpotPriceQuality(TAmounts< TIn, TOut > const &pool, Quality const &quality, std::uint16_t tfee, Rules const &rules, beast::Journal j)
Generate AMM offer so that either updated Spot Price Quality (SPQ) is equal to LOB quality (in this c...
Definition: AMMHelpers.h:332
ripple::tfSetfAuth
constexpr std::uint32_t tfSetfAuth
Definition: TxFlags.h:112
@@ -7403,12 +7403,12 @@ $(function() {
ripple::tecAMM_BALANCE
@ tecAMM_BALANCE
Definition: TER.h:316
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:294
ripple::tecNO_AUTH
@ tecNO_AUTH
Definition: TER.h:287
-
ripple::tfLPToken
constexpr std::uint32_t tfLPToken
Definition: TxFlags.h:201
+
ripple::tfLPToken
constexpr std::uint32_t tfLPToken
Definition: TxFlags.h:203
ripple::tfNoRippleDirect
constexpr std::uint32_t tfNoRippleDirect
Definition: TxFlags.h:104
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
ripple::AUCTION_SLOT_INTERVAL_DURATION
std::uint32_t constexpr AUCTION_SLOT_INTERVAL_DURATION
Definition: AMMCore.h:40
ripple::tfLimitQuality
constexpr std::uint32_t tfLimitQuality
Definition: TxFlags.h:106
-
ripple::tfTwoAssetIfEmpty
constexpr std::uint32_t tfTwoAssetIfEmpty
Definition: TxFlags.h:208
+
ripple::tfTwoAssetIfEmpty
constexpr std::uint32_t tfTwoAssetIfEmpty
Definition: TxFlags.h:210
ripple::asfAllowTrustLineClawback
constexpr std::uint32_t asfAllowTrustLineClawback
Definition: TxFlags.h:93
ripple::maxDeletableAMMTrustLines
std::uint16_t constexpr maxDeletableAMMTrustLines
The maximum number of trustlines to delete as part of AMM account deletion cleanup.
Definition: Protocol.h:130
ripple::asfRequireAuth
constexpr std::uint32_t asfRequireAuth
Definition: TxFlags.h:77
diff --git a/AcceptedLedgerTx_8cpp_source.html b/AcceptedLedgerTx_8cpp_source.html index 869f222583..d12079b8f2 100644 --- a/AcceptedLedgerTx_8cpp_source.html +++ b/AcceptedLedgerTx_8cpp_source.html @@ -185,7 +185,7 @@ $(function() {
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::transHuman
std::string transHuman(TER code)
Definition: TER.cpp:260
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:106
-
ripple::accountFunds
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition: View.cpp:366
+
ripple::accountFunds
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition: View.cpp:405
ripple::fhIGNORE_FREEZE
@ fhIGNORE_FREEZE
Definition: View.h:80
ripple::sqlBlobLiteral
std::string sqlBlobLiteral(Blob const &blob)
Format arbitrary binary data as an SQLite "blob literal".
Definition: StringUtilities.cpp:33
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
diff --git a/AccountChannels_8cpp_source.html b/AccountChannels_8cpp_source.html index f9d36eefdd..8c031d56b5 100644 --- a/AccountChannels_8cpp_source.html +++ b/AccountChannels_8cpp_source.html @@ -326,7 +326,7 @@ $(function() {
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::ltANY
@ ltANY
A special type, matching any ledger entry type.
Definition: LedgerFormats.h:78
-
ripple::forEachItemAfter
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.
Definition: View.cpp:495
+
ripple::forEachItemAfter
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.
Definition: View.cpp:534
ripple::doAccountChannels
Json::Value doAccountChannels(RPC::JsonContext &context)
Definition: AccountChannels.cpp:68
std::optional
std::shared_ptr
diff --git a/AccountDelete__test_8cpp_source.html b/AccountDelete__test_8cpp_source.html index b721977133..a62609e083 100644 --- a/AccountDelete__test_8cpp_source.html +++ b/AccountDelete__test_8cpp_source.html @@ -1475,7 +1475,7 @@ $(function() {
ripple::tecNO_DST_INSUF_XRP
@ tecNO_DST_INSUF_XRP
Definition: TER.h:278
ripple::tfUniversal
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:61
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
-
ripple::tfClose
constexpr std::uint32_t tfClose
Definition: TxFlags.h:127
+
ripple::tfClose
constexpr std::uint32_t tfClose
Definition: TxFlags.h:129
ripple::terINSUF_FEE_B
@ terINSUF_FEE_B
Definition: TER.h:216
ripple::temBAD_FEE
@ temBAD_FEE
Definition: TER.h:92
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:87
diff --git a/AccountLines_8cpp_source.html b/AccountLines_8cpp_source.html index faa3b5928c..378783f515 100644 --- a/AccountLines_8cpp_source.html +++ b/AccountLines_8cpp_source.html @@ -140,206 +140,210 @@ $(function() {
62 jPeer[jss::freeze] = true;
63 if (line.getFreezePeer())
64 jPeer[jss::freeze_peer] = true;
-
65}
-
66
-
67// {
-
68// account: <account>
-
69// ledger_hash : <ledger>
-
70// ledger_index : <ledger_index>
-
71// limit: integer // optional
-
72// marker: opaque // optional, resume previous query
-
73// ignore_default: bool // do not return lines in default state (on
-
74// this account's side)
-
75// }
-
76Json::Value
-
77doAccountLines(RPC::JsonContext& context)
-
78{
-
79 auto const& params(context.params);
-
80 if (!params.isMember(jss::account))
-
81 return RPC::missing_field_error(jss::account);
-
82
-
83 if (!params[jss::account].isString())
-
84 return RPC::invalid_field_error(jss::account);
-
85
-
86 std::shared_ptr<ReadView const> ledger;
-
87 auto result = RPC::lookupLedger(ledger, context);
-
88 if (!ledger)
-
89 return result;
-
90
-
91 auto id = parseBase58<AccountID>(params[jss::account].asString());
-
92 if (!id)
-
93 {
-
94 RPC::inject_error(rpcACT_MALFORMED, result);
-
95 return result;
-
96 }
-
97 auto const accountID{std::move(id.value())};
-
98
-
99 if (!ledger->exists(keylet::account(accountID)))
-
100 return rpcError(rpcACT_NOT_FOUND);
-
101
-
102 std::string strPeer;
-
103 if (params.isMember(jss::peer))
-
104 strPeer = params[jss::peer].asString();
+
65 if (line.getDeepFreeze())
+
66 jPeer[jss::deep_freeze] = true;
+
67 if (line.getDeepFreezePeer())
+
68 jPeer[jss::deep_freeze_peer] = true;
+
69}
+
70
+
71// {
+
72// account: <account>
+
73// ledger_hash : <ledger>
+
74// ledger_index : <ledger_index>
+
75// limit: integer // optional
+
76// marker: opaque // optional, resume previous query
+
77// ignore_default: bool // do not return lines in default state (on
+
78// this account's side)
+
79// }
+
80Json::Value
+
81doAccountLines(RPC::JsonContext& context)
+
82{
+
83 auto const& params(context.params);
+
84 if (!params.isMember(jss::account))
+
85 return RPC::missing_field_error(jss::account);
+
86
+
87 if (!params[jss::account].isString())
+
88 return RPC::invalid_field_error(jss::account);
+
89
+
90 std::shared_ptr<ReadView const> ledger;
+
91 auto result = RPC::lookupLedger(ledger, context);
+
92 if (!ledger)
+
93 return result;
+
94
+
95 auto id = parseBase58<AccountID>(params[jss::account].asString());
+
96 if (!id)
+
97 {
+
98 RPC::inject_error(rpcACT_MALFORMED, result);
+
99 return result;
+
100 }
+
101 auto const accountID{std::move(id.value())};
+
102
+
103 if (!ledger->exists(keylet::account(accountID)))
+
104 return rpcError(rpcACT_NOT_FOUND);
105
-
106 auto const raPeerAccount = [&]() -> std::optional<AccountID> {
-
107 return strPeer.empty() ? std::nullopt : parseBase58<AccountID>(strPeer);
-
108 }();
-
109 if (!strPeer.empty() && !raPeerAccount)
-
110 {
-
111 RPC::inject_error(rpcACT_MALFORMED, result);
-
112 return result;
-
113 }
-
114
-
115 unsigned int limit;
-
116 if (auto err = readLimitField(limit, RPC::Tuning::accountLines, context))
-
117 return *err;
+
106 std::string strPeer;
+
107 if (params.isMember(jss::peer))
+
108 strPeer = params[jss::peer].asString();
+
109
+
110 auto const raPeerAccount = [&]() -> std::optional<AccountID> {
+
111 return strPeer.empty() ? std::nullopt : parseBase58<AccountID>(strPeer);
+
112 }();
+
113 if (!strPeer.empty() && !raPeerAccount)
+
114 {
+
115 RPC::inject_error(rpcACT_MALFORMED, result);
+
116 return result;
+
117 }
118
-
119 if (limit == 0)
-
120 return rpcError(rpcINVALID_PARAMS);
-
121
-
122 // this flag allows the requester to ask incoming trustlines in default
-
123 // state be omitted
-
124 bool ignoreDefault = params.isMember(jss::ignore_default) &&
-
125 params[jss::ignore_default].asBool();
-
126
-
127 Json::Value& jsonLines(result[jss::lines] = Json::arrayValue);
-
128 struct VisitData
-
129 {
-
130 std::vector<RPCTrustLine> items;
-
131 AccountID const& accountID;
-
132 std::optional<AccountID> const& raPeerAccount;
-
133 bool ignoreDefault;
-
134 uint32_t foundCount;
-
135 };
-
136 VisitData visitData = {{}, accountID, raPeerAccount, ignoreDefault, 0};
-
137 uint256 startAfter = beast::zero;
-
138 std::uint64_t startHint = 0;
-
139
-
140 if (params.isMember(jss::marker))
-
141 {
-
142 if (!params[jss::marker].isString())
-
143 return RPC::expected_field_error(jss::marker, "string");
-
144
-
145 // Marker is composed of a comma separated index and start hint. The
-
146 // former will be read as hex, and the latter using boost lexical cast.
-
147 std::stringstream marker(params[jss::marker].asString());
-
148 std::string value;
-
149 if (!std::getline(marker, value, ','))
-
150 return rpcError(rpcINVALID_PARAMS);
-
151
-
152 if (!startAfter.parseHex(value))
-
153 return rpcError(rpcINVALID_PARAMS);
-
154
-
155 if (!std::getline(marker, value, ','))
-
156 return rpcError(rpcINVALID_PARAMS);
-
157
-
158 try
-
159 {
-
160 startHint = boost::lexical_cast<std::uint64_t>(value);
-
161 }
-
162 catch (boost::bad_lexical_cast&)
+
119 unsigned int limit;
+
120 if (auto err = readLimitField(limit, RPC::Tuning::accountLines, context))
+
121 return *err;
+
122
+
123 if (limit == 0)
+
124 return rpcError(rpcINVALID_PARAMS);
+
125
+
126 // this flag allows the requester to ask incoming trustlines in default
+
127 // state be omitted
+
128 bool ignoreDefault = params.isMember(jss::ignore_default) &&
+
129 params[jss::ignore_default].asBool();
+
130
+
131 Json::Value& jsonLines(result[jss::lines] = Json::arrayValue);
+
132 struct VisitData
+
133 {
+
134 std::vector<RPCTrustLine> items;
+
135 AccountID const& accountID;
+
136 std::optional<AccountID> const& raPeerAccount;
+
137 bool ignoreDefault;
+
138 uint32_t foundCount;
+
139 };
+
140 VisitData visitData = {{}, accountID, raPeerAccount, ignoreDefault, 0};
+
141 uint256 startAfter = beast::zero;
+
142 std::uint64_t startHint = 0;
+
143
+
144 if (params.isMember(jss::marker))
+
145 {
+
146 if (!params[jss::marker].isString())
+
147 return RPC::expected_field_error(jss::marker, "string");
+
148
+
149 // Marker is composed of a comma separated index and start hint. The
+
150 // former will be read as hex, and the latter using boost lexical cast.
+
151 std::stringstream marker(params[jss::marker].asString());
+
152 std::string value;
+
153 if (!std::getline(marker, value, ','))
+
154 return rpcError(rpcINVALID_PARAMS);
+
155
+
156 if (!startAfter.parseHex(value))
+
157 return rpcError(rpcINVALID_PARAMS);
+
158
+
159 if (!std::getline(marker, value, ','))
+
160 return rpcError(rpcINVALID_PARAMS);
+
161
+
162 try
163 {
-
164 return rpcError(rpcINVALID_PARAMS);
+
164 startHint = boost::lexical_cast<std::uint64_t>(value);
165 }
-
166
-
167 // We then must check if the object pointed to by the marker is actually
-
168 // owned by the account in the request.
-
169 auto const sle = ledger->read({ltANY, startAfter});
+
166 catch (boost::bad_lexical_cast&)
+
167 {
+
168 return rpcError(rpcINVALID_PARAMS);
+
169 }
170
-
171 if (!sle)
-
172 return rpcError(rpcINVALID_PARAMS);
-
173
-
174 if (!RPC::isRelatedToAccount(*ledger, sle, accountID))
-
175 return rpcError(rpcINVALID_PARAMS);
-
176 }
+
171 // We then must check if the object pointed to by the marker is actually
+
172 // owned by the account in the request.
+
173 auto const sle = ledger->read({ltANY, startAfter});
+
174
+
175 if (!sle)
+
176 return rpcError(rpcINVALID_PARAMS);
177
-
178 auto count = 0;
-
179 std::optional<uint256> marker = {};
-
180 std::uint64_t nextHint = 0;
-
181 {
-
182 if (!forEachItemAfter(
-
183 *ledger,
-
184 accountID,
-
185 startAfter,
-
186 startHint,
-
187 limit + 1,
-
188 [&visitData, &count, &marker, &limit, &nextHint](
-
189 std::shared_ptr<SLE const> const& sleCur) {
-
190 if (!sleCur)
-
191 {
-
192 UNREACHABLE("ripple::doAccountLines : null SLE");
-
193 return false;
-
194 }
-
195
-
196 if (++count == limit)
-
197 {
-
198 marker = sleCur->key();
-
199 nextHint =
-
200 RPC::getStartHint(sleCur, visitData.accountID);
-
201 }
-
202
-
203 if (sleCur->getType() != ltRIPPLE_STATE)
-
204 return true;
-
205
-
206 bool ignore = false;
-
207 if (visitData.ignoreDefault)
-
208 {
-
209 if (sleCur->getFieldAmount(sfLowLimit).getIssuer() ==
-
210 visitData.accountID)
-
211 ignore =
-
212 !(sleCur->getFieldU32(sfFlags) & lsfLowReserve);
-
213 else
-
214 ignore = !(
-
215 sleCur->getFieldU32(sfFlags) & lsfHighReserve);
-
216 }
-
217
-
218 if (!ignore && count <= limit)
-
219 {
-
220 auto const line =
-
221 RPCTrustLine::makeItem(visitData.accountID, sleCur);
-
222
-
223 if (line &&
-
224 (!visitData.raPeerAccount ||
-
225 *visitData.raPeerAccount ==
-
226 line->getAccountIDPeer()))
-
227 {
-
228 visitData.items.emplace_back(*line);
-
229 }
-
230 }
-
231
-
232 return true;
-
233 }))
-
234 {
-
235 return rpcError(rpcINVALID_PARAMS);
-
236 }
-
237 }
-
238
-
239 // Both conditions need to be checked because marker is set on the limit-th
-
240 // item, but if there is no item on the limit + 1 iteration, then there is
-
241 // no need to return a marker.
-
242 if (count == limit + 1 && marker)
-
243 {
-
244 result[jss::limit] = limit;
-
245 result[jss::marker] =
-
246 to_string(*marker) + "," + std::to_string(nextHint);
-
247 }
-
248
-
249 result[jss::account] = toBase58(accountID);
-
250
-
251 for (auto const& item : visitData.items)
-
252 addLine(jsonLines, item);
-
253
-
254 context.loadType = Resource::feeMediumBurdenRPC;
-
255 return result;
-
256}
+
178 if (!RPC::isRelatedToAccount(*ledger, sle, accountID))
+
179 return rpcError(rpcINVALID_PARAMS);
+
180 }
+
181
+
182 auto count = 0;
+
183 std::optional<uint256> marker = {};
+
184 std::uint64_t nextHint = 0;
+
185 {
+
186 if (!forEachItemAfter(
+
187 *ledger,
+
188 accountID,
+
189 startAfter,
+
190 startHint,
+
191 limit + 1,
+
192 [&visitData, &count, &marker, &limit, &nextHint](
+
193 std::shared_ptr<SLE const> const& sleCur) {
+
194 if (!sleCur)
+
195 {
+
196 UNREACHABLE("ripple::doAccountLines : null SLE");
+
197 return false;
+
198 }
+
199
+
200 if (++count == limit)
+
201 {
+
202 marker = sleCur->key();
+
203 nextHint =
+
204 RPC::getStartHint(sleCur, visitData.accountID);
+
205 }
+
206
+
207 if (sleCur->getType() != ltRIPPLE_STATE)
+
208 return true;
+
209
+
210 bool ignore = false;
+
211 if (visitData.ignoreDefault)
+
212 {
+
213 if (sleCur->getFieldAmount(sfLowLimit).getIssuer() ==
+
214 visitData.accountID)
+
215 ignore =
+
216 !(sleCur->getFieldU32(sfFlags) & lsfLowReserve);
+
217 else
+
218 ignore = !(
+
219 sleCur->getFieldU32(sfFlags) & lsfHighReserve);
+
220 }
+
221
+
222 if (!ignore && count <= limit)
+
223 {
+
224 auto const line =
+
225 RPCTrustLine::makeItem(visitData.accountID, sleCur);
+
226
+
227 if (line &&
+
228 (!visitData.raPeerAccount ||
+
229 *visitData.raPeerAccount ==
+
230 line->getAccountIDPeer()))
+
231 {
+
232 visitData.items.emplace_back(*line);
+
233 }
+
234 }
+
235
+
236 return true;
+
237 }))
+
238 {
+
239 return rpcError(rpcINVALID_PARAMS);
+
240 }
+
241 }
+
242
+
243 // Both conditions need to be checked because marker is set on the limit-th
+
244 // item, but if there is no item on the limit + 1 iteration, then there is
+
245 // no need to return a marker.
+
246 if (count == limit + 1 && marker)
+
247 {
+
248 result[jss::limit] = limit;
+
249 result[jss::marker] =
+
250 to_string(*marker) + "," + std::to_string(nextHint);
+
251 }
+
252
+
253 result[jss::account] = toBase58(accountID);
+
254
+
255 for (auto const& item : visitData.items)
+
256 addLine(jsonLines, item);
257
-
258} // namespace ripple
+
258 context.loadType = Resource::feeMediumBurdenRPC;
+
259 return result;
+
260}
+
261
+
262} // namespace ripple
std::string
std::stringstream
Json::Value
Represents a JSON value.
Definition: json_value.h:147
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:891
ripple::Issue::currency
Currency currency
Definition: Issue.h:38
-
ripple::RPCTrustLine
Definition: TrustLine.h:206
+
ripple::RPCTrustLine
Definition: TrustLine.h:220
ripple::RPCTrustLine::makeItem
static std::optional< RPCTrustLine > makeItem(AccountID const &accountID, std::shared_ptr< SLE const > const &sle)
Definition: TrustLine.cpp:110
ripple::STAmount
Definition: STAmount.h:50
ripple::STAmount::getText
std::string getText() const override
Definition: STAmount.cpp:515
@@ -367,13 +371,13 @@ $(function() {
ripple::rpcACT_NOT_FOUND
@ rpcACT_NOT_FOUND
Definition: ErrorCodes.h:70
ripple::rpcACT_MALFORMED
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
-
ripple::doAccountLines
Json::Value doAccountLines(RPC::JsonContext &context)
Definition: AccountLines.cpp:77
+
ripple::doAccountLines
Json::Value doAccountLines(RPC::JsonContext &context)
Definition: AccountLines.cpp:81
ripple::lsfHighReserve
@ lsfHighReserve
Definition: LedgerFormats.h:158
ripple::lsfLowReserve
@ lsfLowReserve
Definition: LedgerFormats.h:157
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::ltANY
@ ltANY
A special type, matching any ledger entry type.
Definition: LedgerFormats.h:78
-
ripple::forEachItemAfter
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.
Definition: View.cpp:495
+
ripple::forEachItemAfter
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.
Definition: View.cpp:534
std::optional
std::shared_ptr
ripple::RPC::Context::loadType
Resource::Charge & loadType
Definition: Context.h:43
diff --git a/AccountLines__test_8cpp_source.html b/AccountLines__test_8cpp_source.html index d1f910f718..6dc35862fd 100644 --- a/AccountLines__test_8cpp_source.html +++ b/AccountLines__test_8cpp_source.html @@ -245,1336 +245,1348 @@ $(function() {
167 env.close();
168
169 // Set flags on gw2 trust lines so we can look for them.
-
170 env(trust(alice, gw2Currency(0), gw2, tfSetNoRipple | tfSetFreeze));
-
171 }
-
172 env.close();
-
173 LedgerInfo const ledger58Info = env.closed()->info();
-
174 BEAST_EXPECT(ledger58Info.seq == 58);
-
175
-
176 // A re-usable test for historic ledgers.
-
177 auto testAccountLinesHistory = [this, &env](
-
178 Account const& account,
-
179 LedgerInfo const& info,
-
180 int count) {
-
181 // Get account_lines by ledger index.
-
182 auto const linesSeq = env.rpc(
-
183 "json",
-
184 "account_lines",
-
185 R"({"account": ")" + account.human() +
-
186 R"(", )"
-
187 R"("ledger_index": )" +
-
188 std::to_string(info.seq) + "}");
-
189 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
-
190 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
-
191
-
192 // Get account_lines by ledger hash.
-
193 auto const linesHash = env.rpc(
-
194 "json",
-
195 "account_lines",
-
196 R"({"account": ")" + account.human() +
-
197 R"(", )"
-
198 R"("ledger_hash": ")" +
-
199 to_string(info.hash) + R"("})");
-
200 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
-
201 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
-
202 };
-
203
-
204 // Alice should have no trust lines in ledger 3.
-
205 testAccountLinesHistory(alice, ledger3Info, 0);
-
206
-
207 // Alice should have 26 trust lines in ledger 4.
-
208 testAccountLinesHistory(alice, ledger4Info, 26);
-
209
-
210 // Alice should have 52 trust lines in ledger 58.
-
211 testAccountLinesHistory(alice, ledger58Info, 52);
-
212
-
213 {
-
214 // Surprisingly, it's valid to specify both index and hash, in
-
215 // which case the hash wins.
-
216 auto const lines = env.rpc(
-
217 "json",
-
218 "account_lines",
-
219 R"({"account": ")" + alice.human() +
-
220 R"(", )"
-
221 R"("ledger_hash": ")" +
-
222 to_string(ledger4Info.hash) +
-
223 R"(", )"
-
224 R"("ledger_index": )" +
-
225 std::to_string(ledger58Info.seq) + "}");
-
226 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
-
227 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
-
228 }
-
229 {
-
230 // alice should have 52 trust lines in the current ledger.
-
231 auto const lines = env.rpc(
-
232 "json",
-
233 "account_lines",
-
234 R"({"account": ")" + alice.human() + R"("})");
-
235 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
-
236 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52);
-
237 }
-
238 {
-
239 // alice should have 26 trust lines with gw1.
-
240 auto const lines = env.rpc(
-
241 "json",
-
242 "account_lines",
-
243 R"({"account": ")" + alice.human() +
-
244 R"(", )"
-
245 R"("peer": ")" +
-
246 gw1.human() + R"("})");
-
247 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
-
248 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
-
249 }
-
250 {
-
251 // Use a malformed peer.
-
252 auto const lines = env.rpc(
-
253 "json",
-
254 "account_lines",
-
255 R"({"account": ")" + alice.human() +
-
256 R"(", )"
-
257 R"("peer": )"
-
258 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})");
-
259 BEAST_EXPECT(
-
260 lines[jss::result][jss::error_message] ==
-
261 RPC::make_error(rpcACT_MALFORMED)[jss::error_message]);
-
262 }
-
263 {
-
264 // A negative limit should fail.
-
265 auto const lines = env.rpc(
-
266 "json",
-
267 "account_lines",
-
268 R"({"account": ")" + alice.human() +
-
269 R"(", )"
-
270 R"("limit": -1})");
-
271 BEAST_EXPECT(
-
272 lines[jss::result][jss::error_message] ==
-
273 RPC::expected_field_message(jss::limit, "unsigned integer"));
-
274 }
-
275 {
-
276 // Limit the response to 1 trust line.
-
277 auto const linesA = env.rpc(
-
278 "json",
-
279 "account_lines",
-
280 R"({"account": ")" + alice.human() +
-
281 R"(", )"
-
282 R"("limit": 1})");
-
283 BEAST_EXPECT(linesA[jss::result][jss::lines].isArray());
-
284 BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1);
-
285
-
286 // Pick up from where the marker left off. We should get 51.
-
287 auto marker = linesA[jss::result][jss::marker].asString();
-
288 auto const linesB = env.rpc(
-
289 "json",
-
290 "account_lines",
-
291 R"({"account": ")" + alice.human() +
-
292 R"(", )"
-
293 R"("marker": ")" +
-
294 marker + R"("})");
-
295 BEAST_EXPECT(linesB[jss::result][jss::lines].isArray());
-
296 BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 51);
-
297
-
298 // Go again from where the marker left off, but set a limit of 3.
-
299 auto const linesC = env.rpc(
-
300 "json",
-
301 "account_lines",
-
302 R"({"account": ")" + alice.human() +
-
303 R"(", )"
-
304 R"("limit": 3, )"
-
305 R"("marker": ")" +
-
306 marker + R"("})");
-
307 BEAST_EXPECT(linesC[jss::result][jss::lines].isArray());
-
308 BEAST_EXPECT(linesC[jss::result][jss::lines].size() == 3);
-
309
-
310 // Mess with the marker so it becomes bad and check for the error.
-
311 marker[5] = marker[5] == '7' ? '8' : '7';
-
312 auto const linesD = env.rpc(
-
313 "json",
-
314 "account_lines",
-
315 R"({"account": ")" + alice.human() +
-
316 R"(", )"
-
317 R"("marker": ")" +
-
318 marker + R"("})");
-
319 BEAST_EXPECT(
-
320 linesD[jss::result][jss::error_message] ==
-
321 RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]);
-
322 }
-
323 {
-
324 // A non-string marker should also fail.
-
325 auto const lines = env.rpc(
-
326 "json",
-
327 "account_lines",
-
328 R"({"account": ")" + alice.human() +
-
329 R"(", )"
-
330 R"("marker": true})");
-
331 BEAST_EXPECT(
-
332 lines[jss::result][jss::error_message] ==
-
333 RPC::expected_field_message(jss::marker, "string"));
-
334 }
-
335 {
-
336 // Check that the flags we expect from alice to gw2 are present.
-
337 auto const lines = env.rpc(
-
338 "json",
-
339 "account_lines",
-
340 R"({"account": ")" + alice.human() +
-
341 R"(", )"
-
342 R"("limit": 10, )"
-
343 R"("peer": ")" +
-
344 gw2.human() + R"("})");
-
345 auto const& line = lines[jss::result][jss::lines][0u];
-
346 BEAST_EXPECT(line[jss::freeze].asBool() == true);
-
347 BEAST_EXPECT(line[jss::no_ripple].asBool() == true);
-
348 BEAST_EXPECT(line[jss::peer_authorized].asBool() == true);
-
349 }
-
350 {
-
351 // Check that the flags we expect from gw2 to alice are present.
-
352 auto const linesA = env.rpc(
-
353 "json",
-
354 "account_lines",
-
355 R"({"account": ")" + gw2.human() +
-
356 R"(", )"
-
357 R"("limit": 1, )"
-
358 R"("peer": ")" +
-
359 alice.human() + R"("})");
-
360 auto const& lineA = linesA[jss::result][jss::lines][0u];
-
361 BEAST_EXPECT(lineA[jss::freeze_peer].asBool() == true);
-
362 BEAST_EXPECT(lineA[jss::no_ripple_peer].asBool() == true);
-
363 BEAST_EXPECT(lineA[jss::authorized].asBool() == true);
-
364
-
365 // Continue from the returned marker to make sure that works.
-
366 BEAST_EXPECT(linesA[jss::result].isMember(jss::marker));
-
367 auto const marker = linesA[jss::result][jss::marker].asString();
-
368 auto const linesB = env.rpc(
-
369 "json",
-
370 "account_lines",
-
371 R"({"account": ")" + gw2.human() +
-
372 R"(", )"
-
373 R"("limit": 25, )"
-
374 R"("marker": ")" +
-
375 marker +
-
376 R"(", )"
-
377 R"("peer": ")" +
-
378 alice.human() + R"("})");
-
379 BEAST_EXPECT(linesB[jss::result][jss::lines].isArray());
-
380 BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 25);
-
381 BEAST_EXPECT(!linesB[jss::result].isMember(jss::marker));
-
382 }
-
383 }
-
384
-
385 void
-
386 testAccountLinesMarker()
-
387 {
-
388 testcase("Entry pointed to by marker is not owned by account");
-
389 using namespace test::jtx;
-
390 Env env(*this);
-
391
-
392 // The goal of this test is observe account_lines RPC calls return an
-
393 // error message when the SLE pointed to by the marker is not owned by
-
394 // the Account being traversed.
-
395 //
-
396 // To start, we'll create an environment with some trust lines, offers
-
397 // and a signers list.
-
398 Account const alice{"alice"};
-
399 Account const becky{"becky"};
-
400 Account const gw1{"gw1"};
-
401 env.fund(XRP(10000), alice, becky, gw1);
-
402 env.close();
-
403
-
404 // Give alice a SignerList.
-
405 Account const bogie{"bogie"};
-
406 env(signers(alice, 2, {{bogie, 3}}));
-
407 env.close();
-
408
-
409 auto const EUR = gw1["EUR"];
-
410 env(trust(alice, EUR(200)));
-
411 env(trust(becky, EUR(200)));
-
412 env.close();
-
413
-
414 // Get all account objects for alice and verify that her
-
415 // signerlist is first. This is only a (reliable) coincidence of
-
416 // object naming. So if any of alice's objects are renamed this
-
417 // may fail.
-
418 Json::Value const aliceObjects = env.rpc(
-
419 "json",
-
420 "account_objects",
-
421 R"({"account": ")" + alice.human() +
-
422 R"(", )"
-
423 R"("limit": 10})");
-
424 Json::Value const& aliceSignerList =
-
425 aliceObjects[jss::result][jss::account_objects][0u];
-
426 if (!(aliceSignerList[sfLedgerEntryType.jsonName] == jss::SignerList))
-
427 {
-
428 fail(
-
429 "alice's account objects are misordered. "
-
430 "Please reorder the objects so the SignerList is first.",
-
431 __FILE__,
-
432 __LINE__);
-
433 return;
-
434 }
-
435
-
436 // Get account_lines for alice. Limit at 1, so we get a marker
-
437 // pointing to her SignerList.
-
438 auto const aliceLines1 = env.rpc(
-
439 "json",
-
440 "account_lines",
-
441 R"({"account": ")" + alice.human() + R"(", "limit": 1})");
-
442 BEAST_EXPECT(aliceLines1[jss::result].isMember(jss::marker));
-
443
-
444 // Verify that the marker points at the signer list.
-
445 std::string const aliceMarker =
-
446 aliceLines1[jss::result][jss::marker].asString();
-
447 std::string const markerIndex =
-
448 aliceMarker.substr(0, aliceMarker.find(','));
-
449 BEAST_EXPECT(markerIndex == aliceSignerList[jss::index].asString());
-
450
-
451 // When we fetch Alice's remaining lines we should find one and no more.
-
452 auto const aliceLines2 = env.rpc(
-
453 "json",
-
454 "account_lines",
-
455 R"({"account": ")" + alice.human() + R"(", "marker": ")" +
-
456 aliceMarker + R"("})");
-
457 BEAST_EXPECT(aliceLines2[jss::result][jss::lines].size() == 1);
-
458 BEAST_EXPECT(!aliceLines2[jss::result].isMember(jss::marker));
-
459
-
460 // Get account lines for beckys account, using alices SignerList as a
-
461 // marker. This should cause an error.
-
462 auto const beckyLines = env.rpc(
-
463 "json",
-
464 "account_lines",
-
465 R"({"account": ")" + becky.human() + R"(", "marker": ")" +
-
466 aliceMarker + R"("})");
-
467 BEAST_EXPECT(beckyLines[jss::result].isMember(jss::error_message));
-
468 }
-
469
-
470 void
-
471 testAccountLineDelete()
-
472 {
-
473 testcase("Entry pointed to by marker is removed");
-
474 using namespace test::jtx;
-
475 Env env(*this);
-
476
-
477 // The goal here is to observe account_lines marker behavior if the
-
478 // entry pointed at by a returned marker is removed from the ledger.
-
479 //
-
480 // It isn't easy to explicitly delete a trust line, so we do so in a
-
481 // round-about fashion. It takes 4 actors:
-
482 // o Gateway gw1 issues USD
-
483 // o alice offers to buy 100 USD for 100 XRP.
-
484 // o becky offers to sell 100 USD for 100 XRP.
-
485 // There will now be an inferred trustline between alice and gw1.
-
486 // o alice pays her 100 USD to cheri.
-
487 // alice should now have no USD and no trustline to gw1.
-
488 Account const alice{"alice"};
-
489 Account const becky{"becky"};
-
490 Account const cheri{"cheri"};
-
491 Account const gw1{"gw1"};
-
492 Account const gw2{"gw2"};
-
493 env.fund(XRP(10000), alice, becky, cheri, gw1, gw2);
-
494 env.close();
-
495
-
496 auto const USD = gw1["USD"];
-
497 auto const AUD = gw1["AUD"];
-
498 auto const EUR = gw2["EUR"];
-
499 env(trust(alice, USD(200)));
-
500 env(trust(alice, AUD(200)));
-
501 env(trust(becky, EUR(200)));
-
502 env(trust(cheri, EUR(200)));
-
503 env.close();
-
504
-
505 // becky gets 100 USD from gw1.
-
506 env(pay(gw2, becky, EUR(100)));
-
507 env.close();
-
508
-
509 // alice offers to buy 100 EUR for 100 XRP.
-
510 env(offer(alice, EUR(100), XRP(100)));
-
511 env.close();
-
512
-
513 // becky offers to buy 100 XRP for 100 EUR.
-
514 env(offer(becky, XRP(100), EUR(100)));
-
515 env.close();
-
516
-
517 // Get account_lines for alice. Limit at 1, so we get a marker.
-
518 auto const linesBeg = env.rpc(
-
519 "json",
-
520 "account_lines",
-
521 R"({"account": ")" + alice.human() +
-
522 R"(", )"
-
523 R"("limit": 2})");
-
524 BEAST_EXPECT(
-
525 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
-
526 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
-
527
-
528 // alice pays 100 EUR to cheri.
-
529 env(pay(alice, cheri, EUR(100)));
-
530 env.close();
-
531
-
532 // Since alice paid all her EUR to cheri, alice should no longer
-
533 // have a trust line to gw1. So the old marker should now be invalid.
-
534 auto const linesEnd = env.rpc(
-
535 "json",
-
536 "account_lines",
-
537 R"({"account": ")" + alice.human() +
-
538 R"(", )"
-
539 R"("marker": ")" +
-
540 linesBeg[jss::result][jss::marker].asString() + R"("})");
-
541 BEAST_EXPECT(
-
542 linesEnd[jss::result][jss::error_message] ==
-
543 RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]);
-
544 }
-
545
-
546 void
-
547 testAccountLinesWalkMarkers()
-
548 {
-
549 testcase("Marker can point to any appropriate ledger entry type");
-
550 using namespace test::jtx;
-
551 using namespace std::chrono_literals;
-
552 Env env(*this);
-
553
-
554 // The goal of this test is observe account_lines RPC calls return an
-
555 // error message when the SLE pointed to by the marker is not owned by
-
556 // the Account being traversed.
-
557 //
-
558 // To start, we'll create an environment with some trust lines, offers
-
559 // and a signers list.
-
560 Account const alice{"alice"};
-
561 Account const becky{"becky"};
-
562 Account const gw1{"gw1"};
-
563 env.fund(XRP(10000), alice, becky, gw1);
-
564 env.close();
-
565
-
566 // A couple of helper lambdas
-
567 auto escrow = [&env](
-
568 Account const& account,
-
569 Account const& to,
-
570 STAmount const& amount) {
-
571 Json::Value jv;
-
572 jv[jss::TransactionType] = jss::EscrowCreate;
-
573 jv[jss::Flags] = tfUniversal;
-
574 jv[jss::Account] = account.human();
-
575 jv[jss::Destination] = to.human();
-
576 jv[jss::Amount] = amount.getJson(JsonOptions::none);
-
577 NetClock::time_point finish = env.now() + 1s;
-
578 jv[sfFinishAfter.jsonName] = finish.time_since_epoch().count();
-
579 return jv;
-
580 };
-
581
-
582 auto payChan = [](Account const& account,
-
583 Account const& to,
-
584 STAmount const& amount,
-
585 NetClock::duration const& settleDelay,
-
586 PublicKey const& pk) {
-
587 Json::Value jv;
-
588 jv[jss::TransactionType] = jss::PaymentChannelCreate;
-
589 jv[jss::Flags] = tfUniversal;
-
590 jv[jss::Account] = account.human();
-
591 jv[jss::Destination] = to.human();
-
592 jv[jss::Amount] = amount.getJson(JsonOptions::none);
-
593 jv["SettleDelay"] = settleDelay.count();
-
594 jv["PublicKey"] = strHex(pk.slice());
-
595 return jv;
-
596 };
-
597
-
598 // Test all available object types. Not all of these objects will be
-
599 // included in the search, nor found by `account_objects`. If that ever
-
600 // changes for any reason, this test will help catch that.
-
601 //
-
602 // SignerList, for alice
-
603 Account const bogie{"bogie"};
-
604 env(signers(alice, 2, {{bogie, 3}}));
-
605 env.close();
-
606
-
607 // SignerList, includes alice
-
608 env(signers(becky, 2, {{alice, 3}}));
-
609 env.close();
-
610
-
611 // Trust lines
-
612 auto const EUR = gw1["EUR"];
-
613 env(trust(alice, EUR(200)));
-
614 env(trust(becky, EUR(200)));
+
170 env(trust(
+
171 alice,
+
172 gw2Currency(0),
+
173 gw2,
+
174 tfSetNoRipple | tfSetFreeze | tfSetDeepFreeze));
+
175 }
+
176 env.close();
+
177 LedgerInfo const ledger58Info = env.closed()->info();
+
178 BEAST_EXPECT(ledger58Info.seq == 58);
+
179
+
180 // A re-usable test for historic ledgers.
+
181 auto testAccountLinesHistory = [this, &env](
+
182 Account const& account,
+
183 LedgerInfo const& info,
+
184 int count) {
+
185 // Get account_lines by ledger index.
+
186 auto const linesSeq = env.rpc(
+
187 "json",
+
188 "account_lines",
+
189 R"({"account": ")" + account.human() +
+
190 R"(", )"
+
191 R"("ledger_index": )" +
+
192 std::to_string(info.seq) + "}");
+
193 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
+
194 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
+
195
+
196 // Get account_lines by ledger hash.
+
197 auto const linesHash = env.rpc(
+
198 "json",
+
199 "account_lines",
+
200 R"({"account": ")" + account.human() +
+
201 R"(", )"
+
202 R"("ledger_hash": ")" +
+
203 to_string(info.hash) + R"("})");
+
204 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
+
205 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
+
206 };
+
207
+
208 // Alice should have no trust lines in ledger 3.
+
209 testAccountLinesHistory(alice, ledger3Info, 0);
+
210
+
211 // Alice should have 26 trust lines in ledger 4.
+
212 testAccountLinesHistory(alice, ledger4Info, 26);
+
213
+
214 // Alice should have 52 trust lines in ledger 58.
+
215 testAccountLinesHistory(alice, ledger58Info, 52);
+
216
+
217 {
+
218 // Surprisingly, it's valid to specify both index and hash, in
+
219 // which case the hash wins.
+
220 auto const lines = env.rpc(
+
221 "json",
+
222 "account_lines",
+
223 R"({"account": ")" + alice.human() +
+
224 R"(", )"
+
225 R"("ledger_hash": ")" +
+
226 to_string(ledger4Info.hash) +
+
227 R"(", )"
+
228 R"("ledger_index": )" +
+
229 std::to_string(ledger58Info.seq) + "}");
+
230 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
+
231 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
+
232 }
+
233 {
+
234 // alice should have 52 trust lines in the current ledger.
+
235 auto const lines = env.rpc(
+
236 "json",
+
237 "account_lines",
+
238 R"({"account": ")" + alice.human() + R"("})");
+
239 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
+
240 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52);
+
241 }
+
242 {
+
243 // alice should have 26 trust lines with gw1.
+
244 auto const lines = env.rpc(
+
245 "json",
+
246 "account_lines",
+
247 R"({"account": ")" + alice.human() +
+
248 R"(", )"
+
249 R"("peer": ")" +
+
250 gw1.human() + R"("})");
+
251 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
+
252 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
+
253 }
+
254 {
+
255 // Use a malformed peer.
+
256 auto const lines = env.rpc(
+
257 "json",
+
258 "account_lines",
+
259 R"({"account": ")" + alice.human() +
+
260 R"(", )"
+
261 R"("peer": )"
+
262 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})");
+
263 BEAST_EXPECT(
+
264 lines[jss::result][jss::error_message] ==
+
265 RPC::make_error(rpcACT_MALFORMED)[jss::error_message]);
+
266 }
+
267 {
+
268 // A negative limit should fail.
+
269 auto const lines = env.rpc(
+
270 "json",
+
271 "account_lines",
+
272 R"({"account": ")" + alice.human() +
+
273 R"(", )"
+
274 R"("limit": -1})");
+
275 BEAST_EXPECT(
+
276 lines[jss::result][jss::error_message] ==
+
277 RPC::expected_field_message(jss::limit, "unsigned integer"));
+
278 }
+
279 {
+
280 // Limit the response to 1 trust line.
+
281 auto const linesA = env.rpc(
+
282 "json",
+
283 "account_lines",
+
284 R"({"account": ")" + alice.human() +
+
285 R"(", )"
+
286 R"("limit": 1})");
+
287 BEAST_EXPECT(linesA[jss::result][jss::lines].isArray());
+
288 BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1);
+
289
+
290 // Pick up from where the marker left off. We should get 51.
+
291 auto marker = linesA[jss::result][jss::marker].asString();
+
292 auto const linesB = env.rpc(
+
293 "json",
+
294 "account_lines",
+
295 R"({"account": ")" + alice.human() +
+
296 R"(", )"
+
297 R"("marker": ")" +
+
298 marker + R"("})");
+
299 BEAST_EXPECT(linesB[jss::result][jss::lines].isArray());
+
300 BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 51);
+
301
+
302 // Go again from where the marker left off, but set a limit of 3.
+
303 auto const linesC = env.rpc(
+
304 "json",
+
305 "account_lines",
+
306 R"({"account": ")" + alice.human() +
+
307 R"(", )"
+
308 R"("limit": 3, )"
+
309 R"("marker": ")" +
+
310 marker + R"("})");
+
311 BEAST_EXPECT(linesC[jss::result][jss::lines].isArray());
+
312 BEAST_EXPECT(linesC[jss::result][jss::lines].size() == 3);
+
313
+
314 // Mess with the marker so it becomes bad and check for the error.
+
315 marker[5] = marker[5] == '7' ? '8' : '7';
+
316 auto const linesD = env.rpc(
+
317 "json",
+
318 "account_lines",
+
319 R"({"account": ")" + alice.human() +
+
320 R"(", )"
+
321 R"("marker": ")" +
+
322 marker + R"("})");
+
323 BEAST_EXPECT(
+
324 linesD[jss::result][jss::error_message] ==
+
325 RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]);
+
326 }
+
327 {
+
328 // A non-string marker should also fail.
+
329 auto const lines = env.rpc(
+
330 "json",
+
331 "account_lines",
+
332 R"({"account": ")" + alice.human() +
+
333 R"(", )"
+
334 R"("marker": true})");
+
335 BEAST_EXPECT(
+
336 lines[jss::result][jss::error_message] ==
+
337 RPC::expected_field_message(jss::marker, "string"));
+
338 }
+
339 {
+
340 // Check that the flags we expect from alice to gw2 are present.
+
341 auto const lines = env.rpc(
+
342 "json",
+
343 "account_lines",
+
344 R"({"account": ")" + alice.human() +
+
345 R"(", )"
+
346 R"("limit": 10, )"
+
347 R"("peer": ")" +
+
348 gw2.human() + R"("})");
+
349 auto const& line = lines[jss::result][jss::lines][0u];
+
350 BEAST_EXPECT(line[jss::freeze].asBool() == true);
+
351 BEAST_EXPECT(line[jss::deep_freeze].asBool() == true);
+
352 BEAST_EXPECT(line[jss::no_ripple].asBool() == true);
+
353 BEAST_EXPECT(line[jss::peer_authorized].asBool() == true);
+
354 }
+
355 {
+
356 // Check that the flags we expect from gw2 to alice are present.
+
357 auto const linesA = env.rpc(
+
358 "json",
+
359 "account_lines",
+
360 R"({"account": ")" + gw2.human() +
+
361 R"(", )"
+
362 R"("limit": 1, )"
+
363 R"("peer": ")" +
+
364 alice.human() + R"("})");
+
365 auto const& lineA = linesA[jss::result][jss::lines][0u];
+
366 BEAST_EXPECT(lineA[jss::freeze_peer].asBool() == true);
+
367 BEAST_EXPECT(lineA[jss::deep_freeze_peer].asBool() == true);
+
368 BEAST_EXPECT(lineA[jss::no_ripple_peer].asBool() == true);
+
369 BEAST_EXPECT(lineA[jss::authorized].asBool() == true);
+
370
+
371 // Continue from the returned marker to make sure that works.
+
372 BEAST_EXPECT(linesA[jss::result].isMember(jss::marker));
+
373 auto const marker = linesA[jss::result][jss::marker].asString();
+
374 auto const linesB = env.rpc(
+
375 "json",
+
376 "account_lines",
+
377 R"({"account": ")" + gw2.human() +
+
378 R"(", )"
+
379 R"("limit": 25, )"
+
380 R"("marker": ")" +
+
381 marker +
+
382 R"(", )"
+
383 R"("peer": ")" +
+
384 alice.human() + R"("})");
+
385 BEAST_EXPECT(linesB[jss::result][jss::lines].isArray());
+
386 BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 25);
+
387 BEAST_EXPECT(!linesB[jss::result].isMember(jss::marker));
+
388 }
+
389 }
+
390
+
391 void
+
392 testAccountLinesMarker()
+
393 {
+
394 testcase("Entry pointed to by marker is not owned by account");
+
395 using namespace test::jtx;
+
396 Env env(*this);
+
397
+
398 // The goal of this test is observe account_lines RPC calls return an
+
399 // error message when the SLE pointed to by the marker is not owned by
+
400 // the Account being traversed.
+
401 //
+
402 // To start, we'll create an environment with some trust lines, offers
+
403 // and a signers list.
+
404 Account const alice{"alice"};
+
405 Account const becky{"becky"};
+
406 Account const gw1{"gw1"};
+
407 env.fund(XRP(10000), alice, becky, gw1);
+
408 env.close();
+
409
+
410 // Give alice a SignerList.
+
411 Account const bogie{"bogie"};
+
412 env(signers(alice, 2, {{bogie, 3}}));
+
413 env.close();
+
414
+
415 auto const EUR = gw1["EUR"];
+
416 env(trust(alice, EUR(200)));
+
417 env(trust(becky, EUR(200)));
+
418 env.close();
+
419
+
420 // Get all account objects for alice and verify that her
+
421 // signerlist is first. This is only a (reliable) coincidence of
+
422 // object naming. So if any of alice's objects are renamed this
+
423 // may fail.
+
424 Json::Value const aliceObjects = env.rpc(
+
425 "json",
+
426 "account_objects",
+
427 R"({"account": ")" + alice.human() +
+
428 R"(", )"
+
429 R"("limit": 10})");
+
430 Json::Value const& aliceSignerList =
+
431 aliceObjects[jss::result][jss::account_objects][0u];
+
432 if (!(aliceSignerList[sfLedgerEntryType.jsonName] == jss::SignerList))
+
433 {
+
434 fail(
+
435 "alice's account objects are misordered. "
+
436 "Please reorder the objects so the SignerList is first.",
+
437 __FILE__,
+
438 __LINE__);
+
439 return;
+
440 }
+
441
+
442 // Get account_lines for alice. Limit at 1, so we get a marker
+
443 // pointing to her SignerList.
+
444 auto const aliceLines1 = env.rpc(
+
445 "json",
+
446 "account_lines",
+
447 R"({"account": ")" + alice.human() + R"(", "limit": 1})");
+
448 BEAST_EXPECT(aliceLines1[jss::result].isMember(jss::marker));
+
449
+
450 // Verify that the marker points at the signer list.
+
451 std::string const aliceMarker =
+
452 aliceLines1[jss::result][jss::marker].asString();
+
453 std::string const markerIndex =
+
454 aliceMarker.substr(0, aliceMarker.find(','));
+
455 BEAST_EXPECT(markerIndex == aliceSignerList[jss::index].asString());
+
456
+
457 // When we fetch Alice's remaining lines we should find one and no more.
+
458 auto const aliceLines2 = env.rpc(
+
459 "json",
+
460 "account_lines",
+
461 R"({"account": ")" + alice.human() + R"(", "marker": ")" +
+
462 aliceMarker + R"("})");
+
463 BEAST_EXPECT(aliceLines2[jss::result][jss::lines].size() == 1);
+
464 BEAST_EXPECT(!aliceLines2[jss::result].isMember(jss::marker));
+
465
+
466 // Get account lines for beckys account, using alices SignerList as a
+
467 // marker. This should cause an error.
+
468 auto const beckyLines = env.rpc(
+
469 "json",
+
470 "account_lines",
+
471 R"({"account": ")" + becky.human() + R"(", "marker": ")" +
+
472 aliceMarker + R"("})");
+
473 BEAST_EXPECT(beckyLines[jss::result].isMember(jss::error_message));
+
474 }
+
475
+
476 void
+
477 testAccountLineDelete()
+
478 {
+
479 testcase("Entry pointed to by marker is removed");
+
480 using namespace test::jtx;
+
481 Env env(*this);
+
482
+
483 // The goal here is to observe account_lines marker behavior if the
+
484 // entry pointed at by a returned marker is removed from the ledger.
+
485 //
+
486 // It isn't easy to explicitly delete a trust line, so we do so in a
+
487 // round-about fashion. It takes 4 actors:
+
488 // o Gateway gw1 issues USD
+
489 // o alice offers to buy 100 USD for 100 XRP.
+
490 // o becky offers to sell 100 USD for 100 XRP.
+
491 // There will now be an inferred trustline between alice and gw1.
+
492 // o alice pays her 100 USD to cheri.
+
493 // alice should now have no USD and no trustline to gw1.
+
494 Account const alice{"alice"};
+
495 Account const becky{"becky"};
+
496 Account const cheri{"cheri"};
+
497 Account const gw1{"gw1"};
+
498 Account const gw2{"gw2"};
+
499 env.fund(XRP(10000), alice, becky, cheri, gw1, gw2);
+
500 env.close();
+
501
+
502 auto const USD = gw1["USD"];
+
503 auto const AUD = gw1["AUD"];
+
504 auto const EUR = gw2["EUR"];
+
505 env(trust(alice, USD(200)));
+
506 env(trust(alice, AUD(200)));
+
507 env(trust(becky, EUR(200)));
+
508 env(trust(cheri, EUR(200)));
+
509 env.close();
+
510
+
511 // becky gets 100 USD from gw1.
+
512 env(pay(gw2, becky, EUR(100)));
+
513 env.close();
+
514
+
515 // alice offers to buy 100 EUR for 100 XRP.
+
516 env(offer(alice, EUR(100), XRP(100)));
+
517 env.close();
+
518
+
519 // becky offers to buy 100 XRP for 100 EUR.
+
520 env(offer(becky, XRP(100), EUR(100)));
+
521 env.close();
+
522
+
523 // Get account_lines for alice. Limit at 1, so we get a marker.
+
524 auto const linesBeg = env.rpc(
+
525 "json",
+
526 "account_lines",
+
527 R"({"account": ")" + alice.human() +
+
528 R"(", )"
+
529 R"("limit": 2})");
+
530 BEAST_EXPECT(
+
531 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
+
532 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
+
533
+
534 // alice pays 100 EUR to cheri.
+
535 env(pay(alice, cheri, EUR(100)));
+
536 env.close();
+
537
+
538 // Since alice paid all her EUR to cheri, alice should no longer
+
539 // have a trust line to gw1. So the old marker should now be invalid.
+
540 auto const linesEnd = env.rpc(
+
541 "json",
+
542 "account_lines",
+
543 R"({"account": ")" + alice.human() +
+
544 R"(", )"
+
545 R"("marker": ")" +
+
546 linesBeg[jss::result][jss::marker].asString() + R"("})");
+
547 BEAST_EXPECT(
+
548 linesEnd[jss::result][jss::error_message] ==
+
549 RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]);
+
550 }
+
551
+
552 void
+
553 testAccountLinesWalkMarkers()
+
554 {
+
555 testcase("Marker can point to any appropriate ledger entry type");
+
556 using namespace test::jtx;
+
557 using namespace std::chrono_literals;
+
558 Env env(*this);
+
559
+
560 // The goal of this test is observe account_lines RPC calls return an
+
561 // error message when the SLE pointed to by the marker is not owned by
+
562 // the Account being traversed.
+
563 //
+
564 // To start, we'll create an environment with some trust lines, offers
+
565 // and a signers list.
+
566 Account const alice{"alice"};
+
567 Account const becky{"becky"};
+
568 Account const gw1{"gw1"};
+
569 env.fund(XRP(10000), alice, becky, gw1);
+
570 env.close();
+
571
+
572 // A couple of helper lambdas
+
573 auto escrow = [&env](
+
574 Account const& account,
+
575 Account const& to,
+
576 STAmount const& amount) {
+
577 Json::Value jv;
+
578 jv[jss::TransactionType] = jss::EscrowCreate;
+
579 jv[jss::Flags] = tfUniversal;
+
580 jv[jss::Account] = account.human();
+
581 jv[jss::Destination] = to.human();
+
582 jv[jss::Amount] = amount.getJson(JsonOptions::none);
+
583 NetClock::time_point finish = env.now() + 1s;
+
584 jv[sfFinishAfter.jsonName] = finish.time_since_epoch().count();
+
585 return jv;
+
586 };
+
587
+
588 auto payChan = [](Account const& account,
+
589 Account const& to,
+
590 STAmount const& amount,
+
591 NetClock::duration const& settleDelay,
+
592 PublicKey const& pk) {
+
593 Json::Value jv;
+
594 jv[jss::TransactionType] = jss::PaymentChannelCreate;
+
595 jv[jss::Flags] = tfUniversal;
+
596 jv[jss::Account] = account.human();
+
597 jv[jss::Destination] = to.human();
+
598 jv[jss::Amount] = amount.getJson(JsonOptions::none);
+
599 jv["SettleDelay"] = settleDelay.count();
+
600 jv["PublicKey"] = strHex(pk.slice());
+
601 return jv;
+
602 };
+
603
+
604 // Test all available object types. Not all of these objects will be
+
605 // included in the search, nor found by `account_objects`. If that ever
+
606 // changes for any reason, this test will help catch that.
+
607 //
+
608 // SignerList, for alice
+
609 Account const bogie{"bogie"};
+
610 env(signers(alice, 2, {{bogie, 3}}));
+
611 env.close();
+
612
+
613 // SignerList, includes alice
+
614 env(signers(becky, 2, {{alice, 3}}));
615 env.close();
616
-
617 // Escrow, in each direction
-
618 env(escrow(alice, becky, XRP(1000)));
-
619 env(escrow(becky, alice, XRP(1000)));
-
620
-
621 // Pay channels, in each direction
-
622 env(payChan(alice, becky, XRP(1000), 100s, alice.pk()));
-
623 env(payChan(becky, alice, XRP(1000), 100s, becky.pk()));
-
624
-
625 // Mint NFTs, for each account
-
626 uint256 const aliceNFtokenID =
-
627 token::getNextID(env, alice, 0, tfTransferable);
-
628 env(token::mint(alice, 0), txflags(tfTransferable));
-
629
-
630 uint256 const beckyNFtokenID =
-
631 token::getNextID(env, becky, 0, tfTransferable);
-
632 env(token::mint(becky, 0), txflags(tfTransferable));
-
633
-
634 // NFT Offers, for each other's NFTs
-
635 env(token::createOffer(alice, beckyNFtokenID, drops(1)),
-
636 token::owner(becky));
-
637 env(token::createOffer(becky, aliceNFtokenID, drops(1)),
-
638 token::owner(alice));
+
617 // Trust lines
+
618 auto const EUR = gw1["EUR"];
+
619 env(trust(alice, EUR(200)));
+
620 env(trust(becky, EUR(200)));
+
621 env.close();
+
622
+
623 // Escrow, in each direction
+
624 env(escrow(alice, becky, XRP(1000)));
+
625 env(escrow(becky, alice, XRP(1000)));
+
626
+
627 // Pay channels, in each direction
+
628 env(payChan(alice, becky, XRP(1000), 100s, alice.pk()));
+
629 env(payChan(becky, alice, XRP(1000), 100s, becky.pk()));
+
630
+
631 // Mint NFTs, for each account
+
632 uint256 const aliceNFtokenID =
+
633 token::getNextID(env, alice, 0, tfTransferable);
+
634 env(token::mint(alice, 0), txflags(tfTransferable));
+
635
+
636 uint256 const beckyNFtokenID =
+
637 token::getNextID(env, becky, 0, tfTransferable);
+
638 env(token::mint(becky, 0), txflags(tfTransferable));
639
-
640 env(token::createOffer(becky, beckyNFtokenID, drops(1)),
-
641 txflags(tfSellNFToken),
-
642 token::destination(alice));
-
643 env(token::createOffer(alice, aliceNFtokenID, drops(1)),
-
644 txflags(tfSellNFToken),
-
645 token::destination(becky));
-
646
-
647 env(token::createOffer(gw1, beckyNFtokenID, drops(1)),
-
648 token::owner(becky),
-
649 token::destination(alice));
-
650 env(token::createOffer(gw1, aliceNFtokenID, drops(1)),
-
651 token::owner(alice),
-
652 token::destination(becky));
-
653
-
654 env(token::createOffer(becky, beckyNFtokenID, drops(1)),
-
655 txflags(tfSellNFToken));
-
656 env(token::createOffer(alice, aliceNFtokenID, drops(1)),
-
657 txflags(tfSellNFToken));
-
658
-
659 // Checks, in each direction
-
660 env(check::create(alice, becky, XRP(50)));
-
661 env(check::create(becky, alice, XRP(50)));
-
662
-
663 // Deposit preauth, in each direction
-
664 env(deposit::auth(alice, becky));
-
665 env(deposit::auth(becky, alice));
-
666
-
667 // Offers, one where alice is the owner, and one where alice is the
-
668 // issuer
-
669 auto const USDalice = alice["USD"];
-
670 env(offer(alice, EUR(10), XRP(100)));
-
671 env(offer(becky, USDalice(10), XRP(100)));
+
640 // NFT Offers, for each other's NFTs
+
641 env(token::createOffer(alice, beckyNFtokenID, drops(1)),
+
642 token::owner(becky));
+
643 env(token::createOffer(becky, aliceNFtokenID, drops(1)),
+
644 token::owner(alice));
+
645
+
646 env(token::createOffer(becky, beckyNFtokenID, drops(1)),
+
647 txflags(tfSellNFToken),
+
648 token::destination(alice));
+
649 env(token::createOffer(alice, aliceNFtokenID, drops(1)),
+
650 txflags(tfSellNFToken),
+
651 token::destination(becky));
+
652
+
653 env(token::createOffer(gw1, beckyNFtokenID, drops(1)),
+
654 token::owner(becky),
+
655 token::destination(alice));
+
656 env(token::createOffer(gw1, aliceNFtokenID, drops(1)),
+
657 token::owner(alice),
+
658 token::destination(becky));
+
659
+
660 env(token::createOffer(becky, beckyNFtokenID, drops(1)),
+
661 txflags(tfSellNFToken));
+
662 env(token::createOffer(alice, aliceNFtokenID, drops(1)),
+
663 txflags(tfSellNFToken));
+
664
+
665 // Checks, in each direction
+
666 env(check::create(alice, becky, XRP(50)));
+
667 env(check::create(becky, alice, XRP(50)));
+
668
+
669 // Deposit preauth, in each direction
+
670 env(deposit::auth(alice, becky));
+
671 env(deposit::auth(becky, alice));
672
-
673 // Tickets
-
674 env(ticket::create(alice, 2));
-
675
-
676 // Add another trustline for good measure
-
677 auto const BTCbecky = becky["BTC"];
-
678 env(trust(alice, BTCbecky(200)));
-
679
-
680 env.close();
+
673 // Offers, one where alice is the owner, and one where alice is the
+
674 // issuer
+
675 auto const USDalice = alice["USD"];
+
676 env(offer(alice, EUR(10), XRP(100)));
+
677 env(offer(becky, USDalice(10), XRP(100)));
+
678
+
679 // Tickets
+
680 env(ticket::create(alice, 2));
681
-
682 {
-
683 // Now make repeated calls to `account_lines` with a limit of 1.
-
684 // That should iterate all of alice's relevant objects, even though
-
685 // the list will be empty for most calls.
-
686 auto getNextLine = [](Env& env,
-
687 Account const& alice,
-
688 std::optional<std::string> const marker) {
-
689 Json::Value params(Json::objectValue);
-
690 params[jss::account] = alice.human();
-
691 params[jss::limit] = 1;
-
692 if (marker)
-
693 params[jss::marker] = *marker;
-
694
-
695 return env.rpc("json", "account_lines", to_string(params));
-
696 };
-
697
-
698 auto aliceLines = getNextLine(env, alice, std::nullopt);
-
699 constexpr std::size_t expectedIterations = 16;
-
700 constexpr std::size_t expectedLines = 2;
-
701 constexpr std::size_t expectedNFTs = 1;
-
702 std::size_t foundLines = 0;
+
682 // Add another trustline for good measure
+
683 auto const BTCbecky = becky["BTC"];
+
684 env(trust(alice, BTCbecky(200)));
+
685
+
686 env.close();
+
687
+
688 {
+
689 // Now make repeated calls to `account_lines` with a limit of 1.
+
690 // That should iterate all of alice's relevant objects, even though
+
691 // the list will be empty for most calls.
+
692 auto getNextLine = [](Env& env,
+
693 Account const& alice,
+
694 std::optional<std::string> const marker) {
+
695 Json::Value params(Json::objectValue);
+
696 params[jss::account] = alice.human();
+
697 params[jss::limit] = 1;
+
698 if (marker)
+
699 params[jss::marker] = *marker;
+
700
+
701 return env.rpc("json", "account_lines", to_string(params));
+
702 };
703
-
704 auto hasMarker = [](auto const& aliceLines) {
-
705 return aliceLines[jss::result].isMember(jss::marker);
-
706 };
-
707 auto marker = [](auto const& aliceLines) {
-
708 return aliceLines[jss::result][jss::marker].asString();
-
709 };
-
710 auto checkLines = [](auto const& aliceLines) {
-
711 return aliceLines.isMember(jss::result) &&
-
712 !aliceLines[jss::result].isMember(jss::error_message) &&
-
713 aliceLines[jss::result].isMember(jss::lines) &&
-
714 aliceLines[jss::result][jss::lines].isArray() &&
-
715 aliceLines[jss::result][jss::lines].size() <= 1;
-
716 };
-
717
-
718 BEAST_EXPECT(hasMarker(aliceLines));
-
719 BEAST_EXPECT(checkLines(aliceLines));
-
720 BEAST_EXPECT(aliceLines[jss::result][jss::lines].size() == 0);
-
721
-
722 int iterations = 1;
+
704 auto aliceLines = getNextLine(env, alice, std::nullopt);
+
705 constexpr std::size_t expectedIterations = 16;
+
706 constexpr std::size_t expectedLines = 2;
+
707 constexpr std::size_t expectedNFTs = 1;
+
708 std::size_t foundLines = 0;
+
709
+
710 auto hasMarker = [](auto const& aliceLines) {
+
711 return aliceLines[jss::result].isMember(jss::marker);
+
712 };
+
713 auto marker = [](auto const& aliceLines) {
+
714 return aliceLines[jss::result][jss::marker].asString();
+
715 };
+
716 auto checkLines = [](auto const& aliceLines) {
+
717 return aliceLines.isMember(jss::result) &&
+
718 !aliceLines[jss::result].isMember(jss::error_message) &&
+
719 aliceLines[jss::result].isMember(jss::lines) &&
+
720 aliceLines[jss::result][jss::lines].isArray() &&
+
721 aliceLines[jss::result][jss::lines].size() <= 1;
+
722 };
723
-
724 while (hasMarker(aliceLines))
-
725 {
-
726 // Iterate through the markers
-
727 aliceLines = getNextLine(env, alice, marker(aliceLines));
-
728 BEAST_EXPECT(checkLines(aliceLines));
-
729 foundLines += aliceLines[jss::result][jss::lines].size();
-
730 ++iterations;
-
731 }
-
732 BEAST_EXPECT(expectedLines == foundLines);
-
733
-
734 Json::Value const aliceObjects = env.rpc(
-
735 "json",
-
736 "account_objects",
-
737 R"({"account": ")" + alice.human() +
-
738 R"(", )"
-
739 R"("limit": 200})");
-
740 BEAST_EXPECT(aliceObjects.isMember(jss::result));
-
741 BEAST_EXPECT(
-
742 !aliceObjects[jss::result].isMember(jss::error_message));
-
743 BEAST_EXPECT(
-
744 aliceObjects[jss::result].isMember(jss::account_objects));
-
745 BEAST_EXPECT(
-
746 aliceObjects[jss::result][jss::account_objects].isArray());
-
747 // account_objects does not currently return NFTPages. If
-
748 // that ever changes, without also changing account_lines,
-
749 // this test will need to be updated.
-
750 BEAST_EXPECT(
-
751 aliceObjects[jss::result][jss::account_objects].size() ==
-
752 iterations + expectedNFTs);
-
753 // If ledger object association ever changes, for whatever
-
754 // reason, this test will need to be updated.
-
755 BEAST_EXPECTS(
-
756 iterations == expectedIterations, std::to_string(iterations));
-
757
-
758 // Get becky's objects just to confirm that they're symmetrical
-
759 Json::Value const beckyObjects = env.rpc(
-
760 "json",
-
761 "account_objects",
-
762 R"({"account": ")" + becky.human() +
-
763 R"(", )"
-
764 R"("limit": 200})");
-
765 BEAST_EXPECT(beckyObjects.isMember(jss::result));
-
766 BEAST_EXPECT(
-
767 !beckyObjects[jss::result].isMember(jss::error_message));
-
768 BEAST_EXPECT(
-
769 beckyObjects[jss::result].isMember(jss::account_objects));
-
770 BEAST_EXPECT(
-
771 beckyObjects[jss::result][jss::account_objects].isArray());
-
772 // becky should have the same number of objects as alice, except the
-
773 // 2 tickets that only alice created.
-
774 BEAST_EXPECT(
-
775 beckyObjects[jss::result][jss::account_objects].size() ==
-
776 aliceObjects[jss::result][jss::account_objects].size() - 2);
-
777 }
-
778 }
-
779
-
780 // test API V2
-
781 void
-
782 testAccountLines2()
-
783 {
-
784 testcase("V2: account_lines");
+
724 BEAST_EXPECT(hasMarker(aliceLines));
+
725 BEAST_EXPECT(checkLines(aliceLines));
+
726 BEAST_EXPECT(aliceLines[jss::result][jss::lines].size() == 0);
+
727
+
728 int iterations = 1;
+
729
+
730 while (hasMarker(aliceLines))
+
731 {
+
732 // Iterate through the markers
+
733 aliceLines = getNextLine(env, alice, marker(aliceLines));
+
734 BEAST_EXPECT(checkLines(aliceLines));
+
735 foundLines += aliceLines[jss::result][jss::lines].size();
+
736 ++iterations;
+
737 }
+
738 BEAST_EXPECT(expectedLines == foundLines);
+
739
+
740 Json::Value const aliceObjects = env.rpc(
+
741 "json",
+
742 "account_objects",
+
743 R"({"account": ")" + alice.human() +
+
744 R"(", )"
+
745 R"("limit": 200})");
+
746 BEAST_EXPECT(aliceObjects.isMember(jss::result));
+
747 BEAST_EXPECT(
+
748 !aliceObjects[jss::result].isMember(jss::error_message));
+
749 BEAST_EXPECT(
+
750 aliceObjects[jss::result].isMember(jss::account_objects));
+
751 BEAST_EXPECT(
+
752 aliceObjects[jss::result][jss::account_objects].isArray());
+
753 // account_objects does not currently return NFTPages. If
+
754 // that ever changes, without also changing account_lines,
+
755 // this test will need to be updated.
+
756 BEAST_EXPECT(
+
757 aliceObjects[jss::result][jss::account_objects].size() ==
+
758 iterations + expectedNFTs);
+
759 // If ledger object association ever changes, for whatever
+
760 // reason, this test will need to be updated.
+
761 BEAST_EXPECTS(
+
762 iterations == expectedIterations, std::to_string(iterations));
+
763
+
764 // Get becky's objects just to confirm that they're symmetrical
+
765 Json::Value const beckyObjects = env.rpc(
+
766 "json",
+
767 "account_objects",
+
768 R"({"account": ")" + becky.human() +
+
769 R"(", )"
+
770 R"("limit": 200})");
+
771 BEAST_EXPECT(beckyObjects.isMember(jss::result));
+
772 BEAST_EXPECT(
+
773 !beckyObjects[jss::result].isMember(jss::error_message));
+
774 BEAST_EXPECT(
+
775 beckyObjects[jss::result].isMember(jss::account_objects));
+
776 BEAST_EXPECT(
+
777 beckyObjects[jss::result][jss::account_objects].isArray());
+
778 // becky should have the same number of objects as alice, except the
+
779 // 2 tickets that only alice created.
+
780 BEAST_EXPECT(
+
781 beckyObjects[jss::result][jss::account_objects].size() ==
+
782 aliceObjects[jss::result][jss::account_objects].size() - 2);
+
783 }
+
784 }
785
-
786 using namespace test::jtx;
-
787 Env env(*this);
-
788 {
-
789 // account_lines with mal-formed json2 (missing id field).
-
790 auto const lines = env.rpc(
-
791 "json2",
-
792 "{ "
-
793 R"("method" : "account_lines",)"
-
794 R"("jsonrpc" : "2.0",)"
-
795 R"("ripplerpc" : "2.0")"
-
796 " }");
-
797 BEAST_EXPECT(
-
798 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
799 BEAST_EXPECT(
-
800 lines.isMember(jss::ripplerpc) &&
-
801 lines[jss::ripplerpc] == "2.0");
-
802 }
-
803 {
-
804 // account_lines with no account.
-
805 auto const lines = env.rpc(
-
806 "json2",
-
807 "{ "
-
808 R"("method" : "account_lines",)"
-
809 R"("jsonrpc" : "2.0",)"
-
810 R"("ripplerpc" : "2.0",)"
-
811 R"("id" : 5)"
-
812 " }");
-
813 BEAST_EXPECT(
-
814 lines[jss::error][jss::message] ==
-
815 RPC::missing_field_error(jss::account)[jss::error_message]);
-
816 BEAST_EXPECT(
-
817 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
818 BEAST_EXPECT(
-
819 lines.isMember(jss::ripplerpc) &&
-
820 lines[jss::ripplerpc] == "2.0");
-
821 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
822 }
-
823 {
-
824 // account_lines with a malformed account.
-
825 auto const lines = env.rpc(
-
826 "json2",
-
827 "{ "
-
828 R"("method" : "account_lines",)"
-
829 R"("jsonrpc" : "2.0",)"
-
830 R"("ripplerpc" : "2.0",)"
-
831 R"("id" : 5,)"
-
832 R"("params": )"
-
833 R"({"account": )"
-
834 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
-
835 BEAST_EXPECT(
-
836 lines[jss::error][jss::message] ==
-
837 RPC::make_error(rpcACT_MALFORMED)[jss::error_message]);
-
838 BEAST_EXPECT(
-
839 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
840 BEAST_EXPECT(
-
841 lines.isMember(jss::ripplerpc) &&
-
842 lines[jss::ripplerpc] == "2.0");
-
843 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
844 }
-
845 Account const alice{"alice"};
-
846 {
-
847 // account_lines on an unfunded account.
-
848 auto const lines = env.rpc(
-
849 "json2",
-
850 "{ "
-
851 R"("method" : "account_lines",)"
-
852 R"("jsonrpc" : "2.0",)"
-
853 R"("ripplerpc" : "2.0",)"
-
854 R"("id" : 5,)"
-
855 R"("params": )"
-
856 R"({"account": ")" +
-
857 alice.human() + R"("}})");
-
858 BEAST_EXPECT(
-
859 lines[jss::error][jss::message] ==
-
860 RPC::make_error(rpcACT_NOT_FOUND)[jss::error_message]);
-
861 BEAST_EXPECT(
-
862 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
863 BEAST_EXPECT(
-
864 lines.isMember(jss::ripplerpc) &&
-
865 lines[jss::ripplerpc] == "2.0");
-
866 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
867 }
-
868 env.fund(XRP(10000), alice);
-
869 env.close();
-
870 LedgerInfo const ledger3Info = env.closed()->info();
-
871 BEAST_EXPECT(ledger3Info.seq == 3);
-
872
-
873 {
-
874 // alice is funded but has no lines. An empty array is returned.
-
875 auto const lines = env.rpc(
-
876 "json2",
-
877 "{ "
-
878 R"("method" : "account_lines",)"
-
879 R"("jsonrpc" : "2.0",)"
-
880 R"("ripplerpc" : "2.0",)"
-
881 R"("id" : 5,)"
-
882 R"("params": )"
-
883 R"({"account": ")" +
-
884 alice.human() + R"("}})");
-
885 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
-
886 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 0);
-
887 BEAST_EXPECT(
-
888 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
889 BEAST_EXPECT(
-
890 lines.isMember(jss::ripplerpc) &&
-
891 lines[jss::ripplerpc] == "2.0");
-
892 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
893 }
-
894 {
-
895 // Specify a ledger that doesn't exist.
-
896 auto const lines = env.rpc(
-
897 "json2",
-
898 "{ "
-
899 R"("method" : "account_lines",)"
-
900 R"("jsonrpc" : "2.0",)"
-
901 R"("ripplerpc" : "2.0",)"
-
902 R"("id" : 5,)"
-
903 R"("params": )"
-
904 R"({"account": ")" +
-
905 alice.human() +
-
906 R"(", )"
-
907 R"("ledger_index": "nonsense"}})");
-
908 BEAST_EXPECT(
-
909 lines[jss::error][jss::message] == "ledgerIndexMalformed");
-
910 BEAST_EXPECT(
-
911 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
912 BEAST_EXPECT(
-
913 lines.isMember(jss::ripplerpc) &&
-
914 lines[jss::ripplerpc] == "2.0");
-
915 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
916 }
-
917 {
-
918 // Specify a different ledger that doesn't exist.
-
919 auto const lines = env.rpc(
-
920 "json2",
-
921 "{ "
-
922 R"("method" : "account_lines",)"
-
923 R"("jsonrpc" : "2.0",)"
-
924 R"("ripplerpc" : "2.0",)"
-
925 R"("id" : 5,)"
-
926 R"("params": )"
-
927 R"({"account": ")" +
-
928 alice.human() +
-
929 R"(", )"
-
930 R"("ledger_index": 50000}})");
-
931 BEAST_EXPECT(lines[jss::error][jss::message] == "ledgerNotFound");
-
932 BEAST_EXPECT(
-
933 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
934 BEAST_EXPECT(
-
935 lines.isMember(jss::ripplerpc) &&
-
936 lines[jss::ripplerpc] == "2.0");
-
937 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
938 }
-
939 // Create trust lines to share with alice.
-
940 Account const gw1{"gw1"};
-
941 env.fund(XRP(10000), gw1);
-
942 std::vector<IOU> gw1Currencies;
-
943
-
944 for (char c = 0; c <= ('Z' - 'A'); ++c)
-
945 {
-
946 // gw1 currencies have names "YAA" -> "YAZ".
-
947 gw1Currencies.push_back(
-
948 gw1[std::string("YA") + static_cast<char>('A' + c)]);
-
949 IOU const& gw1Currency = gw1Currencies.back();
-
950
-
951 // Establish trust lines.
-
952 env(trust(alice, gw1Currency(100 + c)));
-
953 env(pay(gw1, alice, gw1Currency(50 + c)));
-
954 }
-
955 env.close();
-
956 LedgerInfo const ledger4Info = env.closed()->info();
-
957 BEAST_EXPECT(ledger4Info.seq == 4);
-
958
-
959 // Add another set of trust lines in another ledger so we can see
-
960 // differences in historic ledgers.
-
961 Account const gw2{"gw2"};
-
962 env.fund(XRP(10000), gw2);
-
963
-
964 // gw2 requires authorization.
-
965 env(fset(gw2, asfRequireAuth));
-
966 env.close();
-
967 std::vector<IOU> gw2Currencies;
-
968
-
969 for (char c = 0; c <= ('Z' - 'A'); ++c)
-
970 {
-
971 // gw2 currencies have names "ZAA" -> "ZAZ".
-
972 gw2Currencies.push_back(
-
973 gw2[std::string("ZA") + static_cast<char>('A' + c)]);
-
974 IOU const& gw2Currency = gw2Currencies.back();
-
975
-
976 // Establish trust lines.
-
977 env(trust(alice, gw2Currency(200 + c)));
-
978 env(trust(gw2, gw2Currency(0), alice, tfSetfAuth));
-
979 env.close();
-
980 env(pay(gw2, alice, gw2Currency(100 + c)));
-
981 env.close();
-
982
-
983 // Set flags on gw2 trust lines so we can look for them.
-
984 env(trust(alice, gw2Currency(0), gw2, tfSetNoRipple | tfSetFreeze));
-
985 }
-
986 env.close();
-
987 LedgerInfo const ledger58Info = env.closed()->info();
-
988 BEAST_EXPECT(ledger58Info.seq == 58);
-
989
-
990 // A re-usable test for historic ledgers.
-
991 auto testAccountLinesHistory = [this, &env](
-
992 Account const& account,
-
993 LedgerInfo const& info,
-
994 int count) {
-
995 // Get account_lines by ledger index.
-
996 auto const linesSeq = env.rpc(
-
997 "json2",
-
998 "{ "
-
999 R"("method" : "account_lines",)"
-
1000 R"("jsonrpc" : "2.0",)"
-
1001 R"("ripplerpc" : "2.0",)"
-
1002 R"("id" : 5,)"
-
1003 R"("params": )"
-
1004 R"({"account": ")" +
-
1005 account.human() +
-
1006 R"(", )"
-
1007 R"("ledger_index": )" +
-
1008 std::to_string(info.seq) + "}}");
-
1009 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
-
1010 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
-
1011 BEAST_EXPECT(
-
1012 linesSeq.isMember(jss::jsonrpc) &&
-
1013 linesSeq[jss::jsonrpc] == "2.0");
-
1014 BEAST_EXPECT(
-
1015 linesSeq.isMember(jss::ripplerpc) &&
-
1016 linesSeq[jss::ripplerpc] == "2.0");
-
1017 BEAST_EXPECT(linesSeq.isMember(jss::id) && linesSeq[jss::id] == 5);
-
1018
-
1019 // Get account_lines by ledger hash.
-
1020 auto const linesHash = env.rpc(
-
1021 "json2",
-
1022 "{ "
-
1023 R"("method" : "account_lines",)"
-
1024 R"("jsonrpc" : "2.0",)"
-
1025 R"("ripplerpc" : "2.0",)"
-
1026 R"("id" : 5,)"
-
1027 R"("params": )"
-
1028 R"({"account": ")" +
-
1029 account.human() +
-
1030 R"(", )"
-
1031 R"("ledger_hash": ")" +
-
1032 to_string(info.hash) + R"("}})");
-
1033 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
-
1034 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
-
1035 BEAST_EXPECT(
-
1036 linesHash.isMember(jss::jsonrpc) &&
-
1037 linesHash[jss::jsonrpc] == "2.0");
-
1038 BEAST_EXPECT(
-
1039 linesHash.isMember(jss::ripplerpc) &&
-
1040 linesHash[jss::ripplerpc] == "2.0");
-
1041 BEAST_EXPECT(
-
1042 linesHash.isMember(jss::id) && linesHash[jss::id] == 5);
-
1043 };
-
1044
-
1045 // Alice should have no trust lines in ledger 3.
-
1046 testAccountLinesHistory(alice, ledger3Info, 0);
-
1047
-
1048 // Alice should have 26 trust lines in ledger 4.
-
1049 testAccountLinesHistory(alice, ledger4Info, 26);
-
1050
-
1051 // Alice should have 52 trust lines in ledger 58.
-
1052 testAccountLinesHistory(alice, ledger58Info, 52);
-
1053
-
1054 {
-
1055 // Surprisingly, it's valid to specify both index and hash, in
-
1056 // which case the hash wins.
-
1057 auto const lines = env.rpc(
-
1058 "json2",
-
1059 "{ "
-
1060 R"("method" : "account_lines",)"
-
1061 R"("jsonrpc" : "2.0",)"
-
1062 R"("ripplerpc" : "2.0",)"
-
1063 R"("id" : 5,)"
-
1064 R"("params": )"
-
1065 R"({"account": ")" +
-
1066 alice.human() +
-
1067 R"(", )"
-
1068 R"("ledger_hash": ")" +
-
1069 to_string(ledger4Info.hash) +
-
1070 R"(", )"
-
1071 R"("ledger_index": )" +
-
1072 std::to_string(ledger58Info.seq) + "}}");
-
1073 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
-
1074 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
-
1075 BEAST_EXPECT(
-
1076 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
1077 BEAST_EXPECT(
-
1078 lines.isMember(jss::ripplerpc) &&
-
1079 lines[jss::ripplerpc] == "2.0");
-
1080 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
1081 }
-
1082 {
-
1083 // alice should have 52 trust lines in the current ledger.
-
1084 auto const lines = env.rpc(
-
1085 "json2",
-
1086 "{ "
-
1087 R"("method" : "account_lines",)"
-
1088 R"("jsonrpc" : "2.0",)"
-
1089 R"("ripplerpc" : "2.0",)"
-
1090 R"("id" : 5,)"
-
1091 R"("params": )"
-
1092 R"({"account": ")" +
-
1093 alice.human() + R"("}})");
-
1094 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
-
1095 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52);
-
1096 BEAST_EXPECT(
-
1097 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
1098 BEAST_EXPECT(
-
1099 lines.isMember(jss::ripplerpc) &&
-
1100 lines[jss::ripplerpc] == "2.0");
-
1101 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
1102 }
-
1103 {
-
1104 // alice should have 26 trust lines with gw1.
-
1105 auto const lines = env.rpc(
-
1106 "json2",
-
1107 "{ "
-
1108 R"("method" : "account_lines",)"
-
1109 R"("jsonrpc" : "2.0",)"
-
1110 R"("ripplerpc" : "2.0",)"
-
1111 R"("id" : 5,)"
-
1112 R"("params": )"
-
1113 R"({"account": ")" +
-
1114 alice.human() +
-
1115 R"(", )"
-
1116 R"("peer": ")" +
-
1117 gw1.human() + R"("}})");
-
1118 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
-
1119 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
-
1120 BEAST_EXPECT(
-
1121 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
1122 BEAST_EXPECT(
-
1123 lines.isMember(jss::ripplerpc) &&
-
1124 lines[jss::ripplerpc] == "2.0");
-
1125 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
1126 }
-
1127 {
-
1128 // Use a malformed peer.
-
1129 auto const lines = env.rpc(
-
1130 "json2",
-
1131 "{ "
-
1132 R"("method" : "account_lines",)"
-
1133 R"("jsonrpc" : "2.0",)"
-
1134 R"("ripplerpc" : "2.0",)"
-
1135 R"("id" : 5,)"
-
1136 R"("params": )"
-
1137 R"({"account": ")" +
-
1138 alice.human() +
-
1139 R"(", )"
-
1140 R"("peer": )"
-
1141 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
-
1142 BEAST_EXPECT(
-
1143 lines[jss::error][jss::message] ==
-
1144 RPC::make_error(rpcACT_MALFORMED)[jss::error_message]);
-
1145 BEAST_EXPECT(
-
1146 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
1147 BEAST_EXPECT(
-
1148 lines.isMember(jss::ripplerpc) &&
-
1149 lines[jss::ripplerpc] == "2.0");
-
1150 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
1151 }
-
1152 {
-
1153 // A negative limit should fail.
-
1154 auto const lines = env.rpc(
-
1155 "json2",
-
1156 "{ "
-
1157 R"("method" : "account_lines",)"
-
1158 R"("jsonrpc" : "2.0",)"
-
1159 R"("ripplerpc" : "2.0",)"
-
1160 R"("id" : 5,)"
-
1161 R"("params": )"
-
1162 R"({"account": ")" +
-
1163 alice.human() +
-
1164 R"(", )"
-
1165 R"("limit": -1}})");
-
1166 BEAST_EXPECT(
-
1167 lines[jss::error][jss::message] ==
-
1168 RPC::expected_field_message(jss::limit, "unsigned integer"));
-
1169 BEAST_EXPECT(
-
1170 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
1171 BEAST_EXPECT(
-
1172 lines.isMember(jss::ripplerpc) &&
-
1173 lines[jss::ripplerpc] == "2.0");
-
1174 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
1175 }
-
1176 {
-
1177 // Limit the response to 1 trust line.
-
1178 auto const linesA = env.rpc(
-
1179 "json2",
-
1180 "{ "
-
1181 R"("method" : "account_lines",)"
-
1182 R"("jsonrpc" : "2.0",)"
-
1183 R"("ripplerpc" : "2.0",)"
-
1184 R"("id" : 5,)"
-
1185 R"("params": )"
-
1186 R"({"account": ")" +
-
1187 alice.human() +
-
1188 R"(", )"
-
1189 R"("limit": 1}})");
-
1190 BEAST_EXPECT(linesA[jss::result][jss::lines].isArray());
-
1191 BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1);
-
1192 BEAST_EXPECT(
-
1193 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0");
-
1194 BEAST_EXPECT(
-
1195 linesA.isMember(jss::ripplerpc) &&
-
1196 linesA[jss::ripplerpc] == "2.0");
-
1197 BEAST_EXPECT(linesA.isMember(jss::id) && linesA[jss::id] == 5);
-
1198
-
1199 // Pick up from where the marker left off. We should get 51.
-
1200 auto marker = linesA[jss::result][jss::marker].asString();
-
1201 auto const linesB = env.rpc(
-
1202 "json2",
-
1203 "{ "
-
1204 R"("method" : "account_lines",)"
-
1205 R"("jsonrpc" : "2.0",)"
-
1206 R"("ripplerpc" : "2.0",)"
-
1207 R"("id" : 5,)"
-
1208 R"("params": )"
-
1209 R"({"account": ")" +
-
1210 alice.human() +
-
1211 R"(", )"
-
1212 R"("marker": ")" +
-
1213 marker + R"("}})");
-
1214 BEAST_EXPECT(linesB[jss::result][jss::lines].isArray());
-
1215 BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 51);
-
1216 BEAST_EXPECT(
-
1217 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
-
1218 BEAST_EXPECT(
-
1219 linesB.isMember(jss::ripplerpc) &&
-
1220 linesB[jss::ripplerpc] == "2.0");
-
1221 BEAST_EXPECT(linesB.isMember(jss::id) && linesB[jss::id] == 5);
-
1222
-
1223 // Go again from where the marker left off, but set a limit of 3.
-
1224 auto const linesC = env.rpc(
-
1225 "json2",
-
1226 "{ "
-
1227 R"("method" : "account_lines",)"
-
1228 R"("jsonrpc" : "2.0",)"
-
1229 R"("ripplerpc" : "2.0",)"
-
1230 R"("id" : 5,)"
-
1231 R"("params": )"
-
1232 R"({"account": ")" +
-
1233 alice.human() +
-
1234 R"(", )"
-
1235 R"("limit": 3, )"
-
1236 R"("marker": ")" +
-
1237 marker + R"("}})");
-
1238 BEAST_EXPECT(linesC[jss::result][jss::lines].isArray());
-
1239 BEAST_EXPECT(linesC[jss::result][jss::lines].size() == 3);
-
1240 BEAST_EXPECT(
-
1241 linesC.isMember(jss::jsonrpc) && linesC[jss::jsonrpc] == "2.0");
-
1242 BEAST_EXPECT(
-
1243 linesC.isMember(jss::ripplerpc) &&
-
1244 linesC[jss::ripplerpc] == "2.0");
-
1245 BEAST_EXPECT(linesC.isMember(jss::id) && linesC[jss::id] == 5);
-
1246
-
1247 // Mess with the marker so it becomes bad and check for the error.
-
1248 marker[5] = marker[5] == '7' ? '8' : '7';
-
1249 auto const linesD = env.rpc(
-
1250 "json2",
-
1251 "{ "
-
1252 R"("method" : "account_lines",)"
-
1253 R"("jsonrpc" : "2.0",)"
-
1254 R"("ripplerpc" : "2.0",)"
-
1255 R"("id" : 5,)"
-
1256 R"("params": )"
-
1257 R"({"account": ")" +
-
1258 alice.human() +
-
1259 R"(", )"
-
1260 R"("marker": ")" +
-
1261 marker + R"("}})");
-
1262 BEAST_EXPECT(
-
1263 linesD[jss::error][jss::message] ==
-
1264 RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]);
-
1265 BEAST_EXPECT(
-
1266 linesD.isMember(jss::jsonrpc) && linesD[jss::jsonrpc] == "2.0");
-
1267 BEAST_EXPECT(
-
1268 linesD.isMember(jss::ripplerpc) &&
-
1269 linesD[jss::ripplerpc] == "2.0");
-
1270 BEAST_EXPECT(linesD.isMember(jss::id) && linesD[jss::id] == 5);
-
1271 }
-
1272 {
-
1273 // A non-string marker should also fail.
-
1274 auto const lines = env.rpc(
-
1275 "json2",
-
1276 "{ "
-
1277 R"("method" : "account_lines",)"
-
1278 R"("jsonrpc" : "2.0",)"
-
1279 R"("ripplerpc" : "2.0",)"
-
1280 R"("id" : 5,)"
-
1281 R"("params": )"
-
1282 R"({"account": ")" +
-
1283 alice.human() +
-
1284 R"(", )"
-
1285 R"("marker": true}})");
-
1286 BEAST_EXPECT(
-
1287 lines[jss::error][jss::message] ==
-
1288 RPC::expected_field_message(jss::marker, "string"));
-
1289 BEAST_EXPECT(
-
1290 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
1291 BEAST_EXPECT(
-
1292 lines.isMember(jss::ripplerpc) &&
-
1293 lines[jss::ripplerpc] == "2.0");
-
1294 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
1295 }
-
1296 {
-
1297 // Check that the flags we expect from alice to gw2 are present.
-
1298 auto const lines = env.rpc(
-
1299 "json2",
-
1300 "{ "
-
1301 R"("method" : "account_lines",)"
-
1302 R"("jsonrpc" : "2.0",)"
-
1303 R"("ripplerpc" : "2.0",)"
-
1304 R"("id" : 5,)"
-
1305 R"("params": )"
-
1306 R"({"account": ")" +
-
1307 alice.human() +
-
1308 R"(", )"
-
1309 R"("limit": 10, )"
-
1310 R"("peer": ")" +
-
1311 gw2.human() + R"("}})");
-
1312 auto const& line = lines[jss::result][jss::lines][0u];
-
1313 BEAST_EXPECT(line[jss::freeze].asBool() == true);
-
1314 BEAST_EXPECT(line[jss::no_ripple].asBool() == true);
-
1315 BEAST_EXPECT(line[jss::peer_authorized].asBool() == true);
-
1316 BEAST_EXPECT(
-
1317 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
-
1318 BEAST_EXPECT(
-
1319 lines.isMember(jss::ripplerpc) &&
-
1320 lines[jss::ripplerpc] == "2.0");
-
1321 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
-
1322 }
-
1323 {
-
1324 // Check that the flags we expect from gw2 to alice are present.
-
1325 auto const linesA = env.rpc(
-
1326 "json2",
-
1327 "{ "
-
1328 R"("method" : "account_lines",)"
-
1329 R"("jsonrpc" : "2.0",)"
-
1330 R"("ripplerpc" : "2.0",)"
-
1331 R"("id" : 5,)"
-
1332 R"("params": )"
-
1333 R"({"account": ")" +
-
1334 gw2.human() +
-
1335 R"(", )"
-
1336 R"("limit": 1, )"
-
1337 R"("peer": ")" +
-
1338 alice.human() + R"("}})");
-
1339 auto const& lineA = linesA[jss::result][jss::lines][0u];
-
1340 BEAST_EXPECT(lineA[jss::freeze_peer].asBool() == true);
-
1341 BEAST_EXPECT(lineA[jss::no_ripple_peer].asBool() == true);
-
1342 BEAST_EXPECT(lineA[jss::authorized].asBool() == true);
-
1343 BEAST_EXPECT(
-
1344 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0");
-
1345 BEAST_EXPECT(
-
1346 linesA.isMember(jss::ripplerpc) &&
-
1347 linesA[jss::ripplerpc] == "2.0");
-
1348 BEAST_EXPECT(linesA.isMember(jss::id) && linesA[jss::id] == 5);
-
1349
-
1350 // Continue from the returned marker to make sure that works.
-
1351 BEAST_EXPECT(linesA[jss::result].isMember(jss::marker));
-
1352 auto const marker = linesA[jss::result][jss::marker].asString();
-
1353 auto const linesB = env.rpc(
-
1354 "json2",
-
1355 "{ "
-
1356 R"("method" : "account_lines",)"
-
1357 R"("jsonrpc" : "2.0",)"
-
1358 R"("ripplerpc" : "2.0",)"
-
1359 R"("id" : 5,)"
-
1360 R"("params": )"
-
1361 R"({"account": ")" +
-
1362 gw2.human() +
-
1363 R"(", )"
-
1364 R"("limit": 25, )"
-
1365 R"("marker": ")" +
-
1366 marker +
-
1367 R"(", )"
-
1368 R"("peer": ")" +
-
1369 alice.human() + R"("}})");
-
1370 BEAST_EXPECT(linesB[jss::result][jss::lines].isArray());
-
1371 BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 25);
-
1372 BEAST_EXPECT(!linesB[jss::result].isMember(jss::marker));
-
1373 BEAST_EXPECT(
-
1374 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
-
1375 BEAST_EXPECT(
-
1376 linesB.isMember(jss::ripplerpc) &&
-
1377 linesB[jss::ripplerpc] == "2.0");
-
1378 BEAST_EXPECT(linesB.isMember(jss::id) && linesB[jss::id] == 5);
-
1379 }
-
1380 }
-
1381
-
1382 // test API V2
-
1383 void
-
1384 testAccountLineDelete2()
-
1385 {
-
1386 testcase("V2: account_lines with removed marker");
-
1387
-
1388 using namespace test::jtx;
-
1389 Env env(*this);
-
1390
-
1391 // The goal here is to observe account_lines marker behavior if the
-
1392 // entry pointed at by a returned marker is removed from the ledger.
-
1393 //
-
1394 // It isn't easy to explicitly delete a trust line, so we do so in a
-
1395 // round-about fashion. It takes 4 actors:
-
1396 // o Gateway gw1 issues EUR
-
1397 // o alice offers to buy 100 EUR for 100 XRP.
-
1398 // o becky offers to sell 100 EUR for 100 XRP.
-
1399 // There will now be an inferred trustline between alice and gw2.
-
1400 // o alice pays her 100 EUR to cheri.
-
1401 // alice should now have no EUR and no trustline to gw2.
-
1402 Account const alice{"alice"};
-
1403 Account const becky{"becky"};
-
1404 Account const cheri{"cheri"};
-
1405 Account const gw1{"gw1"};
-
1406 Account const gw2{"gw2"};
-
1407 env.fund(XRP(10000), alice, becky, cheri, gw1, gw2);
-
1408 env.close();
-
1409
-
1410 auto const USD = gw1["USD"];
-
1411 auto const AUD = gw1["AUD"];
-
1412 auto const EUR = gw2["EUR"];
-
1413 env(trust(alice, USD(200)));
-
1414 env(trust(alice, AUD(200)));
-
1415 env(trust(becky, EUR(200)));
-
1416 env(trust(cheri, EUR(200)));
-
1417 env.close();
-
1418
-
1419 // becky gets 100 EUR from gw1.
-
1420 env(pay(gw2, becky, EUR(100)));
-
1421 env.close();
-
1422
-
1423 // alice offers to buy 100 EUR for 100 XRP.
-
1424 env(offer(alice, EUR(100), XRP(100)));
-
1425 env.close();
-
1426
-
1427 // becky offers to buy 100 XRP for 100 EUR.
-
1428 env(offer(becky, XRP(100), EUR(100)));
+
786 // test API V2
+
787 void
+
788 testAccountLines2()
+
789 {
+
790 testcase("V2: account_lines");
+
791
+
792 using namespace test::jtx;
+
793 Env env(*this);
+
794 {
+
795 // account_lines with mal-formed json2 (missing id field).
+
796 auto const lines = env.rpc(
+
797 "json2",
+
798 "{ "
+
799 R"("method" : "account_lines",)"
+
800 R"("jsonrpc" : "2.0",)"
+
801 R"("ripplerpc" : "2.0")"
+
802 " }");
+
803 BEAST_EXPECT(
+
804 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
805 BEAST_EXPECT(
+
806 lines.isMember(jss::ripplerpc) &&
+
807 lines[jss::ripplerpc] == "2.0");
+
808 }
+
809 {
+
810 // account_lines with no account.
+
811 auto const lines = env.rpc(
+
812 "json2",
+
813 "{ "
+
814 R"("method" : "account_lines",)"
+
815 R"("jsonrpc" : "2.0",)"
+
816 R"("ripplerpc" : "2.0",)"
+
817 R"("id" : 5)"
+
818 " }");
+
819 BEAST_EXPECT(
+
820 lines[jss::error][jss::message] ==
+
821 RPC::missing_field_error(jss::account)[jss::error_message]);
+
822 BEAST_EXPECT(
+
823 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
824 BEAST_EXPECT(
+
825 lines.isMember(jss::ripplerpc) &&
+
826 lines[jss::ripplerpc] == "2.0");
+
827 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
828 }
+
829 {
+
830 // account_lines with a malformed account.
+
831 auto const lines = env.rpc(
+
832 "json2",
+
833 "{ "
+
834 R"("method" : "account_lines",)"
+
835 R"("jsonrpc" : "2.0",)"
+
836 R"("ripplerpc" : "2.0",)"
+
837 R"("id" : 5,)"
+
838 R"("params": )"
+
839 R"({"account": )"
+
840 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
+
841 BEAST_EXPECT(
+
842 lines[jss::error][jss::message] ==
+
843 RPC::make_error(rpcACT_MALFORMED)[jss::error_message]);
+
844 BEAST_EXPECT(
+
845 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
846 BEAST_EXPECT(
+
847 lines.isMember(jss::ripplerpc) &&
+
848 lines[jss::ripplerpc] == "2.0");
+
849 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
850 }
+
851 Account const alice{"alice"};
+
852 {
+
853 // account_lines on an unfunded account.
+
854 auto const lines = env.rpc(
+
855 "json2",
+
856 "{ "
+
857 R"("method" : "account_lines",)"
+
858 R"("jsonrpc" : "2.0",)"
+
859 R"("ripplerpc" : "2.0",)"
+
860 R"("id" : 5,)"
+
861 R"("params": )"
+
862 R"({"account": ")" +
+
863 alice.human() + R"("}})");
+
864 BEAST_EXPECT(
+
865 lines[jss::error][jss::message] ==
+
866 RPC::make_error(rpcACT_NOT_FOUND)[jss::error_message]);
+
867 BEAST_EXPECT(
+
868 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
869 BEAST_EXPECT(
+
870 lines.isMember(jss::ripplerpc) &&
+
871 lines[jss::ripplerpc] == "2.0");
+
872 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
873 }
+
874 env.fund(XRP(10000), alice);
+
875 env.close();
+
876 LedgerInfo const ledger3Info = env.closed()->info();
+
877 BEAST_EXPECT(ledger3Info.seq == 3);
+
878
+
879 {
+
880 // alice is funded but has no lines. An empty array is returned.
+
881 auto const lines = env.rpc(
+
882 "json2",
+
883 "{ "
+
884 R"("method" : "account_lines",)"
+
885 R"("jsonrpc" : "2.0",)"
+
886 R"("ripplerpc" : "2.0",)"
+
887 R"("id" : 5,)"
+
888 R"("params": )"
+
889 R"({"account": ")" +
+
890 alice.human() + R"("}})");
+
891 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
+
892 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 0);
+
893 BEAST_EXPECT(
+
894 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
895 BEAST_EXPECT(
+
896 lines.isMember(jss::ripplerpc) &&
+
897 lines[jss::ripplerpc] == "2.0");
+
898 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
899 }
+
900 {
+
901 // Specify a ledger that doesn't exist.
+
902 auto const lines = env.rpc(
+
903 "json2",
+
904 "{ "
+
905 R"("method" : "account_lines",)"
+
906 R"("jsonrpc" : "2.0",)"
+
907 R"("ripplerpc" : "2.0",)"
+
908 R"("id" : 5,)"
+
909 R"("params": )"
+
910 R"({"account": ")" +
+
911 alice.human() +
+
912 R"(", )"
+
913 R"("ledger_index": "nonsense"}})");
+
914 BEAST_EXPECT(
+
915 lines[jss::error][jss::message] == "ledgerIndexMalformed");
+
916 BEAST_EXPECT(
+
917 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
918 BEAST_EXPECT(
+
919 lines.isMember(jss::ripplerpc) &&
+
920 lines[jss::ripplerpc] == "2.0");
+
921 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
922 }
+
923 {
+
924 // Specify a different ledger that doesn't exist.
+
925 auto const lines = env.rpc(
+
926 "json2",
+
927 "{ "
+
928 R"("method" : "account_lines",)"
+
929 R"("jsonrpc" : "2.0",)"
+
930 R"("ripplerpc" : "2.0",)"
+
931 R"("id" : 5,)"
+
932 R"("params": )"
+
933 R"({"account": ")" +
+
934 alice.human() +
+
935 R"(", )"
+
936 R"("ledger_index": 50000}})");
+
937 BEAST_EXPECT(lines[jss::error][jss::message] == "ledgerNotFound");
+
938 BEAST_EXPECT(
+
939 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
940 BEAST_EXPECT(
+
941 lines.isMember(jss::ripplerpc) &&
+
942 lines[jss::ripplerpc] == "2.0");
+
943 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
944 }
+
945 // Create trust lines to share with alice.
+
946 Account const gw1{"gw1"};
+
947 env.fund(XRP(10000), gw1);
+
948 std::vector<IOU> gw1Currencies;
+
949
+
950 for (char c = 0; c <= ('Z' - 'A'); ++c)
+
951 {
+
952 // gw1 currencies have names "YAA" -> "YAZ".
+
953 gw1Currencies.push_back(
+
954 gw1[std::string("YA") + static_cast<char>('A' + c)]);
+
955 IOU const& gw1Currency = gw1Currencies.back();
+
956
+
957 // Establish trust lines.
+
958 env(trust(alice, gw1Currency(100 + c)));
+
959 env(pay(gw1, alice, gw1Currency(50 + c)));
+
960 }
+
961 env.close();
+
962 LedgerInfo const ledger4Info = env.closed()->info();
+
963 BEAST_EXPECT(ledger4Info.seq == 4);
+
964
+
965 // Add another set of trust lines in another ledger so we can see
+
966 // differences in historic ledgers.
+
967 Account const gw2{"gw2"};
+
968 env.fund(XRP(10000), gw2);
+
969
+
970 // gw2 requires authorization.
+
971 env(fset(gw2, asfRequireAuth));
+
972 env.close();
+
973 std::vector<IOU> gw2Currencies;
+
974
+
975 for (char c = 0; c <= ('Z' - 'A'); ++c)
+
976 {
+
977 // gw2 currencies have names "ZAA" -> "ZAZ".
+
978 gw2Currencies.push_back(
+
979 gw2[std::string("ZA") + static_cast<char>('A' + c)]);
+
980 IOU const& gw2Currency = gw2Currencies.back();
+
981
+
982 // Establish trust lines.
+
983 env(trust(alice, gw2Currency(200 + c)));
+
984 env(trust(gw2, gw2Currency(0), alice, tfSetfAuth));
+
985 env.close();
+
986 env(pay(gw2, alice, gw2Currency(100 + c)));
+
987 env.close();
+
988
+
989 // Set flags on gw2 trust lines so we can look for them.
+
990 env(trust(
+
991 alice,
+
992 gw2Currency(0),
+
993 gw2,
+
994 tfSetNoRipple | tfSetFreeze | tfSetDeepFreeze));
+
995 }
+
996 env.close();
+
997 LedgerInfo const ledger58Info = env.closed()->info();
+
998 BEAST_EXPECT(ledger58Info.seq == 58);
+
999
+
1000 // A re-usable test for historic ledgers.
+
1001 auto testAccountLinesHistory = [this, &env](
+
1002 Account const& account,
+
1003 LedgerInfo const& info,
+
1004 int count) {
+
1005 // Get account_lines by ledger index.
+
1006 auto const linesSeq = env.rpc(
+
1007 "json2",
+
1008 "{ "
+
1009 R"("method" : "account_lines",)"
+
1010 R"("jsonrpc" : "2.0",)"
+
1011 R"("ripplerpc" : "2.0",)"
+
1012 R"("id" : 5,)"
+
1013 R"("params": )"
+
1014 R"({"account": ")" +
+
1015 account.human() +
+
1016 R"(", )"
+
1017 R"("ledger_index": )" +
+
1018 std::to_string(info.seq) + "}}");
+
1019 BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
+
1020 BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
+
1021 BEAST_EXPECT(
+
1022 linesSeq.isMember(jss::jsonrpc) &&
+
1023 linesSeq[jss::jsonrpc] == "2.0");
+
1024 BEAST_EXPECT(
+
1025 linesSeq.isMember(jss::ripplerpc) &&
+
1026 linesSeq[jss::ripplerpc] == "2.0");
+
1027 BEAST_EXPECT(linesSeq.isMember(jss::id) && linesSeq[jss::id] == 5);
+
1028
+
1029 // Get account_lines by ledger hash.
+
1030 auto const linesHash = env.rpc(
+
1031 "json2",
+
1032 "{ "
+
1033 R"("method" : "account_lines",)"
+
1034 R"("jsonrpc" : "2.0",)"
+
1035 R"("ripplerpc" : "2.0",)"
+
1036 R"("id" : 5,)"
+
1037 R"("params": )"
+
1038 R"({"account": ")" +
+
1039 account.human() +
+
1040 R"(", )"
+
1041 R"("ledger_hash": ")" +
+
1042 to_string(info.hash) + R"("}})");
+
1043 BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
+
1044 BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
+
1045 BEAST_EXPECT(
+
1046 linesHash.isMember(jss::jsonrpc) &&
+
1047 linesHash[jss::jsonrpc] == "2.0");
+
1048 BEAST_EXPECT(
+
1049 linesHash.isMember(jss::ripplerpc) &&
+
1050 linesHash[jss::ripplerpc] == "2.0");
+
1051 BEAST_EXPECT(
+
1052 linesHash.isMember(jss::id) && linesHash[jss::id] == 5);
+
1053 };
+
1054
+
1055 // Alice should have no trust lines in ledger 3.
+
1056 testAccountLinesHistory(alice, ledger3Info, 0);
+
1057
+
1058 // Alice should have 26 trust lines in ledger 4.
+
1059 testAccountLinesHistory(alice, ledger4Info, 26);
+
1060
+
1061 // Alice should have 52 trust lines in ledger 58.
+
1062 testAccountLinesHistory(alice, ledger58Info, 52);
+
1063
+
1064 {
+
1065 // Surprisingly, it's valid to specify both index and hash, in
+
1066 // which case the hash wins.
+
1067 auto const lines = env.rpc(
+
1068 "json2",
+
1069 "{ "
+
1070 R"("method" : "account_lines",)"
+
1071 R"("jsonrpc" : "2.0",)"
+
1072 R"("ripplerpc" : "2.0",)"
+
1073 R"("id" : 5,)"
+
1074 R"("params": )"
+
1075 R"({"account": ")" +
+
1076 alice.human() +
+
1077 R"(", )"
+
1078 R"("ledger_hash": ")" +
+
1079 to_string(ledger4Info.hash) +
+
1080 R"(", )"
+
1081 R"("ledger_index": )" +
+
1082 std::to_string(ledger58Info.seq) + "}}");
+
1083 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
+
1084 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
+
1085 BEAST_EXPECT(
+
1086 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
1087 BEAST_EXPECT(
+
1088 lines.isMember(jss::ripplerpc) &&
+
1089 lines[jss::ripplerpc] == "2.0");
+
1090 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
1091 }
+
1092 {
+
1093 // alice should have 52 trust lines in the current ledger.
+
1094 auto const lines = env.rpc(
+
1095 "json2",
+
1096 "{ "
+
1097 R"("method" : "account_lines",)"
+
1098 R"("jsonrpc" : "2.0",)"
+
1099 R"("ripplerpc" : "2.0",)"
+
1100 R"("id" : 5,)"
+
1101 R"("params": )"
+
1102 R"({"account": ")" +
+
1103 alice.human() + R"("}})");
+
1104 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
+
1105 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52);
+
1106 BEAST_EXPECT(
+
1107 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
1108 BEAST_EXPECT(
+
1109 lines.isMember(jss::ripplerpc) &&
+
1110 lines[jss::ripplerpc] == "2.0");
+
1111 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
1112 }
+
1113 {
+
1114 // alice should have 26 trust lines with gw1.
+
1115 auto const lines = env.rpc(
+
1116 "json2",
+
1117 "{ "
+
1118 R"("method" : "account_lines",)"
+
1119 R"("jsonrpc" : "2.0",)"
+
1120 R"("ripplerpc" : "2.0",)"
+
1121 R"("id" : 5,)"
+
1122 R"("params": )"
+
1123 R"({"account": ")" +
+
1124 alice.human() +
+
1125 R"(", )"
+
1126 R"("peer": ")" +
+
1127 gw1.human() + R"("}})");
+
1128 BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
+
1129 BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
+
1130 BEAST_EXPECT(
+
1131 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
1132 BEAST_EXPECT(
+
1133 lines.isMember(jss::ripplerpc) &&
+
1134 lines[jss::ripplerpc] == "2.0");
+
1135 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
1136 }
+
1137 {
+
1138 // Use a malformed peer.
+
1139 auto const lines = env.rpc(
+
1140 "json2",
+
1141 "{ "
+
1142 R"("method" : "account_lines",)"
+
1143 R"("jsonrpc" : "2.0",)"
+
1144 R"("ripplerpc" : "2.0",)"
+
1145 R"("id" : 5,)"
+
1146 R"("params": )"
+
1147 R"({"account": ")" +
+
1148 alice.human() +
+
1149 R"(", )"
+
1150 R"("peer": )"
+
1151 R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})");
+
1152 BEAST_EXPECT(
+
1153 lines[jss::error][jss::message] ==
+
1154 RPC::make_error(rpcACT_MALFORMED)[jss::error_message]);
+
1155 BEAST_EXPECT(
+
1156 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
1157 BEAST_EXPECT(
+
1158 lines.isMember(jss::ripplerpc) &&
+
1159 lines[jss::ripplerpc] == "2.0");
+
1160 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
1161 }
+
1162 {
+
1163 // A negative limit should fail.
+
1164 auto const lines = env.rpc(
+
1165 "json2",
+
1166 "{ "
+
1167 R"("method" : "account_lines",)"
+
1168 R"("jsonrpc" : "2.0",)"
+
1169 R"("ripplerpc" : "2.0",)"
+
1170 R"("id" : 5,)"
+
1171 R"("params": )"
+
1172 R"({"account": ")" +
+
1173 alice.human() +
+
1174 R"(", )"
+
1175 R"("limit": -1}})");
+
1176 BEAST_EXPECT(
+
1177 lines[jss::error][jss::message] ==
+
1178 RPC::expected_field_message(jss::limit, "unsigned integer"));
+
1179 BEAST_EXPECT(
+
1180 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
1181 BEAST_EXPECT(
+
1182 lines.isMember(jss::ripplerpc) &&
+
1183 lines[jss::ripplerpc] == "2.0");
+
1184 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
1185 }
+
1186 {
+
1187 // Limit the response to 1 trust line.
+
1188 auto const linesA = env.rpc(
+
1189 "json2",
+
1190 "{ "
+
1191 R"("method" : "account_lines",)"
+
1192 R"("jsonrpc" : "2.0",)"
+
1193 R"("ripplerpc" : "2.0",)"
+
1194 R"("id" : 5,)"
+
1195 R"("params": )"
+
1196 R"({"account": ")" +
+
1197 alice.human() +
+
1198 R"(", )"
+
1199 R"("limit": 1}})");
+
1200 BEAST_EXPECT(linesA[jss::result][jss::lines].isArray());
+
1201 BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1);
+
1202 BEAST_EXPECT(
+
1203 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0");
+
1204 BEAST_EXPECT(
+
1205 linesA.isMember(jss::ripplerpc) &&
+
1206 linesA[jss::ripplerpc] == "2.0");
+
1207 BEAST_EXPECT(linesA.isMember(jss::id) && linesA[jss::id] == 5);
+
1208
+
1209 // Pick up from where the marker left off. We should get 51.
+
1210 auto marker = linesA[jss::result][jss::marker].asString();
+
1211 auto const linesB = env.rpc(
+
1212 "json2",
+
1213 "{ "
+
1214 R"("method" : "account_lines",)"
+
1215 R"("jsonrpc" : "2.0",)"
+
1216 R"("ripplerpc" : "2.0",)"
+
1217 R"("id" : 5,)"
+
1218 R"("params": )"
+
1219 R"({"account": ")" +
+
1220 alice.human() +
+
1221 R"(", )"
+
1222 R"("marker": ")" +
+
1223 marker + R"("}})");
+
1224 BEAST_EXPECT(linesB[jss::result][jss::lines].isArray());
+
1225 BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 51);
+
1226 BEAST_EXPECT(
+
1227 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
+
1228 BEAST_EXPECT(
+
1229 linesB.isMember(jss::ripplerpc) &&
+
1230 linesB[jss::ripplerpc] == "2.0");
+
1231 BEAST_EXPECT(linesB.isMember(jss::id) && linesB[jss::id] == 5);
+
1232
+
1233 // Go again from where the marker left off, but set a limit of 3.
+
1234 auto const linesC = env.rpc(
+
1235 "json2",
+
1236 "{ "
+
1237 R"("method" : "account_lines",)"
+
1238 R"("jsonrpc" : "2.0",)"
+
1239 R"("ripplerpc" : "2.0",)"
+
1240 R"("id" : 5,)"
+
1241 R"("params": )"
+
1242 R"({"account": ")" +
+
1243 alice.human() +
+
1244 R"(", )"
+
1245 R"("limit": 3, )"
+
1246 R"("marker": ")" +
+
1247 marker + R"("}})");
+
1248 BEAST_EXPECT(linesC[jss::result][jss::lines].isArray());
+
1249 BEAST_EXPECT(linesC[jss::result][jss::lines].size() == 3);
+
1250 BEAST_EXPECT(
+
1251 linesC.isMember(jss::jsonrpc) && linesC[jss::jsonrpc] == "2.0");
+
1252 BEAST_EXPECT(
+
1253 linesC.isMember(jss::ripplerpc) &&
+
1254 linesC[jss::ripplerpc] == "2.0");
+
1255 BEAST_EXPECT(linesC.isMember(jss::id) && linesC[jss::id] == 5);
+
1256
+
1257 // Mess with the marker so it becomes bad and check for the error.
+
1258 marker[5] = marker[5] == '7' ? '8' : '7';
+
1259 auto const linesD = env.rpc(
+
1260 "json2",
+
1261 "{ "
+
1262 R"("method" : "account_lines",)"
+
1263 R"("jsonrpc" : "2.0",)"
+
1264 R"("ripplerpc" : "2.0",)"
+
1265 R"("id" : 5,)"
+
1266 R"("params": )"
+
1267 R"({"account": ")" +
+
1268 alice.human() +
+
1269 R"(", )"
+
1270 R"("marker": ")" +
+
1271 marker + R"("}})");
+
1272 BEAST_EXPECT(
+
1273 linesD[jss::error][jss::message] ==
+
1274 RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]);
+
1275 BEAST_EXPECT(
+
1276 linesD.isMember(jss::jsonrpc) && linesD[jss::jsonrpc] == "2.0");
+
1277 BEAST_EXPECT(
+
1278 linesD.isMember(jss::ripplerpc) &&
+
1279 linesD[jss::ripplerpc] == "2.0");
+
1280 BEAST_EXPECT(linesD.isMember(jss::id) && linesD[jss::id] == 5);
+
1281 }
+
1282 {
+
1283 // A non-string marker should also fail.
+
1284 auto const lines = env.rpc(
+
1285 "json2",
+
1286 "{ "
+
1287 R"("method" : "account_lines",)"
+
1288 R"("jsonrpc" : "2.0",)"
+
1289 R"("ripplerpc" : "2.0",)"
+
1290 R"("id" : 5,)"
+
1291 R"("params": )"
+
1292 R"({"account": ")" +
+
1293 alice.human() +
+
1294 R"(", )"
+
1295 R"("marker": true}})");
+
1296 BEAST_EXPECT(
+
1297 lines[jss::error][jss::message] ==
+
1298 RPC::expected_field_message(jss::marker, "string"));
+
1299 BEAST_EXPECT(
+
1300 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
1301 BEAST_EXPECT(
+
1302 lines.isMember(jss::ripplerpc) &&
+
1303 lines[jss::ripplerpc] == "2.0");
+
1304 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
1305 }
+
1306 {
+
1307 // Check that the flags we expect from alice to gw2 are present.
+
1308 auto const lines = env.rpc(
+
1309 "json2",
+
1310 "{ "
+
1311 R"("method" : "account_lines",)"
+
1312 R"("jsonrpc" : "2.0",)"
+
1313 R"("ripplerpc" : "2.0",)"
+
1314 R"("id" : 5,)"
+
1315 R"("params": )"
+
1316 R"({"account": ")" +
+
1317 alice.human() +
+
1318 R"(", )"
+
1319 R"("limit": 10, )"
+
1320 R"("peer": ")" +
+
1321 gw2.human() + R"("}})");
+
1322 auto const& line = lines[jss::result][jss::lines][0u];
+
1323 BEAST_EXPECT(line[jss::freeze].asBool() == true);
+
1324 BEAST_EXPECT(line[jss::deep_freeze].asBool() == true);
+
1325 BEAST_EXPECT(line[jss::no_ripple].asBool() == true);
+
1326 BEAST_EXPECT(line[jss::peer_authorized].asBool() == true);
+
1327 BEAST_EXPECT(
+
1328 lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
+
1329 BEAST_EXPECT(
+
1330 lines.isMember(jss::ripplerpc) &&
+
1331 lines[jss::ripplerpc] == "2.0");
+
1332 BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
+
1333 }
+
1334 {
+
1335 // Check that the flags we expect from gw2 to alice are present.
+
1336 auto const linesA = env.rpc(
+
1337 "json2",
+
1338 "{ "
+
1339 R"("method" : "account_lines",)"
+
1340 R"("jsonrpc" : "2.0",)"
+
1341 R"("ripplerpc" : "2.0",)"
+
1342 R"("id" : 5,)"
+
1343 R"("params": )"
+
1344 R"({"account": ")" +
+
1345 gw2.human() +
+
1346 R"(", )"
+
1347 R"("limit": 1, )"
+
1348 R"("peer": ")" +
+
1349 alice.human() + R"("}})");
+
1350 auto const& lineA = linesA[jss::result][jss::lines][0u];
+
1351 BEAST_EXPECT(lineA[jss::freeze_peer].asBool() == true);
+
1352 BEAST_EXPECT(lineA[jss::deep_freeze_peer].asBool() == true);
+
1353 BEAST_EXPECT(lineA[jss::no_ripple_peer].asBool() == true);
+
1354 BEAST_EXPECT(lineA[jss::authorized].asBool() == true);
+
1355 BEAST_EXPECT(
+
1356 linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0");
+
1357 BEAST_EXPECT(
+
1358 linesA.isMember(jss::ripplerpc) &&
+
1359 linesA[jss::ripplerpc] == "2.0");
+
1360 BEAST_EXPECT(linesA.isMember(jss::id) && linesA[jss::id] == 5);
+
1361
+
1362 // Continue from the returned marker to make sure that works.
+
1363 BEAST_EXPECT(linesA[jss::result].isMember(jss::marker));
+
1364 auto const marker = linesA[jss::result][jss::marker].asString();
+
1365 auto const linesB = env.rpc(
+
1366 "json2",
+
1367 "{ "
+
1368 R"("method" : "account_lines",)"
+
1369 R"("jsonrpc" : "2.0",)"
+
1370 R"("ripplerpc" : "2.0",)"
+
1371 R"("id" : 5,)"
+
1372 R"("params": )"
+
1373 R"({"account": ")" +
+
1374 gw2.human() +
+
1375 R"(", )"
+
1376 R"("limit": 25, )"
+
1377 R"("marker": ")" +
+
1378 marker +
+
1379 R"(", )"
+
1380 R"("peer": ")" +
+
1381 alice.human() + R"("}})");
+
1382 BEAST_EXPECT(linesB[jss::result][jss::lines].isArray());
+
1383 BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 25);
+
1384 BEAST_EXPECT(!linesB[jss::result].isMember(jss::marker));
+
1385 BEAST_EXPECT(
+
1386 linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
+
1387 BEAST_EXPECT(
+
1388 linesB.isMember(jss::ripplerpc) &&
+
1389 linesB[jss::ripplerpc] == "2.0");
+
1390 BEAST_EXPECT(linesB.isMember(jss::id) && linesB[jss::id] == 5);
+
1391 }
+
1392 }
+
1393
+
1394 // test API V2
+
1395 void
+
1396 testAccountLineDelete2()
+
1397 {
+
1398 testcase("V2: account_lines with removed marker");
+
1399
+
1400 using namespace test::jtx;
+
1401 Env env(*this);
+
1402
+
1403 // The goal here is to observe account_lines marker behavior if the
+
1404 // entry pointed at by a returned marker is removed from the ledger.
+
1405 //
+
1406 // It isn't easy to explicitly delete a trust line, so we do so in a
+
1407 // round-about fashion. It takes 4 actors:
+
1408 // o Gateway gw1 issues EUR
+
1409 // o alice offers to buy 100 EUR for 100 XRP.
+
1410 // o becky offers to sell 100 EUR for 100 XRP.
+
1411 // There will now be an inferred trustline between alice and gw2.
+
1412 // o alice pays her 100 EUR to cheri.
+
1413 // alice should now have no EUR and no trustline to gw2.
+
1414 Account const alice{"alice"};
+
1415 Account const becky{"becky"};
+
1416 Account const cheri{"cheri"};
+
1417 Account const gw1{"gw1"};
+
1418 Account const gw2{"gw2"};
+
1419 env.fund(XRP(10000), alice, becky, cheri, gw1, gw2);
+
1420 env.close();
+
1421
+
1422 auto const USD = gw1["USD"];
+
1423 auto const AUD = gw1["AUD"];
+
1424 auto const EUR = gw2["EUR"];
+
1425 env(trust(alice, USD(200)));
+
1426 env(trust(alice, AUD(200)));
+
1427 env(trust(becky, EUR(200)));
+
1428 env(trust(cheri, EUR(200)));
1429 env.close();
1430
-
1431 // Get account_lines for alice. Limit at 1, so we get a marker.
-
1432 auto const linesBeg = env.rpc(
-
1433 "json2",
-
1434 "{ "
-
1435 R"("method" : "account_lines",)"
-
1436 R"("jsonrpc" : "2.0",)"
-
1437 R"("ripplerpc" : "2.0",)"
-
1438 R"("id" : 5,)"
-
1439 R"("params": )"
-
1440 R"({"account": ")" +
-
1441 alice.human() +
-
1442 R"(", )"
-
1443 R"("limit": 2}})");
-
1444 BEAST_EXPECT(
-
1445 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
-
1446 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
-
1447 BEAST_EXPECT(
-
1448 linesBeg.isMember(jss::jsonrpc) && linesBeg[jss::jsonrpc] == "2.0");
-
1449 BEAST_EXPECT(
-
1450 linesBeg.isMember(jss::ripplerpc) &&
-
1451 linesBeg[jss::ripplerpc] == "2.0");
-
1452 BEAST_EXPECT(linesBeg.isMember(jss::id) && linesBeg[jss::id] == 5);
-
1453
-
1454 // alice pays 100 USD to cheri.
-
1455 env(pay(alice, cheri, EUR(100)));
-
1456 env.close();
-
1457
-
1458 // Since alice paid all her EUR to cheri, alice should no longer
-
1459 // have a trust line to gw1. So the old marker should now be invalid.
-
1460 auto const linesEnd = env.rpc(
-
1461 "json2",
-
1462 "{ "
-
1463 R"("method" : "account_lines",)"
-
1464 R"("jsonrpc" : "2.0",)"
-
1465 R"("ripplerpc" : "2.0",)"
-
1466 R"("id" : 5,)"
-
1467 R"("params": )"
-
1468 R"({"account": ")" +
-
1469 alice.human() +
-
1470 R"(", )"
-
1471 R"("marker": ")" +
-
1472 linesBeg[jss::result][jss::marker].asString() + R"("}})");
-
1473 BEAST_EXPECT(
-
1474 linesEnd[jss::error][jss::message] ==
-
1475 RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]);
-
1476 BEAST_EXPECT(
-
1477 linesEnd.isMember(jss::jsonrpc) && linesEnd[jss::jsonrpc] == "2.0");
-
1478 BEAST_EXPECT(
-
1479 linesEnd.isMember(jss::ripplerpc) &&
-
1480 linesEnd[jss::ripplerpc] == "2.0");
-
1481 BEAST_EXPECT(linesEnd.isMember(jss::id) && linesEnd[jss::id] == 5);
-
1482 }
-
1483
-
1484 void
-
1485 run() override
-
1486 {
-
1487 testAccountLines();
-
1488 testAccountLinesMarker();
-
1489 testAccountLineDelete();
-
1490 testAccountLinesWalkMarkers();
-
1491 testAccountLines2();
-
1492 testAccountLineDelete2();
-
1493 }
-
1494};
+
1431 // becky gets 100 EUR from gw1.
+
1432 env(pay(gw2, becky, EUR(100)));
+
1433 env.close();
+
1434
+
1435 // alice offers to buy 100 EUR for 100 XRP.
+
1436 env(offer(alice, EUR(100), XRP(100)));
+
1437 env.close();
+
1438
+
1439 // becky offers to buy 100 XRP for 100 EUR.
+
1440 env(offer(becky, XRP(100), EUR(100)));
+
1441 env.close();
+
1442
+
1443 // Get account_lines for alice. Limit at 1, so we get a marker.
+
1444 auto const linesBeg = env.rpc(
+
1445 "json2",
+
1446 "{ "
+
1447 R"("method" : "account_lines",)"
+
1448 R"("jsonrpc" : "2.0",)"
+
1449 R"("ripplerpc" : "2.0",)"
+
1450 R"("id" : 5,)"
+
1451 R"("params": )"
+
1452 R"({"account": ")" +
+
1453 alice.human() +
+
1454 R"(", )"
+
1455 R"("limit": 2}})");
+
1456 BEAST_EXPECT(
+
1457 linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
+
1458 BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
+
1459 BEAST_EXPECT(
+
1460 linesBeg.isMember(jss::jsonrpc) && linesBeg[jss::jsonrpc] == "2.0");
+
1461 BEAST_EXPECT(
+
1462 linesBeg.isMember(jss::ripplerpc) &&
+
1463 linesBeg[jss::ripplerpc] == "2.0");
+
1464 BEAST_EXPECT(linesBeg.isMember(jss::id) && linesBeg[jss::id] == 5);
+
1465
+
1466 // alice pays 100 USD to cheri.
+
1467 env(pay(alice, cheri, EUR(100)));
+
1468 env.close();
+
1469
+
1470 // Since alice paid all her EUR to cheri, alice should no longer
+
1471 // have a trust line to gw1. So the old marker should now be invalid.
+
1472 auto const linesEnd = env.rpc(
+
1473 "json2",
+
1474 "{ "
+
1475 R"("method" : "account_lines",)"
+
1476 R"("jsonrpc" : "2.0",)"
+
1477 R"("ripplerpc" : "2.0",)"
+
1478 R"("id" : 5,)"
+
1479 R"("params": )"
+
1480 R"({"account": ")" +
+
1481 alice.human() +
+
1482 R"(", )"
+
1483 R"("marker": ")" +
+
1484 linesBeg[jss::result][jss::marker].asString() + R"("}})");
+
1485 BEAST_EXPECT(
+
1486 linesEnd[jss::error][jss::message] ==
+
1487 RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]);
+
1488 BEAST_EXPECT(
+
1489 linesEnd.isMember(jss::jsonrpc) && linesEnd[jss::jsonrpc] == "2.0");
+
1490 BEAST_EXPECT(
+
1491 linesEnd.isMember(jss::ripplerpc) &&
+
1492 linesEnd[jss::ripplerpc] == "2.0");
+
1493 BEAST_EXPECT(linesEnd.isMember(jss::id) && linesEnd[jss::id] == 5);
+
1494 }
1495
-
1496BEAST_DEFINE_TESTSUITE(AccountLines, rpc, ripple);
-
1497
-
1498} // namespace RPC
-
1499} // namespace ripple
+
1496 void
+
1497 run() override
+
1498 {
+
1499 testAccountLines();
+
1500 testAccountLinesMarker();
+
1501 testAccountLineDelete();
+
1502 testAccountLinesWalkMarkers();
+
1503 testAccountLines2();
+
1504 testAccountLineDelete2();
+
1505 }
+
1506};
+
1507
+
1508BEAST_DEFINE_TESTSUITE(AccountLines, rpc, ripple);
+
1509
+
1510} // namespace RPC
+
1511} // namespace ripple
std::vector::back
T back(T... args)
std::string
Json::Value
Represents a JSON value.
Definition: json_value.h:147
@@ -1585,6 +1597,7 @@ $(function() {
ripple::NetClock::time_point
std::chrono::time_point< NetClock > time_point
Definition: chrono.h:70
ripple::NetClock::duration
std::chrono::duration< rep, period > duration
Definition: chrono.h:69
ripple::RPC::AccountLines_test
Definition: AccountLines_test.cpp:31
+
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lineA[jss::deep_freeze_peer].asBool()==true)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesB[jss::result][jss::lines].isArray())
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(ledger3Info.seq==3)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesEnd.isMember(jss::ripplerpc) &&linesEnd[jss::ripplerpc]=="2.0")
@@ -1592,22 +1605,22 @@ $(function() {
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesD.isMember(jss::id) &&linesD[jss::id]==5)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(line[jss::no_ripple].asBool()==true)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesD[jss::error][jss::message]==RPC::make_error(rpcINVALID_PARAMS)[jss::error_message])
-
ripple::RPC::AccountLines_test::linesC
auto const linesC
Definition: AccountLines_test.cpp:1224
+
ripple::RPC::AccountLines_test::linesC
auto const linesC
Definition: AccountLines_test.cpp:1234
ripple::RPC::AccountLines_test::testAccountLinesHistory
testAccountLinesHistory(alice, ledger4Info, 26)
-
ripple::RPC::AccountLines_test::testAccountLinesHistory
auto testAccountLinesHistory
Definition: AccountLines_test.cpp:991
-
ripple::RPC::AccountLines_test::linesD
auto const linesD
Definition: AccountLines_test.cpp:1249
+
ripple::RPC::AccountLines_test::testAccountLinesHistory
auto testAccountLinesHistory
Definition: AccountLines_test.cpp:1001
+
ripple::RPC::AccountLines_test::linesD
auto const linesD
Definition: AccountLines_test.cpp:1259
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesB.isMember(jss::ripplerpc) &&linesB[jss::ripplerpc]=="2.0")
-
ripple::RPC::AccountLines_test::gw2
Account const gw2
Definition: AccountLines_test.cpp:961
+
ripple::RPC::AccountLines_test::gw2
Account const gw2
Definition: AccountLines_test.cpp:967
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesC.isMember(jss::jsonrpc) &&linesC[jss::jsonrpc]=="2.0")
-
ripple::RPC::AccountLines_test::testAccountLineDelete2
void testAccountLineDelete2()
Definition: AccountLines_test.cpp:1384
+
ripple::RPC::AccountLines_test::testAccountLineDelete2
void testAccountLineDelete2()
Definition: AccountLines_test.cpp:1396
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(ledger4Info.seq==4)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lines[jss::result][jss::lines].size()==26)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesA.isMember(jss::ripplerpc) &&linesA[jss::ripplerpc]=="2.0")
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesB.isMember(jss::jsonrpc) &&linesB[jss::jsonrpc]=="2.0")
-
ripple::RPC::AccountLines_test::line
auto const & line
Definition: AccountLines_test.cpp:1312
+
ripple::RPC::AccountLines_test::line
auto const & line
Definition: AccountLines_test.cpp:1322
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesD.isMember(jss::ripplerpc) &&linesD[jss::ripplerpc]=="2.0")
-
ripple::RPC::AccountLines_test::ledger3Info
LedgerInfo const ledger3Info
Definition: AccountLines_test.cpp:870
-
ripple::RPC::AccountLines_test::lineA
auto const & lineA
Definition: AccountLines_test.cpp:1339
+
ripple::RPC::AccountLines_test::ledger3Info
LedgerInfo const ledger3Info
Definition: AccountLines_test.cpp:876
+
ripple::RPC::AccountLines_test::lineA
auto const & lineA
Definition: AccountLines_test.cpp:1350
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lineA[jss::no_ripple_peer].asBool()==true)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lineA[jss::freeze_peer].asBool()==true)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesC[jss::result][jss::lines].size()==3)
@@ -1617,15 +1630,15 @@ $(function() {
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesA[jss::result].isMember(jss::marker))
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesEnd[jss::error][jss::message]==RPC::make_error(rpcINVALID_PARAMS)[jss::error_message])
ripple::RPC::AccountLines_test::env
env(fset(gw2, asfRequireAuth))
-
ripple::RPC::AccountLines_test::gw1
Account const gw1
Definition: AccountLines_test.cpp:940
-
ripple::RPC::AccountLines_test::marker
auto marker
Definition: AccountLines_test.cpp:1200
-
ripple::RPC::AccountLines_test::ledger4Info
LedgerInfo const ledger4Info
Definition: AccountLines_test.cpp:956
-
ripple::RPC::AccountLines_test::gw1Currencies
std::vector< IOU > gw1Currencies
Definition: AccountLines_test.cpp:942
+
ripple::RPC::AccountLines_test::gw1
Account const gw1
Definition: AccountLines_test.cpp:946
+
ripple::RPC::AccountLines_test::marker
auto marker
Definition: AccountLines_test.cpp:1210
+
ripple::RPC::AccountLines_test::ledger4Info
LedgerInfo const ledger4Info
Definition: AccountLines_test.cpp:962
+
ripple::RPC::AccountLines_test::gw1Currencies
std::vector< IOU > gw1Currencies
Definition: AccountLines_test.cpp:948
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lines[jss::result][jss::lines].size()==0)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lines.isMember(jss::id) &&lines[jss::id]==5)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lines[jss::error][jss::message]=="ledgerIndexMalformed")
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lines.isMember(jss::jsonrpc) &&lines[jss::jsonrpc]=="2.0")
-
ripple::RPC::AccountLines_test::linesB
auto const linesB
Definition: AccountLines_test.cpp:1201
+
ripple::RPC::AccountLines_test::linesB
auto const linesB
Definition: AccountLines_test.cpp:1211
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesA[jss::result][jss::lines].isArray())
ripple::RPC::AccountLines_test::testAccountLines
void testAccountLines()
Definition: AccountLines_test.cpp:34
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lines[jss::error][jss::message]==RPC::expected_field_message(jss::limit, "unsigned integer"))
@@ -1633,7 +1646,7 @@ $(function() {
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesB.isMember(jss::id) &&linesB[jss::id]==5)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesB[jss::result][jss::lines].size()==25)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(!linesB[jss::result].isMember(jss::marker))
-
ripple::RPC::AccountLines_test::ledger58Info
LedgerInfo const ledger58Info
Definition: AccountLines_test.cpp:987
+
ripple::RPC::AccountLines_test::ledger58Info
LedgerInfo const ledger58Info
Definition: AccountLines_test.cpp:997
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesC.isMember(jss::id) &&linesC[jss::id]==5)
ripple::RPC::AccountLines_test::testAccountLinesHistory
testAccountLinesHistory(alice, ledger58Info, 52)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesD.isMember(jss::jsonrpc) &&linesD[jss::jsonrpc]=="2.0")
@@ -1643,16 +1656,17 @@ $(function() {
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lines[jss::error][jss::message]==RPC::expected_field_message(jss::marker, "string"))
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesEnd.isMember(jss::jsonrpc) &&linesEnd[jss::jsonrpc]=="2.0")
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesA.isMember(jss::id) &&linesA[jss::id]==5)
-
ripple::RPC::AccountLines_test::run
void run() override
Runs the suite.
Definition: AccountLines_test.cpp:1485
+
ripple::RPC::AccountLines_test::run
void run() override
Runs the suite.
Definition: AccountLines_test.cpp:1497
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lines[jss::error][jss::message]=="ledgerNotFound")
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lineA[jss::authorized].asBool()==true)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lines[jss::error][jss::message]==RPC::make_error(rpcACT_NOT_FOUND)[jss::error_message])
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lines[jss::result][jss::lines].size()==52)
-
ripple::RPC::AccountLines_test::testAccountLines2
void testAccountLines2()
Definition: AccountLines_test.cpp:782
+
ripple::RPC::AccountLines_test::testAccountLines2
void testAccountLines2()
Definition: AccountLines_test.cpp:788
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesA.isMember(jss::jsonrpc) &&linesA[jss::jsonrpc]=="2.0")
+
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(line[jss::deep_freeze].asBool()==true)
ripple::RPC::AccountLines_test::testAccountLinesHistory
testAccountLinesHistory(alice, ledger3Info, 0)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(lines[jss::error][jss::message]==RPC::make_error(rpcACT_MALFORMED)[jss::error_message])
-
ripple::RPC::AccountLines_test::gw2Currencies
std::vector< IOU > gw2Currencies
Definition: AccountLines_test.cpp:967
+
ripple::RPC::AccountLines_test::gw2Currencies
std::vector< IOU > gw2Currencies
Definition: AccountLines_test.cpp:973
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(line[jss::freeze].asBool()==true)
ripple::RPC::AccountLines_test::BEAST_EXPECT
BEAST_EXPECT(linesA[jss::result][jss::lines].size()==1)
std::string::find
T find(T... args)
@@ -1672,11 +1686,12 @@ $(function() {
ripple::test::jtx::finish
Json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
Definition: TestHelpers.cpp:230
ripple::test::jtx::XRP
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:104
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
+
ripple::tfSetDeepFreeze
constexpr std::uint32_t tfSetDeepFreeze
Definition: TxFlags.h:117
ripple::rpcACT_NOT_FOUND
@ rpcACT_NOT_FOUND
Definition: ErrorCodes.h:70
ripple::rpcACT_MALFORMED
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:557
-
ripple::tfSellNFToken
constexpr std::uint32_t const tfSellNFToken
Definition: TxFlags.h:187
+
ripple::tfSellNFToken
constexpr std::uint32_t const tfSellNFToken
Definition: TxFlags.h:189
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::tfSetfAuth
constexpr std::uint32_t tfSetfAuth
Definition: TxFlags.h:112
ripple::tfUniversal
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:61
@@ -1684,7 +1699,7 @@ $(function() {
ripple::asfRequireAuth
constexpr std::uint32_t asfRequireAuth
Definition: TxFlags.h:77
ripple::tfSetFreeze
constexpr std::uint32_t tfSetFreeze
Definition: TxFlags.h:115
ripple::tfSetNoRipple
constexpr std::uint32_t tfSetNoRipple
Definition: TxFlags.h:113
-
ripple::tfTransferable
constexpr std::uint32_t const tfTransferable
Definition: TxFlags.h:134
+
ripple::tfTransferable
constexpr std::uint32_t const tfTransferable
Definition: TxFlags.h:136
std::optional
std::vector::push_back
T push_back(T... args)
std::size
T size(T... args)
diff --git a/AccountObjects__test_8cpp_source.html b/AccountObjects__test_8cpp_source.html index 3de98ae724..f1fb880299 100644 --- a/AccountObjects__test_8cpp_source.html +++ b/AccountObjects__test_8cpp_source.html @@ -1600,7 +1600,7 @@ $(function() {
ripple::tfUniversal
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:61
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::HashPrefix::credential
@ credential
Credentials signature.
-
ripple::tfTransferable
constexpr std::uint32_t const tfTransferable
Definition: TxFlags.h:134
+
ripple::tfTransferable
constexpr std::uint32_t const tfTransferable
Definition: TxFlags.h:136
std::optional
std::vector::push_back
T push_back(T... args)
std::string::replace
T replace(T... args)
diff --git a/AccountOffers_8cpp_source.html b/AccountOffers_8cpp_source.html index 29741c8577..267109ea1b 100644 --- a/AccountOffers_8cpp_source.html +++ b/AccountOffers_8cpp_source.html @@ -294,7 +294,7 @@ $(function() {
ripple::doAccountOffers
Json::Value doAccountOffers(RPC::JsonContext &context)
Definition: AccountOffers.cpp:57
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::ltANY
@ ltANY
A special type, matching any ledger entry type.
Definition: LedgerFormats.h:78
-
ripple::forEachItemAfter
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.
Definition: View.cpp:495
+
ripple::forEachItemAfter
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.
Definition: View.cpp:534
ripple::appendOfferJson
void appendOfferJson(std::shared_ptr< SLE const > const &offer, Json::Value &offers)
Definition: AccountOffers.cpp:35
std::optional
std::shared_ptr
diff --git a/AccountSet__test_8cpp_source.html b/AccountSet__test_8cpp_source.html index b18a648d6b..e431445401 100644 --- a/AccountSet__test_8cpp_source.html +++ b/AccountSet__test_8cpp_source.html @@ -713,7 +713,7 @@ $(function() {
ripple::telBAD_DOMAIN
@ telBAD_DOMAIN
Definition: TER.h:53
ripple::asfRequireDest
constexpr std::uint32_t asfRequireDest
Definition: TxFlags.h:76
ripple::toAmount< STAmount >
STAmount toAmount< STAmount >(STAmount const &amt)
Definition: AmountConversions.h:68
-
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition: View.cpp:573
+
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition: View.cpp:612
ripple::asfAuthorizedNFTokenMinter
constexpr std::uint32_t asfAuthorizedNFTokenMinter
Definition: TxFlags.h:85
ripple::tfOptionalDestTag
constexpr std::uint32_t tfOptionalDestTag
Definition: TxFlags.h:66
ripple::tfAccountSetMask
constexpr std::uint32_t tfAccountSetMask
Definition: TxFlags.h:71
@@ -742,7 +742,7 @@ $(function() {
ripple::asfAllowTrustLineClawback
constexpr std::uint32_t asfAllowTrustLineClawback
Definition: TxFlags.h:93
ripple::asfRequireAuth
constexpr std::uint32_t asfRequireAuth
Definition: TxFlags.h:77
ripple::terPRE_TICKET
@ terPRE_TICKET
Definition: TER.h:226
-
ripple::dirIsEmpty
bool dirIsEmpty(ReadView const &view, Keylet const &k)
Returns true if the directory is empty.
Definition: View.cpp:705
+
ripple::dirIsEmpty
bool dirIsEmpty(ReadView const &view, Keylet const &k)
Returns true if the directory is empty.
Definition: View.cpp:744
ripple::asfDisallowXRP
constexpr std::uint32_t asfDisallowXRP
Definition: TxFlags.h:78
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:111
ripple::temBAD_TRANSFER_RATE
@ temBAD_TRANSFER_RATE
Definition: TER.h:107
diff --git a/AccountTx__test_8cpp_source.html b/AccountTx__test_8cpp_source.html index 6847ec644d..54adb81da7 100644 --- a/AccountTx__test_8cpp_source.html +++ b/AccountTx__test_8cpp_source.html @@ -917,7 +917,7 @@ $(function() {
ripple::tecNO_DST_INSUF_XRP
@ tecNO_DST_INSUF_XRP
Definition: TER.h:278
ripple::tfUniversal
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:61
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
-
ripple::tfClose
constexpr std::uint32_t tfClose
Definition: TxFlags.h:127
+
ripple::tfClose
constexpr std::uint32_t tfClose
Definition: TxFlags.h:129
ripple::HashPrefix::txNode
@ txNode
transaction plus metadata
std::size
T size(T... args)
ripple::JsonOptions::none
@ none
Definition: STBase.h:42
diff --git a/AmendmentTable_8cpp_source.html b/AmendmentTable_8cpp_source.html index f10489c8ad..53ccb03b18 100644 --- a/AmendmentTable_8cpp_source.html +++ b/AmendmentTable_8cpp_source.html @@ -1121,7 +1121,7 @@ $(function() {
ripple::AmendmentVote::obsolete
@ obsolete
ripple::AmendmentVote::up
@ up
ripple::AmendmentVote::down
@ down
-
ripple::tfGotMajority
constexpr std::uint32_t tfGotMajority
Definition: TxFlags.h:122
+
ripple::tfGotMajority
constexpr std::uint32_t tfGotMajority
Definition: TxFlags.h:124
ripple::isAdmin
bool isAdmin(Port const &port, Json::Value const &params, beast::IP::Address const &remoteIp)
Definition: Role.cpp:84
ripple::createFeatureVotes
bool createFeatureVotes(soci::session &session)
createFeatureVotes Creates the FeatureVote table if it does not exist.
Definition: Wallet.cpp:228
ripple::readAmendments
void readAmendments(soci::session &session, std::function< void(boost::optional< std::string > amendment_hash, boost::optional< std::string > amendment_name, boost::optional< AmendmentVote > vote)> const &callback)
readAmendments Reads all amendments from the FeatureVotes table.
Definition: Wallet.cpp:252
@@ -1135,7 +1135,7 @@ $(function() {
ripple::get
T get(Section const &section, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
Definition: BasicConfig.h:356
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:360
ripple::make_AmendmentTable
std::unique_ptr< AmendmentTable > make_AmendmentTable(Application &app, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
Definition: AmendmentTable.cpp:981
-
ripple::tfLostMajority
constexpr std::uint32_t tfLostMajority
Definition: TxFlags.h:123
+
ripple::tfLostMajority
constexpr std::uint32_t tfLostMajority
Definition: TxFlags.h:125
ripple::voteAmendment
void voteAmendment(soci::session &session, uint256 const &amendment, std::string const &name, AmendmentVote vote)
voteAmendment Set the veto value for a particular amendment.
Definition: Wallet.cpp:288
std::optional
std::pair
diff --git a/AmendmentTable_8h_source.html b/AmendmentTable_8h_source.html index 8f1e5781a8..1c6de6a295 100644 --- a/AmendmentTable_8h_source.html +++ b/AmendmentTable_8h_source.html @@ -291,10 +291,10 @@ $(function() {
std::map
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::isAdmin
bool isAdmin(Port const &port, Json::Value const &params, beast::IP::Address const &remoteIp)
Definition: Role.cpp:84
-
ripple::getEnabledAmendments
std::set< uint256 > getEnabledAmendments(ReadView const &view)
Definition: View.cpp:719
+
ripple::getEnabledAmendments
std::set< uint256 > getEnabledAmendments(ReadView const &view)
Definition: View.cpp:758
ripple::VoteBehavior
VoteBehavior
Definition: Feature.h:70
ripple::make_shamapitem
boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition: SHAMapItem.h:160
-
ripple::getMajorityAmendments
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition: View.cpp:736
+
ripple::getMajorityAmendments
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition: View.cpp:775
ripple::make_AmendmentTable
std::unique_ptr< AmendmentTable > make_AmendmentTable(Application &app, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
Definition: AmendmentTable.cpp:981
ripple::SHAMapNodeType::tnTRANSACTION_NM
@ tnTRANSACTION_NM
optional
diff --git a/AmendmentTable__test_8cpp_source.html b/AmendmentTable__test_8cpp_source.html index 27e818cbc5..464db140a1 100644 --- a/AmendmentTable__test_8cpp_source.html +++ b/AmendmentTable__test_8cpp_source.html @@ -1471,7 +1471,7 @@ $(function() {
ripple::test::jtx::supported_amendments
FeatureBitset supported_amendments()
Definition: Env.h:70
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::hash_append
void hash_append(Hasher &h, Slice const &v)
Definition: Slice.h:198
-
ripple::tfGotMajority
constexpr std::uint32_t tfGotMajority
Definition: TxFlags.h:122
+
ripple::tfGotMajority
constexpr std::uint32_t tfGotMajority
Definition: TxFlags.h:124
ripple::weeks
std::chrono::duration< int, std::ratio_multiply< days::period, std::ratio< 7 > > > weeks
Definition: chrono.h:44
ripple::QualityDirection::in
@ in
ripple::TxSearched::all
@ all
@@ -1484,7 +1484,7 @@ $(function() {
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
ripple::make_AmendmentTable
std::unique_ptr< AmendmentTable > make_AmendmentTable(Application &app, std::chrono::seconds majorityTime, std::vector< AmendmentTable::FeatureInfo > const &supported, Section const &enabled, Section const &vetoed, beast::Journal journal)
Definition: AmendmentTable.cpp:981
-
ripple::tfLostMajority
constexpr std::uint32_t tfLostMajority
Definition: TxFlags.h:123
+
ripple::tfLostMajority
constexpr std::uint32_t tfLostMajority
Definition: TxFlags.h:125
std::chrono
std::pair
std::vector::reserve
T reserve(T... args)
diff --git a/ApplyContext_8cpp_source.html b/ApplyContext_8cpp_source.html index 9acd850c45..0bbee98187 100644 --- a/ApplyContext_8cpp_source.html +++ b/ApplyContext_8cpp_source.html @@ -268,7 +268,7 @@ $(function() {
ripple::tefINVARIANT_FAILED
@ tefINVARIANT_FAILED
Definition: TER.h:183
ripple::tecINVARIANT_FAILED
@ tecINVARIANT_FAILED
Definition: TER.h:300
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
-
ripple::getInvariantChecks
InvariantChecks getInvariantChecks()
get a tuple of all invariant checks
Definition: InvariantCheck.h:539
+
ripple::getInvariantChecks
InvariantChecks getInvariantChecks()
get a tuple of all invariant checks
Definition: InvariantCheck.h:649
ripple::ApplyFlags
ApplyFlags
Definition: ApplyView.h:30
ripple::tapDRY_RUN
@ tapDRY_RUN
Definition: ApplyView.h:46
ripple::after
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition: Escrow.cpp:89
diff --git a/BookStep_8cpp_source.html b/BookStep_8cpp_source.html index bc3cd7d169..446a0433b7 100644 --- a/BookStep_8cpp_source.html +++ b/BookStep_8cpp_source.html @@ -1679,7 +1679,7 @@ $(function() {
ripple::StrandDirection::reverse
@ reverse
ripple::StrandDirection::forward
@ forward
ripple::getTradingFee
std::uint16_t getTradingFee(ReadView const &view, SLE const &ammSle, AccountID const &account)
Get AMM trading fee for the given account.
Definition: AMMUtils.cpp:145
-
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition: View.cpp:573
+
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition: View.cpp:612
ripple::lsfHighNoRipple
@ lsfHighNoRipple
Definition: LedgerFormats.h:162
ripple::lsfRequireAuth
@ lsfRequireAuth
Definition: LedgerFormats.h:128
ripple::lsfLowNoRipple
@ lsfLowNoRipple
Definition: LedgerFormats.h:161
diff --git a/BookTip_8cpp_source.html b/BookTip_8cpp_source.html index 89aae67ba7..d92705019f 100644 --- a/BookTip_8cpp_source.html +++ b/BookTip_8cpp_source.html @@ -178,7 +178,7 @@ $(function() {
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::getQuality
std::uint64_t getQuality(uint256 const &uBase)
Definition: Indexes.cpp:125
ripple::dirFirst
bool dirFirst(ApplyView &view, uint256 const &root, std::shared_ptr< SLE > &page, unsigned int &index, uint256 &entry)
Definition: View.cpp:114
-
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1010
+
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1054
ripple::getQualityNext
uint256 getQualityNext(uint256 const &uBase)
Definition: Indexes.cpp:117
ripple::getBookBase
uint256 getBookBase(Book const &book)
Definition: Indexes.cpp:98
std::shared_ptr
diff --git a/CancelCheck_8cpp_source.html b/CancelCheck_8cpp_source.html index 8357cd2de4..15ca0d1235 100644 --- a/CancelCheck_8cpp_source.html +++ b/CancelCheck_8cpp_source.html @@ -228,7 +228,7 @@ $(function() {
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:170
-
ripple::adjustOwnerCount
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
Definition: View.cpp:830
+
ripple::adjustOwnerCount
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
Definition: View.cpp:869
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:134
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:293
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:292
diff --git a/CancelOffer_8cpp_source.html b/CancelOffer_8cpp_source.html index 8638d41b60..afcb934eea 100644 --- a/CancelOffer_8cpp_source.html +++ b/CancelOffer_8cpp_source.html @@ -190,7 +190,7 @@ $(function() {
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
-
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1010
+
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1054
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:173
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:134
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
diff --git a/CashCheck_8cpp_source.html b/CashCheck_8cpp_source.html index 8a78102790..a1b42f7062 100644 --- a/CashCheck_8cpp_source.html +++ b/CashCheck_8cpp_source.html @@ -460,7 +460,7 @@ $(function() {
382 initialBalance.setIssuer(noAccount());
383
384 // clang-format off
-
385 if (TER const ter = trustCreate(
+
385 if (TER const ter = trustCreate(
386 psb, // payment sandbox
387 destLow, // is dest low?
388 issuer, // source
@@ -470,130 +470,131 @@ $(function() {
392 false, // authorize account
393 (sleDst->getFlags() & lsfDefaultRipple) == 0,
394 false, // freeze trust line
-
395 initialBalance, // zero initial balance
-
396 Issue(currency, account_), // limit of zero
-
397 0, // quality in
-
398 0, // quality out
-
399 viewJ); // journal
-
400 !isTesSuccess(ter))
-
401 {
-
402 return ter;
-
403 }
-
404 // clang-format on
-
405
-
406 psb.update(sleDst);
-
407
-
408 // Note that we _don't_ need to be careful about destroying
-
409 // the trust line if the check cashing fails. The transaction
-
410 // machinery will automatically clean it up.
-
411 }
-
412
-
413 // Since the destination is signing the check, they clearly want
-
414 // the funds even if their new total funds would exceed the limit
-
415 // on their trust line. So we tweak the trust line limits before
-
416 // calling flow and then restore the trust line limits afterwards.
-
417 auto const sleTrustLine = psb.peek(trustLineKey);
-
418 if (!sleTrustLine)
-
419 return tecNO_LINE;
-
420
-
421 SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
-
422 STAmount const savedLimit = sleTrustLine->at(tweakedLimit);
-
423
-
424 // Make sure the tweaked limits are restored when we leave scope.
-
425 scope_exit fixup(
-
426 [&psb, &trustLineKey, &tweakedLimit, &savedLimit]() {
-
427 if (auto const sleTrustLine = psb.peek(trustLineKey))
-
428 sleTrustLine->at(tweakedLimit) = savedLimit;
-
429 });
-
430
-
431 if (checkCashMakesTrustLine)
-
432 {
-
433 // Set the trust line limit to the highest possible value
-
434 // while flow runs.
-
435 STAmount const bigAmount(
-
436 trustLineIssue, STAmount::cMaxValue, STAmount::cMaxOffset);
-
437 sleTrustLine->at(tweakedLimit) = bigAmount;
-
438 }
-
439
-
440 // Let flow() do the heavy lifting on a check for an IOU.
-
441 auto const result = flow(
-
442 psb,
-
443 flowDeliver,
-
444 srcId,
-
445 account_,
-
446 STPathSet{},
-
447 true, // default path
-
448 static_cast<bool>(optDeliverMin), // partial payment
-
449 true, // owner pays transfer fee
-
450 OfferCrossing::no,
-
451 std::nullopt,
-
452 sleCheck->getFieldAmount(sfSendMax),
-
453 viewJ);
-
454
-
455 if (result.result() != tesSUCCESS)
-
456 {
-
457 JLOG(ctx_.journal.warn()) << "flow failed when cashing check.";
-
458 return result.result();
-
459 }
-
460
-
461 // Make sure that deliverMin was satisfied.
-
462 if (optDeliverMin)
-
463 {
-
464 if (result.actualAmountOut < *optDeliverMin)
-
465 {
-
466 JLOG(ctx_.journal.warn())
-
467 << "flow did not produce DeliverMin.";
-
468 return tecPATH_PARTIAL;
-
469 }
-
470 if (doFix1623 && !checkCashMakesTrustLine)
-
471 // Set the delivered_amount metadata.
-
472 ctx_.deliver(result.actualAmountOut);
-
473 }
-
474
-
475 // Set the delivered amount metadata in all cases, not just
-
476 // for DeliverMin.
-
477 if (checkCashMakesTrustLine)
-
478 ctx_.deliver(result.actualAmountOut);
-
479
-
480 sleCheck = psb.peek(keylet::check(ctx_.tx[sfCheckID]));
-
481 }
-
482 }
-
483
-
484 // Check was cashed. If not a self send (and it shouldn't be), remove
-
485 // check link from destination directory.
-
486 if (srcId != account_ &&
-
487 !psb.dirRemove(
-
488 keylet::ownerDir(account_),
-
489 sleCheck->at(sfDestinationNode),
-
490 sleCheck->key(),
-
491 true))
-
492 {
-
493 JLOG(j_.fatal()) << "Unable to delete check from destination.";
-
494 return tefBAD_LEDGER;
-
495 }
-
496
-
497 // Remove check from check owner's directory.
-
498 if (!psb.dirRemove(
-
499 keylet::ownerDir(srcId),
-
500 sleCheck->at(sfOwnerNode),
-
501 sleCheck->key(),
-
502 true))
-
503 {
-
504 JLOG(j_.fatal()) << "Unable to delete check from owner.";
-
505 return tefBAD_LEDGER;
-
506 }
-
507
-
508 // If we succeeded, update the check owner's reserve.
-
509 adjustOwnerCount(psb, psb.peek(keylet::account(srcId)), -1, viewJ);
-
510
-
511 // Remove check from ledger.
-
512 psb.erase(sleCheck);
-
513
-
514 psb.apply(ctx_.rawView());
-
515 return tesSUCCESS;
-
516}
-
517
-
518} // namespace ripple
+
395 false, // deep freeze trust line
+
396 initialBalance, // zero initial balance
+
397 Issue(currency, account_), // limit of zero
+
398 0, // quality in
+
399 0, // quality out
+
400 viewJ); // journal
+
401 !isTesSuccess(ter))
+
402 {
+
403 return ter;
+
404 }
+
405 // clang-format on
+
406
+
407 psb.update(sleDst);
+
408
+
409 // Note that we _don't_ need to be careful about destroying
+
410 // the trust line if the check cashing fails. The transaction
+
411 // machinery will automatically clean it up.
+
412 }
+
413
+
414 // Since the destination is signing the check, they clearly want
+
415 // the funds even if their new total funds would exceed the limit
+
416 // on their trust line. So we tweak the trust line limits before
+
417 // calling flow and then restore the trust line limits afterwards.
+
418 auto const sleTrustLine = psb.peek(trustLineKey);
+
419 if (!sleTrustLine)
+
420 return tecNO_LINE;
+
421
+
422 SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
+
423 STAmount const savedLimit = sleTrustLine->at(tweakedLimit);
+
424
+
425 // Make sure the tweaked limits are restored when we leave scope.
+
426 scope_exit fixup(
+
427 [&psb, &trustLineKey, &tweakedLimit, &savedLimit]() {
+
428 if (auto const sleTrustLine = psb.peek(trustLineKey))
+
429 sleTrustLine->at(tweakedLimit) = savedLimit;
+
430 });
+
431
+
432 if (checkCashMakesTrustLine)
+
433 {
+
434 // Set the trust line limit to the highest possible value
+
435 // while flow runs.
+
436 STAmount const bigAmount(
+
437 trustLineIssue, STAmount::cMaxValue, STAmount::cMaxOffset);
+
438 sleTrustLine->at(tweakedLimit) = bigAmount;
+
439 }
+
440
+
441 // Let flow() do the heavy lifting on a check for an IOU.
+
442 auto const result = flow(
+
443 psb,
+
444 flowDeliver,
+
445 srcId,
+
446 account_,
+
447 STPathSet{},
+
448 true, // default path
+
449 static_cast<bool>(optDeliverMin), // partial payment
+
450 true, // owner pays transfer fee
+
451 OfferCrossing::no,
+
452 std::nullopt,
+
453 sleCheck->getFieldAmount(sfSendMax),
+
454 viewJ);
+
455
+
456 if (result.result() != tesSUCCESS)
+
457 {
+
458 JLOG(ctx_.journal.warn()) << "flow failed when cashing check.";
+
459 return result.result();
+
460 }
+
461
+
462 // Make sure that deliverMin was satisfied.
+
463 if (optDeliverMin)
+
464 {
+
465 if (result.actualAmountOut < *optDeliverMin)
+
466 {
+
467 JLOG(ctx_.journal.warn())
+
468 << "flow did not produce DeliverMin.";
+
469 return tecPATH_PARTIAL;
+
470 }
+
471 if (doFix1623 && !checkCashMakesTrustLine)
+
472 // Set the delivered_amount metadata.
+
473 ctx_.deliver(result.actualAmountOut);
+
474 }
+
475
+
476 // Set the delivered amount metadata in all cases, not just
+
477 // for DeliverMin.
+
478 if (checkCashMakesTrustLine)
+
479 ctx_.deliver(result.actualAmountOut);
+
480
+
481 sleCheck = psb.peek(keylet::check(ctx_.tx[sfCheckID]));
+
482 }
+
483 }
+
484
+
485 // Check was cashed. If not a self send (and it shouldn't be), remove
+
486 // check link from destination directory.
+
487 if (srcId != account_ &&
+
488 !psb.dirRemove(
+
489 keylet::ownerDir(account_),
+
490 sleCheck->at(sfDestinationNode),
+
491 sleCheck->key(),
+
492 true))
+
493 {
+
494 JLOG(j_.fatal()) << "Unable to delete check from destination.";
+
495 return tefBAD_LEDGER;
+
496 }
+
497
+
498 // Remove check from check owner's directory.
+
499 if (!psb.dirRemove(
+
500 keylet::ownerDir(srcId),
+
501 sleCheck->at(sfOwnerNode),
+
502 sleCheck->key(),
+
503 true))
+
504 {
+
505 JLOG(j_.fatal()) << "Unable to delete check from owner.";
+
506 return tefBAD_LEDGER;
+
507 }
+
508
+
509 // If we succeeded, update the check owner's reserve.
+
510 adjustOwnerCount(psb, psb.peek(keylet::account(srcId)), -1, viewJ);
+
511
+
512 // Remove check from ledger.
+
513 psb.erase(sleCheck);
+
514
+
515 psb.apply(ctx_.rawView());
+
516 return tesSUCCESS;
+
517}
+
518
+
519} // namespace ripple
algorithm
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:341
beast::Journal::error
Stream error() const
Definition: Journal.h:335
@@ -652,7 +653,7 @@ $(function() {
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:177
ripple::badCurrency
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
Definition: UintTypes.cpp:129
-
ripple::accountFunds
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition: View.cpp:366
+
ripple::accountFunds
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition: View.cpp:405
ripple::fhZERO_IF_FROZEN
@ fhZERO_IF_FROZEN
Definition: View.h:80
ripple::isLegalNet
bool isLegalNet(STAmount const &value)
Definition: STAmount.h:581
ripple::lsfRequireDestTag
@ lsfRequireDestTag
Definition: LedgerFormats.h:126
@@ -662,14 +663,14 @@ $(function() {
ripple::lsfLowAuth
@ lsfLowAuth
Definition: LedgerFormats.h:159
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
-
ripple::transferXRP
TER transferXRP(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &amount, beast::Journal j)
Definition: View.cpp:1772
+
ripple::transferXRP
TER transferXRP(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &amount, beast::Journal j)
Definition: View.cpp:1818
ripple::flow
StrandResult< TInAmt, TOutAmt > flow(PaymentSandbox const &baseView, Strand const &strand, std::optional< TInAmt > const &maxIn, TOutAmt const &out, beast::Journal j)
Request out amount from a strand.
Definition: StrandFlow.h:106
ripple::isFrozen
bool isFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition: View.cpp:238
-
ripple::trustCreate
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.
Definition: View.cpp:856
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:170
ripple::no
@ no
Definition: Steps.h:42
ripple::adjustOwnerCount
static bool adjustOwnerCount(ApplyContext &ctx, int count)
Definition: SetOracle.cpp:186
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:134
+
ripple::trustCreate
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, bool bDeepFreeze, STAmount const &saBalance, STAmount const &saLimit, std::uint32_t uQualityIn, std::uint32_t uQualityOut, beast::Journal j)
Create a trust line.
Definition: View.cpp:895
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:293
ripple::tecNO_LINE_INSUF_RESERVE
@ tecNO_LINE_INSUF_RESERVE
Definition: TER.h:279
ripple::tecNO_ISSUER
@ tecNO_ISSUER
Definition: TER.h:286
@@ -688,7 +689,7 @@ $(function() {
ripple::tfUniversalMask
constexpr std::uint32_t tfUniversalMask
Definition: TxFlags.h:62
ripple::hasExpired
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
Definition: View.cpp:164
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:587
-
ripple::xrpLiquid
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
Definition: View.cpp:430
+
ripple::xrpLiquid
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
Definition: View.cpp:469
ripple::temBAD_AMOUNT
@ temBAD_AMOUNT
Definition: TER.h:89
ripple::temBAD_CURRENCY
@ temBAD_CURRENCY
Definition: TER.h:90
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:87
diff --git a/Change_8cpp_source.html b/Change_8cpp_source.html index b91633131f..d801607e62 100644 --- a/Change_8cpp_source.html +++ b/Change_8cpp_source.html @@ -656,7 +656,7 @@ $(function() {
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:106
ripple::preflight0
NotTEC preflight0(PreflightContext const &ctx)
Performs early sanity checks on the txid.
Definition: Transactor.cpp:42
-
ripple::tfGotMajority
constexpr std::uint32_t tfGotMajority
Definition: TxFlags.h:122
+
ripple::tfGotMajority
constexpr std::uint32_t tfGotMajority
Definition: TxFlags.h:124
ripple::lsfHighReserve
@ lsfHighReserve
Definition: LedgerFormats.h:158
ripple::lsfLowReserve
@ lsfLowReserve
Definition: LedgerFormats.h:157
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:316
@@ -669,7 +669,7 @@ $(function() {
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:243
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
-
ripple::tfLostMajority
constexpr std::uint32_t tfLostMajority
Definition: TxFlags.h:123
+
ripple::tfLostMajority
constexpr std::uint32_t tfLostMajority
Definition: TxFlags.h:125
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:587
ripple::temBAD_SRC_ACCOUNT
@ temBAD_SRC_ACCOUNT
Definition: TER.h:106
ripple::temUNKNOWN
@ temUNKNOWN
Definition: TER.h:124
diff --git a/Check__test_8cpp_source.html b/Check__test_8cpp_source.html index fd797a8377..53791a4ff5 100644 --- a/Check__test_8cpp_source.html +++ b/Check__test_8cpp_source.html @@ -2885,7 +2885,7 @@ $(function() {
ripple::tecEXPIRED
@ tecEXPIRED
Definition: TER.h:301
ripple::tecNO_AUTH
@ tecNO_AUTH
Definition: TER.h:287
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
-
ripple::forEachItem
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.
Definition: View.cpp:467
+
ripple::forEachItem
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.
Definition: View.cpp:506
ripple::asfRequireAuth
constexpr std::uint32_t asfRequireAuth
Definition: TxFlags.h:77
ripple::terNO_RIPPLE
@ terNO_RIPPLE
Definition: TER.h:224
ripple::terNO_LINE
@ terNO_LINE
Definition: TER.h:219
diff --git a/Clawback_8cpp_source.html b/Clawback_8cpp_source.html index d27d424651..a5eb72f7b2 100644 --- a/Clawback_8cpp_source.html +++ b/Clawback_8cpp_source.html @@ -403,9 +403,9 @@ $(function() {
ripple::fhIGNORE_FREEZE
@ fhIGNORE_FREEZE
Definition: View.h:80
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
ripple::preflightHelper
static NotTEC preflightHelper(PreflightContext const &ctx)
-
ripple::tfClawbackMask
constexpr std::uint32_t const tfClawbackMask
Definition: TxFlags.h:198
+
ripple::tfClawbackMask
constexpr std::uint32_t const tfClawbackMask
Definition: TxFlags.h:200
ripple::lsfAllowTrustLineClawback
@ lsfAllowTrustLineClawback
Definition: LedgerFormats.h:149
-
ripple::lsfMPTCanClawback
@ lsfMPTCanClawback
Definition: LedgerFormats.h:185
+
ripple::lsfMPTCanClawback
@ lsfMPTCanClawback
Definition: LedgerFormats.h:187
ripple::lsfNoFreeze
@ lsfNoFreeze
Definition: LedgerFormats.h:132
ripple::preclaimHelper< MPTIssue >
TER preclaimHelper< MPTIssue >(PreclaimContext const &ctx, SLE const &sleIssuer, AccountID const &issuer, AccountID const &holder, STAmount const &clawAmount)
Definition: Clawback.cpp:163
ripple::ahIGNORE_AUTH
@ ahIGNORE_AUTH
Definition: View.h:83
@@ -424,10 +424,10 @@ $(function() {
ripple::tecNO_LINE
@ tecNO_LINE
Definition: TER.h:288
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
ripple::applyHelper
static TER applyHelper(ApplyContext &ctx)
-
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:271
+
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:297
ripple::preclaimHelper
static TER preclaimHelper(PreclaimContext const &ctx, SLE const &sleIssuer, AccountID const &issuer, AccountID const &holder, STAmount const &clawAmount)
ripple::applyHelper< MPTIssue >
TER applyHelper< MPTIssue >(ApplyContext &ctx)
Definition: Clawback.cpp:258
-
ripple::rippleCredit
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
Definition: View.cpp:2015
+
ripple::rippleCredit
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
Definition: View.cpp:2061
ripple::terNO_ACCOUNT
@ terNO_ACCOUNT
Definition: TER.h:217
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:627
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:587
diff --git a/CreateCheck_8cpp_source.html b/CreateCheck_8cpp_source.html index e4cbb72ba9..dc9fa14e0f 100644 --- a/CreateCheck_8cpp_source.html +++ b/CreateCheck_8cpp_source.html @@ -366,7 +366,7 @@ $(function() {
ripple::lsfDisallowIncomingCheck
@ lsfDisallowIncomingCheck
Definition: LedgerFormats.h:142
ripple::lsfLowFreeze
@ lsfLowFreeze
Definition: LedgerFormats.h:163
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
-
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:848
+
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:887
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:173
ripple::adjustOwnerCount
static bool adjustOwnerCount(ApplyContext &ctx, int count)
Definition: SetOracle.cpp:186
diff --git a/CreateOffer_8cpp_source.html b/CreateOffer_8cpp_source.html index 1da74a7d20..ee668dcbed 100644 --- a/CreateOffer_8cpp_source.html +++ b/CreateOffer_8cpp_source.html @@ -337,1011 +337,1037 @@ $(function() {
259 }
260 }
261
-
262 return tesSUCCESS;
-
263}
-
264
-
265bool
-
266CreateOffer::dry_offer(ApplyView& view, Offer const& offer)
-
267{
-
268 if (offer.fully_consumed())
-
269 return true;
-
270 auto const amount = accountFunds(
-
271 view,
-
272 offer.owner(),
-
273 offer.amount().out,
-
274 fhZERO_IF_FROZEN,
-
275 ctx_.app.journal("View"));
-
276 return (amount <= beast::zero);
-
277}
-
278
-
279std::pair<bool, Quality>
-
280CreateOffer::select_path(
-
281 bool have_direct,
-
282 OfferStream const& direct,
-
283 bool have_bridge,
-
284 OfferStream const& leg1,
-
285 OfferStream const& leg2)
-
286{
-
287 // If we don't have any viable path, why are we here?!
-
288 XRPL_ASSERT(
-
289 have_direct || have_bridge,
-
290 "ripple::CreateOffer::select_path : valid inputs");
-
291
-
292 // If there's no bridged path, the direct is the best by default.
-
293 if (!have_bridge)
-
294 return std::make_pair(true, direct.tip().quality());
-
295
-
296 Quality const bridged_quality(
-
297 composed_quality(leg1.tip().quality(), leg2.tip().quality()));
-
298
-
299 if (have_direct)
-
300 {
-
301 // We compare the quality of the composed quality of the bridged
-
302 // offers and compare it against the direct offer to pick the best.
-
303 Quality const direct_quality(direct.tip().quality());
+
262 // An account can not create a trustline to itself, so no line can exist
+
263 // to be frozen. Additionally, an issuer can always accept its own
+
264 // issuance.
+
265 if (issue.account == id)
+
266 {
+
267 return tesSUCCESS;
+
268 }
+
269
+
270 auto const trustLine =
+
271 view.read(keylet::line(id, issue.account, issue.currency));
+
272
+
273 if (!trustLine)
+
274 {
+
275 return tesSUCCESS;
+
276 }
+
277
+
278 // There's no difference which side enacted deep freeze, accepting
+
279 // tokens shouldn't be possible.
+
280 bool const deepFrozen =
+
281 (*trustLine)[sfFlags] & (lsfLowDeepFreeze | lsfHighDeepFreeze);
+
282
+
283 if (deepFrozen)
+
284 {
+
285 return tecFROZEN;
+
286 }
+
287
+
288 return tesSUCCESS;
+
289}
+
290
+
291bool
+
292CreateOffer::dry_offer(ApplyView& view, Offer const& offer)
+
293{
+
294 if (offer.fully_consumed())
+
295 return true;
+
296 auto const amount = accountFunds(
+
297 view,
+
298 offer.owner(),
+
299 offer.amount().out,
+
300 fhZERO_IF_FROZEN,
+
301 ctx_.app.journal("View"));
+
302 return (amount <= beast::zero);
+
303}
304
-
305 if (bridged_quality < direct_quality)
-
306 return std::make_pair(true, direct_quality);
-
307 }
-
308
-
309 // Either there was no direct offer, or it didn't have a better quality
-
310 // than the bridge.
-
311 return std::make_pair(false, bridged_quality);
-
312}
-
313
-
314bool
-
315CreateOffer::reachedOfferCrossingLimit(Taker const& taker) const
-
316{
-
317 auto const crossings =
-
318 taker.get_direct_crossings() + (2 * taker.get_bridge_crossings());
-
319
-
320 // The crossing limit is part of the Ripple protocol and
-
321 // changing it is a transaction-processing change.
-
322 return crossings >= 850;
-
323}
+
305std::pair<bool, Quality>
+
306CreateOffer::select_path(
+
307 bool have_direct,
+
308 OfferStream const& direct,
+
309 bool have_bridge,
+
310 OfferStream const& leg1,
+
311 OfferStream const& leg2)
+
312{
+
313 // If we don't have any viable path, why are we here?!
+
314 XRPL_ASSERT(
+
315 have_direct || have_bridge,
+
316 "ripple::CreateOffer::select_path : valid inputs");
+
317
+
318 // If there's no bridged path, the direct is the best by default.
+
319 if (!have_bridge)
+
320 return std::make_pair(true, direct.tip().quality());
+
321
+
322 Quality const bridged_quality(
+
323 composed_quality(leg1.tip().quality(), leg2.tip().quality()));
324
-
325std::pair<TER, Amounts>
-
326CreateOffer::bridged_cross(
-
327 Taker& taker,
-
328 ApplyView& view,
-
329 ApplyView& view_cancel,
-
330 NetClock::time_point const when)
-
331{
-
332 auto const& takerAmount = taker.original_offer();
-
333
-
334 XRPL_ASSERT(
-
335 !isXRP(takerAmount.in) && !isXRP(takerAmount.out),
-
336 "ripple::CreateOffer::bridged_cross : neither is XRP");
-
337
-
338 if (isXRP(takerAmount.in) || isXRP(takerAmount.out))
-
339 Throw<std::logic_error>("Bridging with XRP and an endpoint.");
-
340
-
341 OfferStream offers_direct(
-
342 view,
-
343 view_cancel,
-
344 Book(taker.issue_in(), taker.issue_out()),
-
345 when,
-
346 stepCounter_,
-
347 j_);
-
348
-
349 OfferStream offers_leg1(
-
350 view,
-
351 view_cancel,
-
352 Book(taker.issue_in(), xrpIssue()),
-
353 when,
-
354 stepCounter_,
-
355 j_);
-
356
-
357 OfferStream offers_leg2(
-
358 view,
-
359 view_cancel,
-
360 Book(xrpIssue(), taker.issue_out()),
-
361 when,
-
362 stepCounter_,
-
363 j_);
-
364
-
365 TER cross_result = tesSUCCESS;
+
325 if (have_direct)
+
326 {
+
327 // We compare the quality of the composed quality of the bridged
+
328 // offers and compare it against the direct offer to pick the best.
+
329 Quality const direct_quality(direct.tip().quality());
+
330
+
331 if (bridged_quality < direct_quality)
+
332 return std::make_pair(true, direct_quality);
+
333 }
+
334
+
335 // Either there was no direct offer, or it didn't have a better quality
+
336 // than the bridge.
+
337 return std::make_pair(false, bridged_quality);
+
338}
+
339
+
340bool
+
341CreateOffer::reachedOfferCrossingLimit(Taker const& taker) const
+
342{
+
343 auto const crossings =
+
344 taker.get_direct_crossings() + (2 * taker.get_bridge_crossings());
+
345
+
346 // The crossing limit is part of the Ripple protocol and
+
347 // changing it is a transaction-processing change.
+
348 return crossings >= 850;
+
349}
+
350
+
351std::pair<TER, Amounts>
+
352CreateOffer::bridged_cross(
+
353 Taker& taker,
+
354 ApplyView& view,
+
355 ApplyView& view_cancel,
+
356 NetClock::time_point const when)
+
357{
+
358 auto const& takerAmount = taker.original_offer();
+
359
+
360 XRPL_ASSERT(
+
361 !isXRP(takerAmount.in) && !isXRP(takerAmount.out),
+
362 "ripple::CreateOffer::bridged_cross : neither is XRP");
+
363
+
364 if (isXRP(takerAmount.in) || isXRP(takerAmount.out))
+
365 Throw<std::logic_error>("Bridging with XRP and an endpoint.");
366
-
367 // Note the subtle distinction here: self-offers encountered in the
-
368 // bridge are taken, but self-offers encountered in the direct book
-
369 // are not.
-
370 bool have_bridge = offers_leg1.step() && offers_leg2.step();
-
371 bool have_direct = step_account(offers_direct, taker);
-
372 int count = 0;
-
373
-
374 auto viewJ = ctx_.app.journal("View");
-
375
-
376 // Modifying the order or logic of the operations in the loop will cause
-
377 // a protocol breaking change.
-
378 while (have_direct || have_bridge)
-
379 {
-
380 bool leg1_consumed = false;
-
381 bool leg2_consumed = false;
-
382 bool direct_consumed = false;
-
383
-
384 auto const [use_direct, quality] = select_path(
-
385 have_direct, offers_direct, have_bridge, offers_leg1, offers_leg2);
-
386
-
387 // We are always looking at the best quality; we are done with
-
388 // crossing as soon as we cross the quality boundary.
-
389 if (taker.reject(quality))
-
390 break;
-
391
-
392 count++;
-
393
-
394 if (use_direct)
-
395 {
-
396 if (auto stream = j_.debug())
-
397 {
-
398 stream << count << " Direct:";
-
399 stream << " offer: " << offers_direct.tip();
-
400 stream << " in: " << offers_direct.tip().amount().in;
-
401 stream << " out: " << offers_direct.tip().amount().out;
-
402 stream << " owner: " << offers_direct.tip().owner();
-
403 stream << " funds: "
-
404 << accountFunds(
-
405 view,
-
406 offers_direct.tip().owner(),
-
407 offers_direct.tip().amount().out,
-
408 fhIGNORE_FREEZE,
-
409 viewJ);
-
410 }
-
411
-
412 cross_result = taker.cross(offers_direct.tip());
-
413
-
414 JLOG(j_.debug()) << "Direct Result: " << transToken(cross_result);
-
415
-
416 if (dry_offer(view, offers_direct.tip()))
-
417 {
-
418 direct_consumed = true;
-
419 have_direct = step_account(offers_direct, taker);
-
420 }
-
421 }
-
422 else
-
423 {
-
424 if (auto stream = j_.debug())
-
425 {
-
426 auto const owner1_funds_before = accountFunds(
-
427 view,
-
428 offers_leg1.tip().owner(),
-
429 offers_leg1.tip().amount().out,
-
430 fhIGNORE_FREEZE,
-
431 viewJ);
-
432
-
433 auto const owner2_funds_before = accountFunds(
-
434 view,
-
435 offers_leg2.tip().owner(),
-
436 offers_leg2.tip().amount().out,
-
437 fhIGNORE_FREEZE,
-
438 viewJ);
+
367 OfferStream offers_direct(
+
368 view,
+
369 view_cancel,
+
370 Book(taker.issue_in(), taker.issue_out()),
+
371 when,
+
372 stepCounter_,
+
373 j_);
+
374
+
375 OfferStream offers_leg1(
+
376 view,
+
377 view_cancel,
+
378 Book(taker.issue_in(), xrpIssue()),
+
379 when,
+
380 stepCounter_,
+
381 j_);
+
382
+
383 OfferStream offers_leg2(
+
384 view,
+
385 view_cancel,
+
386 Book(xrpIssue(), taker.issue_out()),
+
387 when,
+
388 stepCounter_,
+
389 j_);
+
390
+
391 TER cross_result = tesSUCCESS;
+
392
+
393 // Note the subtle distinction here: self-offers encountered in the
+
394 // bridge are taken, but self-offers encountered in the direct book
+
395 // are not.
+
396 bool have_bridge = offers_leg1.step() && offers_leg2.step();
+
397 bool have_direct = step_account(offers_direct, taker);
+
398 int count = 0;
+
399
+
400 auto viewJ = ctx_.app.journal("View");
+
401
+
402 // Modifying the order or logic of the operations in the loop will cause
+
403 // a protocol breaking change.
+
404 while (have_direct || have_bridge)
+
405 {
+
406 bool leg1_consumed = false;
+
407 bool leg2_consumed = false;
+
408 bool direct_consumed = false;
+
409
+
410 auto const [use_direct, quality] = select_path(
+
411 have_direct, offers_direct, have_bridge, offers_leg1, offers_leg2);
+
412
+
413 // We are always looking at the best quality; we are done with
+
414 // crossing as soon as we cross the quality boundary.
+
415 if (taker.reject(quality))
+
416 break;
+
417
+
418 count++;
+
419
+
420 if (use_direct)
+
421 {
+
422 if (auto stream = j_.debug())
+
423 {
+
424 stream << count << " Direct:";
+
425 stream << " offer: " << offers_direct.tip();
+
426 stream << " in: " << offers_direct.tip().amount().in;
+
427 stream << " out: " << offers_direct.tip().amount().out;
+
428 stream << " owner: " << offers_direct.tip().owner();
+
429 stream << " funds: "
+
430 << accountFunds(
+
431 view,
+
432 offers_direct.tip().owner(),
+
433 offers_direct.tip().amount().out,
+
434 fhIGNORE_FREEZE,
+
435 viewJ);
+
436 }
+
437
+
438 cross_result = taker.cross(offers_direct.tip());
439
-
440 stream << count << " Bridge:";
-
441 stream << " offer1: " << offers_leg1.tip();
-
442 stream << " in: " << offers_leg1.tip().amount().in;
-
443 stream << " out: " << offers_leg1.tip().amount().out;
-
444 stream << " owner: " << offers_leg1.tip().owner();
-
445 stream << " funds: " << owner1_funds_before;
-
446 stream << " offer2: " << offers_leg2.tip();
-
447 stream << " in: " << offers_leg2.tip().amount().in;
-
448 stream << " out: " << offers_leg2.tip().amount().out;
-
449 stream << " owner: " << offers_leg2.tip().owner();
-
450 stream << " funds: " << owner2_funds_before;
-
451 }
-
452
-
453 cross_result = taker.cross(offers_leg1.tip(), offers_leg2.tip());
-
454
-
455 JLOG(j_.debug()) << "Bridge Result: " << transToken(cross_result);
-
456
-
457 if (view.rules().enabled(fixTakerDryOfferRemoval))
-
458 {
-
459 // have_bridge can be true the next time 'round only if
-
460 // neither of the OfferStreams are dry.
-
461 leg1_consumed = dry_offer(view, offers_leg1.tip());
-
462 if (leg1_consumed)
-
463 have_bridge &= offers_leg1.step();
-
464
-
465 leg2_consumed = dry_offer(view, offers_leg2.tip());
-
466 if (leg2_consumed)
-
467 have_bridge &= offers_leg2.step();
-
468 }
-
469 else
-
470 {
-
471 // This old behavior may leave an empty offer in the book for
-
472 // the second leg.
-
473 if (dry_offer(view, offers_leg1.tip()))
-
474 {
-
475 leg1_consumed = true;
-
476 have_bridge = (have_bridge && offers_leg1.step());
-
477 }
-
478 if (dry_offer(view, offers_leg2.tip()))
-
479 {
-
480 leg2_consumed = true;
-
481 have_bridge = (have_bridge && offers_leg2.step());
-
482 }
-
483 }
-
484 }
-
485
-
486 if (cross_result != tesSUCCESS)
-
487 {
-
488 cross_result = tecFAILED_PROCESSING;
-
489 break;
-
490 }
-
491
-
492 if (taker.done())
-
493 {
-
494 JLOG(j_.debug()) << "The taker reports he's done during crossing!";
-
495 break;
-
496 }
-
497
-
498 if (reachedOfferCrossingLimit(taker))
-
499 {
-
500 JLOG(j_.debug()) << "The offer crossing limit has been exceeded!";
-
501 break;
-
502 }
-
503
-
504 // Postcondition: If we aren't done, then we *must* have consumed at
-
505 // least one offer fully.
-
506 XRPL_ASSERT(
-
507 direct_consumed || leg1_consumed || leg2_consumed,
-
508 "ripple::CreateOffer::bridged_cross : consumed an offer");
-
509
-
510 if (!direct_consumed && !leg1_consumed && !leg2_consumed)
-
511 Throw<std::logic_error>(
-
512 "bridged crossing: nothing was fully consumed.");
-
513 }
-
514
-
515 return std::make_pair(cross_result, taker.remaining_offer());
-
516}
+
440 JLOG(j_.debug()) << "Direct Result: " << transToken(cross_result);
+
441
+
442 if (dry_offer(view, offers_direct.tip()))
+
443 {
+
444 direct_consumed = true;
+
445 have_direct = step_account(offers_direct, taker);
+
446 }
+
447 }
+
448 else
+
449 {
+
450 if (auto stream = j_.debug())
+
451 {
+
452 auto const owner1_funds_before = accountFunds(
+
453 view,
+
454 offers_leg1.tip().owner(),
+
455 offers_leg1.tip().amount().out,
+
456 fhIGNORE_FREEZE,
+
457 viewJ);
+
458
+
459 auto const owner2_funds_before = accountFunds(
+
460 view,
+
461 offers_leg2.tip().owner(),
+
462 offers_leg2.tip().amount().out,
+
463 fhIGNORE_FREEZE,
+
464 viewJ);
+
465
+
466 stream << count << " Bridge:";
+
467 stream << " offer1: " << offers_leg1.tip();
+
468 stream << " in: " << offers_leg1.tip().amount().in;
+
469 stream << " out: " << offers_leg1.tip().amount().out;
+
470 stream << " owner: " << offers_leg1.tip().owner();
+
471 stream << " funds: " << owner1_funds_before;
+
472 stream << " offer2: " << offers_leg2.tip();
+
473 stream << " in: " << offers_leg2.tip().amount().in;
+
474 stream << " out: " << offers_leg2.tip().amount().out;
+
475 stream << " owner: " << offers_leg2.tip().owner();
+
476 stream << " funds: " << owner2_funds_before;
+
477 }
+
478
+
479 cross_result = taker.cross(offers_leg1.tip(), offers_leg2.tip());
+
480
+
481 JLOG(j_.debug()) << "Bridge Result: " << transToken(cross_result);
+
482
+
483 if (view.rules().enabled(fixTakerDryOfferRemoval))
+
484 {
+
485 // have_bridge can be true the next time 'round only if
+
486 // neither of the OfferStreams are dry.
+
487 leg1_consumed = dry_offer(view, offers_leg1.tip());
+
488 if (leg1_consumed)
+
489 have_bridge &= offers_leg1.step();
+
490
+
491 leg2_consumed = dry_offer(view, offers_leg2.tip());
+
492 if (leg2_consumed)
+
493 have_bridge &= offers_leg2.step();
+
494 }
+
495 else
+
496 {
+
497 // This old behavior may leave an empty offer in the book for
+
498 // the second leg.
+
499 if (dry_offer(view, offers_leg1.tip()))
+
500 {
+
501 leg1_consumed = true;
+
502 have_bridge = (have_bridge && offers_leg1.step());
+
503 }
+
504 if (dry_offer(view, offers_leg2.tip()))
+
505 {
+
506 leg2_consumed = true;
+
507 have_bridge = (have_bridge && offers_leg2.step());
+
508 }
+
509 }
+
510 }
+
511
+
512 if (cross_result != tesSUCCESS)
+
513 {
+
514 cross_result = tecFAILED_PROCESSING;
+
515 break;
+
516 }
517
-
518std::pair<TER, Amounts>
-
519CreateOffer::direct_cross(
-
520 Taker& taker,
-
521 ApplyView& view,
-
522 ApplyView& view_cancel,
-
523 NetClock::time_point const when)
-
524{
-
525 OfferStream offers(
-
526 view,
-
527 view_cancel,
-
528 Book(taker.issue_in(), taker.issue_out()),
-
529 when,
-
530 stepCounter_,
-
531 j_);
-
532
-
533 TER cross_result(tesSUCCESS);
-
534 int count = 0;
+
518 if (taker.done())
+
519 {
+
520 JLOG(j_.debug()) << "The taker reports he's done during crossing!";
+
521 break;
+
522 }
+
523
+
524 if (reachedOfferCrossingLimit(taker))
+
525 {
+
526 JLOG(j_.debug()) << "The offer crossing limit has been exceeded!";
+
527 break;
+
528 }
+
529
+
530 // Postcondition: If we aren't done, then we *must* have consumed at
+
531 // least one offer fully.
+
532 XRPL_ASSERT(
+
533 direct_consumed || leg1_consumed || leg2_consumed,
+
534 "ripple::CreateOffer::bridged_cross : consumed an offer");
535
-
536 bool have_offer = step_account(offers, taker);
-
537
-
538 // Modifying the order or logic of the operations in the loop will cause
-
539 // a protocol breaking change.
-
540 while (have_offer)
-
541 {
-
542 bool direct_consumed = false;
-
543 auto& offer(offers.tip());
-
544
-
545 // We are done with crossing as soon as we cross the quality boundary
-
546 if (taker.reject(offer.quality()))
-
547 break;
-
548
-
549 count++;
-
550
-
551 if (auto stream = j_.debug())
-
552 {
-
553 stream << count << " Direct:";
-
554 stream << " offer: " << offer;
-
555 stream << " in: " << offer.amount().in;
-
556 stream << " out: " << offer.amount().out;
-
557 stream << "quality: " << offer.quality();
-
558 stream << " owner: " << offer.owner();
-
559 stream << " funds: "
-
560 << accountFunds(
-
561 view,
-
562 offer.owner(),
-
563 offer.amount().out,
-
564 fhIGNORE_FREEZE,
-
565 ctx_.app.journal("View"));
-
566 }
-
567
-
568 cross_result = taker.cross(offer);
-
569
-
570 JLOG(j_.debug()) << "Direct Result: " << transToken(cross_result);
-
571
-
572 if (dry_offer(view, offer))
-
573 {
-
574 direct_consumed = true;
-
575 have_offer = step_account(offers, taker);
-
576 }
-
577
-
578 if (cross_result != tesSUCCESS)
-
579 {
-
580 cross_result = tecFAILED_PROCESSING;
-
581 break;
-
582 }
-
583
-
584 if (taker.done())
-
585 {
-
586 JLOG(j_.debug()) << "The taker reports he's done during crossing!";
-
587 break;
-
588 }
-
589
-
590 if (reachedOfferCrossingLimit(taker))
-
591 {
-
592 JLOG(j_.debug()) << "The offer crossing limit has been exceeded!";
-
593 break;
-
594 }
+
536 if (!direct_consumed && !leg1_consumed && !leg2_consumed)
+
537 Throw<std::logic_error>(
+
538 "bridged crossing: nothing was fully consumed.");
+
539 }
+
540
+
541 return std::make_pair(cross_result, taker.remaining_offer());
+
542}
+
543
+
544std::pair<TER, Amounts>
+
545CreateOffer::direct_cross(
+
546 Taker& taker,
+
547 ApplyView& view,
+
548 ApplyView& view_cancel,
+
549 NetClock::time_point const when)
+
550{
+
551 OfferStream offers(
+
552 view,
+
553 view_cancel,
+
554 Book(taker.issue_in(), taker.issue_out()),
+
555 when,
+
556 stepCounter_,
+
557 j_);
+
558
+
559 TER cross_result(tesSUCCESS);
+
560 int count = 0;
+
561
+
562 bool have_offer = step_account(offers, taker);
+
563
+
564 // Modifying the order or logic of the operations in the loop will cause
+
565 // a protocol breaking change.
+
566 while (have_offer)
+
567 {
+
568 bool direct_consumed = false;
+
569 auto& offer(offers.tip());
+
570
+
571 // We are done with crossing as soon as we cross the quality boundary
+
572 if (taker.reject(offer.quality()))
+
573 break;
+
574
+
575 count++;
+
576
+
577 if (auto stream = j_.debug())
+
578 {
+
579 stream << count << " Direct:";
+
580 stream << " offer: " << offer;
+
581 stream << " in: " << offer.amount().in;
+
582 stream << " out: " << offer.amount().out;
+
583 stream << "quality: " << offer.quality();
+
584 stream << " owner: " << offer.owner();
+
585 stream << " funds: "
+
586 << accountFunds(
+
587 view,
+
588 offer.owner(),
+
589 offer.amount().out,
+
590 fhIGNORE_FREEZE,
+
591 ctx_.app.journal("View"));
+
592 }
+
593
+
594 cross_result = taker.cross(offer);
595
-
596 // Postcondition: If we aren't done, then we *must* have consumed the
-
597 // offer on the books fully!
-
598 XRPL_ASSERT(
-
599 direct_consumed,
-
600 "ripple::CreateOffer::direct_cross : consumed an offer");
-
601
-
602 if (!direct_consumed)
-
603 Throw<std::logic_error>(
-
604 "direct crossing: nothing was fully consumed.");
-
605 }
-
606
-
607 return std::make_pair(cross_result, taker.remaining_offer());
-
608}
+
596 JLOG(j_.debug()) << "Direct Result: " << transToken(cross_result);
+
597
+
598 if (dry_offer(view, offer))
+
599 {
+
600 direct_consumed = true;
+
601 have_offer = step_account(offers, taker);
+
602 }
+
603
+
604 if (cross_result != tesSUCCESS)
+
605 {
+
606 cross_result = tecFAILED_PROCESSING;
+
607 break;
+
608 }
609
-
610// Step through the stream for as long as possible, skipping any offers
-
611// that are from the taker or which cross the taker's threshold.
-
612// Return false if the is no offer in the book, true otherwise.
-
613bool
-
614CreateOffer::step_account(OfferStream& stream, Taker const& taker)
-
615{
-
616 while (stream.step())
-
617 {
-
618 auto const& offer = stream.tip();
-
619
-
620 // This offer at the tip crosses the taker's threshold. We're done.
-
621 if (taker.reject(offer.quality()))
-
622 return true;
-
623
-
624 // This offer at the tip is not from the taker. We're done.
-
625 if (offer.owner() != taker.account())
-
626 return true;
-
627 }
-
628
-
629 // We ran out of offers. Can't advance.
-
630 return false;
-
631}
+
610 if (taker.done())
+
611 {
+
612 JLOG(j_.debug()) << "The taker reports he's done during crossing!";
+
613 break;
+
614 }
+
615
+
616 if (reachedOfferCrossingLimit(taker))
+
617 {
+
618 JLOG(j_.debug()) << "The offer crossing limit has been exceeded!";
+
619 break;
+
620 }
+
621
+
622 // Postcondition: If we aren't done, then we *must* have consumed the
+
623 // offer on the books fully!
+
624 XRPL_ASSERT(
+
625 direct_consumed,
+
626 "ripple::CreateOffer::direct_cross : consumed an offer");
+
627
+
628 if (!direct_consumed)
+
629 Throw<std::logic_error>(
+
630 "direct crossing: nothing was fully consumed.");
+
631 }
632
-
633// Fill as much of the offer as possible by consuming offers
-
634// already on the books. Return the status and the amount of
-
635// the offer to left unfilled.
-
636std::pair<TER, Amounts>
-
637CreateOffer::takerCross(
-
638 Sandbox& sb,
-
639 Sandbox& sbCancel,
-
640 Amounts const& takerAmount)
+
633 return std::make_pair(cross_result, taker.remaining_offer());
+
634}
+
635
+
636// Step through the stream for as long as possible, skipping any offers
+
637// that are from the taker or which cross the taker's threshold.
+
638// Return false if the is no offer in the book, true otherwise.
+
639bool
+
640CreateOffer::step_account(OfferStream& stream, Taker const& taker)
641{
-
642 NetClock::time_point const when = sb.parentCloseTime();
-
643
-
644 beast::WrappedSink takerSink(j_, "Taker ");
+
642 while (stream.step())
+
643 {
+
644 auto const& offer = stream.tip();
645
-
646 Taker taker(
-
647 cross_type_,
-
648 sb,
-
649 account_,
-
650 takerAmount,
-
651 ctx_.tx.getFlags(),
-
652 beast::Journal(takerSink));
-
653
-
654 // If the taker is unfunded before we begin crossing
-
655 // there's nothing to do - just return an error.
-
656 //
-
657 // We check this in preclaim, but when selling XRP
-
658 // charged fees can cause a user's available balance
-
659 // to go to 0 (by causing it to dip below the reserve)
-
660 // so we check this case again.
-
661 if (taker.unfunded())
-
662 {
-
663 JLOG(j_.debug()) << "Not crossing: taker is unfunded.";
-
664 return {tecUNFUNDED_OFFER, takerAmount};
-
665 }
-
666
-
667 try
-
668 {
-
669 if (cross_type_ == CrossType::IouToIou)
-
670 return bridged_cross(taker, sb, sbCancel, when);
+
646 // This offer at the tip crosses the taker's threshold. We're done.
+
647 if (taker.reject(offer.quality()))
+
648 return true;
+
649
+
650 // This offer at the tip is not from the taker. We're done.
+
651 if (offer.owner() != taker.account())
+
652 return true;
+
653 }
+
654
+
655 // We ran out of offers. Can't advance.
+
656 return false;
+
657}
+
658
+
659// Fill as much of the offer as possible by consuming offers
+
660// already on the books. Return the status and the amount of
+
661// the offer to left unfilled.
+
662std::pair<TER, Amounts>
+
663CreateOffer::takerCross(
+
664 Sandbox& sb,
+
665 Sandbox& sbCancel,
+
666 Amounts const& takerAmount)
+
667{
+
668 NetClock::time_point const when = sb.parentCloseTime();
+
669
+
670 beast::WrappedSink takerSink(j_, "Taker ");
671
-
672 return direct_cross(taker, sb, sbCancel, when);
-
673 }
-
674 catch (std::exception const& e)
-
675 {
-
676 JLOG(j_.error()) << "Exception during offer crossing: " << e.what();
-
677 return {tecINTERNAL, taker.remaining_offer()};
-
678 }
-
679}
-
680
-
681std::pair<TER, Amounts>
-
682CreateOffer::flowCross(
-
683 PaymentSandbox& psb,
-
684 PaymentSandbox& psbCancel,
-
685 Amounts const& takerAmount)
-
686{
-
687 try
+
672 Taker taker(
+
673 cross_type_,
+
674 sb,
+
675 account_,
+
676 takerAmount,
+
677 ctx_.tx.getFlags(),
+
678 beast::Journal(takerSink));
+
679
+
680 // If the taker is unfunded before we begin crossing
+
681 // there's nothing to do - just return an error.
+
682 //
+
683 // We check this in preclaim, but when selling XRP
+
684 // charged fees can cause a user's available balance
+
685 // to go to 0 (by causing it to dip below the reserve)
+
686 // so we check this case again.
+
687 if (taker.unfunded())
688 {
-
689 // If the taker is unfunded before we begin crossing there's nothing
-
690 // to do - just return an error.
-
691 //
-
692 // We check this in preclaim, but when selling XRP charged fees can
-
693 // cause a user's available balance to go to 0 (by causing it to dip
-
694 // below the reserve) so we check this case again.
-
695 STAmount const inStartBalance =
-
696 accountFunds(psb, account_, takerAmount.in, fhZERO_IF_FROZEN, j_);
-
697 if (inStartBalance <= beast::zero)
-
698 {
-
699 // The account balance can't cover even part of the offer.
-
700 JLOG(j_.debug()) << "Not crossing: taker is unfunded.";
-
701 return {tecUNFUNDED_OFFER, takerAmount};
-
702 }
-
703
-
704 // If the gateway has a transfer rate, accommodate that. The
-
705 // gateway takes its cut without any special consent from the
-
706 // offer taker. Set sendMax to allow for the gateway's cut.
-
707 Rate gatewayXferRate{QUALITY_ONE};
-
708 STAmount sendMax = takerAmount.in;
-
709 if (!sendMax.native() && (account_ != sendMax.getIssuer()))
-
710 {
-
711 gatewayXferRate = transferRate(psb, sendMax.getIssuer());
-
712 if (gatewayXferRate.value != QUALITY_ONE)
-
713 {
-
714 sendMax = multiplyRound(
-
715 takerAmount.in,
-
716 gatewayXferRate,
-
717 takerAmount.in.issue(),
-
718 true);
-
719 }
-
720 }
-
721
-
722 // Payment flow code compares quality after the transfer rate is
-
723 // included. Since transfer rate is incorporated compute threshold.
-
724 Quality threshold{takerAmount.out, sendMax};
-
725
-
726 // If we're creating a passive offer adjust the threshold so we only
-
727 // cross offers that have a better quality than this one.
-
728 std::uint32_t const txFlags = ctx_.tx.getFlags();
-
729 if (txFlags & tfPassive)
-
730 ++threshold;
-
731
-
732 // Don't send more than our balance.
-
733 if (sendMax > inStartBalance)
-
734 sendMax = inStartBalance;
-
735
-
736 // Always invoke flow() with the default path. However if neither
-
737 // of the takerAmount currencies are XRP then we cross through an
-
738 // additional path with XRP as the intermediate between two books.
-
739 // This second path we have to build ourselves.
-
740 STPathSet paths;
-
741 if (!takerAmount.in.native() && !takerAmount.out.native())
-
742 {
-
743 STPath path;
-
744 path.emplace_back(std::nullopt, xrpCurrency(), std::nullopt);
-
745 paths.emplace_back(std::move(path));
+
689 JLOG(j_.debug()) << "Not crossing: taker is unfunded.";
+
690 return {tecUNFUNDED_OFFER, takerAmount};
+
691 }
+
692
+
693 try
+
694 {
+
695 if (cross_type_ == CrossType::IouToIou)
+
696 return bridged_cross(taker, sb, sbCancel, when);
+
697
+
698 return direct_cross(taker, sb, sbCancel, when);
+
699 }
+
700 catch (std::exception const& e)
+
701 {
+
702 JLOG(j_.error()) << "Exception during offer crossing: " << e.what();
+
703 return {tecINTERNAL, taker.remaining_offer()};
+
704 }
+
705}
+
706
+
707std::pair<TER, Amounts>
+
708CreateOffer::flowCross(
+
709 PaymentSandbox& psb,
+
710 PaymentSandbox& psbCancel,
+
711 Amounts const& takerAmount)
+
712{
+
713 try
+
714 {
+
715 // If the taker is unfunded before we begin crossing there's nothing
+
716 // to do - just return an error.
+
717 //
+
718 // We check this in preclaim, but when selling XRP charged fees can
+
719 // cause a user's available balance to go to 0 (by causing it to dip
+
720 // below the reserve) so we check this case again.
+
721 STAmount const inStartBalance =
+
722 accountFunds(psb, account_, takerAmount.in, fhZERO_IF_FROZEN, j_);
+
723 if (inStartBalance <= beast::zero)
+
724 {
+
725 // The account balance can't cover even part of the offer.
+
726 JLOG(j_.debug()) << "Not crossing: taker is unfunded.";
+
727 return {tecUNFUNDED_OFFER, takerAmount};
+
728 }
+
729
+
730 // If the gateway has a transfer rate, accommodate that. The
+
731 // gateway takes its cut without any special consent from the
+
732 // offer taker. Set sendMax to allow for the gateway's cut.
+
733 Rate gatewayXferRate{QUALITY_ONE};
+
734 STAmount sendMax = takerAmount.in;
+
735 if (!sendMax.native() && (account_ != sendMax.getIssuer()))
+
736 {
+
737 gatewayXferRate = transferRate(psb, sendMax.getIssuer());
+
738 if (gatewayXferRate.value != QUALITY_ONE)
+
739 {
+
740 sendMax = multiplyRound(
+
741 takerAmount.in,
+
742 gatewayXferRate,
+
743 takerAmount.in.issue(),
+
744 true);
+
745 }
746 }
-
747 // Special handling for the tfSell flag.
-
748 STAmount deliver = takerAmount.out;
-
749 OfferCrossing offerCrossing = OfferCrossing::yes;
-
750 if (txFlags & tfSell)
-
751 {
-
752 offerCrossing = OfferCrossing::sell;
-
753 // We are selling, so we will accept *more* than the offer
-
754 // specified. Since we don't know how much they might offer,
-
755 // we allow delivery of the largest possible amount.
-
756 if (deliver.native())
-
757 deliver = STAmount{STAmount::cMaxNative};
-
758 else
-
759 // We can't use the maximum possible currency here because
-
760 // there might be a gateway transfer rate to account for.
-
761 // Since the transfer rate cannot exceed 200%, we use 1/2
-
762 // maxValue for our limit.
-
763 deliver = STAmount{
-
764 takerAmount.out.issue(),
-
765 STAmount::cMaxValue / 2,
-
766 STAmount::cMaxOffset};
-
767 }
-
768
-
769 // Call the payment engine's flow() to do the actual work.
-
770 auto const result = flow(
-
771 psb,
-
772 deliver,
-
773 account_,
-
774 account_,
-
775 paths,
-
776 true, // default path
-
777 !(txFlags & tfFillOrKill), // partial payment
-
778 true, // owner pays transfer fee
-
779 offerCrossing,
-
780 threshold,
-
781 sendMax,
-
782 j_);
-
783
-
784 // If stale offers were found remove them.
-
785 for (auto const& toRemove : result.removableOffers)
-
786 {
-
787 if (auto otr = psb.peek(keylet::offer(toRemove)))
-
788 offerDelete(psb, otr, j_);
-
789 if (auto otr = psbCancel.peek(keylet::offer(toRemove)))
-
790 offerDelete(psbCancel, otr, j_);
-
791 }
-
792
-
793 // Determine the size of the final offer after crossing.
-
794 auto afterCross = takerAmount; // If !tesSUCCESS offer unchanged
-
795 if (isTesSuccess(result.result()))
-
796 {
-
797 STAmount const takerInBalance = accountFunds(
-
798 psb, account_, takerAmount.in, fhZERO_IF_FROZEN, j_);
-
799
-
800 if (takerInBalance <= beast::zero)
-
801 {
-
802 // If offer crossing exhausted the account's funds don't
-
803 // create the offer.
-
804 afterCross.in.clear();
-
805 afterCross.out.clear();
-
806 }
-
807 else
-
808 {
-
809 STAmount const rate{
-
810 Quality{takerAmount.out, takerAmount.in}.rate()};
-
811
-
812 if (txFlags & tfSell)
-
813 {
-
814 // If selling then scale the new out amount based on how
-
815 // much we sold during crossing. This preserves the offer
-
816 // Quality,
-
817
-
818 // Reduce the offer that is placed by the crossed amount.
-
819 // Note that we must ignore the portion of the
-
820 // actualAmountIn that may have been consumed by a
-
821 // gateway's transfer rate.
-
822 STAmount nonGatewayAmountIn = result.actualAmountIn;
-
823 if (gatewayXferRate.value != QUALITY_ONE)
-
824 nonGatewayAmountIn = divideRound(
-
825 result.actualAmountIn,
-
826 gatewayXferRate,
-
827 takerAmount.in.issue(),
-
828 true);
-
829
-
830 afterCross.in -= nonGatewayAmountIn;
-
831
-
832 // It's possible that the divRound will cause our subtract
-
833 // to go slightly negative. So limit afterCross.in to zero.
-
834 if (afterCross.in < beast::zero)
-
835 // We should verify that the difference *is* small, but
-
836 // what is a good threshold to check?
-
837 afterCross.in.clear();
-
838
-
839 afterCross.out = [&]() {
-
840 // Careful analysis showed that rounding up this
-
841 // divRound result could lead to placing a reduced
-
842 // offer in the ledger that blocks order books. So
-
843 // the fixReducedOffersV1 amendment changes the
-
844 // behavior to round down instead.
-
845 if (psb.rules().enabled(fixReducedOffersV1))
-
846 return divRoundStrict(
-
847 afterCross.in,
-
848 rate,
-
849 takerAmount.out.issue(),
-
850 false);
-
851
-
852 return divRound(
-
853 afterCross.in, rate, takerAmount.out.issue(), true);
-
854 }();
-
855 }
-
856 else
-
857 {
-
858 // If not selling, we scale the input based on the
-
859 // remaining output. This too preserves the offer
-
860 // Quality.
-
861 afterCross.out -= result.actualAmountOut;
-
862 XRPL_ASSERT(
-
863 afterCross.out >= beast::zero,
-
864 "ripple::CreateOffer::flowCross : minimum offer");
-
865 if (afterCross.out < beast::zero)
-
866 afterCross.out.clear();
-
867 afterCross.in = mulRound(
-
868 afterCross.out, rate, takerAmount.in.issue(), true);
-
869 }
-
870 }
-
871 }
-
872
-
873 // Return how much of the offer is left.
-
874 return {tesSUCCESS, afterCross};
-
875 }
-
876 catch (std::exception const& e)
-
877 {
-
878 JLOG(j_.error()) << "Exception during offer crossing: " << e.what();
-
879 }
-
880 return {tecINTERNAL, takerAmount};
-
881}
-
882
-
883std::pair<TER, Amounts>
-
884CreateOffer::cross(Sandbox& sb, Sandbox& sbCancel, Amounts const& takerAmount)
-
885{
-
886 if (sb.rules().enabled(featureFlowCross))
-
887 {
-
888 PaymentSandbox psbFlow{&sb};
-
889 PaymentSandbox psbCancelFlow{&sbCancel};
-
890 auto const ret = flowCross(psbFlow, psbCancelFlow, takerAmount);
-
891 psbFlow.apply(sb);
-
892 psbCancelFlow.apply(sbCancel);
-
893 return ret;
-
894 }
-
895
-
896 Sandbox sbTaker{&sb};
-
897 Sandbox sbCancelTaker{&sbCancel};
-
898 auto const ret = takerCross(sbTaker, sbCancelTaker, takerAmount);
-
899 sbTaker.apply(sb);
-
900 sbCancelTaker.apply(sbCancel);
-
901 return ret;
-
902}
-
903
-
904std::string
-
905CreateOffer::format_amount(STAmount const& amount)
-
906{
-
907 std::string txt = amount.getText();
-
908 txt += "/";
-
909 txt += to_string(amount.issue().currency);
-
910 return txt;
-
911}
-
912
-
913void
-
914CreateOffer::preCompute()
-
915{
-
916 cross_type_ = CrossType::IouToIou;
-
917 bool const pays_xrp = ctx_.tx.getFieldAmount(sfTakerPays).native();
-
918 bool const gets_xrp = ctx_.tx.getFieldAmount(sfTakerGets).native();
-
919 if (pays_xrp && !gets_xrp)
-
920 cross_type_ = CrossType::IouToXrp;
-
921 else if (gets_xrp && !pays_xrp)
-
922 cross_type_ = CrossType::XrpToIou;
-
923
-
924 return Transactor::preCompute();
-
925}
-
926
-
927std::pair<TER, bool>
-
928CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel)
-
929{
-
930 using beast::zero;
-
931
-
932 std::uint32_t const uTxFlags = ctx_.tx.getFlags();
-
933
-
934 bool const bPassive(uTxFlags & tfPassive);
-
935 bool const bImmediateOrCancel(uTxFlags & tfImmediateOrCancel);
-
936 bool const bFillOrKill(uTxFlags & tfFillOrKill);
-
937 bool const bSell(uTxFlags & tfSell);
+
747
+
748 // Payment flow code compares quality after the transfer rate is
+
749 // included. Since transfer rate is incorporated compute threshold.
+
750 Quality threshold{takerAmount.out, sendMax};
+
751
+
752 // If we're creating a passive offer adjust the threshold so we only
+
753 // cross offers that have a better quality than this one.
+
754 std::uint32_t const txFlags = ctx_.tx.getFlags();
+
755 if (txFlags & tfPassive)
+
756 ++threshold;
+
757
+
758 // Don't send more than our balance.
+
759 if (sendMax > inStartBalance)
+
760 sendMax = inStartBalance;
+
761
+
762 // Always invoke flow() with the default path. However if neither
+
763 // of the takerAmount currencies are XRP then we cross through an
+
764 // additional path with XRP as the intermediate between two books.
+
765 // This second path we have to build ourselves.
+
766 STPathSet paths;
+
767 if (!takerAmount.in.native() && !takerAmount.out.native())
+
768 {
+
769 STPath path;
+
770 path.emplace_back(std::nullopt, xrpCurrency(), std::nullopt);
+
771 paths.emplace_back(std::move(path));
+
772 }
+
773 // Special handling for the tfSell flag.
+
774 STAmount deliver = takerAmount.out;
+
775 OfferCrossing offerCrossing = OfferCrossing::yes;
+
776 if (txFlags & tfSell)
+
777 {
+
778 offerCrossing = OfferCrossing::sell;
+
779 // We are selling, so we will accept *more* than the offer
+
780 // specified. Since we don't know how much they might offer,
+
781 // we allow delivery of the largest possible amount.
+
782 if (deliver.native())
+
783 deliver = STAmount{STAmount::cMaxNative};
+
784 else
+
785 // We can't use the maximum possible currency here because
+
786 // there might be a gateway transfer rate to account for.
+
787 // Since the transfer rate cannot exceed 200%, we use 1/2
+
788 // maxValue for our limit.
+
789 deliver = STAmount{
+
790 takerAmount.out.issue(),
+
791 STAmount::cMaxValue / 2,
+
792 STAmount::cMaxOffset};
+
793 }
+
794
+
795 // Call the payment engine's flow() to do the actual work.
+
796 auto const result = flow(
+
797 psb,
+
798 deliver,
+
799 account_,
+
800 account_,
+
801 paths,
+
802 true, // default path
+
803 !(txFlags & tfFillOrKill), // partial payment
+
804 true, // owner pays transfer fee
+
805 offerCrossing,
+
806 threshold,
+
807 sendMax,
+
808 j_);
+
809
+
810 // If stale offers were found remove them.
+
811 for (auto const& toRemove : result.removableOffers)
+
812 {
+
813 if (auto otr = psb.peek(keylet::offer(toRemove)))
+
814 offerDelete(psb, otr, j_);
+
815 if (auto otr = psbCancel.peek(keylet::offer(toRemove)))
+
816 offerDelete(psbCancel, otr, j_);
+
817 }
+
818
+
819 // Determine the size of the final offer after crossing.
+
820 auto afterCross = takerAmount; // If !tesSUCCESS offer unchanged
+
821 if (isTesSuccess(result.result()))
+
822 {
+
823 STAmount const takerInBalance = accountFunds(
+
824 psb, account_, takerAmount.in, fhZERO_IF_FROZEN, j_);
+
825
+
826 if (takerInBalance <= beast::zero)
+
827 {
+
828 // If offer crossing exhausted the account's funds don't
+
829 // create the offer.
+
830 afterCross.in.clear();
+
831 afterCross.out.clear();
+
832 }
+
833 else
+
834 {
+
835 STAmount const rate{
+
836 Quality{takerAmount.out, takerAmount.in}.rate()};
+
837
+
838 if (txFlags & tfSell)
+
839 {
+
840 // If selling then scale the new out amount based on how
+
841 // much we sold during crossing. This preserves the offer
+
842 // Quality,
+
843
+
844 // Reduce the offer that is placed by the crossed amount.
+
845 // Note that we must ignore the portion of the
+
846 // actualAmountIn that may have been consumed by a
+
847 // gateway's transfer rate.
+
848 STAmount nonGatewayAmountIn = result.actualAmountIn;
+
849 if (gatewayXferRate.value != QUALITY_ONE)
+
850 nonGatewayAmountIn = divideRound(
+
851 result.actualAmountIn,
+
852 gatewayXferRate,
+
853 takerAmount.in.issue(),
+
854 true);
+
855
+
856 afterCross.in -= nonGatewayAmountIn;
+
857
+
858 // It's possible that the divRound will cause our subtract
+
859 // to go slightly negative. So limit afterCross.in to zero.
+
860 if (afterCross.in < beast::zero)
+
861 // We should verify that the difference *is* small, but
+
862 // what is a good threshold to check?
+
863 afterCross.in.clear();
+
864
+
865 afterCross.out = [&]() {
+
866 // Careful analysis showed that rounding up this
+
867 // divRound result could lead to placing a reduced
+
868 // offer in the ledger that blocks order books. So
+
869 // the fixReducedOffersV1 amendment changes the
+
870 // behavior to round down instead.
+
871 if (psb.rules().enabled(fixReducedOffersV1))
+
872 return divRoundStrict(
+
873 afterCross.in,
+
874 rate,
+
875 takerAmount.out.issue(),
+
876 false);
+
877
+
878 return divRound(
+
879 afterCross.in, rate, takerAmount.out.issue(), true);
+
880 }();
+
881 }
+
882 else
+
883 {
+
884 // If not selling, we scale the input based on the
+
885 // remaining output. This too preserves the offer
+
886 // Quality.
+
887 afterCross.out -= result.actualAmountOut;
+
888 XRPL_ASSERT(
+
889 afterCross.out >= beast::zero,
+
890 "ripple::CreateOffer::flowCross : minimum offer");
+
891 if (afterCross.out < beast::zero)
+
892 afterCross.out.clear();
+
893 afterCross.in = mulRound(
+
894 afterCross.out, rate, takerAmount.in.issue(), true);
+
895 }
+
896 }
+
897 }
+
898
+
899 // Return how much of the offer is left.
+
900 return {tesSUCCESS, afterCross};
+
901 }
+
902 catch (std::exception const& e)
+
903 {
+
904 JLOG(j_.error()) << "Exception during offer crossing: " << e.what();
+
905 }
+
906 return {tecINTERNAL, takerAmount};
+
907}
+
908
+
909std::pair<TER, Amounts>
+
910CreateOffer::cross(Sandbox& sb, Sandbox& sbCancel, Amounts const& takerAmount)
+
911{
+
912 if (sb.rules().enabled(featureFlowCross))
+
913 {
+
914 PaymentSandbox psbFlow{&sb};
+
915 PaymentSandbox psbCancelFlow{&sbCancel};
+
916 auto const ret = flowCross(psbFlow, psbCancelFlow, takerAmount);
+
917 psbFlow.apply(sb);
+
918 psbCancelFlow.apply(sbCancel);
+
919 return ret;
+
920 }
+
921
+
922 Sandbox sbTaker{&sb};
+
923 Sandbox sbCancelTaker{&sbCancel};
+
924 auto const ret = takerCross(sbTaker, sbCancelTaker, takerAmount);
+
925 sbTaker.apply(sb);
+
926 sbCancelTaker.apply(sbCancel);
+
927 return ret;
+
928}
+
929
+
930std::string
+
931CreateOffer::format_amount(STAmount const& amount)
+
932{
+
933 std::string txt = amount.getText();
+
934 txt += "/";
+
935 txt += to_string(amount.issue().currency);
+
936 return txt;
+
937}
938
-
939 auto saTakerPays = ctx_.tx[sfTakerPays];
-
940 auto saTakerGets = ctx_.tx[sfTakerGets];
-
941
-
942 auto const cancelSequence = ctx_.tx[~sfOfferSequence];
-
943
-
944 // Note that we we use the value from the sequence or ticket as the
-
945 // offer sequence. For more explanation see comments in SeqProxy.h.
-
946 auto const offerSequence = ctx_.tx.getSeqProxy().value();
-
947
-
948 // This is the original rate of the offer, and is the rate at which
-
949 // it will be placed, even if crossing offers change the amounts that
-
950 // end up on the books.
-
951 auto uRate = getRate(saTakerGets, saTakerPays);
+
939void
+
940CreateOffer::preCompute()
+
941{
+
942 cross_type_ = CrossType::IouToIou;
+
943 bool const pays_xrp = ctx_.tx.getFieldAmount(sfTakerPays).native();
+
944 bool const gets_xrp = ctx_.tx.getFieldAmount(sfTakerGets).native();
+
945 if (pays_xrp && !gets_xrp)
+
946 cross_type_ = CrossType::IouToXrp;
+
947 else if (gets_xrp && !pays_xrp)
+
948 cross_type_ = CrossType::XrpToIou;
+
949
+
950 return Transactor::preCompute();
+
951}
952
-
953 auto viewJ = ctx_.app.journal("View");
-
954
-
955 TER result = tesSUCCESS;
-
956
-
957 // Process a cancellation request that's passed along with an offer.
-
958 if (cancelSequence)
-
959 {
-
960 auto const sleCancel =
-
961 sb.peek(keylet::offer(account_, *cancelSequence));
-
962
-
963 // It's not an error to not find the offer to cancel: it might have
-
964 // been consumed or removed. If it is found, however, it's an error
-
965 // to fail to delete it.
-
966 if (sleCancel)
-
967 {
-
968 JLOG(j_.debug()) << "Create cancels order " << *cancelSequence;
-
969 result = offerDelete(sb, sleCancel, viewJ);
-
970 }
-
971 }
-
972
-
973 auto const expiration = ctx_.tx[~sfExpiration];
-
974
-
975 if (hasExpired(sb, expiration))
-
976 {
-
977 // If the offer has expired, the transaction has successfully
-
978 // done nothing, so short circuit from here.
-
979 //
-
980 // The return code change is attached to featureDepositPreauth as a
-
981 // convenience. The change is not big enough to deserve a fix code.
-
982 TER const ter{
-
983 sb.rules().enabled(featureDepositPreauth) ? TER{tecEXPIRED}
-
984 : TER{tesSUCCESS}};
-
985 return {ter, true};
-
986 }
-
987
-
988 bool const bOpenLedger = sb.open();
-
989 bool crossed = false;
-
990
-
991 if (result == tesSUCCESS)
-
992 {
-
993 // If a tick size applies, round the offer to the tick size
-
994 auto const& uPaysIssuerID = saTakerPays.getIssuer();
-
995 auto const& uGetsIssuerID = saTakerGets.getIssuer();
-
996
-
997 std::uint8_t uTickSize = Quality::maxTickSize;
-
998 if (!isXRP(uPaysIssuerID))
-
999 {
-
1000 auto const sle = sb.read(keylet::account(uPaysIssuerID));
-
1001 if (sle && sle->isFieldPresent(sfTickSize))
-
1002 uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
-
1003 }
-
1004 if (!isXRP(uGetsIssuerID))
-
1005 {
-
1006 auto const sle = sb.read(keylet::account(uGetsIssuerID));
-
1007 if (sle && sle->isFieldPresent(sfTickSize))
-
1008 uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
-
1009 }
-
1010 if (uTickSize < Quality::maxTickSize)
-
1011 {
-
1012 auto const rate =
-
1013 Quality{saTakerGets, saTakerPays}.round(uTickSize).rate();
-
1014
-
1015 // We round the side that's not exact,
-
1016 // just as if the offer happened to execute
-
1017 // at a slightly better (for the placer) rate
-
1018 if (bSell)
-
1019 {
-
1020 // this is a sell, round taker pays
-
1021 saTakerPays = multiply(saTakerGets, rate, saTakerPays.issue());
-
1022 }
-
1023 else
-
1024 {
-
1025 // this is a buy, round taker gets
-
1026 saTakerGets = divide(saTakerPays, rate, saTakerGets.issue());
-
1027 }
-
1028 if (!saTakerGets || !saTakerPays)
-
1029 {
-
1030 JLOG(j_.debug()) << "Offer rounded to zero";
-
1031 return {result, true};
-
1032 }
-
1033
-
1034 uRate = getRate(saTakerGets, saTakerPays);
+
953std::pair<TER, bool>
+
954CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel)
+
955{
+
956 using beast::zero;
+
957
+
958 std::uint32_t const uTxFlags = ctx_.tx.getFlags();
+
959
+
960 bool const bPassive(uTxFlags & tfPassive);
+
961 bool const bImmediateOrCancel(uTxFlags & tfImmediateOrCancel);
+
962 bool const bFillOrKill(uTxFlags & tfFillOrKill);
+
963 bool const bSell(uTxFlags & tfSell);
+
964
+
965 auto saTakerPays = ctx_.tx[sfTakerPays];
+
966 auto saTakerGets = ctx_.tx[sfTakerGets];
+
967
+
968 auto const cancelSequence = ctx_.tx[~sfOfferSequence];
+
969
+
970 // Note that we we use the value from the sequence or ticket as the
+
971 // offer sequence. For more explanation see comments in SeqProxy.h.
+
972 auto const offerSequence = ctx_.tx.getSeqProxy().value();
+
973
+
974 // This is the original rate of the offer, and is the rate at which
+
975 // it will be placed, even if crossing offers change the amounts that
+
976 // end up on the books.
+
977 auto uRate = getRate(saTakerGets, saTakerPays);
+
978
+
979 auto viewJ = ctx_.app.journal("View");
+
980
+
981 TER result = tesSUCCESS;
+
982
+
983 // Process a cancellation request that's passed along with an offer.
+
984 if (cancelSequence)
+
985 {
+
986 auto const sleCancel =
+
987 sb.peek(keylet::offer(account_, *cancelSequence));
+
988
+
989 // It's not an error to not find the offer to cancel: it might have
+
990 // been consumed or removed. If it is found, however, it's an error
+
991 // to fail to delete it.
+
992 if (sleCancel)
+
993 {
+
994 JLOG(j_.debug()) << "Create cancels order " << *cancelSequence;
+
995 result = offerDelete(sb, sleCancel, viewJ);
+
996 }
+
997 }
+
998
+
999 auto const expiration = ctx_.tx[~sfExpiration];
+
1000
+
1001 if (hasExpired(sb, expiration))
+
1002 {
+
1003 // If the offer has expired, the transaction has successfully
+
1004 // done nothing, so short circuit from here.
+
1005 //
+
1006 // The return code change is attached to featureDepositPreauth as a
+
1007 // convenience. The change is not big enough to deserve a fix code.
+
1008 TER const ter{
+
1009 sb.rules().enabled(featureDepositPreauth) ? TER{tecEXPIRED}
+
1010 : TER{tesSUCCESS}};
+
1011 return {ter, true};
+
1012 }
+
1013
+
1014 bool const bOpenLedger = sb.open();
+
1015 bool crossed = false;
+
1016
+
1017 if (result == tesSUCCESS)
+
1018 {
+
1019 // If a tick size applies, round the offer to the tick size
+
1020 auto const& uPaysIssuerID = saTakerPays.getIssuer();
+
1021 auto const& uGetsIssuerID = saTakerGets.getIssuer();
+
1022
+
1023 std::uint8_t uTickSize = Quality::maxTickSize;
+
1024 if (!isXRP(uPaysIssuerID))
+
1025 {
+
1026 auto const sle = sb.read(keylet::account(uPaysIssuerID));
+
1027 if (sle && sle->isFieldPresent(sfTickSize))
+
1028 uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
+
1029 }
+
1030 if (!isXRP(uGetsIssuerID))
+
1031 {
+
1032 auto const sle = sb.read(keylet::account(uGetsIssuerID));
+
1033 if (sle && sle->isFieldPresent(sfTickSize))
+
1034 uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
1035 }
-
1036
-
1037 // We reverse pays and gets because during crossing we are taking.
-
1038 Amounts const takerAmount(saTakerGets, saTakerPays);
-
1039
-
1040 // The amount of the offer that is unfilled after crossing has been
-
1041 // performed. It may be equal to the original amount (didn't cross),
-
1042 // empty (fully crossed), or something in-between.
-
1043 Amounts place_offer;
-
1044
-
1045 JLOG(j_.debug()) << "Attempting cross: "
-
1046 << to_string(takerAmount.in.issue()) << " -> "
-
1047 << to_string(takerAmount.out.issue());
-
1048
-
1049 if (auto stream = j_.trace())
-
1050 {
-
1051 stream << " mode: " << (bPassive ? "passive " : "")
-
1052 << (bSell ? "sell" : "buy");
-
1053 stream << " in: " << format_amount(takerAmount.in);
-
1054 stream << " out: " << format_amount(takerAmount.out);
-
1055 }
-
1056
-
1057 std::tie(result, place_offer) = cross(sb, sbCancel, takerAmount);
-
1058
-
1059 // We expect the implementation of cross to succeed
-
1060 // or give a tec.
-
1061 XRPL_ASSERT(
-
1062 result == tesSUCCESS || isTecClaim(result),
-
1063 "ripple::CreateOffer::applyGuts : result is tesSUCCESS or "
-
1064 "tecCLAIM");
+
1036 if (uTickSize < Quality::maxTickSize)
+
1037 {
+
1038 auto const rate =
+
1039 Quality{saTakerGets, saTakerPays}.round(uTickSize).rate();
+
1040
+
1041 // We round the side that's not exact,
+
1042 // just as if the offer happened to execute
+
1043 // at a slightly better (for the placer) rate
+
1044 if (bSell)
+
1045 {
+
1046 // this is a sell, round taker pays
+
1047 saTakerPays = multiply(saTakerGets, rate, saTakerPays.issue());
+
1048 }
+
1049 else
+
1050 {
+
1051 // this is a buy, round taker gets
+
1052 saTakerGets = divide(saTakerPays, rate, saTakerGets.issue());
+
1053 }
+
1054 if (!saTakerGets || !saTakerPays)
+
1055 {
+
1056 JLOG(j_.debug()) << "Offer rounded to zero";
+
1057 return {result, true};
+
1058 }
+
1059
+
1060 uRate = getRate(saTakerGets, saTakerPays);
+
1061 }
+
1062
+
1063 // We reverse pays and gets because during crossing we are taking.
+
1064 Amounts const takerAmount(saTakerGets, saTakerPays);
1065
-
1066 if (auto stream = j_.trace())
-
1067 {
-
1068 stream << "Cross result: " << transToken(result);
-
1069 stream << " in: " << format_amount(place_offer.in);
-
1070 stream << " out: " << format_amount(place_offer.out);
-
1071 }
-
1072
-
1073 if (result == tecFAILED_PROCESSING && bOpenLedger)
-
1074 result = telFAILED_PROCESSING;
-
1075
-
1076 if (result != tesSUCCESS)
-
1077 {
-
1078 JLOG(j_.debug()) << "final result: " << transToken(result);
-
1079 return {result, true};
-
1080 }
-
1081
-
1082 XRPL_ASSERT(
-
1083 saTakerGets.issue() == place_offer.in.issue(),
-
1084 "ripple::CreateOffer::applyGuts : taker gets issue match");
-
1085 XRPL_ASSERT(
-
1086 saTakerPays.issue() == place_offer.out.issue(),
-
1087 "ripple::CreateOffer::applyGuts : taker pays issue match");
-
1088
-
1089 if (takerAmount != place_offer)
-
1090 crossed = true;
+
1066 // The amount of the offer that is unfilled after crossing has been
+
1067 // performed. It may be equal to the original amount (didn't cross),
+
1068 // empty (fully crossed), or something in-between.
+
1069 Amounts place_offer;
+
1070
+
1071 JLOG(j_.debug()) << "Attempting cross: "
+
1072 << to_string(takerAmount.in.issue()) << " -> "
+
1073 << to_string(takerAmount.out.issue());
+
1074
+
1075 if (auto stream = j_.trace())
+
1076 {
+
1077 stream << " mode: " << (bPassive ? "passive " : "")
+
1078 << (bSell ? "sell" : "buy");
+
1079 stream << " in: " << format_amount(takerAmount.in);
+
1080 stream << " out: " << format_amount(takerAmount.out);
+
1081 }
+
1082
+
1083 std::tie(result, place_offer) = cross(sb, sbCancel, takerAmount);
+
1084
+
1085 // We expect the implementation of cross to succeed
+
1086 // or give a tec.
+
1087 XRPL_ASSERT(
+
1088 result == tesSUCCESS || isTecClaim(result),
+
1089 "ripple::CreateOffer::applyGuts : result is tesSUCCESS or "
+
1090 "tecCLAIM");
1091
-
1092 // The offer that we need to place after offer crossing should
-
1093 // never be negative. If it is, something went very very wrong.
-
1094 if (place_offer.in < zero || place_offer.out < zero)
-
1095 {
-
1096 JLOG(j_.fatal()) << "Cross left offer negative!"
-
1097 << " in: " << format_amount(place_offer.in)
-
1098 << " out: " << format_amount(place_offer.out);
-
1099 return {tefINTERNAL, true};
-
1100 }
+
1092 if (auto stream = j_.trace())
+
1093 {
+
1094 stream << "Cross result: " << transToken(result);
+
1095 stream << " in: " << format_amount(place_offer.in);
+
1096 stream << " out: " << format_amount(place_offer.out);
+
1097 }
+
1098
+
1099 if (result == tecFAILED_PROCESSING && bOpenLedger)
+
1100 result = telFAILED_PROCESSING;
1101
-
1102 if (place_offer.in == zero || place_offer.out == zero)
+
1102 if (result != tesSUCCESS)
1103 {
-
1104 JLOG(j_.debug()) << "Offer fully crossed!";
+
1104 JLOG(j_.debug()) << "final result: " << transToken(result);
1105 return {result, true};
1106 }
1107
-
1108 // We now need to adjust the offer to reflect the amount left after
-
1109 // crossing. We reverse in and out here, since during crossing we
-
1110 // were the taker.
-
1111 saTakerPays = place_offer.out;
-
1112 saTakerGets = place_offer.in;
-
1113 }
+
1108 XRPL_ASSERT(
+
1109 saTakerGets.issue() == place_offer.in.issue(),
+
1110 "ripple::CreateOffer::applyGuts : taker gets issue match");
+
1111 XRPL_ASSERT(
+
1112 saTakerPays.issue() == place_offer.out.issue(),
+
1113 "ripple::CreateOffer::applyGuts : taker pays issue match");
1114
-
1115 XRPL_ASSERT(
-
1116 saTakerPays > zero && saTakerGets > zero,
-
1117 "ripple::CreateOffer::applyGuts : taker pays and gets positive");
-
1118
-
1119 if (result != tesSUCCESS)
-
1120 {
-
1121 JLOG(j_.debug()) << "final result: " << transToken(result);
-
1122 return {result, true};
-
1123 }
-
1124
-
1125 if (auto stream = j_.trace())
-
1126 {
-
1127 stream << "Place" << (crossed ? " remaining " : " ") << "offer:";
-
1128 stream << " Pays: " << saTakerPays.getFullText();
-
1129 stream << " Gets: " << saTakerGets.getFullText();
-
1130 }
-
1131
-
1132 // For 'fill or kill' offers, failure to fully cross means that the
-
1133 // entire operation should be aborted, with only fees paid.
-
1134 if (bFillOrKill)
-
1135 {
-
1136 JLOG(j_.trace()) << "Fill or Kill: offer killed";
-
1137 if (sb.rules().enabled(fix1578))
-
1138 return {tecKILLED, false};
-
1139 return {tesSUCCESS, false};
-
1140 }
-
1141
-
1142 // For 'immediate or cancel' offers, the amount remaining doesn't get
-
1143 // placed - it gets canceled and the operation succeeds.
-
1144 if (bImmediateOrCancel)
-
1145 {
-
1146 JLOG(j_.trace()) << "Immediate or cancel: offer canceled";
-
1147 if (!crossed && sb.rules().enabled(featureImmediateOfferKilled))
-
1148 // If the ImmediateOfferKilled amendment is enabled, any
-
1149 // ImmediateOrCancel offer that transfers absolutely no funds
-
1150 // returns tecKILLED rather than tesSUCCESS. Motivation for the
-
1151 // change is here: https://github.com/ripple/rippled/issues/4115
-
1152 return {tecKILLED, false};
-
1153 return {tesSUCCESS, true};
-
1154 }
-
1155
-
1156 auto const sleCreator = sb.peek(keylet::account(account_));
-
1157 if (!sleCreator)
-
1158 return {tefINTERNAL, false};
-
1159
-
1160 {
-
1161 XRPAmount reserve =
-
1162 sb.fees().accountReserve(sleCreator->getFieldU32(sfOwnerCount) + 1);
-
1163
-
1164 if (mPriorBalance < reserve)
-
1165 {
-
1166 // If we are here, the signing account had an insufficient reserve
-
1167 // *prior* to our processing. If something actually crossed, then
-
1168 // we allow this; otherwise, we just claim a fee.
-
1169 if (!crossed)
-
1170 result = tecINSUF_RESERVE_OFFER;
-
1171
-
1172 if (result != tesSUCCESS)
-
1173 {
-
1174 JLOG(j_.debug()) << "final result: " << transToken(result);
-
1175 }
-
1176
-
1177 return {result, true};
-
1178 }
-
1179 }
-
1180
-
1181 // We need to place the remainder of the offer into its order book.
-
1182 auto const offer_index = keylet::offer(account_, offerSequence);
-
1183
-
1184 // Add offer to owner's directory.
-
1185 auto const ownerNode = sb.dirInsert(
-
1186 keylet::ownerDir(account_), offer_index, describeOwnerDir(account_));
-
1187
-
1188 if (!ownerNode)
-
1189 {
-
1190 JLOG(j_.debug())
-
1191 << "final result: failed to add offer to owner's directory";
-
1192 return {tecDIR_FULL, true};
-
1193 }
-
1194
-
1195 // Update owner count.
-
1196 adjustOwnerCount(sb, sleCreator, 1, viewJ);
+
1115 if (takerAmount != place_offer)
+
1116 crossed = true;
+
1117
+
1118 // The offer that we need to place after offer crossing should
+
1119 // never be negative. If it is, something went very very wrong.
+
1120 if (place_offer.in < zero || place_offer.out < zero)
+
1121 {
+
1122 JLOG(j_.fatal()) << "Cross left offer negative!"
+
1123 << " in: " << format_amount(place_offer.in)
+
1124 << " out: " << format_amount(place_offer.out);
+
1125 return {tefINTERNAL, true};
+
1126 }
+
1127
+
1128 if (place_offer.in == zero || place_offer.out == zero)
+
1129 {
+
1130 JLOG(j_.debug()) << "Offer fully crossed!";
+
1131 return {result, true};
+
1132 }
+
1133
+
1134 // We now need to adjust the offer to reflect the amount left after
+
1135 // crossing. We reverse in and out here, since during crossing we
+
1136 // were the taker.
+
1137 saTakerPays = place_offer.out;
+
1138 saTakerGets = place_offer.in;
+
1139 }
+
1140
+
1141 XRPL_ASSERT(
+
1142 saTakerPays > zero && saTakerGets > zero,
+
1143 "ripple::CreateOffer::applyGuts : taker pays and gets positive");
+
1144
+
1145 if (result != tesSUCCESS)
+
1146 {
+
1147 JLOG(j_.debug()) << "final result: " << transToken(result);
+
1148 return {result, true};
+
1149 }
+
1150
+
1151 if (auto stream = j_.trace())
+
1152 {
+
1153 stream << "Place" << (crossed ? " remaining " : " ") << "offer:";
+
1154 stream << " Pays: " << saTakerPays.getFullText();
+
1155 stream << " Gets: " << saTakerGets.getFullText();
+
1156 }
+
1157
+
1158 // For 'fill or kill' offers, failure to fully cross means that the
+
1159 // entire operation should be aborted, with only fees paid.
+
1160 if (bFillOrKill)
+
1161 {
+
1162 JLOG(j_.trace()) << "Fill or Kill: offer killed";
+
1163 if (sb.rules().enabled(fix1578))
+
1164 return {tecKILLED, false};
+
1165 return {tesSUCCESS, false};
+
1166 }
+
1167
+
1168 // For 'immediate or cancel' offers, the amount remaining doesn't get
+
1169 // placed - it gets canceled and the operation succeeds.
+
1170 if (bImmediateOrCancel)
+
1171 {
+
1172 JLOG(j_.trace()) << "Immediate or cancel: offer canceled";
+
1173 if (!crossed && sb.rules().enabled(featureImmediateOfferKilled))
+
1174 // If the ImmediateOfferKilled amendment is enabled, any
+
1175 // ImmediateOrCancel offer that transfers absolutely no funds
+
1176 // returns tecKILLED rather than tesSUCCESS. Motivation for the
+
1177 // change is here: https://github.com/ripple/rippled/issues/4115
+
1178 return {tecKILLED, false};
+
1179 return {tesSUCCESS, true};
+
1180 }
+
1181
+
1182 auto const sleCreator = sb.peek(keylet::account(account_));
+
1183 if (!sleCreator)
+
1184 return {tefINTERNAL, false};
+
1185
+
1186 {
+
1187 XRPAmount reserve =
+
1188 sb.fees().accountReserve(sleCreator->getFieldU32(sfOwnerCount) + 1);
+
1189
+
1190 if (mPriorBalance < reserve)
+
1191 {
+
1192 // If we are here, the signing account had an insufficient reserve
+
1193 // *prior* to our processing. If something actually crossed, then
+
1194 // we allow this; otherwise, we just claim a fee.
+
1195 if (!crossed)
+
1196 result = tecINSUF_RESERVE_OFFER;
1197
-
1198 JLOG(j_.trace()) << "adding to book: " << to_string(saTakerPays.issue())
-
1199 << " : " << to_string(saTakerGets.issue());
-
1200
-
1201 Book const book{saTakerPays.issue(), saTakerGets.issue()};
+
1198 if (result != tesSUCCESS)
+
1199 {
+
1200 JLOG(j_.debug()) << "final result: " << transToken(result);
+
1201 }
1202
-
1203 // Add offer to order book, using the original rate
-
1204 // before any crossing occured.
-
1205 auto dir = keylet::quality(keylet::book(book), uRate);
-
1206 bool const bookExisted = static_cast<bool>(sb.peek(dir));
-
1207
-
1208 auto const bookNode = sb.dirAppend(dir, offer_index, [&](SLE::ref sle) {
-
1209 sle->setFieldH160(sfTakerPaysCurrency, saTakerPays.issue().currency);
-
1210 sle->setFieldH160(sfTakerPaysIssuer, saTakerPays.issue().account);
-
1211 sle->setFieldH160(sfTakerGetsCurrency, saTakerGets.issue().currency);
-
1212 sle->setFieldH160(sfTakerGetsIssuer, saTakerGets.issue().account);
-
1213 sle->setFieldU64(sfExchangeRate, uRate);
-
1214 });
-
1215
-
1216 if (!bookNode)
-
1217 {
-
1218 JLOG(j_.debug()) << "final result: failed to add offer to book";
-
1219 return {tecDIR_FULL, true};
-
1220 }
-
1221
-
1222 auto sleOffer = std::make_shared<SLE>(offer_index);
-
1223 sleOffer->setAccountID(sfAccount, account_);
-
1224 sleOffer->setFieldU32(sfSequence, offerSequence);
-
1225 sleOffer->setFieldH256(sfBookDirectory, dir.key);
-
1226 sleOffer->setFieldAmount(sfTakerPays, saTakerPays);
-
1227 sleOffer->setFieldAmount(sfTakerGets, saTakerGets);
-
1228 sleOffer->setFieldU64(sfOwnerNode, *ownerNode);
-
1229 sleOffer->setFieldU64(sfBookNode, *bookNode);
-
1230 if (expiration)
-
1231 sleOffer->setFieldU32(sfExpiration, *expiration);
-
1232 if (bPassive)
-
1233 sleOffer->setFlag(lsfPassive);
-
1234 if (bSell)
-
1235 sleOffer->setFlag(lsfSell);
-
1236 sb.insert(sleOffer);
-
1237
-
1238 if (!bookExisted)
-
1239 ctx_.app.getOrderBookDB().addOrderBook(book);
-
1240
-
1241 JLOG(j_.debug()) << "final result: success";
-
1242
-
1243 return {tesSUCCESS, true};
-
1244}
-
1245
-
1246TER
-
1247CreateOffer::doApply()
-
1248{
-
1249 // This is the ledger view that we work against. Transactions are applied
-
1250 // as we go on processing transactions.
-
1251 Sandbox sb(&ctx_.view());
-
1252
-
1253 // This is a ledger with just the fees paid and any unfunded or expired
-
1254 // offers we encounter removed. It's used when handling Fill-or-Kill offers,
-
1255 // if the order isn't going to be placed, to avoid wasting the work we did.
-
1256 Sandbox sbCancel(&ctx_.view());
-
1257
-
1258 auto const result = applyGuts(sb, sbCancel);
-
1259 if (result.second)
-
1260 sb.apply(ctx_.rawView());
-
1261 else
-
1262 sbCancel.apply(ctx_.rawView());
-
1263 return result.first;
-
1264}
-
1265
-
1266} // namespace ripple
+
1203 return {result, true};
+
1204 }
+
1205 }
+
1206
+
1207 // We need to place the remainder of the offer into its order book.
+
1208 auto const offer_index = keylet::offer(account_, offerSequence);
+
1209
+
1210 // Add offer to owner's directory.
+
1211 auto const ownerNode = sb.dirInsert(
+
1212 keylet::ownerDir(account_), offer_index, describeOwnerDir(account_));
+
1213
+
1214 if (!ownerNode)
+
1215 {
+
1216 JLOG(j_.debug())
+
1217 << "final result: failed to add offer to owner's directory";
+
1218 return {tecDIR_FULL, true};
+
1219 }
+
1220
+
1221 // Update owner count.
+
1222 adjustOwnerCount(sb, sleCreator, 1, viewJ);
+
1223
+
1224 JLOG(j_.trace()) << "adding to book: " << to_string(saTakerPays.issue())
+
1225 << " : " << to_string(saTakerGets.issue());
+
1226
+
1227 Book const book{saTakerPays.issue(), saTakerGets.issue()};
+
1228
+
1229 // Add offer to order book, using the original rate
+
1230 // before any crossing occured.
+
1231 auto dir = keylet::quality(keylet::book(book), uRate);
+
1232 bool const bookExisted = static_cast<bool>(sb.peek(dir));
+
1233
+
1234 auto const bookNode = sb.dirAppend(dir, offer_index, [&](SLE::ref sle) {
+
1235 sle->setFieldH160(sfTakerPaysCurrency, saTakerPays.issue().currency);
+
1236 sle->setFieldH160(sfTakerPaysIssuer, saTakerPays.issue().account);
+
1237 sle->setFieldH160(sfTakerGetsCurrency, saTakerGets.issue().currency);
+
1238 sle->setFieldH160(sfTakerGetsIssuer, saTakerGets.issue().account);
+
1239 sle->setFieldU64(sfExchangeRate, uRate);
+
1240 });
+
1241
+
1242 if (!bookNode)
+
1243 {
+
1244 JLOG(j_.debug()) << "final result: failed to add offer to book";
+
1245 return {tecDIR_FULL, true};
+
1246 }
+
1247
+
1248 auto sleOffer = std::make_shared<SLE>(offer_index);
+
1249 sleOffer->setAccountID(sfAccount, account_);
+
1250 sleOffer->setFieldU32(sfSequence, offerSequence);
+
1251 sleOffer->setFieldH256(sfBookDirectory, dir.key);
+
1252 sleOffer->setFieldAmount(sfTakerPays, saTakerPays);
+
1253 sleOffer->setFieldAmount(sfTakerGets, saTakerGets);
+
1254 sleOffer->setFieldU64(sfOwnerNode, *ownerNode);
+
1255 sleOffer->setFieldU64(sfBookNode, *bookNode);
+
1256 if (expiration)
+
1257 sleOffer->setFieldU32(sfExpiration, *expiration);
+
1258 if (bPassive)
+
1259 sleOffer->setFlag(lsfPassive);
+
1260 if (bSell)
+
1261 sleOffer->setFlag(lsfSell);
+
1262 sb.insert(sleOffer);
+
1263
+
1264 if (!bookExisted)
+
1265 ctx_.app.getOrderBookDB().addOrderBook(book);
+
1266
+
1267 JLOG(j_.debug()) << "final result: success";
+
1268
+
1269 return {tesSUCCESS, true};
+
1270}
+
1271
+
1272TER
+
1273CreateOffer::doApply()
+
1274{
+
1275 // This is the ledger view that we work against. Transactions are applied
+
1276 // as we go on processing transactions.
+
1277 Sandbox sb(&ctx_.view());
+
1278
+
1279 // This is a ledger with just the fees paid and any unfunded or expired
+
1280 // offers we encounter removed. It's used when handling Fill-or-Kill offers,
+
1281 // if the order isn't going to be placed, to avoid wasting the work we did.
+
1282 Sandbox sbCancel(&ctx_.view());
+
1283
+
1284 auto const result = applyGuts(sb, sbCancel);
+
1285 if (result.second)
+
1286 sb.apply(ctx_.rawView());
+
1287 else
+
1288 sbCancel.apply(ctx_.rawView());
+
1289 return result.first;
+
1290}
+
1291
+
1292} // namespace ripple
std::string
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:59
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:341
@@ -1367,25 +1393,25 @@ $(function() {
ripple::BasicTaker::issue_out
Issue const & issue_out() const
Returns the Issue associated with the output of the offer.
Definition: Taker.h:200
ripple::BasicTaker::unfunded
bool unfunded() const
Returns true if the taker has run out of funds.
Definition: Taker.cpp:112
ripple::Book
Specifies an order book.
Definition: Book.h:34
-
ripple::CreateOffer::bridged_cross
std::pair< TER, Amounts > bridged_cross(Taker &taker, ApplyView &view, ApplyView &view_cancel, NetClock::time_point const when)
Definition: CreateOffer.cpp:326
+
ripple::CreateOffer::bridged_cross
std::pair< TER, Amounts > bridged_cross(Taker &taker, ApplyView &view, ApplyView &view_cancel, NetClock::time_point const when)
Definition: CreateOffer.cpp:352
ripple::CreateOffer::stepCounter_
OfferStream::StepCounter stepCounter_
Definition: CreateOffer.h:142
-
ripple::CreateOffer::flowCross
std::pair< TER, Amounts > flowCross(PaymentSandbox &psb, PaymentSandbox &psbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:682
+
ripple::CreateOffer::flowCross
std::pair< TER, Amounts > flowCross(PaymentSandbox &psb, PaymentSandbox &psbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:708
ripple::CreateOffer::checkAcceptAsset
static TER checkAcceptAsset(ReadView const &view, ApplyFlags const flags, AccountID const id, beast::Journal const j, Issue const &issue)
Definition: CreateOffer.cpp:205
-
ripple::CreateOffer::preCompute
void preCompute() override
Gather information beyond what the Transactor base class gathers.
Definition: CreateOffer.cpp:914
-
ripple::CreateOffer::dry_offer
bool dry_offer(ApplyView &view, Offer const &offer)
Definition: CreateOffer.cpp:266
+
ripple::CreateOffer::preCompute
void preCompute() override
Gather information beyond what the Transactor base class gathers.
Definition: CreateOffer.cpp:940
+
ripple::CreateOffer::dry_offer
bool dry_offer(ApplyView &view, Offer const &offer)
Definition: CreateOffer.cpp:292
ripple::CreateOffer::preclaim
static TER preclaim(PreclaimContext const &ctx)
Enforce constraints beyond those of the Transactor base class.
Definition: CreateOffer.cpp:129
-
ripple::CreateOffer::step_account
static bool step_account(OfferStream &stream, Taker const &taker)
Definition: CreateOffer.cpp:614
-
ripple::CreateOffer::format_amount
static std::string format_amount(STAmount const &amount)
Definition: CreateOffer.cpp:905
-
ripple::CreateOffer::reachedOfferCrossingLimit
bool reachedOfferCrossingLimit(Taker const &taker) const
Definition: CreateOffer.cpp:315
-
ripple::CreateOffer::takerCross
std::pair< TER, Amounts > takerCross(Sandbox &sb, Sandbox &sbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:637
-
ripple::CreateOffer::direct_cross
std::pair< TER, Amounts > direct_cross(Taker &taker, ApplyView &view, ApplyView &view_cancel, NetClock::time_point const when)
Definition: CreateOffer.cpp:519
+
ripple::CreateOffer::step_account
static bool step_account(OfferStream &stream, Taker const &taker)
Definition: CreateOffer.cpp:640
+
ripple::CreateOffer::format_amount
static std::string format_amount(STAmount const &amount)
Definition: CreateOffer.cpp:931
+
ripple::CreateOffer::reachedOfferCrossingLimit
bool reachedOfferCrossingLimit(Taker const &taker) const
Definition: CreateOffer.cpp:341
+
ripple::CreateOffer::takerCross
std::pair< TER, Amounts > takerCross(Sandbox &sb, Sandbox &sbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:663
+
ripple::CreateOffer::direct_cross
std::pair< TER, Amounts > direct_cross(Taker &taker, ApplyView &view, ApplyView &view_cancel, NetClock::time_point const when)
Definition: CreateOffer.cpp:545
ripple::CreateOffer::preflight
static NotTEC preflight(PreflightContext const &ctx)
Enforce constraints beyond those of the Transactor base class.
Definition: CreateOffer.cpp:43
ripple::CreateOffer::makeTxConsequences
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
Definition: CreateOffer.cpp:32
ripple::CreateOffer::cross_type_
CrossType cross_type_
Definition: CreateOffer.h:139
-
ripple::CreateOffer::doApply
TER doApply() override
Precondition: fee collection is likely.
Definition: CreateOffer.cpp:1247
-
ripple::CreateOffer::applyGuts
std::pair< TER, bool > applyGuts(Sandbox &view, Sandbox &view_cancel)
Definition: CreateOffer.cpp:928
-
ripple::CreateOffer::select_path
static std::pair< bool, Quality > select_path(bool have_direct, OfferStream const &direct, bool have_bridge, OfferStream const &leg1, OfferStream const &leg2)
Definition: CreateOffer.cpp:280
-
ripple::CreateOffer::cross
std::pair< TER, Amounts > cross(Sandbox &sb, Sandbox &sbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:884
+
ripple::CreateOffer::doApply
TER doApply() override
Precondition: fee collection is likely.
Definition: CreateOffer.cpp:1273
+
ripple::CreateOffer::applyGuts
std::pair< TER, bool > applyGuts(Sandbox &view, Sandbox &view_cancel)
Definition: CreateOffer.cpp:954
+
ripple::CreateOffer::select_path
static std::pair< bool, Quality > select_path(bool have_direct, OfferStream const &direct, bool have_bridge, OfferStream const &leg1, OfferStream const &leg2)
Definition: CreateOffer.cpp:306
+
ripple::CreateOffer::cross
std::pair< TER, Amounts > cross(Sandbox &sb, Sandbox &sbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:910
ripple::Issue
A currency issued by an account.
Definition: Issue.h:36
ripple::Issue::account
AccountID account
Definition: Issue.h:39
ripple::Issue::currency
Currency currency
Definition: Issue.h:38
@@ -1457,7 +1483,7 @@ $(function() {
ripple::xrpIssue
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:118
ripple::divide
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:87
ripple::badCurrency
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
Definition: UintTypes.cpp:129
-
ripple::accountFunds
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition: View.cpp:366
+
ripple::accountFunds
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition: View.cpp:405
ripple::fhZERO_IF_FROZEN
@ fhZERO_IF_FROZEN
Definition: View.h:80
ripple::fhIGNORE_FREEZE
@ fhIGNORE_FREEZE
Definition: View.h:80
ripple::isTecClaim
bool isTecClaim(TER x)
Definition: TER.h:662
@@ -1466,22 +1492,24 @@ $(function() {
ripple::tfOfferCreateMask
constexpr std::uint32_t tfOfferCreateMask
Definition: TxFlags.h:100
ripple::divRoundStrict
STAmount divRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
Definition: STAmount.cpp:1627
ripple::isLegalNet
bool isLegalNet(STAmount const &value)
Definition: STAmount.h:581
-
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition: View.cpp:573
+
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition: View.cpp:612
+
ripple::lsfHighDeepFreeze
@ lsfHighDeepFreeze
Definition: LedgerFormats.h:166
ripple::lsfRequireAuth
@ lsfRequireAuth
Definition: LedgerFormats.h:128
ripple::lsfSell
@ lsfSell
Definition: LedgerFormats.h:154
+
ripple::lsfLowDeepFreeze
@ lsfLowDeepFreeze
Definition: LedgerFormats.h:165
ripple::lsfHighAuth
@ lsfHighAuth
Definition: LedgerFormats.h:160
ripple::lsfLowAuth
@ lsfLowAuth
Definition: LedgerFormats.h:159
ripple::lsfPassive
@ lsfPassive
Definition: LedgerFormats.h:153
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:47
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
-
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:848
+
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:887
ripple::tfFillOrKill
constexpr std::uint32_t tfFillOrKill
Definition: TxFlags.h:98
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
ripple::divideRound
STAmount divideRound(STAmount const &amount, Rate const &rate, bool roundUp)
Definition: Rate2.cpp:98
ripple::flow
StrandResult< TInAmt, TOutAmt > flow(PaymentSandbox const &baseView, Strand const &strand, std::optional< TInAmt > const &maxIn, TOutAmt const &out, beast::Journal j)
Request out amount from a strand.
Definition: StrandFlow.h:106
ripple::tfPassive
constexpr std::uint32_t tfPassive
Definition: TxFlags.h:96
ripple::tfImmediateOrCancel
constexpr std::uint32_t tfImmediateOrCancel
Definition: TxFlags.h:97
-
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1010
+
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1054
ripple::getRate
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition: STAmount.cpp:451
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:173
ripple::OfferCrossing
OfferCrossing
Definition: Steps.h:42
diff --git a/CreateOffer_8h_source.html b/CreateOffer_8h_source.html index 039faa9861..ab4eb1908a 100644 --- a/CreateOffer_8h_source.html +++ b/CreateOffer_8h_source.html @@ -224,27 +224,27 @@ $(function() {
ripple::ApplyContext
State information when applying a tx.
Definition: ApplyContext.h:36
ripple::ApplyView
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:140
ripple::CreateOffer
Transactor specialized for creating offers in the ledger.
Definition: CreateOffer.h:35
-
ripple::CreateOffer::bridged_cross
std::pair< TER, Amounts > bridged_cross(Taker &taker, ApplyView &view, ApplyView &view_cancel, NetClock::time_point const when)
Definition: CreateOffer.cpp:326
+
ripple::CreateOffer::bridged_cross
std::pair< TER, Amounts > bridged_cross(Taker &taker, ApplyView &view, ApplyView &view_cancel, NetClock::time_point const when)
Definition: CreateOffer.cpp:352
ripple::CreateOffer::stepCounter_
OfferStream::StepCounter stepCounter_
Definition: CreateOffer.h:142
-
ripple::CreateOffer::flowCross
std::pair< TER, Amounts > flowCross(PaymentSandbox &psb, PaymentSandbox &psbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:682
+
ripple::CreateOffer::flowCross
std::pair< TER, Amounts > flowCross(PaymentSandbox &psb, PaymentSandbox &psbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:708
ripple::CreateOffer::checkAcceptAsset
static TER checkAcceptAsset(ReadView const &view, ApplyFlags const flags, AccountID const id, beast::Journal const j, Issue const &issue)
Definition: CreateOffer.cpp:205
ripple::CreateOffer::CreateOffer
CreateOffer(ApplyContext &ctx)
Construct a Transactor subclass that creates an offer in the ledger.
Definition: CreateOffer.h:40
-
ripple::CreateOffer::preCompute
void preCompute() override
Gather information beyond what the Transactor base class gathers.
Definition: CreateOffer.cpp:914
-
ripple::CreateOffer::dry_offer
bool dry_offer(ApplyView &view, Offer const &offer)
Definition: CreateOffer.cpp:266
+
ripple::CreateOffer::preCompute
void preCompute() override
Gather information beyond what the Transactor base class gathers.
Definition: CreateOffer.cpp:940
+
ripple::CreateOffer::dry_offer
bool dry_offer(ApplyView &view, Offer const &offer)
Definition: CreateOffer.cpp:292
ripple::CreateOffer::preclaim
static TER preclaim(PreclaimContext const &ctx)
Enforce constraints beyond those of the Transactor base class.
Definition: CreateOffer.cpp:129
-
ripple::CreateOffer::step_account
static bool step_account(OfferStream &stream, Taker const &taker)
Definition: CreateOffer.cpp:614
-
ripple::CreateOffer::format_amount
static std::string format_amount(STAmount const &amount)
Definition: CreateOffer.cpp:905
+
ripple::CreateOffer::step_account
static bool step_account(OfferStream &stream, Taker const &taker)
Definition: CreateOffer.cpp:640
+
ripple::CreateOffer::format_amount
static std::string format_amount(STAmount const &amount)
Definition: CreateOffer.cpp:931
ripple::CreateOffer::ConsequencesFactory
static constexpr ConsequencesFactoryType ConsequencesFactory
Definition: CreateOffer.h:37
-
ripple::CreateOffer::reachedOfferCrossingLimit
bool reachedOfferCrossingLimit(Taker const &taker) const
Definition: CreateOffer.cpp:315
-
ripple::CreateOffer::takerCross
std::pair< TER, Amounts > takerCross(Sandbox &sb, Sandbox &sbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:637
-
ripple::CreateOffer::direct_cross
std::pair< TER, Amounts > direct_cross(Taker &taker, ApplyView &view, ApplyView &view_cancel, NetClock::time_point const when)
Definition: CreateOffer.cpp:519
+
ripple::CreateOffer::reachedOfferCrossingLimit
bool reachedOfferCrossingLimit(Taker const &taker) const
Definition: CreateOffer.cpp:341
+
ripple::CreateOffer::takerCross
std::pair< TER, Amounts > takerCross(Sandbox &sb, Sandbox &sbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:663
+
ripple::CreateOffer::direct_cross
std::pair< TER, Amounts > direct_cross(Taker &taker, ApplyView &view, ApplyView &view_cancel, NetClock::time_point const when)
Definition: CreateOffer.cpp:545
ripple::CreateOffer::preflight
static NotTEC preflight(PreflightContext const &ctx)
Enforce constraints beyond those of the Transactor base class.
Definition: CreateOffer.cpp:43
ripple::CreateOffer::makeTxConsequences
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
Definition: CreateOffer.cpp:32
ripple::CreateOffer::cross_type_
CrossType cross_type_
Definition: CreateOffer.h:139
-
ripple::CreateOffer::doApply
TER doApply() override
Precondition: fee collection is likely.
Definition: CreateOffer.cpp:1247
-
ripple::CreateOffer::applyGuts
std::pair< TER, bool > applyGuts(Sandbox &view, Sandbox &view_cancel)
Definition: CreateOffer.cpp:928
-
ripple::CreateOffer::select_path
static std::pair< bool, Quality > select_path(bool have_direct, OfferStream const &direct, bool have_bridge, OfferStream const &leg1, OfferStream const &leg2)
Definition: CreateOffer.cpp:280
-
ripple::CreateOffer::cross
std::pair< TER, Amounts > cross(Sandbox &sb, Sandbox &sbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:884
+
ripple::CreateOffer::doApply
TER doApply() override
Precondition: fee collection is likely.
Definition: CreateOffer.cpp:1273
+
ripple::CreateOffer::applyGuts
std::pair< TER, bool > applyGuts(Sandbox &view, Sandbox &view_cancel)
Definition: CreateOffer.cpp:954
+
ripple::CreateOffer::select_path
static std::pair< bool, Quality > select_path(bool have_direct, OfferStream const &direct, bool have_bridge, OfferStream const &leg1, OfferStream const &leg2)
Definition: CreateOffer.cpp:306
+
ripple::CreateOffer::cross
std::pair< TER, Amounts > cross(Sandbox &sb, Sandbox &sbCancel, Amounts const &takerAmount)
Definition: CreateOffer.cpp:910
ripple::Issue
A currency issued by an account.
Definition: Issue.h:36
ripple::OfferStream
Presents and consumes the offers in an order book.
Definition: OfferStream.h:148
ripple::PaymentSandbox
A wrapper which makes credits unavailable to balances.
Definition: PaymentSandbox.h:113
diff --git a/CreateTicket_8cpp_source.html b/CreateTicket_8cpp_source.html index 09e67be545..3f2c1ac4cb 100644 --- a/CreateTicket_8cpp_source.html +++ b/CreateTicket_8cpp_source.html @@ -267,7 +267,7 @@ $(function() {
ripple::keylet::ticket
static ticket_t const ticket
Definition: Indexes.h:170
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
-
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:848
+
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:887
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:173
ripple::adjustOwnerCount
static bool adjustOwnerCount(ApplyContext &ctx, int count)
Definition: SetOracle.cpp:186
diff --git a/CredentialHelpers_8cpp_source.html b/CredentialHelpers_8cpp_source.html index 9d736d1ee1..dd16e88f1a 100644 --- a/CredentialHelpers_8cpp_source.html +++ b/CredentialHelpers_8cpp_source.html @@ -424,7 +424,7 @@ $(function() {
ripple::keylet::depositPreauth
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Definition: Indexes.cpp:318
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::lsfDepositAuth
@ lsfDepositAuth
Definition: LedgerFormats.h:136
-
ripple::lsfAccepted
@ lsfAccepted
Definition: LedgerFormats.h:191
+
ripple::lsfAccepted
@ lsfAccepted
Definition: LedgerFormats.h:193
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:170
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:173
diff --git a/Credentials_8cpp_source.html b/Credentials_8cpp_source.html index 69cdda22d8..4b7679b4a3 100644 --- a/Credentials_8cpp_source.html +++ b/Credentials_8cpp_source.html @@ -500,9 +500,9 @@ $(function() {
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:350
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::maxCredentialURILength
std::size_t constexpr maxCredentialURILength
The maximum length of a URI inside a Credential.
Definition: Protocol.h:100
-
ripple::lsfAccepted
@ lsfAccepted
Definition: LedgerFormats.h:191
+
ripple::lsfAccepted
@ lsfAccepted
Definition: LedgerFormats.h:193
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
-
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:848
+
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:887
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:173
ripple::adjustOwnerCount
static bool adjustOwnerCount(ApplyContext &ctx, int count)
Definition: SetOracle.cpp:186
diff --git a/Credentials__test_8cpp_source.html b/Credentials__test_8cpp_source.html index a80901909f..f503f6fd6e 100644 --- a/Credentials__test_8cpp_source.html +++ b/Credentials__test_8cpp_source.html @@ -1189,7 +1189,7 @@ $(function() {
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::xrpAccount
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:170
ripple::maxCredentialURILength
std::size_t constexpr maxCredentialURILength
The maximum length of a URI inside a Credential.
Definition: Protocol.h:100
-
ripple::lsfAccepted
@ lsfAccepted
Definition: LedgerFormats.h:191
+
ripple::lsfAccepted
@ lsfAccepted
Definition: LedgerFormats.h:193
ripple::TxSearched::all
@ all
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::maxCredentialTypeLength
std::size_t constexpr maxCredentialTypeLength
The maximum length of a CredentialType inside a Credential.
Definition: Protocol.h:103
diff --git a/DID_8cpp_source.html b/DID_8cpp_source.html index f61a1116e2..44b9a8752f 100644 --- a/DID_8cpp_source.html +++ b/DID_8cpp_source.html @@ -350,7 +350,7 @@ $(function() {
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:316
ripple::maxDIDDocumentLength
std::size_t constexpr maxDIDDocumentLength
The maximum length of a Data element inside a DID.
Definition: Protocol.h:88
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
-
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:848
+
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:887
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:170
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:173
diff --git a/DeleteAccount_8cpp_source.html b/DeleteAccount_8cpp_source.html index d3e362a7ff..2ccc7a0456 100644 --- a/DeleteAccount_8cpp_source.html +++ b/DeleteAccount_8cpp_source.html @@ -565,7 +565,7 @@ $(function() {
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
ripple::SkipEntry::No
@ No
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
-
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1010
+
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1054
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:170
ripple::tefTOO_BIG
@ tefTOO_BIG
Definition: TER.h:184
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:134
@@ -579,11 +579,11 @@ $(function() {
ripple::verifyDepositPreauth
TER verifyDepositPreauth(ApplyContext &ctx, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst)
Definition: CredentialHelpers.cpp:276
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::LedgerEntryType
LedgerEntryType
Identifiers for on-ledger objects.
Definition: LedgerFormats.h:54
-
ripple::cleanupOnAccountDelete
TER cleanupOnAccountDelete(ApplyView &view, Keylet const &ownerDirKeylet, EntryDeleter const &deleter, beast::Journal j, std::optional< uint16_t > maxNodesToDelete)
Definition: View.cpp:1888
+
ripple::cleanupOnAccountDelete
TER cleanupOnAccountDelete(ApplyView &view, Keylet const &ownerDirKeylet, EntryDeleter const &deleter, beast::Journal j, std::optional< uint16_t > maxNodesToDelete)
Definition: View.cpp:1934
ripple::tfUniversalMask
constexpr std::uint32_t tfUniversalMask
Definition: TxFlags.h:62
ripple::terNO_ACCOUNT
@ terNO_ACCOUNT
Definition: TER.h:217
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:627
-
ripple::dirIsEmpty
bool dirIsEmpty(ReadView const &view, Keylet const &k)
Returns true if the directory is empty.
Definition: View.cpp:705
+
ripple::dirIsEmpty
bool dirIsEmpty(ReadView const &view, Keylet const &k)
Returns true if the directory is empty.
Definition: View.cpp:744
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:587
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:111
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:114
diff --git a/DepositAuthorized_8cpp_source.html b/DepositAuthorized_8cpp_source.html index 09f3359a96..68f4c37025 100644 --- a/DepositAuthorized_8cpp_source.html +++ b/DepositAuthorized_8cpp_source.html @@ -301,7 +301,7 @@ $(function() {
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
ripple::rpcDST_ACT_NOT_FOUND
@ rpcDST_ACT_NOT_FOUND
Definition: ErrorCodes.h:105
ripple::lsfDepositAuth
@ lsfDepositAuth
Definition: LedgerFormats.h:136
-
ripple::lsfAccepted
@ lsfAccepted
Definition: LedgerFormats.h:191
+
ripple::lsfAccepted
@ lsfAccepted
Definition: LedgerFormats.h:193
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
ripple::doDepositAuthorized
Json::Value doDepositAuthorized(RPC::JsonContext &context)
Definition: DepositAuthorized.cpp:40
ripple::maxCredentialsArraySize
std::size_t constexpr maxCredentialsArraySize
The maximum number of credentials can be passed in array.
Definition: Protocol.h:106
diff --git a/DepositPreauth_8cpp_source.html b/DepositPreauth_8cpp_source.html index ce9ed2b426..3a824ea09a 100644 --- a/DepositPreauth_8cpp_source.html +++ b/DepositPreauth_8cpp_source.html @@ -438,7 +438,7 @@ $(function() {
ripple::keylet::depositPreauth
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Definition: Indexes.cpp:318
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
-
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:848
+
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:887
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:170
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:173
diff --git a/DirectStep_8cpp_source.html b/DirectStep_8cpp_source.html index fa82c9458d..a0fe4d2662 100644 --- a/DirectStep_8cpp_source.html +++ b/DirectStep_8cpp_source.html @@ -1166,7 +1166,7 @@ $(function() {
ripple::StrandDirection::reverse
@ reverse
ripple::StrandDirection::forward
@ forward
ripple::checkFreeze
TER checkFreeze(ReadView const &view, AccountID const &src, AccountID const &dst, Currency const &currency)
Definition: StepChecks.h:32
-
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition: View.cpp:573
+
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition: View.cpp:612
ripple::lsfHighNoRipple
@ lsfHighNoRipple
Definition: LedgerFormats.h:162
ripple::lsfRequireAuth
@ lsfRequireAuth
Definition: LedgerFormats.h:128
ripple::lsfLowNoRipple
@ lsfLowNoRipple
Definition: LedgerFormats.h:161
@@ -1176,7 +1176,7 @@ $(function() {
ripple::creditLimit
STAmount creditLimit(ReadView const &view, AccountID const &account, AccountID const &issuer, Currency const &currency)
Calculate the maximum amount of IOUs that an account can hold.
Definition: Credit.cpp:28
ripple::toAmount< IOUAmount >
IOUAmount toAmount< IOUAmount >(STAmount const &amt)
Definition: AmountConversions.h:75
ripple::creditBalance
STAmount creditBalance(ReadView const &view, AccountID const &account, AccountID const &issuer, Currency const &currency)
Returns the amount of IOUs issued by issuer that are held by an account.
Definition: Credit.cpp:65
-
ripple::checkNoRipple
TER checkNoRipple(ReadView const &view, AccountID const &prev, AccountID const &cur, AccountID const &next, Currency const &currency, beast::Journal j)
Definition: StepChecks.h:61
+
ripple::checkNoRipple
TER checkNoRipple(ReadView const &view, AccountID const &prev, AccountID const &cur, AccountID const &next, Currency const &currency, beast::Journal j)
Definition: StepChecks.h:67
ripple::getRate
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition: STAmount.cpp:451
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:173
ripple::QualityDirection
QualityDirection
Definition: Steps.h:40
@@ -1189,11 +1189,11 @@ $(function() {
ripple::tecPATH_DRY
@ tecPATH_DRY
Definition: TER.h:281
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
ripple::mulRatio
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
Definition: IOUAmount.cpp:182
-
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:271
+
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:297
ripple::make_DirectStepI
std::pair< TER, std::unique_ptr< Step > > make_DirectStepI(StrandContext const &ctx, AccountID const &src, AccountID const &dst, Currency const &c)
Definition: DirectStep.cpp:983
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::creditLimit2
IOUAmount creditLimit2(ReadView const &v, AccountID const &acc, AccountID const &iss, Currency const &cur)
Definition: Credit.cpp:55
-
ripple::rippleCredit
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
Definition: View.cpp:2015
+
ripple::rippleCredit
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
Definition: View.cpp:2061
ripple::terNO_ACCOUNT
@ terNO_ACCOUNT
Definition: TER.h:217
ripple::terNO_RIPPLE
@ terNO_RIPPLE
Definition: TER.h:224
ripple::terNO_AUTH
@ terNO_AUTH
Definition: TER.h:218
diff --git a/Directory__test_8cpp_source.html b/Directory__test_8cpp_source.html index ee1100cd21..477dd1539a 100644 --- a/Directory__test_8cpp_source.html +++ b/Directory__test_8cpp_source.html @@ -628,7 +628,7 @@ $(function() {
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::tapNONE
@ tapNONE
Definition: ApplyView.h:31
ripple::getBookBase
uint256 getBookBase(Book const &book)
Definition: Indexes.cpp:98
-
ripple::dirIsEmpty
bool dirIsEmpty(ReadView const &view, Keylet const &k)
Returns true if the directory is empty.
Definition: View.cpp:705
+
ripple::dirIsEmpty
bool dirIsEmpty(ReadView const &view, Keylet const &k)
Returns true if the directory is empty.
Definition: View.cpp:744
ripple::default_prng
beast::xor_shift_engine & default_prng()
Return the default random engine.
Definition: include/xrpl/basics/random.h:65
std::string::push_back
T push_back(T... args)
std::shuffle
T shuffle(T... args)
diff --git a/Escrow_8cpp_source.html b/Escrow_8cpp_source.html index 7979af4da4..60ed40dea9 100644 --- a/Escrow_8cpp_source.html +++ b/Escrow_8cpp_source.html @@ -740,7 +740,7 @@ $(function() {
ripple::lsfRequireDestTag
@ lsfRequireDestTag
Definition: LedgerFormats.h:126
ripple::lsfDisallowXRP
@ lsfDisallowXRP
Definition: LedgerFormats.h:130
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:656
-
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:848
+
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:887
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:82
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:170
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:173
diff --git a/Feature1_8cpp_source.html b/Feature1_8cpp_source.html index 977444dd76..46c348011d 100644 --- a/Feature1_8cpp_source.html +++ b/Feature1_8cpp_source.html @@ -195,7 +195,7 @@ $(function() {
ripple::isAdmin
bool isAdmin(Port const &port, Json::Value const &params, beast::IP::Address const &remoteIp)
Definition: Role.cpp:84
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
ripple::doFeature
Json::Value doFeature(RPC::JsonContext &context)
Definition: Feature1.cpp:36
-
ripple::getMajorityAmendments
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition: View.cpp:736
+
ripple::getMajorityAmendments
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition: View.cpp:775
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
ripple::Role::ADMIN
@ ADMIN
ripple::RPC::Context::role
Role role
Definition: Context.h:47
diff --git a/Feature_8h_source.html b/Feature_8h_source.html index fc29fe2ae5..cef5e41979 100644 --- a/Feature_8h_source.html +++ b/Feature_8h_source.html @@ -120,7 +120,7 @@ $(function() {
80// Feature.cpp. Because it's only used to reserve storage, and determine how
81// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
82// the actual number of amendments. A LogicError on startup will verify this.
-
83static constexpr std::size_t numFeatures = 85;
+
83static constexpr std::size_t numFeatures = 86;
84
88std::map<std::string, VoteBehavior> const&
89supportedAmendments();
diff --git a/Feature__test_8cpp_source.html b/Feature__test_8cpp_source.html index a2c72b4e34..328057ca4f 100644 --- a/Feature__test_8cpp_source.html +++ b/Feature__test_8cpp_source.html @@ -755,7 +755,7 @@ $(function() {
ripple::VoteBehavior::DefaultNo
@ DefaultNo
ripple::VoteBehavior::DefaultYes
@ DefaultYes
ripple::VoteBehavior::Obsolete
@ Obsolete
-
ripple::getMajorityAmendments
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition: View.cpp:736
+
ripple::getMajorityAmendments
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition: View.cpp:775
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
std::size_t
std::unique_ptr
diff --git a/FixNFTokenPageLinks__test_8cpp_source.html b/FixNFTokenPageLinks__test_8cpp_source.html index e7d8995017..d40b64b599 100644 --- a/FixNFTokenPageLinks__test_8cpp_source.html +++ b/FixNFTokenPageLinks__test_8cpp_source.html @@ -778,13 +778,13 @@ $(function() {
ripple::nft::toTaxon
Taxon toTaxon(std::uint32_t i)
Definition: nft.h:42
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::telINSUF_FEE_P
@ telINSUF_FEE_P
Definition: TER.h:57
-
ripple::tfSellNFToken
constexpr std::uint32_t const tfSellNFToken
Definition: TxFlags.h:187
+
ripple::tfSellNFToken
constexpr std::uint32_t const tfSellNFToken
Definition: TxFlags.h:189
ripple::tfPassive
constexpr std::uint32_t tfPassive
Definition: TxFlags.h:96
ripple::tefINVALID_LEDGER_FIX_TYPE
@ tefINVALID_LEDGER_FIX_TYPE
Definition: TER.h:187
ripple::tecOBJECT_NOT_FOUND
@ tecOBJECT_NOT_FOUND
Definition: TER.h:313
ripple::tecFAILED_PROCESSING
@ tecFAILED_PROCESSING
Definition: TER.h:273
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
-
ripple::tfTransferable
constexpr std::uint32_t const tfTransferable
Definition: TxFlags.h:134
+
ripple::tfTransferable
constexpr std::uint32_t const tfTransferable
Definition: TxFlags.h:136
ripple::temINVALID
@ temINVALID
Definition: TER.h:110
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:111
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:114
diff --git a/Flow__test_8cpp_source.html b/Flow__test_8cpp_source.html index 6980ea0dc7..146026c206 100644 --- a/Flow__test_8cpp_source.html +++ b/Flow__test_8cpp_source.html @@ -1614,7 +1614,7 @@ $(function() {
ripple::lsfLowNoRipple
@ lsfLowNoRipple
Definition: LedgerFormats.h:161
ripple::flow
StrandResult< TInAmt, TOutAmt > flow(PaymentSandbox const &baseView, Strand const &strand, std::optional< TInAmt > const &maxIn, TOutAmt const &out, beast::Journal j)
Request out amount from a strand.
Definition: StrandFlow.h:106
ripple::tfPassive
constexpr std::uint32_t tfPassive
Definition: TxFlags.h:96
-
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1010
+
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1054
ripple::getRate
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition: STAmount.cpp:451
ripple::no
@ no
Definition: Steps.h:42
ripple::tfPartialPayment
constexpr std::uint32_t tfPartialPayment
Definition: TxFlags.h:105
@@ -1625,7 +1625,7 @@ $(function() {
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:242
ripple::tfLimitQuality
constexpr std::uint32_t tfLimitQuality
Definition: TxFlags.h:106
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
-
ripple::forEachItem
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.
Definition: View.cpp:467
+
ripple::forEachItem
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.
Definition: View.cpp:506
ripple::tapNONE
@ tapNONE
Definition: ApplyView.h:31
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:627
ripple::tfSetNoRipple
constexpr std::uint32_t tfSetNoRipple
Definition: TxFlags.h:113
diff --git a/Freeze__test_8cpp_source.html b/Freeze__test_8cpp_source.html index 98914545c2..6826ef51cd 100644 --- a/Freeze__test_8cpp_source.html +++ b/Freeze__test_8cpp_source.html @@ -95,547 +95,2087 @@ $(function() {
17*/
18//==============================================================================
19#include <test/jtx.h>
-
20#include <xrpl/protocol/AccountID.h>
-
21#include <xrpl/protocol/Feature.h>
-
22#include <xrpl/protocol/SField.h>
-
23#include <xrpl/protocol/TxFlags.h>
-
24#include <xrpl/protocol/jss.h>
-
25
-
26namespace ripple {
-
27
-
28class Freeze_test : public beast::unit_test::suite
-
29{
-
30 void
-
31 testRippleState(FeatureBitset features)
-
32 {
-
33 testcase("RippleState Freeze");
-
34
-
35 using namespace test::jtx;
-
36 Env env(*this, features);
-
37
-
38 Account G1{"G1"};
-
39 Account alice{"alice"};
-
40 Account bob{"bob"};
-
41
-
42 env.fund(XRP(1000), G1, alice, bob);
-
43 env.close();
-
44
-
45 env.trust(G1["USD"](100), bob);
-
46 env.trust(G1["USD"](100), alice);
-
47 env.close();
-
48
-
49 env(pay(G1, bob, G1["USD"](10)));
-
50 env(pay(G1, alice, G1["USD"](100)));
-
51 env.close();
-
52
-
53 env(offer(alice, XRP(500), G1["USD"](100)));
-
54 env.close();
-
55
-
56 {
-
57 auto lines = getAccountLines(env, bob);
-
58 if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
-
59 return;
-
60 BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
-
61 BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "100");
-
62 BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "10");
-
63 }
-
64
-
65 {
-
66 auto lines = getAccountLines(env, alice);
-
67 if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
-
68 return;
-
69 BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
-
70 BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "100");
-
71 BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "100");
-
72 }
-
73
-
74 {
-
75 // Account with line unfrozen (proving operations normally work)
-
76 // test: can make Payment on that line
-
77 env(pay(alice, bob, G1["USD"](1)));
-
78
-
79 // test: can receive Payment on that line
-
80 env(pay(bob, alice, G1["USD"](1)));
-
81 env.close();
-
82 }
-
83
-
84 {
-
85 // Is created via a TrustSet with SetFreeze flag
-
86 // test: sets LowFreeze | HighFreeze flags
-
87 env(trust(G1, bob["USD"](0), tfSetFreeze));
-
88 auto affected = env.meta()->getJson(
-
89 JsonOptions::none)[sfAffectedNodes.fieldName];
-
90 if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
-
91 return;
-
92 auto ff =
-
93 affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
-
94 BEAST_EXPECT(
-
95 ff[sfLowLimit.fieldName] ==
-
96 G1["USD"](0).value().getJson(JsonOptions::none));
-
97 BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfLowFreeze);
-
98 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze));
-
99 env.close();
-
100 }
-
101
-
102 {
-
103 // Account with line frozen by issuer
-
104 // test: can buy more assets on that line
-
105 env(offer(bob, G1["USD"](5), XRP(25)));
-
106 auto affected = env.meta()->getJson(
-
107 JsonOptions::none)[sfAffectedNodes.fieldName];
-
108 if (!BEAST_EXPECT(checkArraySize(affected, 5u)))
-
109 return;
-
110 auto ff =
-
111 affected[3u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
-
112 BEAST_EXPECT(
-
113 ff[sfHighLimit.fieldName] ==
-
114 bob["USD"](100).value().getJson(JsonOptions::none));
-
115 auto amt = STAmount{Issue{to_currency("USD"), noAccount()}, -15}
-
116 .value()
-
117 .getJson(JsonOptions::none);
-
118 BEAST_EXPECT(ff[sfBalance.fieldName] == amt);
-
119 env.close();
-
120 }
-
121
-
122 {
-
123 // test: can not sell assets from that line
-
124 env(offer(bob, XRP(1), G1["USD"](5)), ter(tecUNFUNDED_OFFER));
-
125
-
126 // test: can receive Payment on that line
-
127 env(pay(alice, bob, G1["USD"](1)));
-
128
-
129 // test: can not make Payment from that line
-
130 env(pay(bob, alice, G1["USD"](1)), ter(tecPATH_DRY));
-
131 }
-
132
-
133 {
-
134 // check G1 account lines
-
135 // test: shows freeze
-
136 auto lines = getAccountLines(env, G1);
-
137 Json::Value bobLine;
-
138 for (auto const& it : lines[jss::lines])
-
139 {
-
140 if (it[jss::account] == bob.human())
-
141 {
-
142 bobLine = it;
-
143 break;
-
144 }
-
145 }
-
146 if (!BEAST_EXPECT(bobLine))
-
147 return;
-
148 BEAST_EXPECT(bobLine[jss::freeze] == true);
-
149 BEAST_EXPECT(bobLine[jss::balance] == "-16");
-
150 }
-
151
-
152 {
-
153 // test: shows freeze peer
-
154 auto lines = getAccountLines(env, bob);
-
155 Json::Value g1Line;
-
156 for (auto const& it : lines[jss::lines])
-
157 {
-
158 if (it[jss::account] == G1.human())
-
159 {
-
160 g1Line = it;
-
161 break;
-
162 }
-
163 }
-
164 if (!BEAST_EXPECT(g1Line))
-
165 return;
-
166 BEAST_EXPECT(g1Line[jss::freeze_peer] == true);
-
167 BEAST_EXPECT(g1Line[jss::balance] == "16");
-
168 }
-
169
-
170 {
-
171 // Is cleared via a TrustSet with ClearFreeze flag
-
172 // test: sets LowFreeze | HighFreeze flags
-
173 env(trust(G1, bob["USD"](0), tfClearFreeze));
-
174 auto affected = env.meta()->getJson(
-
175 JsonOptions::none)[sfAffectedNodes.fieldName];
-
176 if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
-
177 return;
-
178 auto ff =
-
179 affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
-
180 BEAST_EXPECT(
-
181 ff[sfLowLimit.fieldName] ==
-
182 G1["USD"](0).value().getJson(JsonOptions::none));
-
183 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowFreeze));
-
184 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze));
-
185 env.close();
-
186 }
-
187 }
-
188
-
189 void
-
190 testGlobalFreeze(FeatureBitset features)
-
191 {
-
192 testcase("Global Freeze");
-
193
-
194 using namespace test::jtx;
-
195 Env env(*this, features);
-
196
-
197 Account G1{"G1"};
-
198 Account A1{"A1"};
-
199 Account A2{"A2"};
-
200 Account A3{"A3"};
-
201 Account A4{"A4"};
-
202
-
203 env.fund(XRP(12000), G1);
-
204 env.fund(XRP(1000), A1);
-
205 env.fund(XRP(20000), A2, A3, A4);
-
206 env.close();
-
207
-
208 env.trust(G1["USD"](1200), A1);
-
209 env.trust(G1["USD"](200), A2);
-
210 env.trust(G1["BTC"](100), A3);
-
211 env.trust(G1["BTC"](100), A4);
-
212 env.close();
-
213
-
214 env(pay(G1, A1, G1["USD"](1000)));
-
215 env(pay(G1, A2, G1["USD"](100)));
-
216 env(pay(G1, A3, G1["BTC"](100)));
-
217 env(pay(G1, A4, G1["BTC"](100)));
-
218 env.close();
+
20#include <test/jtx/AMM.h>
+
21#include <xrpl/protocol/AccountID.h>
+
22#include <xrpl/protocol/Feature.h>
+
23#include <xrpl/protocol/SField.h>
+
24#include <xrpl/protocol/TxFlags.h>
+
25#include <xrpl/protocol/jss.h>
+
26
+
27namespace ripple {
+
28
+
29class Freeze_test : public beast::unit_test::suite
+
30{
+
31 void
+
32 testRippleState(FeatureBitset features)
+
33 {
+
34 testcase("RippleState Freeze");
+
35
+
36 using namespace test::jtx;
+
37 Env env(*this, features);
+
38
+
39 Account G1{"G1"};
+
40 Account alice{"alice"};
+
41 Account bob{"bob"};
+
42
+
43 env.fund(XRP(1000), G1, alice, bob);
+
44 env.close();
+
45
+
46 env.trust(G1["USD"](100), bob);
+
47 env.trust(G1["USD"](100), alice);
+
48 env.close();
+
49
+
50 env(pay(G1, bob, G1["USD"](10)));
+
51 env(pay(G1, alice, G1["USD"](100)));
+
52 env.close();
+
53
+
54 env(offer(alice, XRP(500), G1["USD"](100)));
+
55 env.close();
+
56
+
57 {
+
58 auto lines = getAccountLines(env, bob);
+
59 if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
+
60 return;
+
61 BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
+
62 BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "100");
+
63 BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "10");
+
64 }
+
65
+
66 {
+
67 auto lines = getAccountLines(env, alice);
+
68 if (!BEAST_EXPECT(checkArraySize(lines[jss::lines], 1u)))
+
69 return;
+
70 BEAST_EXPECT(lines[jss::lines][0u][jss::account] == G1.human());
+
71 BEAST_EXPECT(lines[jss::lines][0u][jss::limit] == "100");
+
72 BEAST_EXPECT(lines[jss::lines][0u][jss::balance] == "100");
+
73 }
+
74
+
75 {
+
76 // Account with line unfrozen (proving operations normally work)
+
77 // test: can make Payment on that line
+
78 env(pay(alice, bob, G1["USD"](1)));
+
79
+
80 // test: can receive Payment on that line
+
81 env(pay(bob, alice, G1["USD"](1)));
+
82 env.close();
+
83 }
+
84
+
85 {
+
86 // Is created via a TrustSet with SetFreeze flag
+
87 // test: sets LowFreeze | HighFreeze flags
+
88 env(trust(G1, bob["USD"](0), tfSetFreeze));
+
89 auto affected = env.meta()->getJson(
+
90 JsonOptions::none)[sfAffectedNodes.fieldName];
+
91 if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
+
92 return;
+
93 auto ff =
+
94 affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
+
95 BEAST_EXPECT(
+
96 ff[sfLowLimit.fieldName] ==
+
97 G1["USD"](0).value().getJson(JsonOptions::none));
+
98 BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfLowFreeze);
+
99 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze));
+
100 env.close();
+
101 }
+
102
+
103 {
+
104 // Account with line frozen by issuer
+
105 // test: can buy more assets on that line
+
106 env(offer(bob, G1["USD"](5), XRP(25)));
+
107 auto affected = env.meta()->getJson(
+
108 JsonOptions::none)[sfAffectedNodes.fieldName];
+
109 if (!BEAST_EXPECT(checkArraySize(affected, 5u)))
+
110 return;
+
111 auto ff =
+
112 affected[3u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
+
113 BEAST_EXPECT(
+
114 ff[sfHighLimit.fieldName] ==
+
115 bob["USD"](100).value().getJson(JsonOptions::none));
+
116 auto amt = STAmount{Issue{to_currency("USD"), noAccount()}, -15}
+
117 .value()
+
118 .getJson(JsonOptions::none);
+
119 BEAST_EXPECT(ff[sfBalance.fieldName] == amt);
+
120 env.close();
+
121 }
+
122
+
123 {
+
124 // test: can not sell assets from that line
+
125 env(offer(bob, XRP(1), G1["USD"](5)), ter(tecUNFUNDED_OFFER));
+
126
+
127 // test: can receive Payment on that line
+
128 env(pay(alice, bob, G1["USD"](1)));
+
129
+
130 // test: can not make Payment from that line
+
131 env(pay(bob, alice, G1["USD"](1)), ter(tecPATH_DRY));
+
132 }
+
133
+
134 {
+
135 // check G1 account lines
+
136 // test: shows freeze
+
137 auto lines = getAccountLines(env, G1);
+
138 Json::Value bobLine;
+
139 for (auto const& it : lines[jss::lines])
+
140 {
+
141 if (it[jss::account] == bob.human())
+
142 {
+
143 bobLine = it;
+
144 break;
+
145 }
+
146 }
+
147 if (!BEAST_EXPECT(bobLine))
+
148 return;
+
149 BEAST_EXPECT(bobLine[jss::freeze] == true);
+
150 BEAST_EXPECT(bobLine[jss::balance] == "-16");
+
151 }
+
152
+
153 {
+
154 // test: shows freeze peer
+
155 auto lines = getAccountLines(env, bob);
+
156 Json::Value g1Line;
+
157 for (auto const& it : lines[jss::lines])
+
158 {
+
159 if (it[jss::account] == G1.human())
+
160 {
+
161 g1Line = it;
+
162 break;
+
163 }
+
164 }
+
165 if (!BEAST_EXPECT(g1Line))
+
166 return;
+
167 BEAST_EXPECT(g1Line[jss::freeze_peer] == true);
+
168 BEAST_EXPECT(g1Line[jss::balance] == "16");
+
169 }
+
170
+
171 {
+
172 // Is cleared via a TrustSet with ClearFreeze flag
+
173 // test: sets LowFreeze | HighFreeze flags
+
174 env(trust(G1, bob["USD"](0), tfClearFreeze));
+
175 auto affected = env.meta()->getJson(
+
176 JsonOptions::none)[sfAffectedNodes.fieldName];
+
177 if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
+
178 return;
+
179 auto ff =
+
180 affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
+
181 BEAST_EXPECT(
+
182 ff[sfLowLimit.fieldName] ==
+
183 G1["USD"](0).value().getJson(JsonOptions::none));
+
184 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowFreeze));
+
185 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze));
+
186 env.close();
+
187 }
+
188 }
+
189
+
190 void
+
191 testDeepFreeze(FeatureBitset features)
+
192 {
+
193 testcase("Deep Freeze");
+
194
+
195 using namespace test::jtx;
+
196 Env env(*this, features);
+
197
+
198 Account G1{"G1"};
+
199 Account A1{"A1"};
+
200
+
201 env.fund(XRP(10000), G1, A1);
+
202 env.close();
+
203
+
204 env.trust(G1["USD"](1000), A1);
+
205 env.close();
+
206
+
207 if (features[featureDeepFreeze])
+
208 {
+
209 // test: Issuer deep freezing the trust line in a single
+
210 // transaction
+
211 env(trust(G1, A1["USD"](0), tfSetFreeze | tfSetDeepFreeze));
+
212 {
+
213 auto const flags = getTrustlineFlags(env, 2u, 1u);
+
214 BEAST_EXPECT(flags & lsfLowFreeze);
+
215 BEAST_EXPECT(flags & lsfLowDeepFreeze);
+
216 BEAST_EXPECT(!(flags & (lsfHighFreeze | lsfHighDeepFreeze)));
+
217 env.close();
+
218 }
219
-
220 env(offer(G1, XRP(10000), G1["USD"](100)), txflags(tfPassive));
-
221 env(offer(G1, G1["USD"](100), XRP(10000)), txflags(tfPassive));
-
222 env(offer(A1, XRP(10000), G1["USD"](100)), txflags(tfPassive));
-
223 env(offer(A2, G1["USD"](100), XRP(10000)), txflags(tfPassive));
-
224 env.close();
-
225
-
226 {
-
227 // Is toggled via AccountSet using SetFlag and ClearFlag
-
228 // test: SetFlag GlobalFreeze
-
229 env.require(nflags(G1, asfGlobalFreeze));
-
230 env(fset(G1, asfGlobalFreeze));
-
231 env.require(flags(G1, asfGlobalFreeze));
-
232 env.require(nflags(G1, asfNoFreeze));
+
220 // test: Issuer clearing deep freeze and normal freeze in a single
+
221 // transaction
+
222 env(trust(G1, A1["USD"](0), tfClearFreeze | tfClearDeepFreeze));
+
223 {
+
224 auto const flags = getTrustlineFlags(env, 2u, 1u);
+
225 BEAST_EXPECT(!(flags & (lsfLowFreeze | lsfLowDeepFreeze)));
+
226 BEAST_EXPECT(!(flags & (lsfHighFreeze | lsfHighDeepFreeze)));
+
227 env.close();
+
228 }
+
229
+
230 // test: Issuer deep freezing not already frozen line must fail
+
231 env(trust(G1, A1["USD"](0), tfSetDeepFreeze),
+
232 ter(tecNO_PERMISSION));
233
-
234 // test: ClearFlag GlobalFreeze
-
235 env(fclear(G1, asfGlobalFreeze));
-
236 env.require(nflags(G1, asfGlobalFreeze));
-
237 env.require(nflags(G1, asfNoFreeze));
-
238 }
-
239
-
240 {
-
241 // Account without GlobalFreeze (proving operations normally work)
-
242 // test: visible offers where taker_pays is unfrozen issuer
-
243 auto offers = env.rpc(
-
244 "book_offers",
-
245 std::string("USD/") + G1.human(),
-
246 "XRP")[jss::result][jss::offers];
-
247 if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
-
248 return;
-
249 std::set<std::string> accounts;
-
250 for (auto const& offer : offers)
-
251 {
-
252 accounts.insert(offer[jss::Account].asString());
-
253 }
-
254 BEAST_EXPECT(accounts.find(A2.human()) != std::end(accounts));
-
255 BEAST_EXPECT(accounts.find(G1.human()) != std::end(accounts));
-
256
-
257 // test: visible offers where taker_gets is unfrozen issuer
-
258 offers = env.rpc(
-
259 "book_offers",
-
260 "XRP",
-
261 std::string("USD/") + G1.human())[jss::result][jss::offers];
-
262 if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
-
263 return;
-
264 accounts.clear();
-
265 for (auto const& offer : offers)
-
266 {
-
267 accounts.insert(offer[jss::Account].asString());
-
268 }
-
269 BEAST_EXPECT(accounts.find(A1.human()) != std::end(accounts));
-
270 BEAST_EXPECT(accounts.find(G1.human()) != std::end(accounts));
+
234 env(trust(G1, A1["USD"](0), tfSetFreeze));
+
235 env.close();
+
236
+
237 // test: Issuer deep freezing already frozen trust line
+
238 env(trust(G1, A1["USD"](0), tfSetDeepFreeze));
+
239 {
+
240 auto const flags = getTrustlineFlags(env, 2u, 1u);
+
241 BEAST_EXPECT(flags & lsfLowFreeze);
+
242 BEAST_EXPECT(flags & lsfLowDeepFreeze);
+
243 BEAST_EXPECT(!(flags & (lsfHighFreeze | lsfHighDeepFreeze)));
+
244 env.close();
+
245 }
+
246
+
247 // test: Holder clearing freeze flags has no effect. Each sides'
+
248 // flags are independent
+
249 env(trust(A1, G1["USD"](0), tfClearFreeze | tfClearDeepFreeze));
+
250 {
+
251 auto const flags = getTrustlineFlags(env, 2u, 1u);
+
252 BEAST_EXPECT(flags & lsfLowFreeze);
+
253 BEAST_EXPECT(flags & lsfLowDeepFreeze);
+
254 BEAST_EXPECT(!(flags & (lsfHighFreeze | lsfHighDeepFreeze)));
+
255 env.close();
+
256 }
+
257
+
258 // test: Issuer can't clear normal freeze when line is deep frozen
+
259 env(trust(G1, A1["USD"](0), tfClearFreeze), ter(tecNO_PERMISSION));
+
260
+
261 // test: Issuer clearing deep freeze but normal freeze is still in
+
262 // effect
+
263 env(trust(G1, A1["USD"](0), tfClearDeepFreeze));
+
264 {
+
265 auto const flags = getTrustlineFlags(env, 2u, 1u);
+
266 BEAST_EXPECT(flags & lsfLowFreeze);
+
267 BEAST_EXPECT(!(flags & lsfLowDeepFreeze));
+
268 BEAST_EXPECT(!(flags & (lsfHighFreeze | lsfHighDeepFreeze)));
+
269 env.close();
+
270 }
271 }
-
272
+
272 else
273 {
-
274 // Offers/Payments
-
275 // test: assets can be bought on the market
-
276 env(offer(A3, G1["BTC"](1), XRP(1)));
-
277
-
278 // test: assets can be sold on the market
-
279 env(offer(A4, XRP(1), G1["BTC"](1)));
-
280
-
281 // test: direct issues can be sent
-
282 env(pay(G1, A2, G1["USD"](1)));
-
283
-
284 // test: direct redemptions can be sent
-
285 env(pay(A2, G1, G1["USD"](1)));
-
286
-
287 // test: via rippling can be sent
-
288 env(pay(A2, A1, G1["USD"](1)));
-
289
-
290 // test: via rippling can be sent back
-
291 env(pay(A1, A2, G1["USD"](1)));
-
292 }
+
274 // test: applying deep freeze before amendment fails
+
275 env(trust(G1, A1["USD"](0), tfSetDeepFreeze), ter(temINVALID_FLAG));
+
276
+
277 // test: clearing deep freeze before amendment fails
+
278 env(trust(G1, A1["USD"](0), tfClearDeepFreeze),
+
279 ter(temINVALID_FLAG));
+
280 }
+
281 }
+
282
+
283 void
+
284 testCreateFrozenTrustline(FeatureBitset features)
+
285 {
+
286 testcase("Create Frozen Trustline");
+
287
+
288 using namespace test::jtx;
+
289 Env env(*this, features);
+
290
+
291 Account G1{"G1"};
+
292 Account A1{"A1"};
293
-
294 {
-
295 // Account with GlobalFreeze
-
296 // set GlobalFreeze first
-
297 // test: SetFlag GlobalFreeze will toggle back to freeze
-
298 env.require(nflags(G1, asfGlobalFreeze));
-
299 env(fset(G1, asfGlobalFreeze));
-
300 env.require(flags(G1, asfGlobalFreeze));
-
301 env.require(nflags(G1, asfNoFreeze));
-
302
-
303 // test: assets can't be bought on the market
-
304 env(offer(A3, G1["BTC"](1), XRP(1)), ter(tecFROZEN));
+
294 env.fund(XRP(10000), G1, A1);
+
295 env.close();
+
296
+
297 // test: can create frozen trustline
+
298 {
+
299 env(trust(G1, A1["USD"](1000), tfSetFreeze));
+
300 auto const flags = getTrustlineFlags(env, 5u, 3u, false);
+
301 BEAST_EXPECT(flags & lsfLowFreeze);
+
302 env.close();
+
303 env.require(lines(A1, 1));
+
304 }
305
-
306 // test: assets can't be sold on the market
-
307 env(offer(A4, XRP(1), G1["BTC"](1)), ter(tecFROZEN));
-
308 }
-
309
-
310 {
-
311 // offers are filtered (seems to be broken?)
-
312 // test: account_offers always shows own offers
-
313 auto offers = getAccountOffers(env, G1)[jss::offers];
-
314 if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
-
315 return;
-
316
-
317 // test: book_offers shows offers
-
318 // (should these actually be filtered?)
-
319 offers = env.rpc(
-
320 "book_offers",
-
321 "XRP",
-
322 std::string("USD/") + G1.human())[jss::result][jss::offers];
-
323 if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
-
324 return;
-
325
-
326 offers = env.rpc(
-
327 "book_offers",
-
328 std::string("USD/") + G1.human(),
-
329 "XRP")[jss::result][jss::offers];
-
330 if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
-
331 return;
-
332 }
-
333
-
334 {
-
335 // Payments
-
336 // test: direct issues can be sent
-
337 env(pay(G1, A2, G1["USD"](1)));
-
338
-
339 // test: direct redemptions can be sent
-
340 env(pay(A2, G1, G1["USD"](1)));
-
341
-
342 // test: via rippling cant be sent
-
343 env(pay(A2, A1, G1["USD"](1)), ter(tecPATH_DRY));
-
344 }
-
345 }
+
306 // Cleanup
+
307 env(trust(G1, A1["USD"](0), tfClearFreeze));
+
308 env.close();
+
309 env.require(lines(G1, 0));
+
310 env.require(lines(A1, 0));
+
311
+
312 // test: cannot create deep frozen trustline without normal freeze
+
313 if (features[featureDeepFreeze])
+
314 {
+
315 env(trust(G1, A1["USD"](1000), tfSetDeepFreeze),
+
316 ter(tecNO_PERMISSION));
+
317 env.close();
+
318 env.require(lines(A1, 0));
+
319 }
+
320
+
321 // test: can create deep frozen trustline together with normal freeze
+
322 if (features[featureDeepFreeze])
+
323 {
+
324 env(trust(G1, A1["USD"](1000), tfSetFreeze | tfSetDeepFreeze));
+
325 auto const flags = getTrustlineFlags(env, 5u, 3u, false);
+
326 BEAST_EXPECT(flags & lsfLowFreeze);
+
327 BEAST_EXPECT(flags & lsfLowDeepFreeze);
+
328 env.close();
+
329 env.require(lines(A1, 1));
+
330 }
+
331 }
+
332
+
333 void
+
334 testSetAndClear(FeatureBitset features)
+
335 {
+
336 testcase("Freeze Set and Clear");
+
337
+
338 using namespace test::jtx;
+
339 Env env(*this, features);
+
340
+
341 Account G1{"G1"};
+
342 Account A1{"A1"};
+
343
+
344 env.fund(XRP(10000), G1, A1);
+
345 env.close();
346
-
347 void
-
348 testNoFreeze(FeatureBitset features)
-
349 {
-
350 testcase("No Freeze");
-
351
-
352 using namespace test::jtx;
-
353 Env env(*this, features);
-
354
-
355 Account G1{"G1"};
-
356 Account A1{"A1"};
-
357
-
358 env.fund(XRP(12000), G1);
-
359 env.fund(XRP(1000), A1);
-
360 env.close();
-
361
-
362 env.trust(G1["USD"](1000), A1);
-
363 env.close();
-
364
-
365 env(pay(G1, A1, G1["USD"](1000)));
-
366 env.close();
-
367
-
368 // TrustSet NoFreeze
-
369 // test: should set NoFreeze in Flags
-
370 env.require(nflags(G1, asfNoFreeze));
-
371 env(fset(G1, asfNoFreeze));
-
372 env.require(flags(G1, asfNoFreeze));
-
373 env.require(nflags(G1, asfGlobalFreeze));
-
374
-
375 // test: cannot be cleared
-
376 env(fclear(G1, asfNoFreeze));
-
377 env.require(flags(G1, asfNoFreeze));
-
378 env.require(nflags(G1, asfGlobalFreeze));
-
379
-
380 // test: can set GlobalFreeze
-
381 env(fset(G1, asfGlobalFreeze));
-
382 env.require(flags(G1, asfNoFreeze));
-
383 env.require(flags(G1, asfGlobalFreeze));
+
347 env.trust(G1["USD"](1000), A1);
+
348 env.close();
+
349
+
350 if (features[featureDeepFreeze])
+
351 {
+
352 // test: can't have both set and clear flag families in the same
+
353 // transaction
+
354 env(trust(G1, A1["USD"](0), tfSetFreeze | tfClearFreeze),
+
355 ter(tecNO_PERMISSION));
+
356 env(trust(G1, A1["USD"](0), tfSetFreeze | tfClearDeepFreeze),
+
357 ter(tecNO_PERMISSION));
+
358 env(trust(G1, A1["USD"](0), tfSetDeepFreeze | tfClearFreeze),
+
359 ter(tecNO_PERMISSION));
+
360 env(trust(G1, A1["USD"](0), tfSetDeepFreeze | tfClearDeepFreeze),
+
361 ter(tecNO_PERMISSION));
+
362 }
+
363 else
+
364 {
+
365 // test: old behavior, transaction succeed with no effect on a
+
366 // trust line
+
367 env(trust(G1, A1["USD"](0), tfSetFreeze | tfClearFreeze));
+
368 {
+
369 auto affected = env.meta()->getJson(
+
370 JsonOptions::none)[sfAffectedNodes.fieldName];
+
371 BEAST_EXPECT(checkArraySize(
+
372 affected, 1u)); // means no trustline changes
+
373 }
+
374 }
+
375 }
+
376
+
377 void
+
378 testGlobalFreeze(FeatureBitset features)
+
379 {
+
380 testcase("Global Freeze");
+
381
+
382 using namespace test::jtx;
+
383 Env env(*this, features);
384
-
385 // test: cannot unset GlobalFreeze
-
386 env(fclear(G1, asfGlobalFreeze));
-
387 env.require(flags(G1, asfNoFreeze));
-
388 env.require(flags(G1, asfGlobalFreeze));
-
389
-
390 // test: trustlines can't be frozen
-
391 env(trust(G1, A1["USD"](0), tfSetFreeze));
-
392 auto affected =
-
393 env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
-
394 if (!BEAST_EXPECT(checkArraySize(affected, 1u)))
-
395 return;
-
396
-
397 auto let =
-
398 affected[0u][sfModifiedNode.fieldName][sfLedgerEntryType.fieldName];
-
399 BEAST_EXPECT(let == jss::AccountRoot);
-
400 }
+
385 Account G1{"G1"};
+
386 Account A1{"A1"};
+
387 Account A2{"A2"};
+
388 Account A3{"A3"};
+
389 Account A4{"A4"};
+
390
+
391 env.fund(XRP(12000), G1);
+
392 env.fund(XRP(1000), A1);
+
393 env.fund(XRP(20000), A2, A3, A4);
+
394 env.close();
+
395
+
396 env.trust(G1["USD"](1200), A1);
+
397 env.trust(G1["USD"](200), A2);
+
398 env.trust(G1["BTC"](100), A3);
+
399 env.trust(G1["BTC"](100), A4);
+
400 env.close();
401
-
402 void
-
403 testOffersWhenFrozen(FeatureBitset features)
-
404 {
-
405 testcase("Offers for Frozen Trust Lines");
-
406
-
407 using namespace test::jtx;
-
408 Env env(*this, features);
-
409
-
410 Account G1{"G1"};
-
411 Account A2{"A2"};
-
412 Account A3{"A3"};
-
413 Account A4{"A4"};
-
414
-
415 env.fund(XRP(1000), G1, A3, A4);
-
416 env.fund(XRP(2000), A2);
-
417 env.close();
-
418
-
419 env.trust(G1["USD"](1000), A2);
-
420 env.trust(G1["USD"](2000), A3);
-
421 env.trust(G1["USD"](2000), A4);
-
422 env.close();
-
423
-
424 env(pay(G1, A3, G1["USD"](2000)));
-
425 env(pay(G1, A4, G1["USD"](2000)));
-
426 env.close();
+
402 env(pay(G1, A1, G1["USD"](1000)));
+
403 env(pay(G1, A2, G1["USD"](100)));
+
404 env(pay(G1, A3, G1["BTC"](100)));
+
405 env(pay(G1, A4, G1["BTC"](100)));
+
406 env.close();
+
407
+
408 env(offer(G1, XRP(10000), G1["USD"](100)), txflags(tfPassive));
+
409 env(offer(G1, G1["USD"](100), XRP(10000)), txflags(tfPassive));
+
410 env(offer(A1, XRP(10000), G1["USD"](100)), txflags(tfPassive));
+
411 env(offer(A2, G1["USD"](100), XRP(10000)), txflags(tfPassive));
+
412 env.close();
+
413
+
414 {
+
415 // Is toggled via AccountSet using SetFlag and ClearFlag
+
416 // test: SetFlag GlobalFreeze
+
417 env.require(nflags(G1, asfGlobalFreeze));
+
418 env(fset(G1, asfGlobalFreeze));
+
419 env.require(flags(G1, asfGlobalFreeze));
+
420 env.require(nflags(G1, asfNoFreeze));
+
421
+
422 // test: ClearFlag GlobalFreeze
+
423 env(fclear(G1, asfGlobalFreeze));
+
424 env.require(nflags(G1, asfGlobalFreeze));
+
425 env.require(nflags(G1, asfNoFreeze));
+
426 }
427
-
428 env(offer(A3, XRP(1000), G1["USD"](1000)), txflags(tfPassive));
-
429 env.close();
-
430
-
431 // removal after successful payment
-
432 // test: make a payment with partially consuming offer
-
433 env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1)));
-
434 env.close();
-
435
-
436 // test: offer was only partially consumed
-
437 auto offers = getAccountOffers(env, A3)[jss::offers];
-
438 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
-
439 return;
-
440 BEAST_EXPECT(
-
441 offers[0u][jss::taker_gets] ==
-
442 G1["USD"](999).value().getJson(JsonOptions::none));
-
443
-
444 // test: someone else creates an offer providing liquidity
-
445 env(offer(A4, XRP(999), G1["USD"](999)));
-
446 env.close();
-
447
-
448 // test: owner of partially consumed offers line is frozen
-
449 env(trust(G1, A3["USD"](0), tfSetFreeze));
-
450 auto affected =
-
451 env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
-
452 if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
-
453 return;
-
454 auto ff =
-
455 affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
-
456 BEAST_EXPECT(
-
457 ff[sfHighLimit.fieldName] ==
-
458 G1["USD"](0).value().getJson(JsonOptions::none));
-
459 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowFreeze));
-
460 BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfHighFreeze);
-
461 env.close();
-
462
-
463 // verify offer on the books
-
464 offers = getAccountOffers(env, A3)[jss::offers];
-
465 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
-
466 return;
-
467
-
468 // test: Can make a payment via the new offer
-
469 env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1)));
-
470 env.close();
+
428 {
+
429 // Account without GlobalFreeze (proving operations normally work)
+
430 // test: visible offers where taker_pays is unfrozen issuer
+
431 auto offers = env.rpc(
+
432 "book_offers",
+
433 std::string("USD/") + G1.human(),
+
434 "XRP")[jss::result][jss::offers];
+
435 if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
+
436 return;
+
437 std::set<std::string> accounts;
+
438 for (auto const& offer : offers)
+
439 {
+
440 accounts.insert(offer[jss::Account].asString());
+
441 }
+
442 BEAST_EXPECT(accounts.find(A2.human()) != std::end(accounts));
+
443 BEAST_EXPECT(accounts.find(G1.human()) != std::end(accounts));
+
444
+
445 // test: visible offers where taker_gets is unfrozen issuer
+
446 offers = env.rpc(
+
447 "book_offers",
+
448 "XRP",
+
449 std::string("USD/") + G1.human())[jss::result][jss::offers];
+
450 if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
+
451 return;
+
452 accounts.clear();
+
453 for (auto const& offer : offers)
+
454 {
+
455 accounts.insert(offer[jss::Account].asString());
+
456 }
+
457 BEAST_EXPECT(accounts.find(A1.human()) != std::end(accounts));
+
458 BEAST_EXPECT(accounts.find(G1.human()) != std::end(accounts));
+
459 }
+
460
+
461 {
+
462 // Offers/Payments
+
463 // test: assets can be bought on the market
+
464 env(offer(A3, G1["BTC"](1), XRP(1)));
+
465
+
466 // test: assets can be sold on the market
+
467 env(offer(A4, XRP(1), G1["BTC"](1)));
+
468
+
469 // test: direct issues can be sent
+
470 env(pay(G1, A2, G1["USD"](1)));
471
-
472 // test: Partially consumed offer was removed by tes* payment
-
473 offers = getAccountOffers(env, A3)[jss::offers];
-
474 if (!BEAST_EXPECT(checkArraySize(offers, 0u)))
-
475 return;
-
476
-
477 // removal buy successful OfferCreate
-
478 // test: freeze the new offer
-
479 env(trust(G1, A4["USD"](0), tfSetFreeze));
-
480 affected =
-
481 env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
-
482 if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
-
483 return;
-
484 ff = affected[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
-
485 BEAST_EXPECT(
-
486 ff[sfLowLimit.fieldName] ==
-
487 G1["USD"](0).value().getJson(JsonOptions::none));
-
488 BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfLowFreeze);
-
489 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze));
-
490 env.close();
-
491
-
492 // test: can no longer create a crossing offer
-
493 env(offer(A2, G1["USD"](999), XRP(999)));
-
494 affected =
-
495 env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
-
496 if (!BEAST_EXPECT(checkArraySize(affected, 8u)))
-
497 return;
-
498 auto created = affected[0u][sfCreatedNode.fieldName];
-
499 BEAST_EXPECT(
-
500 created[sfNewFields.fieldName][jss::Account] == A2.human());
-
501 env.close();
-
502
-
503 // test: offer was removed by offer_create
-
504 offers = getAccountOffers(env, A4)[jss::offers];
-
505 if (!BEAST_EXPECT(checkArraySize(offers, 0u)))
-
506 return;
-
507 }
-
508
-
509public:
-
510 void
-
511 run() override
-
512 {
-
513 auto testAll = [this](FeatureBitset features) {
-
514 testRippleState(features);
-
515 testGlobalFreeze(features);
-
516 testNoFreeze(features);
-
517 testOffersWhenFrozen(features);
-
518 };
-
519 using namespace test::jtx;
-
520 auto const sa = supported_amendments();
-
521 testAll(sa - featureFlowCross);
-
522 testAll(sa);
-
523 }
-
524};
-
525
-
526BEAST_DEFINE_TESTSUITE(Freeze, app, ripple);
-
527} // namespace ripple
+
472 // test: direct redemptions can be sent
+
473 env(pay(A2, G1, G1["USD"](1)));
+
474
+
475 // test: via rippling can be sent
+
476 env(pay(A2, A1, G1["USD"](1)));
+
477
+
478 // test: via rippling can be sent back
+
479 env(pay(A1, A2, G1["USD"](1)));
+
480 }
+
481
+
482 {
+
483 // Account with GlobalFreeze
+
484 // set GlobalFreeze first
+
485 // test: SetFlag GlobalFreeze will toggle back to freeze
+
486 env.require(nflags(G1, asfGlobalFreeze));
+
487 env(fset(G1, asfGlobalFreeze));
+
488 env.require(flags(G1, asfGlobalFreeze));
+
489 env.require(nflags(G1, asfNoFreeze));
+
490
+
491 // test: assets can't be bought on the market
+
492 env(offer(A3, G1["BTC"](1), XRP(1)), ter(tecFROZEN));
+
493
+
494 // test: assets can't be sold on the market
+
495 env(offer(A4, XRP(1), G1["BTC"](1)), ter(tecFROZEN));
+
496 }
+
497
+
498 {
+
499 // offers are filtered (seems to be broken?)
+
500 // test: account_offers always shows own offers
+
501 auto offers = getAccountOffers(env, G1)[jss::offers];
+
502 if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
+
503 return;
+
504
+
505 // test: book_offers shows offers
+
506 // (should these actually be filtered?)
+
507 offers = env.rpc(
+
508 "book_offers",
+
509 "XRP",
+
510 std::string("USD/") + G1.human())[jss::result][jss::offers];
+
511 if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
+
512 return;
+
513
+
514 offers = env.rpc(
+
515 "book_offers",
+
516 std::string("USD/") + G1.human(),
+
517 "XRP")[jss::result][jss::offers];
+
518 if (!BEAST_EXPECT(checkArraySize(offers, 2u)))
+
519 return;
+
520 }
+
521
+
522 {
+
523 // Payments
+
524 // test: direct issues can be sent
+
525 env(pay(G1, A2, G1["USD"](1)));
+
526
+
527 // test: direct redemptions can be sent
+
528 env(pay(A2, G1, G1["USD"](1)));
+
529
+
530 // test: via rippling cant be sent
+
531 env(pay(A2, A1, G1["USD"](1)), ter(tecPATH_DRY));
+
532 }
+
533 }
+
534
+
535 void
+
536 testNoFreeze(FeatureBitset features)
+
537 {
+
538 testcase("No Freeze");
+
539
+
540 using namespace test::jtx;
+
541 Env env(*this, features);
+
542
+
543 Account G1{"G1"};
+
544 Account A1{"A1"};
+
545 Account frozenAcc{"A2"};
+
546 Account deepFrozenAcc{"A3"};
+
547
+
548 env.fund(XRP(12000), G1);
+
549 env.fund(XRP(1000), A1);
+
550 env.fund(XRP(1000), frozenAcc);
+
551 env.fund(XRP(1000), deepFrozenAcc);
+
552 env.close();
+
553
+
554 env.trust(G1["USD"](1000), A1);
+
555 env.trust(G1["USD"](1000), frozenAcc);
+
556 env.trust(G1["USD"](1000), deepFrozenAcc);
+
557 env.close();
+
558
+
559 env(pay(G1, A1, G1["USD"](1000)));
+
560 env(pay(G1, frozenAcc, G1["USD"](1000)));
+
561 env(pay(G1, deepFrozenAcc, G1["USD"](1000)));
+
562
+
563 // Freezing and deep freezing some of the trust lines to check deep
+
564 // freeze and clearing of freeze separately
+
565 env(trust(G1, frozenAcc["USD"](0), tfSetFreeze));
+
566 {
+
567 auto const flags = getTrustlineFlags(env, 2u, 1u);
+
568 BEAST_EXPECT(flags & lsfLowFreeze);
+
569 BEAST_EXPECT(!(flags & lsfHighFreeze));
+
570 }
+
571 if (features[featureDeepFreeze])
+
572 {
+
573 env(trust(
+
574 G1, deepFrozenAcc["USD"](0), tfSetFreeze | tfSetDeepFreeze));
+
575 {
+
576 auto const flags = getTrustlineFlags(env, 2u, 1u);
+
577 BEAST_EXPECT(!(flags & (lsfLowFreeze | lsfLowDeepFreeze)));
+
578 BEAST_EXPECT(flags & lsfHighFreeze);
+
579 BEAST_EXPECT(flags & lsfHighDeepFreeze);
+
580 }
+
581 }
+
582 env.close();
+
583
+
584 // TrustSet NoFreeze
+
585 // test: should set NoFreeze in Flags
+
586 env.require(nflags(G1, asfNoFreeze));
+
587 env(fset(G1, asfNoFreeze));
+
588 env.require(flags(G1, asfNoFreeze));
+
589 env.require(nflags(G1, asfGlobalFreeze));
+
590
+
591 // test: cannot be cleared
+
592 env(fclear(G1, asfNoFreeze));
+
593 env.require(flags(G1, asfNoFreeze));
+
594 env.require(nflags(G1, asfGlobalFreeze));
+
595
+
596 // test: can set GlobalFreeze
+
597 env(fset(G1, asfGlobalFreeze));
+
598 env.require(flags(G1, asfNoFreeze));
+
599 env.require(flags(G1, asfGlobalFreeze));
+
600
+
601 // test: cannot unset GlobalFreeze
+
602 env(fclear(G1, asfGlobalFreeze));
+
603 env.require(flags(G1, asfNoFreeze));
+
604 env.require(flags(G1, asfGlobalFreeze));
+
605
+
606 // test: trustlines can't be frozen when no freeze enacted
+
607 if (features[featureDeepFreeze])
+
608 {
+
609 env(trust(G1, A1["USD"](0), tfSetFreeze), ter(tecNO_PERMISSION));
+
610
+
611 // test: cannot deep freeze already frozen line when no freeze
+
612 // enacted
+
613 env(trust(G1, frozenAcc["USD"](0), tfSetDeepFreeze),
+
614 ter(tecNO_PERMISSION));
+
615 }
+
616 else
+
617 {
+
618 // test: previous functionality, checking there's no changes to a
+
619 // trust line
+
620 env(trust(G1, A1["USD"](0), tfSetFreeze));
+
621 auto affected = env.meta()->getJson(
+
622 JsonOptions::none)[sfAffectedNodes.fieldName];
+
623 if (!BEAST_EXPECT(checkArraySize(affected, 1u)))
+
624 return;
+
625
+
626 auto let = affected[0u][sfModifiedNode.fieldName]
+
627 [sfLedgerEntryType.fieldName];
+
628 BEAST_EXPECT(let == jss::AccountRoot);
+
629 }
+
630
+
631 // test: can clear freeze on account
+
632 env(trust(G1, frozenAcc["USD"](0), tfClearFreeze));
+
633 {
+
634 auto const flags = getTrustlineFlags(env, 2u, 1u);
+
635 BEAST_EXPECT(!(flags & lsfLowFreeze));
+
636 }
+
637
+
638 if (features[featureDeepFreeze])
+
639 {
+
640 // test: can clear deep freeze on account
+
641 env(trust(G1, deepFrozenAcc["USD"](0), tfClearDeepFreeze));
+
642 {
+
643 auto const flags = getTrustlineFlags(env, 2u, 1u);
+
644 BEAST_EXPECT(flags & lsfHighFreeze);
+
645 BEAST_EXPECT(!(flags & lsfHighDeepFreeze));
+
646 }
+
647 }
+
648 }
+
649
+
650 void
+
651 testOffersWhenFrozen(FeatureBitset features)
+
652 {
+
653 testcase("Offers for Frozen Trust Lines");
+
654
+
655 using namespace test::jtx;
+
656 Env env(*this, features);
+
657
+
658 Account G1{"G1"};
+
659 Account A2{"A2"};
+
660 Account A3{"A3"};
+
661 Account A4{"A4"};
+
662
+
663 env.fund(XRP(1000), G1, A3, A4);
+
664 env.fund(XRP(2000), A2);
+
665 env.close();
+
666
+
667 env.trust(G1["USD"](1000), A2);
+
668 env.trust(G1["USD"](2000), A3);
+
669 env.trust(G1["USD"](2000), A4);
+
670 env.close();
+
671
+
672 env(pay(G1, A3, G1["USD"](2000)));
+
673 env(pay(G1, A4, G1["USD"](2000)));
+
674 env.close();
+
675
+
676 env(offer(A3, XRP(1000), G1["USD"](1000)), txflags(tfPassive));
+
677 env.close();
+
678
+
679 // removal after successful payment
+
680 // test: make a payment with partially consuming offer
+
681 env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1)));
+
682 env.close();
+
683
+
684 // test: offer was only partially consumed
+
685 auto offers = getAccountOffers(env, A3)[jss::offers];
+
686 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
+
687 return;
+
688 BEAST_EXPECT(
+
689 offers[0u][jss::taker_gets] ==
+
690 G1["USD"](999).value().getJson(JsonOptions::none));
+
691
+
692 // test: someone else creates an offer providing liquidity
+
693 env(offer(A4, XRP(999), G1["USD"](999)));
+
694 env.close();
+
695
+
696 // test: owner of partially consumed offers line is frozen
+
697 env(trust(G1, A3["USD"](0), tfSetFreeze));
+
698 auto affected =
+
699 env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
+
700 if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
+
701 return;
+
702 auto ff =
+
703 affected[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
+
704 BEAST_EXPECT(
+
705 ff[sfHighLimit.fieldName] ==
+
706 G1["USD"](0).value().getJson(JsonOptions::none));
+
707 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfLowFreeze));
+
708 BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfHighFreeze);
+
709 env.close();
+
710
+
711 // verify offer on the books
+
712 offers = getAccountOffers(env, A3)[jss::offers];
+
713 if (!BEAST_EXPECT(checkArraySize(offers, 1u)))
+
714 return;
+
715
+
716 // test: Can make a payment via the new offer
+
717 env(pay(A2, G1, G1["USD"](1)), paths(G1["USD"]), sendmax(XRP(1)));
+
718 env.close();
+
719
+
720 // test: Partially consumed offer was removed by tes* payment
+
721 offers = getAccountOffers(env, A3)[jss::offers];
+
722 if (!BEAST_EXPECT(checkArraySize(offers, 0u)))
+
723 return;
+
724
+
725 // removal buy successful OfferCreate
+
726 // test: freeze the new offer
+
727 env(trust(G1, A4["USD"](0), tfSetFreeze));
+
728 affected =
+
729 env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
+
730 if (!BEAST_EXPECT(checkArraySize(affected, 2u)))
+
731 return;
+
732 ff = affected[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName];
+
733 BEAST_EXPECT(
+
734 ff[sfLowLimit.fieldName] ==
+
735 G1["USD"](0).value().getJson(JsonOptions::none));
+
736 BEAST_EXPECT(ff[jss::Flags].asUInt() & lsfLowFreeze);
+
737 BEAST_EXPECT(!(ff[jss::Flags].asUInt() & lsfHighFreeze));
+
738 env.close();
+
739
+
740 // test: can no longer create a crossing offer
+
741 env(offer(A2, G1["USD"](999), XRP(999)));
+
742 affected =
+
743 env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
+
744 if (!BEAST_EXPECT(checkArraySize(affected, 8u)))
+
745 return;
+
746 auto created = affected[0u][sfCreatedNode.fieldName];
+
747 BEAST_EXPECT(
+
748 created[sfNewFields.fieldName][jss::Account] == A2.human());
+
749 env.close();
+
750
+
751 // test: offer was removed by offer_create
+
752 offers = getAccountOffers(env, A4)[jss::offers];
+
753 if (!BEAST_EXPECT(checkArraySize(offers, 0u)))
+
754 return;
+
755 }
+
756
+
757 void
+
758 testOffersWhenDeepFrozen(FeatureBitset features)
+
759 {
+
760 testcase("Offers on frozen trust lines");
+
761
+
762 using namespace test::jtx;
+
763 Env env(*this, features);
+
764
+
765 Account G1{"G1"};
+
766 Account A1{"A1"};
+
767 Account A2{"A2"};
+
768 Account A3{"A3"};
+
769 auto const USD{G1["USD"]};
+
770
+
771 env.fund(XRP(10000), G1, A1, A2, A3);
+
772 env.close();
+
773
+
774 auto const limit = USD(10000);
+
775 env.trust(limit, A1, A2, A3);
+
776 env.close();
+
777
+
778 env(pay(G1, A1, USD(1000)));
+
779 env(pay(G1, A2, USD(1000)));
+
780 env.close();
+
781
+
782 // Making large passive sell offer
+
783 // Wants to sell 50 USD for 100 XRP
+
784 env(offer(A2, XRP(100), USD(50)), txflags(tfPassive));
+
785 env.close();
+
786 // Making large passive buy offer
+
787 // Wants to buy 100 USD for 100 XRP
+
788 env(offer(A3, USD(100), XRP(100)), txflags(tfPassive));
+
789 env.close();
+
790 env.require(offers(A2, 1), offers(A3, 1));
+
791
+
792 // Checking A1 can buy from A2 by crossing it's offer
+
793 env(offer(A1, USD(1), XRP(2)), txflags(tfFillOrKill));
+
794 env.close();
+
795 env.require(balance(A1, USD(1001)), balance(A2, USD(999)));
+
796
+
797 // Checking A1 can sell to A3 by crossing it's offer
+
798 env(offer(A1, XRP(1), USD(1)), txflags(tfFillOrKill));
+
799 env.close();
+
800 env.require(balance(A1, USD(1000)), balance(A3, USD(1)));
+
801
+
802 // Testing aggressive and passive offer placing, trustline frozen by
+
803 // the issuer
+
804 {
+
805 env(trust(G1, A1["USD"](0), tfSetFreeze));
+
806 env.close();
+
807
+
808 // test: can still make passive buy offer
+
809 env(offer(A1, USD(1), XRP(0.5)), txflags(tfPassive));
+
810 env.close();
+
811 env.require(balance(A1, USD(1000)), offers(A1, 1));
+
812 // Cleanup
+
813 env(offer_cancel(A1, env.seq(A1) - 1));
+
814 env.require(offers(A1, 0));
+
815 env.close();
+
816
+
817 // test: can still buy from A2
+
818 env(offer(A1, USD(1), XRP(2)), txflags(tfFillOrKill));
+
819 env.close();
+
820 env.require(
+
821 balance(A1, USD(1001)), balance(A2, USD(998)), offers(A1, 0));
+
822
+
823 // test: cannot create passive sell offer
+
824 env(offer(A1, XRP(2), USD(1)),
+
825 txflags(tfPassive),
+
826 ter(tecUNFUNDED_OFFER));
+
827 env.close();
+
828 env.require(balance(A1, USD(1001)), offers(A1, 0));
+
829
+
830 // test: cannot sell to A3
+
831 env(offer(A1, XRP(1), USD(1)),
+
832 txflags(tfFillOrKill),
+
833 ter(tecUNFUNDED_OFFER));
+
834 env.close();
+
835 env.require(balance(A1, USD(1001)), offers(A1, 0));
+
836
+
837 env(trust(G1, A1["USD"](0), tfClearFreeze));
+
838 env.close();
+
839 }
+
840
+
841 // Testing aggressive and passive offer placing, trustline deep frozen
+
842 // by the issuer
+
843 if (features[featureDeepFreeze])
+
844 {
+
845 env(trust(G1, A1["USD"](0), tfSetFreeze | tfSetDeepFreeze));
+
846 env.close();
+
847
+
848 // test: cannot create passive buy offer
+
849 env(offer(A1, USD(1), XRP(0.5)),
+
850 txflags(tfPassive),
+
851 ter(tecFROZEN));
+
852 env.close();
+
853
+
854 // test: cannot buy from A2
+
855 env(offer(A1, USD(1), XRP(2)),
+
856 txflags(tfFillOrKill),
+
857 ter(tecFROZEN));
+
858 env.close();
+
859
+
860 // test: cannot create passive sell offer
+
861 env(offer(A1, XRP(2), USD(1)),
+
862 txflags(tfPassive),
+
863 ter(tecUNFUNDED_OFFER));
+
864 env.close();
+
865
+
866 // test: cannot sell to A3
+
867 env(offer(A1, XRP(1), USD(1)),
+
868 txflags(tfFillOrKill),
+
869 ter(tecUNFUNDED_OFFER));
+
870 env.close();
+
871
+
872 env(trust(G1, A1["USD"](0), tfClearFreeze | tfClearDeepFreeze));
+
873 env.close();
+
874 env.require(balance(A1, USD(1001)), offers(A1, 0));
+
875 }
+
876
+
877 // Testing already existing offers behavior after trustline is frozen by
+
878 // the issuer
+
879 {
+
880 env.require(balance(A1, USD(1001)));
+
881 env(offer(A1, XRP(1.9), USD(1)));
+
882 env(offer(A1, USD(1), XRP(1.1)));
+
883 env.close();
+
884 env.require(balance(A1, USD(1001)), offers(A1, 2));
+
885
+
886 env(trust(G1, A1["USD"](0), tfSetFreeze));
+
887 env.close();
+
888
+
889 // test: A2 wants to sell to A1, must succeed
+
890 env.require(balance(A1, USD(1001)), balance(A2, USD(998)));
+
891 env(offer(A2, XRP(1.1), USD(1)), txflags(tfFillOrKill));
+
892 env.close();
+
893 env.require(
+
894 balance(A1, USD(1002)), balance(A2, USD(997)), offers(A1, 1));
+
895
+
896 // test: A3 wants to buy from A1, must fail
+
897 env.require(
+
898 balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 1));
+
899 env(offer(A3, USD(1), XRP(1.9)),
+
900 txflags(tfFillOrKill),
+
901 ter(tecKILLED));
+
902 env.close();
+
903 env.require(
+
904 balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 0));
+
905
+
906 env(trust(G1, A1["USD"](0), tfClearFreeze));
+
907 env.close();
+
908 }
+
909
+
910 // Testing existing offers behavior after trustline is deep frozen by
+
911 // the issuer
+
912 if (features[featureDeepFreeze])
+
913 {
+
914 env.require(balance(A1, USD(1002)));
+
915 env(offer(A1, XRP(1.9), USD(1)));
+
916 env(offer(A1, USD(1), XRP(1.1)));
+
917 env.close();
+
918 env.require(balance(A1, USD(1002)), offers(A1, 2));
+
919
+
920 env(trust(G1, A1["USD"](0), tfSetFreeze | tfSetDeepFreeze));
+
921 env.close();
+
922
+
923 // test: A2 wants to sell to A1, must fail
+
924 env.require(balance(A1, USD(1002)), balance(A2, USD(997)));
+
925 env(offer(A2, XRP(1.1), USD(1)),
+
926 txflags(tfFillOrKill),
+
927 ter(tecKILLED));
+
928 env.close();
+
929 env.require(
+
930 balance(A1, USD(1002)), balance(A2, USD(997)), offers(A1, 1));
+
931
+
932 // test: A3 wants to buy from A1, must fail
+
933 env.require(
+
934 balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 1));
+
935 env(offer(A3, USD(1), XRP(1.9)),
+
936 txflags(tfFillOrKill),
+
937 ter(tecKILLED));
+
938 env.close();
+
939 env.require(
+
940 balance(A1, USD(1002)), balance(A3, USD(1)), offers(A1, 0));
+
941
+
942 env(trust(G1, A1["USD"](0), tfClearFreeze | tfClearDeepFreeze));
+
943 env.close();
+
944 }
+
945
+
946 // Testing aggressive and passive offer placing, trustline frozen by
+
947 // the holder
+
948 {
+
949 env(trust(A1, limit, tfSetFreeze));
+
950 env.close();
+
951
+
952 // test: A1 can make passive buy offer
+
953 env(offer(A1, USD(1), XRP(0.5)), txflags(tfPassive));
+
954 env.close();
+
955 env.require(balance(A1, USD(1002)), offers(A1, 1));
+
956 // Cleanup
+
957 env(offer_cancel(A1, env.seq(A1) - 1));
+
958 env.require(offers(A1, 0));
+
959 env.close();
+
960
+
961 // test: A1 wants to buy, must fail
+
962 if (features[featureFlowCross])
+
963 {
+
964 env(offer(A1, USD(1), XRP(2)),
+
965 txflags(tfFillOrKill),
+
966 ter(tecKILLED));
+
967 env.close();
+
968 env.require(
+
969 balance(A1, USD(1002)),
+
970 balance(A2, USD(997)),
+
971 offers(A1, 0));
+
972 }
+
973 else
+
974 {
+
975 // The transaction that should be here would succeed.
+
976 // I don't want to adjust balances in following tests. Flow
+
977 // cross feature flag is not relevant to this particular test
+
978 // case so we're not missing out some corner cases checks.
+
979 }
+
980
+
981 // test: A1 can create passive sell offer
+
982 env(offer(A1, XRP(2), USD(1)), txflags(tfPassive));
+
983 env.close();
+
984 env.require(balance(A1, USD(1002)), offers(A1, 1));
+
985 // Cleanup
+
986 env(offer_cancel(A1, env.seq(A1) - 1));
+
987 env.require(offers(A1, 0));
+
988 env.close();
+
989
+
990 // test: A1 can sell to A3
+
991 env(offer(A1, XRP(1), USD(1)), txflags(tfFillOrKill));
+
992 env.close();
+
993 env.require(balance(A1, USD(1001)), offers(A1, 0));
+
994
+
995 env(trust(A1, limit, tfClearFreeze));
+
996 env.close();
+
997 }
+
998
+
999 // Testing aggressive and passive offer placing, trustline deep frozen
+
1000 // by the holder
+
1001 if (features[featureDeepFreeze])
+
1002 {
+
1003 env(trust(A1, limit, tfSetFreeze | tfSetDeepFreeze));
+
1004 env.close();
+
1005
+
1006 // test: A1 cannot create passive buy offer
+
1007 env(offer(A1, USD(1), XRP(0.5)),
+
1008 txflags(tfPassive),
+
1009 ter(tecFROZEN));
+
1010 env.close();
+
1011
+
1012 // test: A1 cannot buy, must fail
+
1013 env(offer(A1, USD(1), XRP(2)),
+
1014 txflags(tfFillOrKill),
+
1015 ter(tecFROZEN));
+
1016 env.close();
+
1017
+
1018 // test: A1 cannot create passive sell offer
+
1019 env(offer(A1, XRP(2), USD(1)),
+
1020 txflags(tfPassive),
+
1021 ter(tecUNFUNDED_OFFER));
+
1022 env.close();
+
1023
+
1024 // test: A1 cannot sell to A3
+
1025 env(offer(A1, XRP(1), USD(1)),
+
1026 txflags(tfFillOrKill),
+
1027 ter(tecUNFUNDED_OFFER));
+
1028 env.close();
+
1029
+
1030 env(trust(A1, limit, tfClearFreeze | tfClearDeepFreeze));
+
1031 env.close();
+
1032 }
+
1033 }
+
1034
+
1035 void
+
1036 testPathsWhenFrozen(FeatureBitset features)
+
1037 {
+
1038 testcase("Longer paths payment on frozen trust lines");
+
1039 using namespace test::jtx;
+
1040 using path = test::jtx::path;
+
1041
+
1042 Env env(*this, features);
+
1043 Account G1{"G1"};
+
1044 Account A1{"A1"};
+
1045 Account A2{"A2"};
+
1046 auto const USD{G1["USD"]};
+
1047
+
1048 env.fund(XRP(10000), G1, A1, A2);
+
1049 env.close();
+
1050
+
1051 auto const limit = USD(10000);
+
1052 env.trust(limit, A1, A2);
+
1053 env.close();
+
1054
+
1055 env(pay(G1, A1, USD(1000)));
+
1056 env(pay(G1, A2, USD(1000)));
+
1057 env.close();
+
1058
+
1059 env(offer(A2, XRP(100), USD(100)), txflags(tfPassive));
+
1060 env.close();
+
1061
+
1062 // Testing payments A1 <-> G1 using offer from A2 frozen by issuer.
+
1063 {
+
1064 env(trust(G1, A2["USD"](0), tfSetFreeze));
+
1065 env.close();
+
1066
+
1067 // test: A1 cannot send USD using XRP through A2 offer
+
1068 env(pay(A1, G1, USD(10)),
+
1069 path(~USD),
+
1070 sendmax(XRP(11)),
+
1071 txflags(tfNoRippleDirect),
+
1072 ter(tecPATH_PARTIAL));
+
1073 env.close();
+
1074
+
1075 // test: G1 cannot send USD using XRP through A2 offer
+
1076 env(pay(G1, A1, USD(10)),
+
1077 path(~USD),
+
1078 sendmax(XRP(11)),
+
1079 txflags(tfNoRippleDirect),
+
1080 ter(tecPATH_PARTIAL));
+
1081 env.close();
+
1082
+
1083 env(trust(G1, A2["USD"](0), tfClearFreeze));
+
1084 env.close();
+
1085 }
+
1086
+
1087 // Testing payments A1 <-> G1 using offer from A2 deep frozen by issuer.
+
1088 if (features[featureDeepFreeze])
+
1089 {
+
1090 env(trust(G1, A2["USD"](0), tfSetFreeze | tfSetDeepFreeze));
+
1091 env.close();
+
1092
+
1093 // test: A1 cannot send USD using XRP through A2 offer
+
1094 env(pay(A1, G1, USD(10)),
+
1095 path(~USD),
+
1096 sendmax(XRP(11)),
+
1097 txflags(tfNoRippleDirect),
+
1098 ter(tecPATH_PARTIAL));
+
1099 env.close();
+
1100
+
1101 // test: G1 cannot send USD using XRP through A2 offer
+
1102 env(pay(G1, A1, USD(10)),
+
1103 path(~USD),
+
1104 sendmax(XRP(11)),
+
1105 txflags(tfNoRippleDirect),
+
1106 ter(tecPATH_PARTIAL));
+
1107 env.close();
+
1108
+
1109 env(trust(G1, A2["USD"](0), tfClearFreeze | tfClearDeepFreeze));
+
1110 env.close();
+
1111 }
+
1112
+
1113 // Testing payments A1 <-> G1 using offer from A2 frozen by currency
+
1114 // holder.
+
1115 {
+
1116 env(trust(A2, limit, tfSetFreeze));
+
1117 env.close();
+
1118
+
1119 // test: A1 can send USD using XRP through A2 offer
+
1120 env(pay(A1, G1, USD(10)),
+
1121 path(~USD),
+
1122 sendmax(XRP(11)),
+
1123 txflags(tfNoRippleDirect));
+
1124 env.close();
+
1125
+
1126 // test: G1 can send USD using XRP through A2 offer
+
1127 env(pay(G1, A1, USD(10)),
+
1128 path(~USD),
+
1129 sendmax(XRP(11)),
+
1130 txflags(tfNoRippleDirect));
+
1131 env.close();
+
1132
+
1133 env(trust(A2, limit, tfClearFreeze));
+
1134 env.close();
+
1135 }
+
1136
+
1137 // Testing payments A1 <-> G1 using offer from A2 deep frozen by
+
1138 // currency holder.
+
1139 if (features[featureDeepFreeze])
+
1140 {
+
1141 env(trust(A2, limit, tfSetFreeze | tfSetDeepFreeze));
+
1142 env.close();
+
1143
+
1144 // test: A1 cannot send USD using XRP through A2 offer
+
1145 env(pay(A1, G1, USD(10)),
+
1146 path(~USD),
+
1147 sendmax(XRP(11)),
+
1148 txflags(tfNoRippleDirect),
+
1149 ter(tecPATH_PARTIAL));
+
1150 env.close();
+
1151
+
1152 // test: G1 cannot send USD using XRP through A2 offer
+
1153 env(pay(G1, A1, USD(10)),
+
1154 path(~USD),
+
1155 sendmax(XRP(11)),
+
1156 txflags(tfNoRippleDirect),
+
1157 ter(tecPATH_PARTIAL));
+
1158 env.close();
+
1159
+
1160 env(trust(A2, limit, tfClearFreeze | tfClearDeepFreeze));
+
1161 env.close();
+
1162 }
+
1163
+
1164 // Cleanup
+
1165 env(offer_cancel(A1, env.seq(A1) - 1));
+
1166 env.require(offers(A1, 0));
+
1167 env.close();
+
1168
+
1169 env(offer(A2, USD(100), XRP(100)), txflags(tfPassive));
+
1170 env.close();
+
1171
+
1172 // Testing payments A1 <-> G1 using offer from A2 frozen by issuer.
+
1173 {
+
1174 env(trust(G1, A2["USD"](0), tfSetFreeze));
+
1175 env.close();
+
1176
+
1177 // test: A1 can send XRP using USD through A2 offer
+
1178 env(pay(A1, G1, XRP(10)),
+
1179 path(~XRP),
+
1180 sendmax(USD(11)),
+
1181 txflags(tfNoRippleDirect));
+
1182 env.close();
+
1183
+
1184 // test: G1 can send XRP using USD through A2 offer
+
1185 env(pay(G1, A1, XRP(10)),
+
1186 path(~XRP),
+
1187 sendmax(USD(11)),
+
1188 txflags(tfNoRippleDirect));
+
1189 env.close();
+
1190
+
1191 env(trust(G1, A2["USD"](0), tfClearFreeze));
+
1192 env.close();
+
1193 }
+
1194
+
1195 // Testing payments A1 <-> G1 using offer from A2 deep frozen by
+
1196 // issuer.
+
1197 if (features[featureDeepFreeze])
+
1198 {
+
1199 env(trust(G1, A2["USD"](0), tfSetFreeze | tfSetDeepFreeze));
+
1200 env.close();
+
1201
+
1202 // test: A1 cannot send XRP using USD through A2 offer
+
1203 env(pay(A1, G1, XRP(10)),
+
1204 path(~XRP),
+
1205 sendmax(USD(11)),
+
1206 txflags(tfNoRippleDirect),
+
1207 ter(tecPATH_PARTIAL));
+
1208 env.close();
+
1209
+
1210 // test: G1 cannot send XRP using USD through A2 offer
+
1211 env(pay(G1, A1, XRP(10)),
+
1212 path(~XRP),
+
1213 sendmax(USD(11)),
+
1214 txflags(tfNoRippleDirect),
+
1215 ter(tecPATH_PARTIAL));
+
1216 env.close();
+
1217
+
1218 env(trust(G1, A2["USD"](0), tfClearFreeze | tfClearDeepFreeze));
+
1219 env.close();
+
1220 }
+
1221
+
1222 // Testing payments A1 <-> G1 using offer from A2 frozen by currency
+
1223 // holder.
+
1224 {
+
1225 env(trust(A2, limit, tfSetFreeze));
+
1226 env.close();
+
1227
+
1228 // test: A1 can send XRP using USD through A2 offer
+
1229 env(pay(A1, G1, XRP(10)),
+
1230 path(~XRP),
+
1231 sendmax(USD(11)),
+
1232 txflags(tfNoRippleDirect));
+
1233 env.close();
+
1234
+
1235 // test: G1 can send XRP using USD through A2 offer
+
1236 env(pay(G1, A1, XRP(10)),
+
1237 path(~XRP),
+
1238 sendmax(USD(11)),
+
1239 txflags(tfNoRippleDirect));
+
1240 env.close();
+
1241
+
1242 env(trust(A2, limit, tfClearFreeze));
+
1243 env.close();
+
1244 }
+
1245
+
1246 // Testing payments A1 <-> G1 using offer from A2 deep frozen by
+
1247 // currency holder.
+
1248 if (features[featureDeepFreeze])
+
1249 {
+
1250 env(trust(A2, limit, tfSetFreeze | tfSetDeepFreeze));
+
1251 env.close();
+
1252
+
1253 // test: A1 cannot send XRP using USD through A2 offer
+
1254 env(pay(A1, G1, XRP(10)),
+
1255 path(~XRP),
+
1256 sendmax(USD(11)),
+
1257 txflags(tfNoRippleDirect),
+
1258 ter(tecPATH_PARTIAL));
+
1259 env.close();
+
1260
+
1261 // test: G1 cannot send XRP using USD through A2 offer
+
1262 env(pay(G1, A1, XRP(10)),
+
1263 path(~XRP),
+
1264 sendmax(USD(11)),
+
1265 txflags(tfNoRippleDirect),
+
1266 ter(tecPATH_PARTIAL));
+
1267 env.close();
+
1268
+
1269 env(trust(A2, limit, tfClearFreeze | tfClearDeepFreeze));
+
1270 env.close();
+
1271 }
+
1272
+
1273 // Cleanup
+
1274 env(offer_cancel(A1, env.seq(A1) - 1));
+
1275 env.require(offers(A1, 0));
+
1276 env.close();
+
1277 }
+
1278
+
1279 void
+
1280 testPaymentsWhenDeepFrozen(FeatureBitset features)
+
1281 {
+
1282 testcase("Direct payments on frozen trust lines");
+
1283
+
1284 using namespace test::jtx;
+
1285 Env env(*this, features);
+
1286
+
1287 Account G1{"G1"};
+
1288 Account A1{"A1"};
+
1289 Account A2{"A2"};
+
1290 auto const USD{G1["USD"]};
+
1291
+
1292 env.fund(XRP(10000), G1, A1, A2);
+
1293 env.close();
+
1294
+
1295 auto const limit = USD(10000);
+
1296 env.trust(limit, A1, A2);
+
1297 env.close();
+
1298
+
1299 env(pay(G1, A1, USD(1000)));
+
1300 env(pay(G1, A2, USD(1000)));
+
1301 env.close();
+
1302
+
1303 // Checking payments before freeze
+
1304 // To issuer:
+
1305 env(pay(A1, G1, USD(1)));
+
1306 env(pay(A2, G1, USD(1)));
+
1307 env.close();
+
1308
+
1309 // To each other:
+
1310 env(pay(A1, A2, USD(1)));
+
1311 env(pay(A2, A1, USD(1)));
+
1312 env.close();
+
1313
+
1314 // Freeze A1
+
1315 env(trust(G1, A1["USD"](0), tfSetFreeze));
+
1316 env.close();
+
1317
+
1318 // Issuer and A1 can send payments to each other
+
1319 env(pay(A1, G1, USD(1)));
+
1320 env(pay(G1, A1, USD(1)));
+
1321 env.close();
+
1322
+
1323 // A1 cannot send tokens to A2
+
1324 env(pay(A1, A2, USD(1)), ter(tecPATH_DRY));
+
1325
+
1326 // A2 can still send to A1
+
1327 env(pay(A2, A1, USD(1)));
+
1328 env.close();
+
1329
+
1330 if (features[featureDeepFreeze])
+
1331 {
+
1332 // Deep freeze A1
+
1333 env(trust(G1, A1["USD"](0), tfSetDeepFreeze));
+
1334 env.close();
+
1335
+
1336 // Issuer and A1 can send payments to each other
+
1337 env(pay(A1, G1, USD(1)));
+
1338 env(pay(G1, A1, USD(1)));
+
1339 env.close();
+
1340
+
1341 // A1 cannot send tokens to A2
+
1342 env(pay(A1, A2, USD(1)), ter(tecPATH_DRY));
+
1343
+
1344 // A2 cannot send tokens to A1
+
1345 env(pay(A2, A1, USD(1)), ter(tecPATH_DRY));
+
1346
+
1347 // Clear deep freeze on A1
+
1348 env(trust(G1, A1["USD"](0), tfClearDeepFreeze));
+
1349 env.close();
+
1350 }
+
1351
+
1352 // Clear freeze on A1
+
1353 env(trust(G1, A1["USD"](0), tfClearFreeze));
+
1354 env.close();
+
1355
+
1356 // A1 freezes trust line
+
1357 env(trust(A1, limit, tfSetFreeze));
+
1358 env.close();
+
1359
+
1360 // Issuer and A2 must not be affected
+
1361 env(pay(A2, G1, USD(1)));
+
1362 env(pay(G1, A2, USD(1)));
+
1363 env.close();
+
1364
+
1365 // A1 can send tokens to the issuer
+
1366 env(pay(A1, G1, USD(1)));
+
1367 env.close();
+
1368 // A1 can send tokens to A2
+
1369 env(pay(A1, A2, USD(1)));
+
1370 env.close();
+
1371
+
1372 // Issuer can sent tokens to A1
+
1373 env(pay(G1, A1, USD(1)));
+
1374 // A2 cannot send tokens to A1
+
1375 env(pay(A2, A1, USD(1)), ter(tecPATH_DRY));
+
1376
+
1377 if (features[featureDeepFreeze])
+
1378 {
+
1379 // A1 deep freezes trust line
+
1380 env(trust(A1, limit, tfSetDeepFreeze));
+
1381 env.close();
+
1382
+
1383 // Issuer and A2 must not be affected
+
1384 env(pay(A2, G1, USD(1)));
+
1385 env(pay(G1, A2, USD(1)));
+
1386 env.close();
+
1387
+
1388 // A1 can still send token to issuer
+
1389 env(pay(A1, G1, USD(1)));
+
1390 env.close();
+
1391
+
1392 // Issuer can send tokens to A1
+
1393 env(pay(G1, A1, USD(1)));
+
1394 // A2 cannot send tokens to A1
+
1395 env(pay(A2, A1, USD(1)), ter(tecPATH_DRY));
+
1396 // A1 cannot send tokens to A2
+
1397 env(pay(A1, A2, USD(1)), ter(tecPATH_DRY));
+
1398 }
+
1399 }
+
1400
+
1401 void
+
1402 testChecksWhenFrozen(FeatureBitset features)
+
1403 {
+
1404 testcase("Checks on frozen trust lines");
+
1405
+
1406 using namespace test::jtx;
+
1407 Env env(*this, features);
+
1408
+
1409 Account G1{"G1"};
+
1410 Account A1{"A1"};
+
1411 Account A2{"A2"};
+
1412 auto const USD{G1["USD"]};
+
1413
+
1414 env.fund(XRP(10000), G1, A1, A2);
+
1415 env.close();
+
1416
+
1417 auto const limit = USD(10000);
+
1418 env.trust(limit, A1, A2);
+
1419 env.close();
+
1420
+
1421 env(pay(G1, A1, USD(1000)));
+
1422 env(pay(G1, A2, USD(1000)));
+
1423 env.close();
+
1424
+
1425 // Confirming we can write and cash checks
+
1426 {
+
1427 uint256 const checkId{getCheckIndex(G1, env.seq(G1))};
+
1428 env(check::create(G1, A1, USD(10)));
+
1429 env.close();
+
1430 env(check::cash(A1, checkId, USD(10)));
+
1431 env.close();
+
1432 }
+
1433
+
1434 {
+
1435 uint256 const checkId{getCheckIndex(G1, env.seq(G1))};
+
1436 env(check::create(G1, A2, USD(10)));
+
1437 env.close();
+
1438 env(check::cash(A2, checkId, USD(10)));
+
1439 env.close();
+
1440 }
+
1441
+
1442 {
+
1443 uint256 const checkId{getCheckIndex(A1, env.seq(A1))};
+
1444 env(check::create(A1, G1, USD(10)));
+
1445 env.close();
+
1446 env(check::cash(G1, checkId, USD(10)));
+
1447 env.close();
+
1448 }
+
1449
+
1450 {
+
1451 uint256 const checkId{getCheckIndex(A1, env.seq(A1))};
+
1452 env(check::create(A1, A2, USD(10)));
+
1453 env.close();
+
1454 env(check::cash(A2, checkId, USD(10)));
+
1455 env.close();
+
1456 }
+
1457
+
1458 {
+
1459 uint256 const checkId{getCheckIndex(A2, env.seq(A2))};
+
1460 env(check::create(A2, G1, USD(10)));
+
1461 env.close();
+
1462 env(check::cash(G1, checkId, USD(10)));
+
1463 env.close();
+
1464 }
+
1465
+
1466 {
+
1467 uint256 const checkId{getCheckIndex(A2, env.seq(A2))};
+
1468 env(check::create(A2, A1, USD(10)));
+
1469 env.close();
+
1470 env(check::cash(A1, checkId, USD(10)));
+
1471 env.close();
+
1472 }
+
1473
+
1474 // Testing creation and cashing of checks on a trustline frozen by
+
1475 // issuer
+
1476 {
+
1477 env(trust(G1, A1["USD"](0), tfSetFreeze));
+
1478 env.close();
+
1479
+
1480 // test: issuer writes check to A1.
+
1481 {
+
1482 uint256 const checkId{getCheckIndex(G1, env.seq(G1))};
+
1483 env(check::create(G1, A1, USD(10)));
+
1484 env.close();
+
1485 env(check::cash(A1, checkId, USD(10)), ter(tecFROZEN));
+
1486 env.close();
+
1487 }
+
1488
+
1489 // test: A2 writes check to A1.
+
1490 {
+
1491 uint256 const checkId{getCheckIndex(A2, env.seq(A2))};
+
1492 env(check::create(A2, A1, USD(10)));
+
1493 env.close();
+
1494 // Same as previous test
+
1495 env(check::cash(A1, checkId, USD(10)), ter(tecFROZEN));
+
1496 env.close();
+
1497 }
+
1498
+
1499 // test: A1 writes check to issuer
+
1500 {
+
1501 env(check::create(A1, G1, USD(10)), ter(tecFROZEN));
+
1502 env.close();
+
1503 }
+
1504
+
1505 // test: A1 writes check to A2
+
1506 {
+
1507 // Same as previous test
+
1508 env(check::create(A1, A2, USD(10)), ter(tecFROZEN));
+
1509 env.close();
+
1510 }
+
1511
+
1512 // Unfreeze the trustline to create a couple of checks so that we
+
1513 // could try to cash them later when the trustline is frozen again.
+
1514 env(trust(G1, A1["USD"](0), tfClearFreeze));
+
1515 env.close();
+
1516
+
1517 uint256 const checkId1{getCheckIndex(A1, env.seq(A1))};
+
1518 env(check::create(A1, G1, USD(10)));
+
1519 env.close();
+
1520 uint256 const checkId2{getCheckIndex(A1, env.seq(A1))};
+
1521 env(check::create(A1, A2, USD(10)));
+
1522 env.close();
+
1523
+
1524 env(trust(G1, A1["USD"](0), tfSetFreeze));
+
1525 env.close();
+
1526
+
1527 // test: issuer tries to cash the check from A1
+
1528 {
+
1529 env(check::cash(G1, checkId1, USD(10)), ter(tecPATH_PARTIAL));
+
1530 env.close();
+
1531 }
+
1532
+
1533 // test: A2 tries to cash the check from A1
+
1534 {
+
1535 env(check::cash(A2, checkId2, USD(10)), ter(tecPATH_PARTIAL));
+
1536 env.close();
+
1537 }
+
1538
+
1539 env(trust(G1, A1["USD"](0), tfClearFreeze));
+
1540 env.close();
+
1541 }
+
1542
+
1543 // Testing creation and cashing of checks on a trustline deep frozen by
+
1544 // issuer
+
1545 if (features[featureDeepFreeze])
+
1546 {
+
1547 env(trust(G1, A1["USD"](0), tfSetFreeze | tfSetDeepFreeze));
+
1548 env.close();
+
1549
+
1550 // test: issuer writes check to A1.
+
1551 {
+
1552 uint256 const checkId{getCheckIndex(G1, env.seq(G1))};
+
1553 env(check::create(G1, A1, USD(10)));
+
1554 env.close();
+
1555
+
1556 env(check::cash(A1, checkId, USD(10)), ter(tecFROZEN));
+
1557 env.close();
+
1558 }
+
1559
+
1560 // test: A2 writes check to A1.
+
1561 {
+
1562 uint256 const checkId{getCheckIndex(A2, env.seq(A2))};
+
1563 env(check::create(A2, A1, USD(10)));
+
1564 env.close();
+
1565 // Same as previous test
+
1566 env(check::cash(A1, checkId, USD(10)), ter(tecFROZEN));
+
1567 env.close();
+
1568 }
+
1569
+
1570 // test: A1 writes check to issuer
+
1571 {
+
1572 env(check::create(A1, G1, USD(10)), ter(tecFROZEN));
+
1573 env.close();
+
1574 }
+
1575
+
1576 // test: A1 writes check to A2
+
1577 {
+
1578 // Same as previous test
+
1579 env(check::create(A1, A2, USD(10)), ter(tecFROZEN));
+
1580 env.close();
+
1581 }
+
1582
+
1583 // Unfreeze the trustline to create a couple of checks so that we
+
1584 // could try to cash them later when the trustline is frozen again.
+
1585 env(trust(G1, A1["USD"](0), tfClearFreeze | tfClearDeepFreeze));
+
1586 env.close();
+
1587
+
1588 uint256 const checkId1{getCheckIndex(A1, env.seq(A1))};
+
1589 env(check::create(A1, G1, USD(10)));
+
1590 env.close();
+
1591 uint256 const checkId2{getCheckIndex(A1, env.seq(A1))};
+
1592 env(check::create(A1, A2, USD(10)));
+
1593 env.close();
+
1594
+
1595 env(trust(G1, A1["USD"](0), tfSetFreeze | tfSetDeepFreeze));
+
1596 env.close();
+
1597
+
1598 // test: issuer tries to cash the check from A1
+
1599 {
+
1600 env(check::cash(G1, checkId1, USD(10)), ter(tecPATH_PARTIAL));
+
1601 env.close();
+
1602 }
+
1603
+
1604 // test: A2 tries to cash the check from A1
+
1605 {
+
1606 env(check::cash(A2, checkId2, USD(10)), ter(tecPATH_PARTIAL));
+
1607 env.close();
+
1608 }
+
1609
+
1610 env(trust(G1, A1["USD"](0), tfClearFreeze | tfClearDeepFreeze));
+
1611 env.close();
+
1612 }
+
1613
+
1614 // Testing creation and cashing of checks on a trustline frozen by
+
1615 // a currency holder
+
1616 {
+
1617 env(trust(A1, limit, tfSetFreeze));
+
1618 env.close();
+
1619
+
1620 // test: issuer writes check to A1.
+
1621 {
+
1622 env(check::create(G1, A1, USD(10)), ter(tecFROZEN));
+
1623 env.close();
+
1624 }
+
1625
+
1626 // test: A2 writes check to A1.
+
1627 {
+
1628 env(check::create(A2, A1, USD(10)), ter(tecFROZEN));
+
1629 env.close();
+
1630 }
+
1631
+
1632 // test: A1 writes check to issuer
+
1633 {
+
1634 uint256 const checkId{getCheckIndex(A1, env.seq(A1))};
+
1635 env(check::create(A1, G1, USD(10)));
+
1636 env.close();
+
1637 env(check::cash(G1, checkId, USD(10)));
+
1638 env.close();
+
1639 }
+
1640
+
1641 // test: A1 writes check to A2
+
1642 {
+
1643 uint256 const checkId{getCheckIndex(A1, env.seq(A1))};
+
1644 env(check::create(A1, A2, USD(10)));
+
1645 env.close();
+
1646 env(check::cash(A2, checkId, USD(10)));
+
1647 env.close();
+
1648 }
+
1649
+
1650 env(trust(A1, limit, tfClearFreeze));
+
1651 env.close();
+
1652 }
+
1653
+
1654 // Testing creation and cashing of checks on a trustline deep frozen by
+
1655 // a currency holder
+
1656 if (features[featureDeepFreeze])
+
1657 {
+
1658 env(trust(A1, limit, tfSetFreeze | tfSetDeepFreeze));
+
1659 env.close();
+
1660
+
1661 // test: issuer writes check to A1.
+
1662 {
+
1663 env(check::create(G1, A1, USD(10)), ter(tecFROZEN));
+
1664 env.close();
+
1665 }
+
1666
+
1667 // test: A2 writes check to A1.
+
1668 {
+
1669 env(check::create(A2, A1, USD(10)), ter(tecFROZEN));
+
1670 env.close();
+
1671 }
+
1672
+
1673 // test: A1 writes check to issuer
+
1674 {
+
1675 uint256 const checkId{getCheckIndex(A1, env.seq(A1))};
+
1676 env(check::create(A1, G1, USD(10)));
+
1677 env.close();
+
1678 env(check::cash(G1, checkId, USD(10)), ter(tecPATH_PARTIAL));
+
1679 env.close();
+
1680 }
+
1681
+
1682 // test: A1 writes check to A2
+
1683 {
+
1684 uint256 const checkId{getCheckIndex(A1, env.seq(A1))};
+
1685 env(check::create(A1, A2, USD(10)));
+
1686 env.close();
+
1687 env(check::cash(A2, checkId, USD(10)), ter(tecPATH_PARTIAL));
+
1688 env.close();
+
1689 }
+
1690
+
1691 env(trust(A1, limit, tfClearFreeze | tfClearDeepFreeze));
+
1692 env.close();
+
1693 }
+
1694 }
+
1695
+
1696 void
+
1697 testAMMWhenFreeze(FeatureBitset features)
+
1698 {
+
1699 testcase("AMM payments on frozen trust lines");
+
1700 using namespace test::jtx;
+
1701 using path = test::jtx::path;
+
1702
+
1703 Env env(*this, features);
+
1704 Account G1{"G1"};
+
1705 Account A1{"A1"};
+
1706 Account A2{"A2"};
+
1707 auto const USD{G1["USD"]};
+
1708
+
1709 env.fund(XRP(10000), G1, A1, A2);
+
1710 env.close();
+
1711
+
1712 env.trust(G1["USD"](10000), A1, A2);
+
1713 env.close();
+
1714
+
1715 env(pay(G1, A1, USD(1000)));
+
1716 env(pay(G1, A2, USD(1000)));
+
1717 env.close();
+
1718
+
1719 AMM ammG1(env, G1, XRP(1'000), USD(1'000));
+
1720 env.close();
+
1721
+
1722 // Testing basic payment using AMM when freezing one of the trust lines.
+
1723 {
+
1724 env(trust(G1, A1["USD"](0), tfSetFreeze));
+
1725 env.close();
+
1726
+
1727 // test: can still use XRP to make payment
+
1728 env(pay(A1, A2, USD(10)),
+
1729 path(~USD),
+
1730 sendmax(XRP(11)),
+
1731 txflags(tfNoRippleDirect));
+
1732 env.close();
+
1733
+
1734 // test: cannot use USD to make payment
+
1735 env(pay(A1, A2, XRP(10)),
+
1736 path(~XRP),
+
1737 sendmax(USD(11)),
+
1738 txflags(tfNoRippleDirect),
+
1739 ter(tecPATH_DRY));
+
1740 env.close();
+
1741
+
1742 // test: can still receive USD payments.
+
1743 env(pay(A2, A1, USD(10)),
+
1744 path(~USD),
+
1745 sendmax(XRP(11)),
+
1746 txflags(tfNoRippleDirect));
+
1747 env.close();
+
1748
+
1749 // test: can still receive XRP payments.
+
1750 env(pay(A2, A1, XRP(10)),
+
1751 path(~XRP),
+
1752 sendmax(USD(11)),
+
1753 txflags(tfNoRippleDirect));
+
1754 env.close();
+
1755
+
1756 env(trust(G1, A1["USD"](0), tfClearFreeze));
+
1757 env.close();
+
1758 }
+
1759
+
1760 // Testing basic payment using AMM when deep freezing one of the trust
+
1761 // lines.
+
1762 if (features[featureDeepFreeze])
+
1763 {
+
1764 env(trust(G1, A1["USD"](0), tfSetFreeze | tfSetDeepFreeze));
+
1765 env.close();
+
1766
+
1767 // test: can still use XRP to make payment
+
1768 env(pay(A1, A2, USD(10)),
+
1769 path(~USD),
+
1770 sendmax(XRP(11)),
+
1771 txflags(tfNoRippleDirect));
+
1772 env.close();
+
1773
+
1774 // test: cannot use USD to make payment
+
1775 env(pay(A1, A2, XRP(10)),
+
1776 path(~XRP),
+
1777 sendmax(USD(11)),
+
1778 txflags(tfNoRippleDirect),
+
1779 ter(tecPATH_DRY));
+
1780 env.close();
+
1781
+
1782 // test: cannot receive USD payments.
+
1783 env(pay(A2, A1, USD(10)),
+
1784 path(~USD),
+
1785 sendmax(XRP(11)),
+
1786 txflags(tfNoRippleDirect),
+
1787 ter(tecPATH_DRY));
+
1788 env.close();
+
1789
+
1790 // test: can still receive XRP payments.
+
1791 env(pay(A2, A1, XRP(10)),
+
1792 path(~XRP),
+
1793 sendmax(USD(11)),
+
1794 txflags(tfNoRippleDirect));
+
1795 env.close();
+
1796
+
1797 env(trust(G1, A1["USD"](0), tfClearFreeze | tfClearDeepFreeze));
+
1798 env.close();
+
1799 }
+
1800 }
+
1801
+
1802 void
+
1803 testNFTOffersWhenFreeze(FeatureBitset features)
+
1804 {
+
1805 testcase("NFT offers on frozen trust lines");
+
1806 using namespace test::jtx;
+
1807
+
1808 Env env(*this, features);
+
1809 Account G1{"G1"};
+
1810 Account A1{"A1"};
+
1811 Account A2{"A2"};
+
1812 auto const USD{G1["USD"]};
+
1813
+
1814 env.fund(XRP(10000), G1, A1, A2);
+
1815 env.close();
+
1816
+
1817 auto const limit = USD(10000);
+
1818 env.trust(limit, A1, A2);
+
1819 env.close();
+
1820
+
1821 env(pay(G1, A1, USD(1000)));
+
1822 env(pay(G1, A2, USD(1000)));
+
1823 env.close();
+
1824
+
1825 // Testing A2 nft offer sell when A2 frozen by issuer
+
1826 {
+
1827 auto const sellOfferIndex = createNFTSellOffer(env, A2, USD(10));
+
1828 env(trust(G1, A2["USD"](0), tfSetFreeze));
+
1829 env.close();
+
1830
+
1831 // test: A2 can still receive USD for his NFT
+
1832 env(token::acceptSellOffer(A1, sellOfferIndex));
+
1833 env.close();
+
1834
+
1835 env(trust(G1, A2["USD"](0), tfClearFreeze));
+
1836 env.close();
+
1837 }
+
1838
+
1839 // Testing A2 nft offer sell when A2 deep frozen by issuer
+
1840 if (features[featureDeepFreeze])
+
1841 {
+
1842 auto const sellOfferIndex = createNFTSellOffer(env, A2, USD(10));
+
1843
+
1844 env(trust(G1, A2["USD"](0), tfSetFreeze | tfSetDeepFreeze));
+
1845 env.close();
+
1846
+
1847 // test: A2 cannot receive USD for his NFT
+
1848 env(token::acceptSellOffer(A1, sellOfferIndex), ter(tecFROZEN));
+
1849 env.close();
+
1850
+
1851 env(trust(G1, A2["USD"](0), tfClearFreeze | tfClearDeepFreeze));
+
1852 env.close();
+
1853 }
+
1854
+
1855 // Testing A1 nft offer sell when A2 frozen by issuer
+
1856 {
+
1857 auto const sellOfferIndex = createNFTSellOffer(env, A1, USD(10));
+
1858 env(trust(G1, A2["USD"](0), tfSetFreeze));
+
1859 env.close();
+
1860
+
1861 // test: A2 cannot send USD for NFT
+
1862 env(token::acceptSellOffer(A2, sellOfferIndex),
+
1863 ter(tecINSUFFICIENT_FUNDS));
+
1864 env.close();
+
1865
+
1866 env(trust(G1, A2["USD"](0), tfClearFreeze));
+
1867 env.close();
+
1868 }
+
1869
+
1870 // Testing A1 nft offer sell when A2 deep frozen by issuer
+
1871 if (features[featureDeepFreeze])
+
1872 {
+
1873 auto const sellOfferIndex = createNFTSellOffer(env, A1, USD(10));
+
1874 env(trust(G1, A2["USD"](0), tfSetFreeze | tfSetDeepFreeze));
+
1875 env.close();
+
1876
+
1877 // test: A2 cannot send USD for NFT
+
1878 env(token::acceptSellOffer(A2, sellOfferIndex),
+
1879 ter(tecINSUFFICIENT_FUNDS));
+
1880 env.close();
+
1881
+
1882 env(trust(G1, A2["USD"](0), tfClearFreeze | tfClearDeepFreeze));
+
1883 env.close();
+
1884 }
+
1885
+
1886 // Testing A2 nft offer sell when A2 frozen by currency holder
+
1887 {
+
1888 auto const sellOfferIndex = createNFTSellOffer(env, A2, USD(10));
+
1889 env(trust(A2, limit, tfSetFreeze));
+
1890 env.close();
+
1891
+
1892 // test: offer can still be accepted.
+
1893 env(token::acceptSellOffer(A1, sellOfferIndex));
+
1894 env.close();
+
1895
+
1896 env(trust(A2, limit, tfClearFreeze));
+
1897 env.close();
+
1898 }
+
1899
+
1900 // Testing A2 nft offer sell when A2 deep frozen by currency holder
+
1901 if (features[featureDeepFreeze])
+
1902 {
+
1903 auto const sellOfferIndex = createNFTSellOffer(env, A2, USD(10));
+
1904
+
1905 env(trust(A2, limit, tfSetFreeze | tfSetDeepFreeze));
+
1906 env.close();
+
1907
+
1908 // test: A2 cannot receive USD for his NFT
+
1909 env(token::acceptSellOffer(A1, sellOfferIndex), ter(tecFROZEN));
+
1910 env.close();
+
1911
+
1912 env(trust(A2, limit, tfClearFreeze | tfClearDeepFreeze));
+
1913 env.close();
+
1914 }
+
1915
+
1916 // Testing A1 nft offer sell when A2 frozen by currency holder
+
1917 {
+
1918 auto const sellOfferIndex = createNFTSellOffer(env, A1, USD(10));
+
1919 env(trust(A2, limit, tfSetFreeze));
+
1920 env.close();
+
1921
+
1922 // test: A2 cannot send USD for NFT
+
1923 env(token::acceptSellOffer(A2, sellOfferIndex));
+
1924 env.close();
+
1925
+
1926 env(trust(A2, limit, tfClearFreeze));
+
1927 env.close();
+
1928 }
+
1929
+
1930 // Testing A1 nft offer sell when A2 deep frozen by currency holder
+
1931 if (features[featureDeepFreeze])
+
1932 {
+
1933 auto const sellOfferIndex = createNFTSellOffer(env, A1, USD(10));
+
1934 env(trust(A2, limit, tfSetFreeze | tfSetDeepFreeze));
+
1935 env.close();
+
1936
+
1937 // test: A2 cannot send USD for NFT
+
1938 env(token::acceptSellOffer(A2, sellOfferIndex),
+
1939 ter(tecINSUFFICIENT_FUNDS));
+
1940 env.close();
+
1941
+
1942 env(trust(A2, limit, tfClearFreeze | tfClearDeepFreeze));
+
1943 env.close();
+
1944 }
+
1945 }
+
1946
+
1947 // Helper function to extract trustline flags from open ledger
+
1948 uint32_t
+
1949 getTrustlineFlags(
+
1950 test::jtx::Env& env,
+
1951 size_t expectedArraySize,
+
1952 size_t expectedArrayIndex,
+
1953 bool modified = true)
+
1954 {
+
1955 using namespace test::jtx;
+
1956 auto const affected =
+
1957 env.meta()->getJson(JsonOptions::none)[sfAffectedNodes.fieldName];
+
1958 if (!BEAST_EXPECT(checkArraySize(affected, expectedArraySize)))
+
1959 return 0;
+
1960
+
1961 if (modified)
+
1962 {
+
1963 return affected[expectedArrayIndex][sfModifiedNode.fieldName]
+
1964 [sfFinalFields.fieldName][jss::Flags]
+
1965 .asUInt();
+
1966 }
+
1967
+
1968 return affected[expectedArrayIndex][sfCreatedNode.fieldName]
+
1969 [sfNewFields.fieldName][jss::Flags]
+
1970 .asUInt();
+
1971 }
+
1972
+
1973 // Helper function that returns the index of the next check on account
+
1974 uint256
+
1975 getCheckIndex(AccountID const& account, std::uint32_t uSequence)
+
1976 {
+
1977 return keylet::check(account, uSequence).key;
+
1978 }
+
1979
+
1980 uint256
+
1981 createNFTSellOffer(
+
1982 test::jtx::Env& env,
+
1983 test::jtx::Account const& account,
+
1984 test::jtx::PrettyAmount const& currency)
+
1985 {
+
1986 using namespace test::jtx;
+
1987 uint256 const nftID{token::getNextID(env, account, 0u, tfTransferable)};
+
1988 env(token::mint(account, 0), txflags(tfTransferable));
+
1989 env.close();
+
1990
+
1991 uint256 const sellOfferIndex =
+
1992 keylet::nftoffer(account, env.seq(account)).key;
+
1993 env(token::createOffer(account, nftID, currency),
+
1994 txflags(tfSellNFToken));
+
1995 env.close();
+
1996
+
1997 return sellOfferIndex;
+
1998 }
+
1999
+
2000public:
+
2001 void
+
2002 run() override
+
2003 {
+
2004 auto testAll = [this](FeatureBitset features) {
+
2005 testRippleState(features);
+
2006 testDeepFreeze(features);
+
2007 testCreateFrozenTrustline(features);
+
2008 testSetAndClear(features);
+
2009 testGlobalFreeze(features);
+
2010 testNoFreeze(features);
+
2011 testOffersWhenFrozen(features);
+
2012 testOffersWhenDeepFrozen(features);
+
2013 testPaymentsWhenDeepFrozen(features);
+
2014 testChecksWhenFrozen(features);
+
2015 testAMMWhenFreeze(features);
+
2016 testPathsWhenFrozen(features);
+
2017 testNFTOffersWhenFreeze(features);
+
2018 };
+
2019 using namespace test::jtx;
+
2020 auto const sa = supported_amendments();
+
2021 testAll(sa - featureFlowCross - featureDeepFreeze);
+
2022 testAll(sa - featureFlowCross);
+
2023 testAll(sa - featureDeepFreeze);
+
2024 testAll(sa);
+
2025 }
+
2026};
+
2027
+
2028BEAST_DEFINE_TESTSUITE(Freeze, app, ripple);
+
2029} // namespace ripple
std::string
Json::Value
Represents a JSON value.
Definition: json_value.h:147
beast::unit_test::suite
A testsuite class.
Definition: suite.h:53
beast::unit_test::suite::testcase
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:153
ripple::FeatureBitset
Definition: Feature.h:120
-
ripple::Freeze_test
Definition: Freeze_test.cpp:29
-
ripple::Freeze_test::testGlobalFreeze
void testGlobalFreeze(FeatureBitset features)
Definition: Freeze_test.cpp:190
-
ripple::Freeze_test::testNoFreeze
void testNoFreeze(FeatureBitset features)
Definition: Freeze_test.cpp:348
-
ripple::Freeze_test::run
void run() override
Runs the suite.
Definition: Freeze_test.cpp:511
-
ripple::Freeze_test::testRippleState
void testRippleState(FeatureBitset features)
Definition: Freeze_test.cpp:31
-
ripple::Freeze_test::testOffersWhenFrozen
void testOffersWhenFrozen(FeatureBitset features)
Definition: Freeze_test.cpp:403
+
ripple::Freeze_test
Definition: Freeze_test.cpp:30
+
ripple::Freeze_test::testOffersWhenDeepFrozen
void testOffersWhenDeepFrozen(FeatureBitset features)
Definition: Freeze_test.cpp:758
+
ripple::Freeze_test::createNFTSellOffer
uint256 createNFTSellOffer(test::jtx::Env &env, test::jtx::Account const &account, test::jtx::PrettyAmount const &currency)
Definition: Freeze_test.cpp:1981
+
ripple::Freeze_test::getTrustlineFlags
uint32_t getTrustlineFlags(test::jtx::Env &env, size_t expectedArraySize, size_t expectedArrayIndex, bool modified=true)
Definition: Freeze_test.cpp:1949
+
ripple::Freeze_test::testGlobalFreeze
void testGlobalFreeze(FeatureBitset features)
Definition: Freeze_test.cpp:378
+
ripple::Freeze_test::testDeepFreeze
void testDeepFreeze(FeatureBitset features)
Definition: Freeze_test.cpp:191
+
ripple::Freeze_test::testPaymentsWhenDeepFrozen
void testPaymentsWhenDeepFrozen(FeatureBitset features)
Definition: Freeze_test.cpp:1280
+
ripple::Freeze_test::testNoFreeze
void testNoFreeze(FeatureBitset features)
Definition: Freeze_test.cpp:536
+
ripple::Freeze_test::testNFTOffersWhenFreeze
void testNFTOffersWhenFreeze(FeatureBitset features)
Definition: Freeze_test.cpp:1803
+
ripple::Freeze_test::testAMMWhenFreeze
void testAMMWhenFreeze(FeatureBitset features)
Definition: Freeze_test.cpp:1697
+
ripple::Freeze_test::testPathsWhenFrozen
void testPathsWhenFrozen(FeatureBitset features)
Definition: Freeze_test.cpp:1036
+
ripple::Freeze_test::run
void run() override
Runs the suite.
Definition: Freeze_test.cpp:2002
+
ripple::Freeze_test::getCheckIndex
uint256 getCheckIndex(AccountID const &account, std::uint32_t uSequence)
Definition: Freeze_test.cpp:1975
+
ripple::Freeze_test::testCreateFrozenTrustline
void testCreateFrozenTrustline(FeatureBitset features)
Definition: Freeze_test.cpp:284
+
ripple::Freeze_test::testRippleState
void testRippleState(FeatureBitset features)
Definition: Freeze_test.cpp:32
+
ripple::Freeze_test::testSetAndClear
void testSetAndClear(FeatureBitset features)
Definition: Freeze_test.cpp:334
+
ripple::Freeze_test::testOffersWhenFrozen
void testOffersWhenFrozen(FeatureBitset features)
Definition: Freeze_test.cpp:651
+
ripple::Freeze_test::testChecksWhenFrozen
void testChecksWhenFrozen(FeatureBitset features)
Definition: Freeze_test.cpp:1402
ripple::Issue
A currency issued by an account.
Definition: Issue.h:36
ripple::STAmount
Definition: STAmount.h:50
+
ripple::base_uint< 256 >
+
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:38
+
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:117
+
ripple::test::jtx::Env::seq
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:216
+
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
+
ripple::test::jtx::Env::meta
std::shared_ptr< STObject const > meta()
Return metadata for the last JTx.
Definition: Env.cpp:451
+
ripple::test::jtx::path
Add a path.
Definition: paths.h:56
std::set::clear
T clear(T... args)
std::end
T end(T... args)
std::set::find
T find(T... args)
std::set::insert
T insert(T... args)
+
std::uint32_t
+
ripple::keylet::nftoffer
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Definition: Indexes.cpp:403
+
ripple::keylet::check
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition: Indexes.cpp:312
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:177
ripple::asfGlobalFreeze
constexpr std::uint32_t asfGlobalFreeze
Definition: TxFlags.h:82
+
ripple::tfSetDeepFreeze
constexpr std::uint32_t tfSetDeepFreeze
Definition: TxFlags.h:117
+
ripple::LedgerNameSpace::AMM
@ AMM
+
ripple::tfSellNFToken
constexpr std::uint32_t const tfSellNFToken
Definition: TxFlags.h:189
+
ripple::lsfHighDeepFreeze
@ lsfHighDeepFreeze
Definition: LedgerFormats.h:166
ripple::lsfHighFreeze
@ lsfHighFreeze
Definition: LedgerFormats.h:164
ripple::lsfLowFreeze
@ lsfLowFreeze
Definition: LedgerFormats.h:163
+
ripple::lsfLowDeepFreeze
@ lsfLowDeepFreeze
Definition: LedgerFormats.h:165
ripple::asfNoFreeze
constexpr std::uint32_t asfNoFreeze
Definition: TxFlags.h:81
+
ripple::tfFillOrKill
constexpr std::uint32_t tfFillOrKill
Definition: TxFlags.h:98
ripple::tfPassive
constexpr std::uint32_t tfPassive
Definition: TxFlags.h:96
ripple::tfClearFreeze
constexpr std::uint32_t tfClearFreeze
Definition: TxFlags.h:116
ripple::tecUNFUNDED_OFFER
@ tecUNFUNDED_OFFER
Definition: TER.h:271
ripple::tecFROZEN
@ tecFROZEN
Definition: TER.h:290
+
ripple::tecKILLED
@ tecKILLED
Definition: TER.h:303
+
ripple::tecINSUFFICIENT_FUNDS
@ tecINSUFFICIENT_FUNDS
Definition: TER.h:312
+
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:292
+
ripple::tecPATH_PARTIAL
@ tecPATH_PARTIAL
Definition: TER.h:269
ripple::tecPATH_DRY
@ tecPATH_DRY
Definition: TER.h:281
+
ripple::tfNoRippleDirect
constexpr std::uint32_t tfNoRippleDirect
Definition: TxFlags.h:104
+
ripple::tfClearDeepFreeze
constexpr std::uint32_t tfClearDeepFreeze
Definition: TxFlags.h:118
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:360
ripple::tfSetFreeze
constexpr std::uint32_t tfSetFreeze
Definition: TxFlags.h:115
+
ripple::tfTransferable
constexpr std::uint32_t const tfTransferable
Definition: TxFlags.h:136
ripple::to_currency
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
+
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:111
std::set
ripple::JsonOptions::none
@ none
Definition: STBase.h:42
+
ripple::Keylet::key
uint256 key
Definition: Keylet.h:40
+
ripple::test::jtx::PrettyAmount
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
Definition: src/test/jtx/amount.h:74