diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index 137ea5d16c..efec2afe0a 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -207,14 +207,14 @@ jobs: env: CONFIG_NAME: ${{ inputs.config_name }} run: | - ASAN_OPTS="halt_on_error=0:use_sigaltstack=0:print_stacktrace=1:detect_container_overflow=0:detect_stack_use_after_return=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp" + ASAN_OPTS="include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-asan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp" if [[ "${CONFIG_NAME}" == *gcc* ]]; then ASAN_OPTS="${ASAN_OPTS}:alloc_dealloc_mismatch=0" fi echo "ASAN_OPTIONS=${ASAN_OPTS}" >> ${GITHUB_ENV} - echo "TSAN_OPTIONS=second_deadlock_stack=1:halt_on_error=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >> ${GITHUB_ENV} - echo "UBSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >> ${GITHUB_ENV} - echo "LSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >> ${GITHUB_ENV} + echo "TSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-tsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >> ${GITHUB_ENV} + echo "UBSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-ubsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >> ${GITHUB_ENV} + echo "LSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-lsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >> ${GITHUB_ENV} - name: Run the separate tests if: ${{ !inputs.build_only }} diff --git a/cspell.config.yaml b/cspell.config.yaml index 49a15f3a37..ac8bb8b0a4 100644 --- a/cspell.config.yaml +++ b/cspell.config.yaml @@ -112,6 +112,7 @@ words: - gpgcheck - gpgkey - hotwallet + - hwaddress - hwrap - ifndef - inequation diff --git a/docs/build/sanitizers.md b/docs/build/sanitizers.md index 3f9809ae98..ac3a0cc865 100644 --- a/docs/build/sanitizers.md +++ b/docs/build/sanitizers.md @@ -89,8 +89,8 @@ cmake --build . --parallel 4 **IMPORTANT**: ASAN with Boost produces many false positives. Use these options: ```bash -export ASAN_OPTIONS="print_stacktrace=1:detect_container_overflow=0:suppressions=path/to/asan.supp:halt_on_error=0:log_path=asan.log" -export LSAN_OPTIONS="suppressions=path/to/lsan.supp:halt_on_error=0:log_path=lsan.log" +export ASAN_OPTIONS="include=sanitizers/suppressions/runtime-asan-options.txt:suppressions=sanitizers/suppressions/asan.supp" +export LSAN_OPTIONS="include=sanitizers/suppressions/runtime-lsan-options.txt:suppressions=sanitizers/suppressions/lsan.supp" # Run tests ./xrpld --unittest --unittest-jobs=5 @@ -108,7 +108,7 @@ export LSAN_OPTIONS="suppressions=path/to/lsan.supp:halt_on_error=0:log_path=lsa ### ThreadSanitizer (TSan) ```bash -export TSAN_OPTIONS="suppressions=path/to/tsan.supp halt_on_error=0 log_path=tsan.log" +export TSAN_OPTIONS="include=sanitizers/suppressions/runtime-tsan-options.txt:suppressions=sanitizers/suppressions/tsan.supp" # Run tests ./xrpld --unittest --unittest-jobs=5 @@ -129,7 +129,7 @@ More details [here](https://github.com/google/sanitizers/wiki/AddressSanitizerLe ### UndefinedBehaviorSanitizer (UBSan) ```bash -export UBSAN_OPTIONS="suppressions=path/to/ubsan.supp:print_stacktrace=1:halt_on_error=0:log_path=ubsan.log" +export UBSAN_OPTIONS="include=sanitizers/suppressions/runtime-ubsan-options.txt:suppressions=sanitizers/suppressions/ubsan.supp" # Run tests ./xrpld --unittest --unittest-jobs=5 diff --git a/include/xrpl/basics/contract.h b/include/xrpl/basics/contract.h index aba021b726..f41c272b61 100644 --- a/include/xrpl/basics/contract.h +++ b/include/xrpl/basics/contract.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -23,16 +24,28 @@ LogThrow(std::string const& title); When called from within a catch block, it will pass control to the next matching exception handler, if any. Otherwise, std::terminate will be called. + + ASAN can't handle sudden jumps in control flow very well. This + function is marked as XRPL_NO_SANITIZE_ADDRESS to prevent it from + triggering false positives, since it throws. */ -[[noreturn]] inline void +[[noreturn]] XRPL_NO_SANITIZE_ADDRESS inline void Rethrow() { LogThrow("Re-throwing exception"); throw; } +/* + Logs and throws an exception of type E. + + ASAN can't handle sudden jumps in control flow very well. This + function is marked as XRPL_NO_SANITIZE_ADDRESS to prevent it from + triggering false positives, since it throws. +*/ + template -[[noreturn]] inline void +[[noreturn]] XRPL_NO_SANITIZE_ADDRESS inline void Throw(Args&&... args) { static_assert( diff --git a/include/xrpl/basics/sanitizers.h b/include/xrpl/basics/sanitizers.h new file mode 100644 index 0000000000..b954952848 --- /dev/null +++ b/include/xrpl/basics/sanitizers.h @@ -0,0 +1,13 @@ +#pragma once + +// Helper to disable ASan/HwASan for specific functions +/* + ASAN flags some false positives with sudden jumps in control flow, like + exceptions, or when encountering coroutine stack switches. This macro can be used to disable ASAN + intrumentation for specific functions. +*/ +#if defined(__GNUC__) || defined(__clang__) +#define XRPL_NO_SANITIZE_ADDRESS __attribute__((no_sanitize("address", "hwaddress"))) +#else +#define XRPL_NO_SANITIZE_ADDRESS +#endif diff --git a/include/xrpl/protocol/Protocol.h b/include/xrpl/protocol/Protocol.h index 7ddf43d175..0db7b217f0 100644 --- a/include/xrpl/protocol/Protocol.h +++ b/include/xrpl/protocol/Protocol.h @@ -209,7 +209,7 @@ std::size_t constexpr maxDIDDocumentLength = 256; std::size_t constexpr maxDIDURILength = 256; /** The maximum length of an Attestation inside a DID */ -std::size_t constexpr maxDIDAttestationLength = 256; +std::size_t constexpr maxDIDDataLength = 256; /** The maximum length of a domain */ std::size_t constexpr maxDomainLength = 256; diff --git a/include/xrpl/protocol/STTx.h b/include/xrpl/protocol/STTx.h index f00f288008..f200c19eac 100644 --- a/include/xrpl/protocol/STTx.h +++ b/include/xrpl/protocol/STTx.h @@ -83,6 +83,9 @@ public: std::uint32_t getSeqValue() const; + AccountID + getFeePayer() const; + boost::container::flat_set getMentionedAccounts() const; diff --git a/include/xrpl/tx/Transactor.h b/include/xrpl/tx/Transactor.h index cd859a16f1..47c326192a 100644 --- a/include/xrpl/tx/Transactor.h +++ b/include/xrpl/tx/Transactor.h @@ -129,8 +129,7 @@ protected: beast::Journal const j_; AccountID const account_; - XRPAmount mPriorBalance; // Balance before fees. - XRPAmount mSourceBalance; // Balance after fees. + XRPAmount preFeeBalance_; // Balance before fees. virtual ~Transactor() = default; Transactor(Transactor const&) = delete; diff --git a/sanitizers/suppressions/asan.supp b/sanitizers/suppressions/asan.supp index 6f2fc6b6d1..e02d580aa6 100644 --- a/sanitizers/suppressions/asan.supp +++ b/sanitizers/suppressions/asan.supp @@ -2,15 +2,6 @@ # # ASAN_OPTIONS="print_stacktrace=1:detect_container_overflow=0:suppressions=sanitizers/suppressions/asan.supp:halt_on_error=0" -# Leaks in Doctest tests: xrpl.test.* -interceptor_name:src/libxrpl/net/HTTPClient.cpp -interceptor_name:src/libxrpl/net/RegisterSSLCerts.cpp -interceptor_name:src/tests/libxrpl/net/HTTPClient.cpp -interceptor_name:xrpl/net/AutoSocket.h -interceptor_name:xrpl/net/HTTPClient.h -interceptor_name:xrpl/net/HTTPClientSSLContext.h -interceptor_name:xrpl/net/RegisterSSLCerts.h - # Suppress false positive stack-buffer errors in thread stack allocation # Related to ASan's __asan_handle_no_return warnings (github.com/google/sanitizers/issues/189) # These occur during multi-threaded test initialization on macOS diff --git a/sanitizers/suppressions/runtime-asan-options.txt b/sanitizers/suppressions/runtime-asan-options.txt new file mode 100644 index 0000000000..fb2727f868 --- /dev/null +++ b/sanitizers/suppressions/runtime-asan-options.txt @@ -0,0 +1,8 @@ +detect_container_overflow=false +detect_stack_use_after_return=false +debug=true +halt_on_error=false +print_stats=true +print_cmdline=true +use_sigaltstack=0 +print_stacktrace=1 diff --git a/sanitizers/suppressions/runtime-lsan-options.txt b/sanitizers/suppressions/runtime-lsan-options.txt new file mode 100644 index 0000000000..fcfccf7bae --- /dev/null +++ b/sanitizers/suppressions/runtime-lsan-options.txt @@ -0,0 +1 @@ +halt_on_error=false diff --git a/sanitizers/suppressions/runtime-tsan-options.txt b/sanitizers/suppressions/runtime-tsan-options.txt new file mode 100644 index 0000000000..aafe997ea4 --- /dev/null +++ b/sanitizers/suppressions/runtime-tsan-options.txt @@ -0,0 +1,3 @@ +halt_on_error=false +verbosity=1 +second_deadlock_stack=1 diff --git a/sanitizers/suppressions/runtime-ubsan-options.txt b/sanitizers/suppressions/runtime-ubsan-options.txt new file mode 100644 index 0000000000..fcfccf7bae --- /dev/null +++ b/sanitizers/suppressions/runtime-ubsan-options.txt @@ -0,0 +1 @@ +halt_on_error=false diff --git a/sanitizers/suppressions/sanitizer-ignorelist.txt b/sanitizers/suppressions/sanitizer-ignorelist.txt index 5dbead48a2..dc9a31f8e4 100644 --- a/sanitizers/suppressions/sanitizer-ignorelist.txt +++ b/sanitizers/suppressions/sanitizer-ignorelist.txt @@ -27,3 +27,11 @@ src:core/JobQueue.cpp src:libxrpl/beast/utility/beast_Journal.cpp src:test/beast/beast_PropertyStream_test.cpp src:src/test/app/Invariants_test.cpp + +# ASan false positive: stack-use-after-scope in ErrorCodes.h inline functions. +# When Clang inlines the StaticString overloads (e.g. invalid_field_error(StaticString)), +# ASan scope-poisons the temporary std::string before the inlined callee finishes reading +# through the const ref. This corrupts the coroutine stack and crashes the Simulate test. +# See asan.supp comments for full explanation and planned fix. +[address] +src:*ErrorCodes.h diff --git a/sanitizers/suppressions/ubsan.supp b/sanitizers/suppressions/ubsan.supp index 1504ef685f..bd38e43c32 100644 --- a/sanitizers/suppressions/ubsan.supp +++ b/sanitizers/suppressions/ubsan.supp @@ -182,6 +182,17 @@ signed-integer-overflow:src/test/beast/LexicalCast_test.cpp # External library suppressions unsigned-integer-overflow:nudb/detail/xxhash.hpp +# Loan_test.cpp intentional underflow in test arithmetic +unsigned-integer-overflow:src/test/app/Loan_test.cpp +undefined:src/test/app/Loan_test.cpp + +# Source tree restructured paths (libxrpl/tx/transactors/) +# These duplicate the xrpld/app/tx/detail entries above for the new layout +unsigned-integer-overflow:src/libxrpl/tx/transactors/oracle/SetOracle.cpp +undefined:src/libxrpl/tx/transactors/oracle/SetOracle.cpp +unsigned-integer-overflow:src/libxrpl/tx/transactors/nft/NFTokenMint.cpp +undefined:src/libxrpl/tx/transactors/nft/NFTokenMint.cpp + # Protobuf intentional overflows in hash functions # Protobuf uses intentional unsigned overflow for hash computation (stringpiece.h:393) unsigned-integer-overflow:google/protobuf/stubs/stringpiece.h diff --git a/src/libxrpl/basics/Number.cpp b/src/libxrpl/basics/Number.cpp index 59a41157db..8bd048ae9e 100644 --- a/src/libxrpl/basics/Number.cpp +++ b/src/libxrpl/basics/Number.cpp @@ -258,7 +258,7 @@ Number::Guard::doRoundUp( } bringIntoRange(negative, mantissa, exponent, minMantissa); if (exponent > maxExponent) - throw std::overflow_error(location); + Throw(std::string(location)); } template @@ -298,7 +298,7 @@ Number::Guard::doRound(rep& drops, std::string location) // or "(maxRep + 1) / 10", neither of which will round up when // converting to rep, though the latter might overflow _before_ // rounding. - throw std::overflow_error(location); // LCOV_EXCL_LINE + Throw(std::string(location)); // LCOV_EXCL_LINE } ++drops; } diff --git a/src/libxrpl/protocol/STTx.cpp b/src/libxrpl/protocol/STTx.cpp index 47d841bc15..9259b2500f 100644 --- a/src/libxrpl/protocol/STTx.cpp +++ b/src/libxrpl/protocol/STTx.cpp @@ -211,6 +211,20 @@ STTx::getSeqValue() const return getSeqProxy().value(); } +AccountID +STTx::getFeePayer() const +{ + // If sfDelegate is present, the delegate account is the payer + // note: if a delegate is specified, its authorization to act on behalf of the account is + // enforced in `Transactor::checkPermission` + // cryptographic signature validity is checked separately (e.g., in `Transactor::checkSign`) + if (isFieldPresent(sfDelegate)) + return getAccountID(sfDelegate); + + // Default payer + return getAccountID(sfAccount); +} + void STTx::sign( PublicKey const& publicKey, diff --git a/src/libxrpl/tx/Transactor.cpp b/src/libxrpl/tx/Transactor.cpp index 23161e66e2..e3c0f16788 100644 --- a/src/libxrpl/tx/Transactor.cpp +++ b/src/libxrpl/tx/Transactor.cpp @@ -484,7 +484,6 @@ Transactor::payFee() auto const feePaid = ctx_.tx[sfFee].xrp(); auto const payer = getFeePayer(view(), ctx_.tx); - auto const sle = view().peek(payer.entry); JLOG(j_.trace()) << "Fee payer: " + to_string(payer.entry.key); @@ -502,13 +501,7 @@ Transactor::payFee() view().update(sle); - if (payer.type == FeePayerType::Account) - // Deduct the fee, so it's not available during the transaction. - // Will only write the account back if the transaction succeeds. - mSourceBalance -= feePaid; - // VFALCO Should we call view().rawDestroyXRP() here as well? - return tesSUCCESS; } @@ -708,8 +701,7 @@ Transactor::apply() if (sle) { - mPriorBalance = STAmount{(*sle)[sfBalance]}.xrp(); - mSourceBalance = mPriorBalance; + preFeeBalance_ = STAmount{(*sle)[sfBalance]}.xrp(); TER result = consumeSeqProxy(sle); if (result != tesSUCCESS) diff --git a/src/libxrpl/tx/transactors/Sponsor/SponsorshipSet.cpp b/src/libxrpl/tx/transactors/Sponsor/SponsorshipSet.cpp index e0d599be6b..15e8d3b1b3 100644 --- a/src/libxrpl/tx/transactors/Sponsor/SponsorshipSet.cpp +++ b/src/libxrpl/tx/transactors/Sponsor/SponsorshipSet.cpp @@ -219,7 +219,7 @@ SponsorshipSet::doApply() auto newSle = std::make_shared(sponsorKeylet); if (auto const ret = checkInsufficientReserve( - ctx_.view(), ctx_.tx, sponsorAccSle, mPriorBalance, reserveSponsorAccSle, 1); + ctx_.view(), ctx_.tx, sponsorAccSle, preFeeBalance_, reserveSponsorAccSle, 1); !isTesSuccess(ret)) return tecUNFUNDED; diff --git a/src/libxrpl/tx/transactors/account/DeleteAccount.cpp b/src/libxrpl/tx/transactors/account/DeleteAccount.cpp index afefb8eb45..9ad736a5dc 100644 --- a/src/libxrpl/tx/transactors/account/DeleteAccount.cpp +++ b/src/libxrpl/tx/transactors/account/DeleteAccount.cpp @@ -400,10 +400,10 @@ DeleteAccount::doApply() // Use the current balance from the SLE, not mSourceBalance, because // the cleanup loop may have returned pre-funded sfFeeAmount from // ltSponsorship objects back to the account's sfBalance. - auto const srcCurrentBalance = STAmount{(*src)[sfBalance]}.xrp(); - (*dst)[sfBalance] = (*dst)[sfBalance] + srcCurrentBalance; - (*src)[sfBalance] = (*src)[sfBalance] - srcCurrentBalance; - ctx_.deliver(srcCurrentBalance); + auto const remainingBalance = src->getFieldAmount(sfBalance).xrp(); + (*dst)[sfBalance] = (*dst)[sfBalance] + remainingBalance; + (*src)[sfBalance] = (*src)[sfBalance] - remainingBalance; + ctx_.deliver(remainingBalance); if (src->isFieldPresent(sfSponsor)) { @@ -445,7 +445,7 @@ DeleteAccount::doApply() } // Re-arm the password change fee if we can and need to. - if (srcCurrentBalance > XRPAmount(0) && dst->isFlag(lsfPasswordSpent)) + if (remainingBalance > XRPAmount(0) && dst->isFlag(lsfPasswordSpent)) dst->clearFlag(lsfPasswordSpent); view().update(dst); diff --git a/src/libxrpl/tx/transactors/account/SetSignerList.cpp b/src/libxrpl/tx/transactors/account/SetSignerList.cpp index d30dfc952d..c859f16f21 100644 --- a/src/libxrpl/tx/transactors/account/SetSignerList.cpp +++ b/src/libxrpl/tx/transactors/account/SetSignerList.cpp @@ -304,7 +304,7 @@ SetSignerList::replaceSignerList() // with CreateTicket. auto const sponsor = getTxReserveSponsor(ctx_.view(), ctx_.tx); if (auto const ret = checkInsufficientReserve( - ctx_.view(), ctx_.tx, sle, mPriorBalance, sponsor, addedOwnerCount); + ctx_.view(), ctx_.tx, sle, preFeeBalance_, sponsor, addedOwnerCount); !isTesSuccess(ret)) return ret; diff --git a/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp b/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp index 6b4f8866cb..170f662380 100644 --- a/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp +++ b/src/libxrpl/tx/transactors/bridge/XChainBridge.cpp @@ -337,7 +337,7 @@ enum class DepositAuthPolicy { normal, dstCanBypass }; struct TransferHelperSubmittingAccountInfo { AccountID account; - STAmount preFeeBalance; + STAmount preFeeBalance_; STAmount postFeeBalance; }; @@ -422,7 +422,7 @@ transferHelper( if (!submittingAccountInfo || submittingAccountInfo->account != src || submittingAccountInfo->postFeeBalance != curBal) return curBal; - return submittingAccountInfo->preFeeBalance; + return submittingAccountInfo->preFeeBalance_; }(); if (availableBalance < amt + reserve) @@ -1858,7 +1858,8 @@ XChainCommit::doApply() auto const amount = ctx_.tx[sfAmount]; auto const bridgeSpec = ctx_.tx[sfXChainBridge]; - if (!psb.read(keylet::account(account))) + auto const sleAccount = psb.read(keylet::account(account)); + if (!sleAccount) return tecINTERNAL; // LCOV_EXCL_LINE auto const sleBridge = readBridge(psb, bridgeSpec); @@ -1869,7 +1870,7 @@ XChainCommit::doApply() // Support dipping into reserves to pay the fee TransferHelperSubmittingAccountInfo submittingAccountInfo{ - account_, mPriorBalance, mSourceBalance}; + account_, preFeeBalance_, (*sleAccount)[sfBalance]}; auto const thTer = transferHelper( psb, @@ -2141,7 +2142,7 @@ XChainCreateAccountCommit::doApply() // Support dipping into reserves to pay the fee TransferHelperSubmittingAccountInfo submittingAccountInfo{ - account_, mPriorBalance, mSourceBalance}; + account_, preFeeBalance_, (*sle)[sfBalance]}; STAmount const toTransfer = amount + reward; auto const thTer = transferHelper( psb, diff --git a/src/libxrpl/tx/transactors/check/CashCheck.cpp b/src/libxrpl/tx/transactors/check/CashCheck.cpp index f32d2813e3..46628addbc 100644 --- a/src/libxrpl/tx/transactors/check/CashCheck.cpp +++ b/src/libxrpl/tx/transactors/check/CashCheck.cpp @@ -316,7 +316,7 @@ CashCheck::doApply() // Can the account cover the trust line's reserve? if (auto const ret = checkInsufficientReserve( - psb, ctx_.tx, sleDst, mPriorBalance, sponsorSle, 1); + psb, ctx_.tx, sleDst, preFeeBalance_, sponsorSle, 1); !isTesSuccess(ret)) { JLOG(j_.trace()) << "Trust line does not exist. " diff --git a/src/libxrpl/tx/transactors/check/CreateCheck.cpp b/src/libxrpl/tx/transactors/check/CreateCheck.cpp index 71743625fc..b52fcbf959 100644 --- a/src/libxrpl/tx/transactors/check/CreateCheck.cpp +++ b/src/libxrpl/tx/transactors/check/CreateCheck.cpp @@ -138,7 +138,7 @@ CreateCheck::doApply() // check the starting balance because we want to allow dipping into the // reserve to pay fees. auto const sponsor = getTxReserveSponsor(view(), ctx_.tx); - if (auto const ret = checkInsufficientReserve(view(), ctx_.tx, sle, mPriorBalance, sponsor, 1); + if (auto const ret = checkInsufficientReserve(view(), ctx_.tx, sle, preFeeBalance_, sponsor, 1); !isTesSuccess(ret)) return ret; // Note that we use the value from the sequence or ticket as the diff --git a/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp b/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp index 219990edb6..8b86e34e14 100644 --- a/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp +++ b/src/libxrpl/tx/transactors/credentials/CredentialAccept.cpp @@ -84,7 +84,7 @@ CredentialAccept::doApply() auto const newSponsor = getTxReserveSponsor(view(), ctx_.tx); if (auto const ret = - checkInsufficientReserve(view(), ctx_.tx, sleSubject, mPriorBalance, newSponsor, 1); + checkInsufficientReserve(view(), ctx_.tx, sleSubject, preFeeBalance_, newSponsor, 1); !isTesSuccess(ret)) return ret; diff --git a/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp b/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp index 6cc60f7d98..b80c74cb3b 100644 --- a/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp +++ b/src/libxrpl/tx/transactors/credentials/CredentialCreate.cpp @@ -116,7 +116,7 @@ CredentialCreate::doApply() auto const sponsor = getTxReserveSponsor(view(), ctx_.tx); if (auto const ret = - checkInsufficientReserve(view(), ctx_.tx, sleIssuer, mPriorBalance, sponsor, 1); + checkInsufficientReserve(view(), ctx_.tx, sleIssuer, preFeeBalance_, sponsor, 1); !isTesSuccess(ret)) return ret; diff --git a/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp b/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp index 8128e27974..759392ccb0 100644 --- a/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp +++ b/src/libxrpl/tx/transactors/delegate/DelegateSet.cpp @@ -69,7 +69,7 @@ DelegateSet::doApply() auto const sponsor = getTxReserveSponsor(view(), ctx_.tx); if (auto const ret = - checkInsufficientReserve(view(), ctx_.tx, sleOwner, mPriorBalance, sponsor, 1); + checkInsufficientReserve(view(), ctx_.tx, sleOwner, preFeeBalance_, sponsor, 1); !isTesSuccess(ret)) return ret; diff --git a/src/libxrpl/tx/transactors/dex/AMMClawback.cpp b/src/libxrpl/tx/transactors/dex/AMMClawback.cpp index eae9208298..10cc999927 100644 --- a/src/libxrpl/tx/transactors/dex/AMMClawback.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMClawback.cpp @@ -173,7 +173,7 @@ AMMClawback::applyGuts(Sandbox& sb) 0, FreezeHandling::fhIGNORE_FREEZE, WithdrawAll::Yes, - mPriorBalance, + preFeeBalance_, ctx_.journal); else std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) = @@ -253,7 +253,7 @@ AMMClawback::equalWithdrawMatchingOneAmount( 0, FreezeHandling::fhIGNORE_FREEZE, WithdrawAll::Yes, - mPriorBalance, + preFeeBalance_, ctx_.journal); auto const& rules = sb.rules(); @@ -285,7 +285,7 @@ AMMClawback::equalWithdrawMatchingOneAmount( 0, FreezeHandling::fhIGNORE_FREEZE, WithdrawAll::No, - mPriorBalance, + preFeeBalance_, ctx_.journal); } @@ -305,7 +305,7 @@ AMMClawback::equalWithdrawMatchingOneAmount( 0, FreezeHandling::fhIGNORE_FREEZE, WithdrawAll::No, - mPriorBalance, + preFeeBalance_, ctx_.journal); } diff --git a/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp b/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp index d6759f01c1..dc9383549a 100644 --- a/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp +++ b/src/libxrpl/tx/transactors/dex/AMMWithdraw.cpp @@ -427,7 +427,7 @@ AMMWithdraw::withdraw( tfee, FreezeHandling::fhZERO_IF_FROZEN, isWithdrawAll(ctx_.tx), - mPriorBalance, + preFeeBalance_, j_); return {ter, newLPTokenBalance}; } @@ -660,7 +660,7 @@ AMMWithdraw::equalWithdrawTokens( tfee, FreezeHandling::fhZERO_IF_FROZEN, isWithdrawAll(ctx_.tx), - mPriorBalance, + preFeeBalance_, ctx_.journal); return {ter, newLPTokenBalance}; } diff --git a/src/libxrpl/tx/transactors/dex/CreateOffer.cpp b/src/libxrpl/tx/transactors/dex/CreateOffer.cpp index e28adafc4b..b589213c6f 100644 --- a/src/libxrpl/tx/transactors/dex/CreateOffer.cpp +++ b/src/libxrpl/tx/transactors/dex/CreateOffer.cpp @@ -727,7 +727,7 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) { auto const sponsor = getTxReserveSponsor(sb, ctx_.tx); if (auto const ret = - checkInsufficientReserve(sb, ctx_.tx, sleCreator, mPriorBalance, sponsor, 1); + checkInsufficientReserve(sb, ctx_.tx, sleCreator, preFeeBalance_, sponsor, 1); !isTesSuccess(ret)) { // If we are here, the signing account had an insufficient reserve diff --git a/src/libxrpl/tx/transactors/did/DIDDelete.cpp b/src/libxrpl/tx/transactors/did/DIDDelete.cpp index 76d22acb0f..6aa419b10a 100644 --- a/src/libxrpl/tx/transactors/did/DIDDelete.cpp +++ b/src/libxrpl/tx/transactors/did/DIDDelete.cpp @@ -33,7 +33,7 @@ DIDDelete::deleteSLE( if (!view.dirRemove(keylet::ownerDir(owner), (*sle)[sfOwnerNode], sle->key(), true)) { // LCOV_EXCL_START - JLOG(j.fatal()) << "Unable to delete DID Token from owner."; + JLOG(j.fatal()) << "Unable to delete DID from owner."; return tefBAD_LEDGER; // LCOV_EXCL_STOP } diff --git a/src/libxrpl/tx/transactors/did/DIDSet.cpp b/src/libxrpl/tx/transactors/did/DIDSet.cpp index 534995b3c2..4a650cd80b 100644 --- a/src/libxrpl/tx/transactors/did/DIDSet.cpp +++ b/src/libxrpl/tx/transactors/did/DIDSet.cpp @@ -41,13 +41,13 @@ DIDSet::preflight(PreflightContext const& ctx) }; if (isTooLong(sfURI, maxDIDURILength) || isTooLong(sfDIDDocument, maxDIDDocumentLength) || - isTooLong(sfData, maxDIDAttestationLength)) + isTooLong(sfData, maxDIDDataLength)) return temMALFORMED; return tesSUCCESS; } -TER +static TER addSLE(ApplyContext& ctx, std::shared_ptr const& sle, AccountID const& owner) { auto const sleAccount = ctx.view().peek(keylet::account(owner)); diff --git a/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp b/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp index 2f1cb6bf78..cba17c361f 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp @@ -165,7 +165,7 @@ EscrowCancel::doApply() ctx_.tx, parityRate, slep, - mPriorBalance, + preFeeBalance_, amount, issuer, account, // sender and receiver are the same diff --git a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp index 0edb548a0e..45efd5e593 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp @@ -392,9 +392,9 @@ EscrowCreate::doApply() // Check reserve and funds availability STAmount const amount{ctx_.tx[sfAmount]}; + auto const balance = sle->getFieldAmount(sfBalance).xrp(); auto const sponsor = getTxReserveSponsor(view(), ctx_.tx); - if (auto const ret = - checkInsufficientReserve(ctx_.view(), ctx_.tx, sle, mSourceBalance, sponsor, 1); + if (auto const ret = checkInsufficientReserve(ctx_.view(), ctx_.tx, sle, balance, sponsor, 1); !isTesSuccess(ret)) return ret; @@ -402,7 +402,7 @@ EscrowCreate::doApply() if (isXRP(amount)) { if (auto const ret = checkInsufficientReserve( - ctx_.view(), ctx_.tx, sle, mSourceBalance - STAmount(amount).xrp(), {}, 1); + ctx_.view(), ctx_.tx, sle, balance - STAmount(amount).xrp(), {}, 1); !isTesSuccess(ret)) return tecUNFUNDED; } diff --git a/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp b/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp index c9ed5a2f56..0adbc212cc 100644 --- a/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp +++ b/src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp @@ -333,7 +333,7 @@ EscrowFinish::doApply() ctx_.tx, lockedRate, sled, - mPriorBalance, + preFeeBalance_, amount, issuer, account, diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp index 9140a0dc23..57d9cbc173 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.cpp @@ -167,7 +167,7 @@ LoanBrokerCoverWithdraw::doApply() associateAsset(*broker, vaultAsset); - return doWithdraw(view(), tx, account_, dstAcct, brokerPseudoID, mPriorBalance, amount, j_); + return doWithdraw(view(), tx, account_, dstAcct, brokerPseudoID, preFeeBalance_, amount, j_); } //------------------------------------------------------------------------------ diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp index 82694f38d6..0fdb8fc177 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp @@ -219,14 +219,14 @@ LoanBrokerSet::doApply() auto const sponsor = getTxReserveSponsor(view, tx); if (auto const ret = - checkInsufficientReserve(view, tx, owner, mPriorBalance, {}, sponsor ? 1 : 2); + checkInsufficientReserve(view, tx, owner, preFeeBalance_, {}, sponsor ? 1 : 2); !isTesSuccess(ret)) return ret; if (sponsor) { if (auto const ret = - checkInsufficientReserve(view, tx, owner, mPriorBalance, sponsor, 1); + checkInsufficientReserve(view, tx, owner, preFeeBalance_, sponsor, 1); !isTesSuccess(ret)) return ret; } @@ -245,7 +245,7 @@ LoanBrokerSet::doApply() auto pseudoId = pseudo->at(sfAccount); if (auto ter = - addEmptyHolding(view, tx, pseudoId, mPriorBalance, sleVault->at(sfAsset), j_)) + addEmptyHolding(view, tx, pseudoId, preFeeBalance_, sleVault->at(sfAsset), j_)) return ter; // Initialize data fields: diff --git a/src/libxrpl/tx/transactors/lending/LoanSet.cpp b/src/libxrpl/tx/transactors/lending/LoanSet.cpp index 56b2000c97..137ebe999d 100644 --- a/src/libxrpl/tx/transactors/lending/LoanSet.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanSet.cpp @@ -84,12 +84,11 @@ LoanSet::preflight(PreflightContext const& ctx) !validNumericMinimum(paymentInterval, LoanSet::minPaymentInterval)) return temINVALID; // Grace period is between min default value and payment interval - else if ( - auto const gracePeriod = tx[~sfGracePeriod]; // - !validNumericRange( - gracePeriod, - paymentInterval.value_or(LoanSet::defaultPaymentInterval), - defaultGracePeriod)) + else if (auto const gracePeriod = tx[~sfGracePeriod]; // + !validNumericRange( + gracePeriod, + paymentInterval.value_or(LoanSet::defaultPaymentInterval), + defaultGracePeriod)) return temINVALID; // Copied from preflight2 @@ -473,7 +472,7 @@ LoanSet::doApply() auto const sponsorSle = getTxReserveSponsor(view, tx); { auto const balance = - account_ == borrower ? mPriorBalance : borrowerSle->at(sfBalance).value().xrp(); + account_ == borrower ? preFeeBalance_ : borrowerSle->at(sfBalance).value().xrp(); if (auto const ret = checkInsufficientReserve(view, tx, borrowerSle, balance, sponsorSle, 1); !isTesSuccess(ret)) diff --git a/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp b/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp index 15317e1a9f..cd62c3daab 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp @@ -363,7 +363,7 @@ NFTokenAcceptOffer::transferNFToken( // NFTs free of reserve. if (view().rules().enabled(fixNFTokenReserve)) { - // To check if there is sufficient reserve, we cannot use mPriorBalance + // To check if there is sufficient reserve, we cannot use preFeeBalance_ // because NFT is sold for a price. So we must use the balance after // the deduction of the potential offer price. A small caveat here is // that the balance has already deducted the transaction fee, meaning diff --git a/src/libxrpl/tx/transactors/nft/NFTokenCreateOffer.cpp b/src/libxrpl/tx/transactors/nft/NFTokenCreateOffer.cpp index d5f9dc9b10..049fa3f170 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenCreateOffer.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenCreateOffer.cpp @@ -75,7 +75,7 @@ NFTokenCreateOffer::doApply() ctx_.tx[~sfExpiration], ctx_.tx.getSeqProxy(), ctx_.tx[sfNFTokenID], - mPriorBalance, + preFeeBalance_, j_, ctx_.tx.getFlags()); } diff --git a/src/libxrpl/tx/transactors/nft/NFTokenMint.cpp b/src/libxrpl/tx/transactors/nft/NFTokenMint.cpp index 8af1054f97..cde661d751 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenMint.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenMint.cpp @@ -296,7 +296,7 @@ NFTokenMint::doApply() ctx_.tx[~sfExpiration], ctx_.tx.getSeqProxy(), nftokenID, - mPriorBalance, + preFeeBalance_, j_); !isTesSuccess(ter)) return ter; @@ -315,7 +315,7 @@ NFTokenMint::doApply() ctx_.view(), ctx_.tx, view().read(keylet::account(account_)), - mPriorBalance, + preFeeBalance_, sponsor, 0); !isTesSuccess(ret)) diff --git a/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp b/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp index 295e5b278f..f10c37eff9 100644 --- a/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp +++ b/src/libxrpl/tx/transactors/payment/DepositPreauth.cpp @@ -145,7 +145,7 @@ DepositPreauth::doApply() // reserve to pay fees. auto const sponsor = getTxReserveSponsor(view(), ctx_.tx); if (auto const ret = - checkInsufficientReserve(view(), ctx_.tx, sleOwner, mPriorBalance, sponsor, 1); + checkInsufficientReserve(view(), ctx_.tx, sleOwner, preFeeBalance_, sponsor, 1); !isTesSuccess(ret)) return ret; @@ -191,7 +191,7 @@ DepositPreauth::doApply() // reserve to pay fees. auto const sponsor = getTxReserveSponsor(view(), ctx_.tx); if (auto const ret = - checkInsufficientReserve(view(), ctx_.tx, sleOwner, mPriorBalance, sponsor, 1); + checkInsufficientReserve(view(), ctx_.tx, sleOwner, preFeeBalance_, sponsor, 1); !isTesSuccess(ret)) return ret; diff --git a/src/libxrpl/tx/transactors/payment/Payment.cpp b/src/libxrpl/tx/transactors/payment/Payment.cpp index 7d6096dcd2..75a4c531f4 100644 --- a/src/libxrpl/tx/transactors/payment/Payment.cpp +++ b/src/libxrpl/tx/transactors/payment/Payment.cpp @@ -582,16 +582,16 @@ Payment::doApply() auto const reserve = calculateReserve(sleSrc, view().fees()) + ((txFlags & tfSponsorCreatedAccount) ? view().fees().reserve : beast::zero); - // mPriorBalance is the balance on the sending account BEFORE the + // preFeeBalance_ is the balance on the sending account BEFORE the // fees were charged. We want to make sure we have enough reserve // to send. Allow final spend to use reserve for fee. auto const mmm = std::max(reserve, ctx_.tx.getFieldAmount(sfFee).xrp()); - if (mPriorBalance < dstAmount.xrp() + mmm) + if (preFeeBalance_ < dstAmount.xrp() + mmm) { // Vote no. However the transaction might succeed, if applied in // a different order. - JLOG(j_.trace()) << "Delay transaction: Insufficient funds: " << to_string(mPriorBalance) + JLOG(j_.trace()) << "Delay transaction: Insufficient funds: " << to_string(preFeeBalance_) << " / " << to_string(dstAmount.xrp() + mmm) << " (" << to_string(reserve) << ")"; @@ -639,7 +639,7 @@ Payment::doApply() } // Do the arithmetic for the transfer and make the ledger change. - sleSrc->setFieldAmount(sfBalance, mSourceBalance - dstAmount); + sleSrc->setFieldAmount(sfBalance, sleSrc->getFieldAmount(sfBalance) - dstAmount); sleDst->setFieldAmount(sfBalance, sleDst->getFieldAmount(sfBalance) + dstAmount); // Re-arm the password change fee if we can and need to. diff --git a/src/libxrpl/tx/transactors/system/CreateTicket.cpp b/src/libxrpl/tx/transactors/system/CreateTicket.cpp index 4d6e74197b..ce2905a513 100644 --- a/src/libxrpl/tx/transactors/system/CreateTicket.cpp +++ b/src/libxrpl/tx/transactors/system/CreateTicket.cpp @@ -63,7 +63,7 @@ CreateTicket::doApply() std::uint32_t const ticketCount = ctx_.tx[sfTicketCount]; auto const sponsor = getTxReserveSponsor(view(), ctx_.tx); if (auto const ret = checkInsufficientReserve( - view(), ctx_.tx, sleAccountRoot, mPriorBalance, sponsor, ticketCount); + view(), ctx_.tx, sleAccountRoot, preFeeBalance_, sponsor, ticketCount); !isTesSuccess(ret)) return ret; diff --git a/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp b/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp index bb019dd2e2..3368685046 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenAuthorize.cpp @@ -162,7 +162,7 @@ MPTokenAuthorize::doApply() return authorizeMPToken( ctx_.view(), tx, - mPriorBalance, + preFeeBalance_, tx[sfMPTokenIssuanceID], account_, ctx_.journal, diff --git a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp index 39f04edf55..6909d5e79d 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp @@ -151,7 +151,7 @@ MPTokenIssuanceCreate::doApply() tx, j_, { - .priorBalance = mPriorBalance, + .priorBalance = preFeeBalance_, .account = account_, .sequence = tx.getSeqValue(), .flags = tx.getFlags(), diff --git a/src/libxrpl/tx/transactors/token/SetTrust.cpp b/src/libxrpl/tx/transactors/token/SetTrust.cpp index bedfb8398b..8e5330861f 100644 --- a/src/libxrpl/tx/transactors/token/SetTrust.cpp +++ b/src/libxrpl/tx/transactors/token/SetTrust.cpp @@ -542,7 +542,7 @@ SetTrust::doApply() { // should be checked PreFunded Sponsor before adjustOwnerCount() if (auto const ret = checkInsufficientReserve( - view(), ctx_.tx, sleLowAccount, mPriorBalance, txSponsorSle, 1); + view(), ctx_.tx, sleLowAccount, preFeeBalance_, txSponsorSle, 1); isSponsoredAndPreFunded && !isTesSuccess(ret)) return tecINSUF_RESERVE_LINE; @@ -569,7 +569,7 @@ SetTrust::doApply() { // should be checked PreFunded Sponsor before adjustOwnerCount() if (auto const ret = checkInsufficientReserve( - view(), ctx_.tx, sleHighAccount, mPriorBalance, txSponsorSle, 1); + view(), ctx_.tx, sleHighAccount, preFeeBalance_, txSponsorSle, 1); isSponsoredAndPreFunded && !isTesSuccess(ret)) return tecINSUF_RESERVE_LINE; @@ -602,8 +602,8 @@ SetTrust::doApply() terResult = trustDelete(view(), sleRippleState, uLowAccountID, uHighAccountID, viewJ); } // Reserve is not scaled by load. - else if (auto const ret = - checkInsufficientReserve(view(), ctx_.tx, sle, mPriorBalance, txSponsorSle, 0); + else if (auto const ret = checkInsufficientReserve( + view(), ctx_.tx, sle, preFeeBalance_, txSponsorSle, 0); !freeTrustLine && bReserveIncrease && !isTesSuccess(ret)) { JLOG(j_.trace()) << "Delay transaction: Insufficent reserve to " @@ -636,7 +636,7 @@ SetTrust::doApply() ctx_.view(), ctx_.tx, sle, - mPriorBalance, + preFeeBalance_, txSponsorSle, 1); !freeTrustLine && !isTesSuccess(ret)) // Reserve is not scaled by load. diff --git a/src/libxrpl/tx/transactors/vault/VaultCreate.cpp b/src/libxrpl/tx/transactors/vault/VaultCreate.cpp index 7c33946e49..5d95d215a0 100644 --- a/src/libxrpl/tx/transactors/vault/VaultCreate.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultCreate.cpp @@ -140,14 +140,16 @@ VaultCreate::doApply() { adjustOwnerCount(view(), owner, sponsor, 2, j_); addSponsorToLedgerEntry(vault, sponsor); - if (auto const ret = checkInsufficientReserve(view(), tx, owner, mPriorBalance, sponsor, 0); + if (auto const ret = + checkInsufficientReserve(view(), tx, owner, preFeeBalance_, sponsor, 0); !isTesSuccess(ret)) return ret; } else { // after Sponsor Amendment, check insufficient reserve first - if (auto const ret = checkInsufficientReserve(view(), tx, owner, mPriorBalance, sponsor, 2); + if (auto const ret = + checkInsufficientReserve(view(), tx, owner, preFeeBalance_, sponsor, 2); !isTesSuccess(ret)) return ret; adjustOwnerCount(view(), owner, sponsor, 2, j_); @@ -161,7 +163,7 @@ VaultCreate::doApply() auto pseudoId = pseudo->at(sfAccount); auto asset = tx[sfAsset]; - if (auto ter = addEmptyHolding(view(), tx, pseudoId, mPriorBalance, asset, j_); + if (auto ter = addEmptyHolding(view(), tx, pseudoId, preFeeBalance_, asset, j_); !isTesSuccess(ter)) return ter; @@ -222,7 +224,7 @@ VaultCreate::doApply() // Explicitly create MPToken for the vault owner if (auto const err = - authorizeMPToken(view(), tx, mPriorBalance, mptIssuanceID, account_, ctx_.journal); + authorizeMPToken(view(), tx, preFeeBalance_, mptIssuanceID, account_, ctx_.journal); !isTesSuccess(err)) return err; @@ -230,7 +232,7 @@ VaultCreate::doApply() if (txFlags & tfVaultPrivate) { if (auto const err = authorizeMPToken( - view(), tx, mPriorBalance, mptIssuanceID, pseudoId, ctx_.journal, {}, account_); + view(), tx, preFeeBalance_, mptIssuanceID, pseudoId, ctx_.journal, {}, account_); !isTesSuccess(err)) return err; } diff --git a/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp b/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp index 6b5f0f5a98..e6815202a0 100644 --- a/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp @@ -146,7 +146,7 @@ VaultDeposit::doApply() if (vault->isFlag(lsfVaultPrivate) && account_ != vault->at(sfOwner)) { if (auto const err = enforceMPTokenAuthorization( - ctx_.view(), ctx_.tx, mptIssuanceID, account_, mPriorBalance, j_); + ctx_.view(), ctx_.tx, mptIssuanceID, account_, preFeeBalance_, j_); !isTesSuccess(err)) return err; } @@ -156,7 +156,12 @@ VaultDeposit::doApply() if (!view().exists(keylet::mptoken(mptIssuanceID, account_))) { if (auto const err = authorizeMPToken( - view(), ctx_.tx, mPriorBalance, mptIssuanceID->value(), account_, ctx_.journal); + view(), + ctx_.tx, + preFeeBalance_, + mptIssuanceID->value(), + account_, + ctx_.journal); !isTesSuccess(err)) return err; } @@ -170,7 +175,7 @@ VaultDeposit::doApply() if (auto const err = authorizeMPToken( view(), ctx_.tx, - mPriorBalance, // priorBalance + preFeeBalance_, // priorBalance mptIssuanceID->value(), // mptIssuanceID sleIssuance->at(sfIssuer), // account ctx_.journal, diff --git a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp index 7540ea9ccc..65ef2ecfdb 100644 --- a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp @@ -233,7 +233,7 @@ VaultWithdraw::doApply() associateAsset(*vault, vaultAsset); return doWithdraw( - view(), ctx_.tx, account_, dstAcct, vaultAccount, mPriorBalance, assetsWithdrawn, j_); + view(), ctx_.tx, account_, dstAcct, vaultAccount, preFeeBalance_, assetsWithdrawn, j_); } } // namespace xrpl diff --git a/src/test/app/DID_test.cpp b/src/test/app/DID_test.cpp index f83571deab..20c367d64f 100644 --- a/src/test/app/DID_test.cpp +++ b/src/test/app/DID_test.cpp @@ -189,7 +189,7 @@ struct DID_test : public beast::unit_test::suite Account const edna{"edna"}; Account const francis{"francis"}; Account const george{"george"}; - env.fund(XRP(5000), alice, bob, charlie, dave, edna, francis); + env.fund(XRP(5000), alice, bob, charlie, dave, edna, francis, george); env.close(); BEAST_EXPECT(ownerCount(env, alice) == 0); BEAST_EXPECT(ownerCount(env, bob) == 0); @@ -355,12 +355,14 @@ struct DID_test : public beast::unit_test::suite testAccountReserve(all); testSetInvalid(all); testDeleteInvalid(all); + testSetValidInitial(all); testSetModify(all); testEnabled(all - emptyDID); testAccountReserve(all - emptyDID); testSetInvalid(all - emptyDID); testDeleteInvalid(all - emptyDID); + testSetValidInitial(all - emptyDID); testSetModify(all - emptyDID); } }; diff --git a/src/test/jtx/did.h b/src/test/jtx/did.h index 9cd98a1324..e6b06f8f7c 100644 --- a/src/test/jtx/did.h +++ b/src/test/jtx/did.h @@ -53,7 +53,7 @@ public: } }; -/** Sets the optional Attestation on a DIDSet. */ +/** Sets the optional Data on a DIDSet. */ class data { private: