diff --git a/include/xrpl/basics/Number.h b/include/xrpl/basics/Number.h index 01b3adb22d4..70baf5d1e47 100644 --- a/include/xrpl/basics/Number.h +++ b/include/xrpl/basics/Number.h @@ -41,6 +41,14 @@ class Number int exponent_{std::numeric_limits<int>::lowest()}; public: + // The range for the mantissa when normalized + constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL; + constexpr static std::int64_t maxMantissa = 9'999'999'999'999'999LL; + + // The range for the exponent when normalized + constexpr static int minExponent = -32768; + constexpr static int maxExponent = 32768; + struct unchecked { explicit unchecked() = default; @@ -191,14 +199,6 @@ class Number constexpr bool isnormal() const noexcept; - // The range for the mantissa when normalized - constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL; - constexpr static std::int64_t maxMantissa = 9'999'999'999'999'999LL; - - // The range for the exponent when normalized - constexpr static int minExponent = -32768; - constexpr static int maxExponent = 32768; - class Guard; }; diff --git a/include/xrpl/protocol/SField.h b/include/xrpl/protocol/SField.h index 942f2a8654b..01909b19862 100644 --- a/include/xrpl/protocol/SField.h +++ b/include/xrpl/protocol/SField.h @@ -49,6 +49,7 @@ template <int> class STBitString; template <class> class STInteger; +class STNumber; class STXChainBridge; class STVector256; class STCurrency; @@ -70,8 +71,9 @@ class STCurrency; STYPE(STI_AMOUNT, 6) \ STYPE(STI_VL, 7) \ STYPE(STI_ACCOUNT, 8) \ + STYPE(STI_NUMBER, 9) \ \ - /* 9-13 are reserved */ \ + /* 10-13 are reserved */ \ STYPE(STI_OBJECT, 14) \ STYPE(STI_ARRAY, 15) \ \ @@ -355,6 +357,7 @@ using SF_ACCOUNT = TypedField<STAccount>; using SF_AMOUNT = TypedField<STAmount>; using SF_ISSUE = TypedField<STIssue>; using SF_CURRENCY = TypedField<STCurrency>; +using SF_NUMBER = TypedField<STNumber>; using SF_VL = TypedField<STBlob>; using SF_VECTOR256 = TypedField<STVector256>; using SF_XCHAIN_BRIDGE = TypedField<STXChainBridge>; diff --git a/include/xrpl/protocol/STNumber.h b/include/xrpl/protocol/STNumber.h new file mode 100644 index 00000000000..c0fce572c8c --- /dev/null +++ b/include/xrpl/protocol/STNumber.h @@ -0,0 +1,88 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef XRPL_PROTOCOL_STNUMBER_H_INCLUDED +#define XRPL_PROTOCOL_STNUMBER_H_INCLUDED + +#include <xrpl/basics/CountedObject.h> +#include <xrpl/basics/Number.h> +#include <xrpl/protocol/STBase.h> + +#include <ostream> + +namespace ripple { + +/** + * A serializable number. + * + * This type is-a `Number`, and can be used everywhere that is accepted. + * This type simply integrates `Number` with the serialization framework, + * letting it be used for fields in ledger entries and transactions. + * It is effectively an `STAmount` sans `Asset`: + * it can represent a value of any token type (XRP, IOU, or MPT) + * without paying the storage cost of duplicating asset information + * that may be deduced from the context. + */ +class STNumber : public STBase, public CountedObject<STNumber> +{ +private: + Number value_; + +public: + using value_type = Number; + + STNumber() = default; + explicit STNumber(SField const& field, Number const& value = Number()); + STNumber(SerialIter& sit, SField const& field); + + SerializedTypeID + getSType() const override; + std::string + getText() const override; + void + add(Serializer& s) const override; + + Number const& + value() const; + void + setValue(Number const& v); + + bool + isEquivalent(STBase const& t) const override; + bool + isDefault() const override; + + operator Number() const + { + return value_; + } + +private: + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; +}; + +std::ostream& +operator<<(std::ostream& out, STNumber const& rhs); + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index c06f109dc56..748a2b5d685 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -245,6 +245,8 @@ class STObject : public STBase, public CountedObject<STObject> getFieldArray(SField const& field) const; const STCurrency& getFieldCurrency(SField const& field) const; + STNumber const& + getFieldNumber(SField const& field) const; /** Get the value of a field. @param A TypedField built from an SField value representing the desired @@ -376,6 +378,8 @@ class STObject : public STBase, public CountedObject<STObject> void setFieldCurrency(SField const& field, STCurrency const&); void + setFieldNumber(SField const& field, STNumber const&); + void setFieldPathSet(SField const& field, STPathSet const&); void setFieldV256(SField const& field, STVector256 const& v); diff --git a/include/xrpl/protocol/Serializer.h b/include/xrpl/protocol/Serializer.h index d8d0b9222e3..0e96078ed14 100644 --- a/include/xrpl/protocol/Serializer.h +++ b/include/xrpl/protocol/Serializer.h @@ -83,12 +83,43 @@ class Serializer add8(unsigned char i); int add16(std::uint16_t i); + + template <typename T> + requires(std::is_same_v< + std::make_unsigned_t<std::remove_cv_t<T>>, + std::uint32_t>) int - add32(std::uint32_t i); // ledger indexes, account sequence, timestamps + add32(T i) + { + int ret = mData.size(); + mData.push_back(static_cast<unsigned char>((i >> 24) & 0xff)); + mData.push_back(static_cast<unsigned char>((i >> 16) & 0xff)); + mData.push_back(static_cast<unsigned char>((i >> 8) & 0xff)); + mData.push_back(static_cast<unsigned char>(i & 0xff)); + return ret; + } + int add32(HashPrefix p); + + template <typename T> + requires(std::is_same_v< + std::make_unsigned_t<std::remove_cv_t<T>>, + std::uint64_t>) int - add64(std::uint64_t i); // native currency amounts + add64(T i) + { + int ret = mData.size(); + mData.push_back(static_cast<unsigned char>((i >> 56) & 0xff)); + mData.push_back(static_cast<unsigned char>((i >> 48) & 0xff)); + mData.push_back(static_cast<unsigned char>((i >> 40) & 0xff)); + mData.push_back(static_cast<unsigned char>((i >> 32) & 0xff)); + mData.push_back(static_cast<unsigned char>((i >> 24) & 0xff)); + mData.push_back(static_cast<unsigned char>((i >> 16) & 0xff)); + mData.push_back(static_cast<unsigned char>((i >> 8) & 0xff)); + mData.push_back(static_cast<unsigned char>(i & 0xff)); + return ret; + } template <typename Integer> int addInteger(Integer); @@ -353,9 +384,13 @@ class SerialIter std::uint32_t get32(); + std::int32_t + geti32(); std::uint64_t get64(); + std::int64_t + geti64(); template <std::size_t Bits, class Tag = void> base_uint<Bits, Tag> diff --git a/include/xrpl/protocol/detail/sfields.macro b/include/xrpl/protocol/detail/sfields.macro index ccf6350cbfc..8384025ee3b 100644 --- a/include/xrpl/protocol/detail/sfields.macro +++ b/include/xrpl/protocol/detail/sfields.macro @@ -191,6 +191,9 @@ TYPED_SFIELD(sfHookHash, UINT256, 31) TYPED_SFIELD(sfHookNamespace, UINT256, 32) TYPED_SFIELD(sfHookSetTxnID, UINT256, 33) +// number (common) +TYPED_SFIELD(sfNumber, NUMBER, 1) + // currency amount (common) TYPED_SFIELD(sfAmount, AMOUNT, 1) TYPED_SFIELD(sfBalance, AMOUNT, 2) diff --git a/include/xrpl/protocol/st.h b/include/xrpl/protocol/st.h index 7b0e3a3b2df..0035deaa1bc 100644 --- a/include/xrpl/protocol/st.h +++ b/include/xrpl/protocol/st.h @@ -29,6 +29,7 @@ #include <xrpl/protocol/STBlob.h> #include <xrpl/protocol/STInteger.h> #include <xrpl/protocol/STLedgerEntry.h> +#include <xrpl/protocol/STNumber.h> #include <xrpl/protocol/STObject.h> #include <xrpl/protocol/STParsedJSON.h> #include <xrpl/protocol/STPathSet.h> diff --git a/src/libxrpl/protocol/STNumber.cpp b/src/libxrpl/protocol/STNumber.cpp new file mode 100644 index 00000000000..3a92bbb02f9 --- /dev/null +++ b/src/libxrpl/protocol/STNumber.cpp @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include <xrpl/protocol/STNumber.h> + +#include <xrpl/protocol/SField.h> + +namespace ripple { + +STNumber::STNumber(SField const& field, Number const& value) + : STBase(field), value_(value) +{ +} + +STNumber::STNumber(SerialIter& sit, SField const& field) : STBase(field) +{ + // We must call these methods in separate statements + // to guarantee their order of execution. + auto mantissa = sit.geti64(); + auto exponent = sit.geti32(); + value_ = Number{mantissa, exponent}; +} + +SerializedTypeID +STNumber::getSType() const +{ + return STI_NUMBER; +} + +std::string +STNumber::getText() const +{ + return to_string(value_); +} + +void +STNumber::add(Serializer& s) const +{ + assert(getFName().isBinary()); + assert(getFName().fieldType == getSType()); + s.add64(value_.mantissa()); + s.add32(value_.exponent()); +} + +Number const& +STNumber::value() const +{ + return value_; +} + +void +STNumber::setValue(Number const& v) +{ + value_ = v; +} + +STBase* +STNumber::copy(std::size_t n, void* buf) const +{ + return emplace(n, buf, *this); +} + +STBase* +STNumber::move(std::size_t n, void* buf) +{ + return emplace(n, buf, std::move(*this)); +} + +bool +STNumber::isEquivalent(STBase const& t) const +{ + assert(t.getSType() == this->getSType()); + STNumber const& v = dynamic_cast<STNumber const&>(t); + return value_ == v; +} + +bool +STNumber::isDefault() const +{ + return value_ == Number(); +} + +std::ostream& +operator<<(std::ostream& out, STNumber const& rhs) +{ + return out << rhs.getText(); +} + +} // namespace ripple diff --git a/src/libxrpl/protocol/STObject.cpp b/src/libxrpl/protocol/STObject.cpp index 7e62fc25bd6..c8fc88348e9 100644 --- a/src/libxrpl/protocol/STObject.cpp +++ b/src/libxrpl/protocol/STObject.cpp @@ -25,6 +25,7 @@ #include <xrpl/protocol/STArray.h> #include <xrpl/protocol/STBlob.h> #include <xrpl/protocol/STCurrency.h> +#include <xrpl/protocol/STNumber.h> #include <xrpl/protocol/STObject.h> namespace ripple { @@ -665,6 +666,13 @@ STObject::getFieldCurrency(SField const& field) const return getFieldByConstRef<STCurrency>(field, empty); } +STNumber const& +STObject::getFieldNumber(SField const& field) const +{ + static STNumber const empty{}; + return getFieldByConstRef<STNumber>(field, empty); +} + void STObject::set(std::unique_ptr<STBase> v) { @@ -765,6 +773,12 @@ STObject::setFieldIssue(SField const& field, STIssue const& v) setFieldUsingAssignment(field, v); } +void +STObject::setFieldNumber(SField const& field, STNumber const& v) +{ + setFieldUsingAssignment(field, v); +} + void STObject::setFieldPathSet(SField const& field, STPathSet const& v) { diff --git a/src/libxrpl/protocol/STVar.cpp b/src/libxrpl/protocol/STVar.cpp index f185595eadb..55927cb33aa 100644 --- a/src/libxrpl/protocol/STVar.cpp +++ b/src/libxrpl/protocol/STVar.cpp @@ -29,6 +29,7 @@ #include <xrpl/protocol/STCurrency.h> #include <xrpl/protocol/STInteger.h> #include <xrpl/protocol/STIssue.h> +#include <xrpl/protocol/STNumber.h> #include <xrpl/protocol/STObject.h> #include <xrpl/protocol/STPathSet.h> #include <xrpl/protocol/STVector256.h> diff --git a/src/libxrpl/protocol/Serializer.cpp b/src/libxrpl/protocol/Serializer.cpp index b99375f80dd..ceaf76faf34 100644 --- a/src/libxrpl/protocol/Serializer.cpp +++ b/src/libxrpl/protocol/Serializer.cpp @@ -21,6 +21,7 @@ #include <xrpl/basics/contract.h> #include <xrpl/protocol/Serializer.h> #include <xrpl/protocol/digest.h> +#include <cstdint> #include <type_traits> namespace ripple { @@ -34,17 +35,6 @@ Serializer::add16(std::uint16_t i) return ret; } -int -Serializer::add32(std::uint32_t i) -{ - int ret = mData.size(); - mData.push_back(static_cast<unsigned char>(i >> 24)); - mData.push_back(static_cast<unsigned char>((i >> 16) & 0xff)); - mData.push_back(static_cast<unsigned char>((i >> 8) & 0xff)); - mData.push_back(static_cast<unsigned char>(i & 0xff)); - return ret; -} - int Serializer::add32(HashPrefix p) { @@ -56,21 +46,6 @@ Serializer::add32(HashPrefix p) return add32(safe_cast<std::uint32_t>(p)); } -int -Serializer::add64(std::uint64_t i) -{ - int ret = mData.size(); - mData.push_back(static_cast<unsigned char>(i >> 56)); - mData.push_back(static_cast<unsigned char>((i >> 48) & 0xff)); - mData.push_back(static_cast<unsigned char>((i >> 40) & 0xff)); - mData.push_back(static_cast<unsigned char>((i >> 32) & 0xff)); - mData.push_back(static_cast<unsigned char>((i >> 24) & 0xff)); - mData.push_back(static_cast<unsigned char>((i >> 16) & 0xff)); - mData.push_back(static_cast<unsigned char>((i >> 8) & 0xff)); - mData.push_back(static_cast<unsigned char>(i & 0xff)); - return ret; -} - template <> int Serializer::addInteger(unsigned char i) @@ -410,6 +385,30 @@ SerialIter::get64() (std::uint64_t(t[6]) << 8) + std::uint64_t(t[7]); } +std::int32_t +SerialIter::geti32() +{ + if (remain_ < 4) + Throw<std::runtime_error>("invalid SerialIter geti32"); + auto t = p_; + p_ += 4; + used_ += 4; + remain_ -= 4; + return boost::endian::load_big_s32(t); +} + +std::int64_t +SerialIter::geti64() +{ + if (remain_ < 8) + Throw<std::runtime_error>("invalid SerialIter geti64"); + auto t = p_; + p_ += 8; + used_ += 8; + remain_ -= 8; + return boost::endian::load_big_s64(t); +} + void SerialIter::getFieldID(int& type, int& name) { diff --git a/src/test/protocol/STNumber_test.cpp b/src/test/protocol/STNumber_test.cpp new file mode 100644 index 00000000000..ed255e32f1c --- /dev/null +++ b/src/test/protocol/STNumber_test.cpp @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include <xrpl/beast/unit_test.h> +#include <xrpl/protocol/Issue.h> +#include <xrpl/protocol/STAmount.h> +#include <xrpl/protocol/STNumber.h> + +#include <limits> +#include <ostream> + +namespace ripple { + +struct STNumber_test : public beast::unit_test::suite +{ + void + testCombo(Number number) + { + STNumber const before{sfNumber, number}; + BEAST_EXPECT(number == before); + Serializer s; + before.add(s); + BEAST_EXPECT(s.size() == 12); + SerialIter sit(s.slice()); + STNumber const after{sit, sfNumber}; + BEAST_EXPECT(after.isEquivalent(before)); + BEAST_EXPECT(number == after); + } + + void + run() override + { + static_assert(!std::is_convertible_v<STNumber*, Number*>); + + { + STNumber const stnum{sfNumber}; + BEAST_EXPECT(stnum.getSType() == STI_NUMBER); + BEAST_EXPECT(stnum.getText() == "0"); + BEAST_EXPECT(stnum.isDefault() == true); + BEAST_EXPECT(stnum.value() == Number{0}); + } + + std::initializer_list<std::int64_t> const mantissas = { + std::numeric_limits<std::int64_t>::min(), + -1, + 0, + 1, + std::numeric_limits<std::int64_t>::max()}; + for (std::int64_t mantissa : mantissas) + testCombo(Number{mantissa}); + + std::initializer_list<std::int32_t> const exponents = { + Number::minExponent, -1, 0, 1, Number::maxExponent - 1}; + for (std::int32_t exponent : exponents) + testCombo(Number{123, exponent}); + + { + STAmount const strikePrice{noIssue(), 100}; + STNumber const factor{sfNumber, 100}; + auto const iouValue = strikePrice.iou(); + IOUAmount totalValue{iouValue * factor}; + STAmount const totalAmount{totalValue, strikePrice.issue()}; + BEAST_EXPECT(totalAmount == Number{10'000}); + } + } +}; + +BEAST_DEFINE_TESTSUITE(STNumber, protocol, ripple); + +void +testCompile(std::ostream& out) +{ + STNumber number{sfNumber, 42}; + out << number; +} + +} // namespace ripple diff --git a/src/test/protocol/Serializer_test.cpp b/src/test/protocol/Serializer_test.cpp new file mode 100644 index 00000000000..d707943856f --- /dev/null +++ b/src/test/protocol/Serializer_test.cpp @@ -0,0 +1,69 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include <xrpl/beast/unit_test.h> +#include <xrpl/protocol/Serializer.h> + +#include <limits> + +namespace ripple { + +struct Serializer_test : public beast::unit_test::suite +{ + void + run() override + { + { + std::initializer_list<std::int32_t> const values = { + std::numeric_limits<std::int32_t>::min(), + -1, + 0, + 1, + std::numeric_limits<std::int32_t>::max()}; + for (std::int32_t value : values) + { + Serializer s; + s.add32(value); + BEAST_EXPECT(s.size() == 4); + SerialIter sit(s.slice()); + BEAST_EXPECT(sit.geti32() == value); + } + } + { + std::initializer_list<std::int64_t> const values = { + std::numeric_limits<std::int64_t>::min(), + -1, + 0, + 1, + std::numeric_limits<std::int64_t>::max()}; + for (std::int64_t value : values) + { + Serializer s; + s.add64(value); + BEAST_EXPECT(s.size() == 8); + SerialIter sit(s.slice()); + BEAST_EXPECT(sit.geti64() == value); + } + } + } +}; + +BEAST_DEFINE_TESTSUITE(Serializer, protocol, ripple); + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp index 2ea13ffabc8..2be784306cd 100644 --- a/src/xrpld/app/tx/detail/Payment.cpp +++ b/src/xrpld/app/tx/detail/Payment.cpp @@ -88,7 +88,7 @@ Payment::preflight(PreflightContext const& ctx) if (txFlags & paymentMask) { - JLOG(j.trace()) << "Malformed transaction: " << "Invalid flags set."; + JLOG(j.trace()) << "Malformed transaction: Invalid flags set."; return temINVALID_FLAG; } @@ -110,9 +110,9 @@ Payment::preflight(PreflightContext const& ctx) if ((mptDirect && dstAmount.asset() != maxSourceAmount.asset()) || (!mptDirect && maxSourceAmount.holds<MPTIssue>())) { - JLOG(j.trace()) << "Malformed transaction: " - << "inconsistent issues: " << dstAmount.getFullText() - << " " << maxSourceAmount.getFullText() << " " + JLOG(j.trace()) << "Malformed transaction: inconsistent issues: " + << dstAmount.getFullText() << " " + << maxSourceAmount.getFullText() << " " << deliverMin.value_or(STAmount{}).getFullText(); return temMALFORMED; } @@ -135,19 +135,19 @@ Payment::preflight(PreflightContext const& ctx) } if (hasMax && maxSourceAmount <= beast::zero) { - JLOG(j.trace()) << "Malformed transaction: " << "bad max amount: " + JLOG(j.trace()) << "Malformed transaction: bad max amount: " << maxSourceAmount.getFullText(); return temBAD_AMOUNT; } if (dstAmount <= beast::zero) { - JLOG(j.trace()) << "Malformed transaction: " - << "bad dst amount: " << dstAmount.getFullText(); + JLOG(j.trace()) << "Malformed transaction: bad dst amount: " + << dstAmount.getFullText(); return temBAD_AMOUNT; } if (badCurrency() == srcAsset || badCurrency() == dstAsset) { - JLOG(j.trace()) << "Malformed transaction: " << "Bad currency."; + JLOG(j.trace()) << "Malformed transaction: Bad currency."; return temBAD_CURRENCY; } if (account == dstAccountID && equalTokens(srcAsset, dstAsset) && !hasPaths) @@ -550,7 +550,7 @@ Payment::doApply() // Vote no. However the transaction might succeed, if applied in // a different order. JLOG(j_.trace()) << "Delay transaction: Insufficient funds: " - << " " << to_string(mPriorBalance) << " / " + << to_string(mPriorBalance) << " / " << to_string(dstAmount.xrp() + mmm) << " (" << to_string(reserve) << ")"; diff --git a/src/xrpld/ledger/detail/CachedView.cpp b/src/xrpld/ledger/detail/CachedView.cpp index 5502c40e6d5..645a2c79c13 100644 --- a/src/xrpld/ledger/detail/CachedView.cpp +++ b/src/xrpld/ledger/detail/CachedView.cpp @@ -63,20 +63,17 @@ CachedViewImpl::read(Keylet const& k) const hits.increment(); else misses.increment(); - std::lock_guard lock(mutex_); - auto const er = map_.emplace(k.key, *digest); - bool const inserted = er.second; - if (sle && !k.check(*sle)) + + if (!cacheHit) { - if (!inserted) - { - // On entry, this function did not find this key in map_. Now - // something (another thread?) has inserted the sle into the map and - // it has the wrong type. - LogicError("CachedView::read: wrong type"); - } - return nullptr; + // Avoid acquiring this lock unless necessary. It is only necessary if + // the key was not found in the map_. The lock is needed to add the key + // and digest. + std::lock_guard lock(mutex_); + map_.emplace(k.key, *digest); } + if (!sle || !k.check(*sle)) + return nullptr; return sle; }