From 0ec17b6026298dc150099b66a2cecad0fe561d1b Mon Sep 17 00:00:00 2001 From: Olek <115580134+oleks-rip@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:58:25 -0500 Subject: [PATCH 1/8] fix: check for valid ammID field in amm_info RPC (#5188) --- src/test/rpc/AMMInfo_test.cpp | 19 +++++++++++++++++++ src/xrpld/rpc/handlers/AMMInfo.cpp | 2 ++ 2 files changed, 21 insertions(+) diff --git a/src/test/rpc/AMMInfo_test.cpp b/src/test/rpc/AMMInfo_test.cpp index e4523bb0473..c1e059a3ead 100644 --- a/src/test/rpc/AMMInfo_test.cpp +++ b/src/test/rpc/AMMInfo_test.cpp @@ -316,6 +316,24 @@ class AMMInfo_test : public jtx::AMMTestBase }); } + void + testInvalidAmmField() + { + using namespace jtx; + testcase("Invalid amm field"); + + testAMM([&](AMM& amm, Env&) { + auto const resp = amm.ammRpcInfo( + std::nullopt, + jss::validated.c_str(), + std::nullopt, + std::nullopt, + gw); + BEAST_EXPECT( + resp.isMember("error") && resp["error"] == "actNotFound"); + }); + } + void run() override { @@ -323,6 +341,7 @@ class AMMInfo_test : public jtx::AMMTestBase testSimpleRpc(); testVoteAndBid(); testFreeze(); + testInvalidAmmField(); } }; diff --git a/src/xrpld/rpc/handlers/AMMInfo.cpp b/src/xrpld/rpc/handlers/AMMInfo.cpp index aad8faea213..9d5b20f1d63 100644 --- a/src/xrpld/rpc/handlers/AMMInfo.cpp +++ b/src/xrpld/rpc/handlers/AMMInfo.cpp @@ -132,6 +132,8 @@ doAMMInfo(RPC::JsonContext& context) if (!sle) return Unexpected(rpcACT_MALFORMED); ammID = sle->getFieldH256(sfAMMID); + if (ammID->isZero()) + return Unexpected(rpcACT_NOT_FOUND); } if (params.isMember(jss::account)) From f419c18056889c857dbfa1f9a97c8ca4779ffa7d Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Mon, 25 Nov 2024 12:12:35 -0800 Subject: [PATCH 2/8] Add a new serialized type: STNumber (#5121) `STNumber` lets objects and transactions contain multiple fields for quantities of XRP, IOU, or MPT without duplicating information about the "issue" (represented by `STIssue`). It is a straightforward serialization of the `Number` type that uniformly represents those quantities. --------- Co-authored-by: John Freeman Co-authored-by: Howard Hinnant --- include/xrpl/basics/Number.h | 16 ++-- include/xrpl/protocol/SField.h | 5 +- include/xrpl/protocol/STNumber.h | 88 +++++++++++++++++ include/xrpl/protocol/STObject.h | 4 + include/xrpl/protocol/Serializer.h | 39 +++++++- include/xrpl/protocol/detail/sfields.macro | 3 + include/xrpl/protocol/st.h | 1 + src/libxrpl/protocol/STNumber.cpp | 105 +++++++++++++++++++++ src/libxrpl/protocol/STObject.cpp | 14 +++ src/libxrpl/protocol/STVar.cpp | 1 + src/libxrpl/protocol/Serializer.cpp | 51 +++++----- src/test/protocol/STNumber_test.cpp | 93 ++++++++++++++++++ src/test/protocol/Serializer_test.cpp | 69 ++++++++++++++ src/xrpld/app/tx/detail/Payment.cpp | 18 ++-- src/xrpld/ledger/detail/CachedView.cpp | 21 ++--- 15 files changed, 470 insertions(+), 58 deletions(-) create mode 100644 include/xrpl/protocol/STNumber.h create mode 100644 src/libxrpl/protocol/STNumber.cpp create mode 100644 src/test/protocol/STNumber_test.cpp create mode 100644 src/test/protocol/Serializer_test.cpp 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::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 class STBitString; template 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; using SF_AMOUNT = TypedField; using SF_ISSUE = TypedField; using SF_CURRENCY = TypedField; +using SF_NUMBER = TypedField; using SF_VL = TypedField; using SF_VECTOR256 = TypedField; using SF_XCHAIN_BRIDGE = TypedField; 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 +#include +#include + +#include + +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 +{ +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 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 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 + requires(std::is_same_v< + std::make_unsigned_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((i >> 24) & 0xff)); + mData.push_back(static_cast((i >> 16) & 0xff)); + mData.push_back(static_cast((i >> 8) & 0xff)); + mData.push_back(static_cast(i & 0xff)); + return ret; + } + int add32(HashPrefix p); + + template + requires(std::is_same_v< + std::make_unsigned_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((i >> 56) & 0xff)); + mData.push_back(static_cast((i >> 48) & 0xff)); + mData.push_back(static_cast((i >> 40) & 0xff)); + mData.push_back(static_cast((i >> 32) & 0xff)); + mData.push_back(static_cast((i >> 24) & 0xff)); + mData.push_back(static_cast((i >> 16) & 0xff)); + mData.push_back(static_cast((i >> 8) & 0xff)); + mData.push_back(static_cast(i & 0xff)); + return ret; + } template 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 base_uint 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 #include #include +#include #include #include #include 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 + +#include + +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(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 #include #include +#include #include namespace ripple { @@ -665,6 +666,13 @@ STObject::getFieldCurrency(SField const& field) const return getFieldByConstRef(field, empty); } +STNumber const& +STObject::getFieldNumber(SField const& field) const +{ + static STNumber const empty{}; + return getFieldByConstRef(field, empty); +} + void STObject::set(std::unique_ptr 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 #include #include +#include #include #include #include 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 #include #include +#include #include 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(i >> 24)); - mData.push_back(static_cast((i >> 16) & 0xff)); - mData.push_back(static_cast((i >> 8) & 0xff)); - mData.push_back(static_cast(i & 0xff)); - return ret; -} - int Serializer::add32(HashPrefix p) { @@ -56,21 +46,6 @@ Serializer::add32(HashPrefix p) return add32(safe_cast(p)); } -int -Serializer::add64(std::uint64_t i) -{ - int ret = mData.size(); - mData.push_back(static_cast(i >> 56)); - mData.push_back(static_cast((i >> 48) & 0xff)); - mData.push_back(static_cast((i >> 40) & 0xff)); - mData.push_back(static_cast((i >> 32) & 0xff)); - mData.push_back(static_cast((i >> 24) & 0xff)); - mData.push_back(static_cast((i >> 16) & 0xff)); - mData.push_back(static_cast((i >> 8) & 0xff)); - mData.push_back(static_cast(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("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("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 +#include +#include +#include + +#include +#include + +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 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 const mantissas = { + std::numeric_limits::min(), + -1, + 0, + 1, + std::numeric_limits::max()}; + for (std::int64_t mantissa : mantissas) + testCombo(Number{mantissa}); + + std::initializer_list 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 +#include + +#include + +namespace ripple { + +struct Serializer_test : public beast::unit_test::suite +{ + void + run() override + { + { + std::initializer_list const values = { + std::numeric_limits::min(), + -1, + 0, + 1, + std::numeric_limits::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 const values = { + std::numeric_limits::min(), + -1, + 0, + 1, + std::numeric_limits::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())) { - 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; } From b54d85d8620e622d567423a1a87dfe79ecdff71c Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Mon, 25 Nov 2024 11:40:11 -0800 Subject: [PATCH 3/8] refactor(AMMClawback): move tfClawTwoAssets check (#5201) Move tfClawTwoAssets check to preflight and return error temINVALID_FLAG --------- Co-authored-by: yinyiqian1 --- include/xrpl/protocol/detail/features.macro | 2 +- src/test/app/AMMClawback_test.cpp | 6 +++--- src/xrpld/app/tx/detail/AMMClawback.cpp | 21 +++++++++++---------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index 24c6e72ae34..31fc90cef80 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -32,9 +32,9 @@ XRPL_FEATURE(Credentials, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(AMMClawback, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (AMMv1_2, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(MPTokensV1, Supported::yes, VoteBehavior::DefaultNo) // InvariantsV1_1 will be changes to Supported::yes when all the // invariants expected to be included under it are complete. -XRPL_FEATURE(MPTokensV1, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(InvariantsV1_1, Supported::no, VoteBehavior::DefaultNo) XRPL_FIX (NFTokenPageLinks, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (InnerObjTemplate2, Supported::yes, VoteBehavior::DefaultNo) diff --git a/src/test/app/AMMClawback_test.cpp b/src/test/app/AMMClawback_test.cpp index 705a1274073..c547a537bfb 100644 --- a/src/test/app/AMMClawback_test.cpp +++ b/src/test/app/AMMClawback_test.cpp @@ -303,13 +303,13 @@ class AMMClawback_test : public jtx::AMMTest // gw creates AMM pool of XRP/USD. AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); - // Return tecNO_PERMISSION because the issuer set tfClawTwoAssets, + // Return temINVALID_FLAG because the issuer set tfClawTwoAssets, // but the issuer only issues USD in the pool. The issuer is not // allowed to set tfClawTwoAssets flag if he did not issue both - // assts in the pool. + // assets in the pool. env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), txflags(tfClawTwoAssets), - ter(tecNO_PERMISSION)); + ter(temINVALID_FLAG)); } // Test clawing back XRP is being prohibited. diff --git a/src/xrpld/app/tx/detail/AMMClawback.cpp b/src/xrpld/app/tx/detail/AMMClawback.cpp index 64150ded6da..cd1e3008e97 100644 --- a/src/xrpld/app/tx/detail/AMMClawback.cpp +++ b/src/xrpld/app/tx/detail/AMMClawback.cpp @@ -42,7 +42,8 @@ AMMClawback::preflight(PreflightContext const& ctx) if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; // LCOV_EXCL_LINE - if (ctx.tx.getFlags() & tfAMMClawbackMask) + auto const flags = ctx.tx.getFlags(); + if (flags & tfAMMClawbackMask) return temINVALID_FLAG; AccountID const issuer = ctx.tx[sfAccount]; @@ -57,10 +58,19 @@ AMMClawback::preflight(PreflightContext const& ctx) std::optional const clawAmount = ctx.tx[~sfAmount]; auto const asset = ctx.tx[sfAsset]; + auto const asset2 = ctx.tx[sfAsset2]; if (isXRP(asset)) return temMALFORMED; + if (flags & tfClawTwoAssets && asset.account != asset2.account) + { + JLOG(ctx.j.trace()) + << "AMMClawback: tfClawTwoAssets can only be enabled when two " + "assets in the AMM pool are both issued by the issuer"; + return temINVALID_FLAG; + } + if (asset.account != issuer) { JLOG(ctx.j.trace()) << "AMMClawback: Asset's account does not " @@ -108,15 +118,6 @@ AMMClawback::preclaim(PreclaimContext const& ctx) (issuerFlagsIn & lsfNoFreeze)) return tecNO_PERMISSION; - auto const flags = ctx.tx.getFlags(); - if (flags & tfClawTwoAssets && asset.account != asset2.account) - { - JLOG(ctx.j.trace()) - << "AMMClawback: tfClawTwoAssets can only be enabled when two " - "assets in the AMM pool are both issued by the issuer"; - return tecNO_PERMISSION; - } - return tesSUCCESS; } From f64cf9187affd69650907d0d92e097eb29693945 Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Mon, 25 Nov 2024 12:27:17 -0800 Subject: [PATCH 4/8] Set version to 2.3.0 --- RELEASENOTES.md | 73 ++++++++++++++++++++++++++++++ src/libxrpl/protocol/BuildInfo.cpp | 2 +- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c6a43f4aa7d..c6e8266e348 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -6,6 +6,79 @@ This document contains the release notes for `rippled`, the reference server imp Have new ideas? Need help with setting up your node? [Please open an issue here](https://github.com/xrplf/rippled/issues/new/choose). +# Version 2.3.0 + +Version 2.3.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release includes 8 new amendments, including Multi-Purpose Tokens, Credentials, Clawback support for AMMs, and the ability to make offers as part of minting NFTs. Additionally, this release includes important fixes for stability, so server operators are encouraged to upgrade as soon as possible. + + +## Action Required + +If you run an XRP Ledger server, upgrade to version 2.3.0 as soon as possible to ensure service continuity. + +Additionally, new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + +## Full Changelog + +### Amendments + +The following amendments are open for voting with this release: + +- **XLS-70 Credentials** - Users can issue Credentials on the ledger and use Credentials to pre-approve incoming payments when using Deposit Authorization instead of individually approving payers. ([#5103](https://github.com/XRPLF/rippled/pull/5103)) + - related fix: #5189 (https://github.com/XRPLF/rippled/pull/5189) +- **XLS-33 Multi-Purpose Tokens** - A new type of fungible token optimized for institutional DeFi including stablecoins. ([#5143](https://github.com/XRPLF/rippled/pull/5143)) +- **XLS-37 AMM Clawback** - Allows clawback-enabled tokens to be used in AMMs, with appropriate guardrails. ([#5142](https://github.com/XRPLF/rippled/pull/5142)) +- **XLS-52 NFTokenMintOffer** - Allows creating an NFT sell offer as part of minting a new NFT. ([#4845](https://github.com/XRPLF/rippled/pull/4845)) +- **fixAMMv1_2** - Fixes two bugs in Automated Market Maker (AMM) transaction processing. ([#5176](https://github.com/XRPLF/rippled/pull/5176)) +- **fixNFTokenPageLinks** - Fixes a bug that can cause NFT directories to have missing links, and introduces a transaction to repair corrupted ledger state. ([#4945](https://github.com/XRPLF/rippled/pull/4945)) +- **fixEnforceNFTokenTrustline** - Fixes two bugs in the interaction between NFT offers and trust lines. ([#4946](https://github.com/XRPLF/rippled/pull/4946)) +- **fixInnerObjTemplate2** - Standardizes the way inner objects are enforced across all transaction and ledger data. ([#5047](https://github.com/XRPLF/rippled/pull/5047)) + +The following amendment is partially implemented but not open for voting: + +- **InvariantsV1_1** - Adds new invariants to ensure transactions process as intended, starting with an invariant to ensure that ledger entries owned by an account are deleted when the account is deleted. ([#4663](https://github.com/XRPLF/rippled/pull/4663)) + +### New Features + +- Allow configuration of SQLite database page size. ([#5135](https://github.com/XRPLF/rippled/pull/5135), [#5140](https://github.com/XRPLF/rippled/pull/5140)) +- In the `libxrpl` C++ library, provide a list of known amendments. ([#5026](https://github.com/XRPLF/rippled/pull/5026)) + +### Deprecations + +- History Shards are removed. ([#5066](https://github.com/XRPLF/rippled/pull/5066)) +- Reporting mode is removed. ([#5092](https://github.com/XRPLF/rippled/pull/5092)) + +For users wanting to store more ledger history, it is recommended to run a Clio server instead. + +### Bug fixes + +- Fix a crash in debug builds when amm_info request contains an invalid AMM account ID. ([#5188](https://github.com/XRPLF/rippled/pull/5188)) +- Fix a crash caused by a race condition in peer-to-peer code. ([#5071](https://github.com/XRPLF/rippled/pull/5071)) +- Fix a crash in certain situations +- Fix several bugs in the book_changes API method. ([#5096](https://github.com/XRPLF/rippled/pull/5096)) +- Fix bug triggered by providing an invalid marker to the account_nfts API method. ([#5045](https://github.com/XRPLF/rippled/pull/5045)) +- Accept lower-case hexadecimal in compact transaction identifier (CTID) parameters in API methods. ([#5049](https://github.com/XRPLF/rippled/pull/5049)) +- Disallow filtering by types that an account can't own in the account_objects API method. ([#5056](https://github.com/XRPLF/rippled/pull/5056)) +- Fix error code returned by the feature API method when providing an invalid parameter. ([#5063](https://github.com/XRPLF/rippled/pull/5063)) +- (API v3) Fix error code returned by amm_info when providing invalid parameters. ([#4924](https://github.com/XRPLF/rippled/pull/4924)) + +### Other Improvements + +- Adds a new default hub, hubs.xrpkuwait.com, to the config file and bootstrapping code. ([#5169](https://github.com/XRPLF/rippled/pull/5169)) +- Improve error message when commandline interface fails with `rpcInternal` because there was no response from the server. ([#4959](https://github.com/XRPLF/rippled/pull/4959)) +- Add tools for debugging specific transactions via replay. ([#5027](https://github.com/XRPLF/rippled/pull/5027), [#5087](https://github.com/XRPLF/rippled/pull/5087)) +- Major reorganization of source code files. ([#4997](https://github.com/XRPLF/rippled/pull/4997)) +- Add new unit tests. ([#4886](https://github.com/XRPLF/rippled/pull/4886)) +- Various improvements to build tools and contributor documentation. ([#5001](https://github.com/XRPLF/rippled/pull/5001), [#5028](https://github.com/XRPLF/rippled/pull/5028), [#5052](https://github.com/XRPLF/rippled/pull/5052), [#5091](https://github.com/XRPLF/rippled/pull/5091), [#5084](https://github.com/XRPLF/rippled/pull/5084), [#5120](https://github.com/XRPLF/rippled/pull/5120), [#5010](https://github.com/XRPLF/rippled/pull/5010). [#5055](https://github.com/XRPLF/rippled/pull/5055), [#5067](https://github.com/XRPLF/rippled/pull/5067), [#5061](https://github.com/XRPLF/rippled/pull/5061), [#5072](https://github.com/XRPLF/rippled/pull/5072), [#5044](https://github.com/XRPLF/rippled/pull/5044) ) +- Various code cleanup and refactoring. ([#4509](https://github.com/XRPLF/rippled/pull/4509), [#4521](https://github.com/XRPLF/rippled/pull/4521), [#4856](https://github.com/XRPLF/rippled/pull/4856), [#5190](https://github.com/XRPLF/rippled/pull/5190), [#5081](https://github.com/XRPLF/rippled/pull/5081), [#5053](https://github.com/XRPLF/rippled/pull/5053), [#5058](https://github.com/XRPLF/rippled/pull/5058), [#5122](https://github.com/XRPLF/rippled/pull/5122), [#5059](https://github.com/XRPLF/rippled/pull/5059), [#5041](https://github.com/XRPLF/rippled/pull/5041)) + + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + # Version 2.2.3 Version 2.2.3 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release fixes a problem that can cause full-history servers to run out of space in their SQLite databases, depending on configuration. There are no new amendments in this release. diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index c3d0bd1f92d..995df262885 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -33,7 +33,7 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "2.3.0-rc2" +char const* const versionString = "2.3.0" // clang-format on #if defined(DEBUG) || defined(SANITIZER) From d7e949193fe3a42c67f36c021daba9fd0d52780c Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Tue, 3 Dec 2024 14:52:21 -0500 Subject: [PATCH 5/8] Add Antithesis intrumentation (#5042) * Copy Antithesis SDK version 0.4.0 to directory external/ * Add build option `voidstar` to enable instrumentation with Antithesis SDK * Define instrumentation macros ASSERT and UNREACHABLE in terms of regular C assert * Replace asserts with named ASSERT or UNREACHABLE * Add UNREACHABLE to LogicError * Document instrumentation macros in CONTRIBUTING.md --- CMakeLists.txt | 1 + CONTRIBUTING.md | 62 + cmake/RippledCompiler.cmake | 13 +- cmake/RippledCore.cmake | 15 + cmake/RippledInstall.cmake | 1 + cmake/RippledSettings.cmake | 3 + external/README.md | 1 + external/antithesis-sdk/.clang-format | 3 + external/antithesis-sdk/CMakeLists.txt | 17 + external/antithesis-sdk/LICENSE | 21 + external/antithesis-sdk/README.md | 8 + .../antithesis_instrumentation.h | 113 ++ external/antithesis-sdk/antithesis_sdk.h | 1093 +++++++++++++++++ include/xrpl/basics/Buffer.h | 7 +- include/xrpl/basics/FeeUnits.h | 16 +- include/xrpl/basics/MathUtilities.h | 2 +- include/xrpl/basics/SlabAllocator.h | 17 +- include/xrpl/basics/Slice.h | 6 +- include/xrpl/basics/base_uint.h | 9 +- .../xrpl/basics/partitioned_unordered_map.h | 7 +- include/xrpl/basics/random.h | 4 +- include/xrpl/basics/scope.h | 6 +- include/xrpl/basics/spinlock.h | 6 +- include/xrpl/beast/asio/io_latency_probe.h | 12 +- include/xrpl/beast/clock/manual_clock.h | 10 +- .../detail/aged_unordered_container.h | 10 +- include/xrpl/beast/core/LexicalCast.h | 11 +- include/xrpl/beast/net/IPAddress.h | 4 +- include/xrpl/beast/net/IPAddressV6.h | 2 +- include/xrpl/beast/utility/Journal.h | 6 +- include/xrpl/beast/utility/instrumentation.h | 64 + include/xrpl/beast/utility/rngfill.h | 5 +- include/xrpl/json/detail/json_assert.h | 3 - include/xrpl/protocol/AmountConversions.h | 16 +- include/xrpl/protocol/Feature.h | 14 +- include/xrpl/protocol/Indexes.h | 2 +- include/xrpl/protocol/Issue.h | 2 +- include/xrpl/protocol/MultiApiJson.h | 13 +- include/xrpl/protocol/Quality.h | 4 +- include/xrpl/protocol/Rate.h | 2 +- include/xrpl/protocol/STAmount.h | 6 +- include/xrpl/protocol/STBitString.h | 6 +- include/xrpl/protocol/STBlob.h | 2 +- include/xrpl/protocol/STInteger.h | 6 +- include/xrpl/protocol/STObject.h | 31 +- include/xrpl/protocol/STPathSet.h | 10 +- include/xrpl/protocol/STValidation.h | 11 +- include/xrpl/protocol/Serializer.h | 8 +- include/xrpl/protocol/TxMeta.h | 4 +- include/xrpl/protocol/detail/b58_utils.h | 20 +- include/xrpl/resource/detail/Entry.h | 2 +- include/xrpl/resource/detail/Key.h | 2 +- include/xrpl/resource/detail/Logic.h | 10 +- include/xrpl/server/detail/BaseHTTPPeer.h | 2 +- include/xrpl/server/detail/BasePeer.h | 2 +- include/xrpl/server/detail/BaseWSPeer.h | 10 +- src/libxrpl/basics/Log.cpp | 10 +- src/libxrpl/basics/Number.cpp | 24 +- src/libxrpl/basics/ResolverAsio.cpp | 35 +- src/libxrpl/basics/contract.cpp | 7 + .../beast/clock/basic_seconds_clock.cpp | 6 +- src/libxrpl/beast/core/SemanticVersion.cpp | 9 +- src/libxrpl/beast/insight/StatsDCollector.cpp | 7 +- .../beast/utility/src/beast_Journal.cpp | 2 +- .../utility/src/beast_PropertyStream.cpp | 10 +- src/libxrpl/crypto/RFC1751.cpp | 22 +- src/libxrpl/crypto/csprng.cpp | 2 +- src/libxrpl/json/Object.cpp | 8 +- src/libxrpl/json/json_reader.cpp | 2 +- src/libxrpl/json/json_value.cpp | 55 +- src/libxrpl/json/json_writer.cpp | 22 +- src/libxrpl/protocol/AMMCore.cpp | 4 +- src/libxrpl/protocol/AccountID.cpp | 4 +- src/libxrpl/protocol/ErrorCodes.cpp | 6 +- src/libxrpl/protocol/Feature.cpp | 16 +- src/libxrpl/protocol/Indexes.cpp | 17 +- src/libxrpl/protocol/Keylet.cpp | 4 +- src/libxrpl/protocol/Quality.cpp | 31 +- src/libxrpl/protocol/Rate2.cpp | 16 +- src/libxrpl/protocol/Rules.cpp | 11 +- src/libxrpl/protocol/SField.cpp | 2 +- src/libxrpl/protocol/STAccount.cpp | 6 +- src/libxrpl/protocol/STAmount.cpp | 55 +- src/libxrpl/protocol/STBase.cpp | 15 +- src/libxrpl/protocol/STBlob.cpp | 7 +- src/libxrpl/protocol/STInteger.cpp | 8 +- src/libxrpl/protocol/STLedgerEntry.cpp | 4 +- src/libxrpl/protocol/STNumber.cpp | 11 +- src/libxrpl/protocol/STObject.cpp | 5 +- src/libxrpl/protocol/STParsedJSON.cpp | 2 +- src/libxrpl/protocol/STPathSet.cpp | 6 +- src/libxrpl/protocol/STTx.cpp | 7 +- src/libxrpl/protocol/STValidation.cpp | 4 +- src/libxrpl/protocol/STVar.cpp | 4 +- src/libxrpl/protocol/STVector256.cpp | 6 +- src/libxrpl/protocol/Serializer.cpp | 12 +- src/libxrpl/protocol/TxMeta.cpp | 33 +- src/libxrpl/protocol/tokens.cpp | 12 +- src/libxrpl/resource/Consumer.cpp | 18 +- src/test/jtx/impl/amount.cpp | 1 - src/test/overlay/short_read_test.cpp | 1 - src/xrpld/app/consensus/RCLConsensus.cpp | 25 +- src/xrpld/app/consensus/RCLCxPeerPos.cpp | 4 +- src/xrpld/app/consensus/RCLCxTx.h | 8 +- src/xrpld/app/consensus/RCLValidations.cpp | 17 +- src/xrpld/app/ledger/AcceptedLedgerTx.cpp | 8 +- src/xrpld/app/ledger/ConsensusTransSetSF.cpp | 9 +- src/xrpld/app/ledger/Ledger.cpp | 40 +- src/xrpld/app/ledger/LedgerHistory.cpp | 52 +- src/xrpld/app/ledger/OpenLedger.h | 5 +- src/xrpld/app/ledger/OrderBookDB.cpp | 4 +- src/xrpld/app/ledger/TransactionStateSF.cpp | 4 +- src/xrpld/app/ledger/detail/BuildLedger.cpp | 11 +- src/xrpld/app/ledger/detail/InboundLedger.cpp | 33 +- .../app/ledger/detail/InboundLedgers.cpp | 17 +- src/xrpld/app/ledger/detail/LedgerCleaner.cpp | 8 +- .../app/ledger/detail/LedgerDeltaAcquire.cpp | 10 +- src/xrpld/app/ledger/detail/LedgerMaster.cpp | 56 +- .../app/ledger/detail/LedgerReplayTask.cpp | 19 +- .../app/ledger/detail/LedgerReplayer.cpp | 5 +- .../app/ledger/detail/SkipListAcquire.cpp | 6 +- .../app/ledger/detail/TimeoutCounter.cpp | 4 +- src/xrpld/app/main/Application.cpp | 61 +- src/xrpld/app/main/GRPCServer.cpp | 2 +- src/xrpld/app/main/LoadManager.cpp | 4 +- src/xrpld/app/main/Main.cpp | 4 + src/xrpld/app/main/NodeStoreScheduler.cpp | 2 +- src/xrpld/app/misc/FeeVoteImpl.cpp | 4 +- src/xrpld/app/misc/HashRouter.cpp | 2 +- src/xrpld/app/misc/NegativeUNLVote.cpp | 12 +- src/xrpld/app/misc/NetworkOPs.cpp | 73 +- src/xrpld/app/misc/SHAMapStoreImp.cpp | 4 +- src/xrpld/app/misc/detail/AMMHelpers.cpp | 4 +- src/xrpld/app/misc/detail/AMMUtils.cpp | 5 +- src/xrpld/app/misc/detail/AmendmentTable.cpp | 4 +- src/xrpld/app/misc/detail/Manifest.cpp | 4 +- src/xrpld/app/misc/detail/Transaction.cpp | 5 +- src/xrpld/app/misc/detail/TxQ.cpp | 91 +- src/xrpld/app/misc/detail/ValidatorList.cpp | 111 +- src/xrpld/app/misc/detail/ValidatorSite.cpp | 9 +- src/xrpld/app/misc/detail/WorkBase.h | 4 +- src/xrpld/app/misc/detail/WorkFile.h | 4 +- src/xrpld/app/paths/Credit.cpp | 16 +- src/xrpld/app/paths/Flow.cpp | 2 +- src/xrpld/app/paths/PathRequest.cpp | 2 +- src/xrpld/app/paths/Pathfinder.cpp | 20 +- src/xrpld/app/paths/RippleLineCache.cpp | 12 +- src/xrpld/app/paths/detail/AMMLiquidity.cpp | 4 +- src/xrpld/app/paths/detail/AmountSpec.h | 19 +- src/xrpld/app/paths/detail/BookStep.cpp | 17 +- src/xrpld/app/paths/detail/DirectStep.cpp | 19 +- src/xrpld/app/paths/detail/FlowDebugInfo.h | 9 +- src/xrpld/app/paths/detail/PaySteps.cpp | 14 +- src/xrpld/app/paths/detail/StepChecks.h | 2 +- src/xrpld/app/paths/detail/StrandFlow.h | 26 +- .../app/paths/detail/XRPEndpointStep.cpp | 5 +- src/xrpld/app/rdb/RelationalDatabase.h | 3 +- src/xrpld/app/rdb/backend/detail/Node.cpp | 11 +- src/xrpld/app/rdb/detail/Vacuum.cpp | 8 +- src/xrpld/app/tx/detail/AMMBid.cpp | 6 +- src/xrpld/app/tx/detail/AMMDeposit.cpp | 4 +- src/xrpld/app/tx/detail/AMMVote.cpp | 5 +- src/xrpld/app/tx/detail/AMMWithdraw.cpp | 4 +- src/xrpld/app/tx/detail/ApplyContext.cpp | 6 +- src/xrpld/app/tx/detail/Change.cpp | 5 +- src/xrpld/app/tx/detail/CreateOffer.cpp | 41 +- src/xrpld/app/tx/detail/DeleteAccount.cpp | 21 +- src/xrpld/app/tx/detail/InvariantCheck.cpp | 9 +- src/xrpld/app/tx/detail/NFTokenMint.cpp | 4 +- src/xrpld/app/tx/detail/NFTokenUtils.cpp | 16 +- src/xrpld/app/tx/detail/Offer.h | 2 +- src/xrpld/app/tx/detail/OfferStream.cpp | 7 +- src/xrpld/app/tx/detail/PayChan.cpp | 8 +- src/xrpld/app/tx/detail/Payment.cpp | 2 +- src/xrpld/app/tx/detail/SetSignerList.cpp | 23 +- src/xrpld/app/tx/detail/Taker.cpp | 78 +- src/xrpld/app/tx/detail/Transactor.cpp | 39 +- src/xrpld/app/tx/detail/XChainBridge.cpp | 9 +- src/xrpld/app/tx/detail/applySteps.cpp | 13 +- src/xrpld/consensus/Consensus.h | 34 +- src/xrpld/consensus/ConsensusTypes.h | 4 +- src/xrpld/consensus/LedgerTiming.h | 8 +- src/xrpld/consensus/LedgerTrie.h | 28 +- src/xrpld/consensus/Validations.h | 6 +- src/xrpld/core/Coro.ipp | 6 +- src/xrpld/core/DatabaseCon.h | 5 +- src/xrpld/core/JobTypes.h | 29 +- src/xrpld/core/detail/Config.cpp | 16 +- src/xrpld/core/detail/DatabaseCon.cpp | 4 +- src/xrpld/core/detail/Job.cpp | 2 +- src/xrpld/core/detail/JobQueue.cpp | 78 +- src/xrpld/core/detail/LoadEvent.cpp | 4 +- src/xrpld/core/detail/Workers.cpp | 6 +- src/xrpld/ledger/ApplyView.h | 8 +- src/xrpld/ledger/ReadView.h | 2 +- src/xrpld/ledger/detail/ApplyStateTable.cpp | 43 +- src/xrpld/ledger/detail/ApplyView.cpp | 4 +- src/xrpld/ledger/detail/ApplyViewImpl.cpp | 2 +- src/xrpld/ledger/detail/BookDirs.cpp | 25 +- src/xrpld/ledger/detail/Dir.cpp | 20 +- src/xrpld/ledger/detail/PaymentSandbox.cpp | 20 +- src/xrpld/ledger/detail/RawStateTable.cpp | 14 +- src/xrpld/ledger/detail/ReadViewFwdRange.ipp | 5 +- src/xrpld/ledger/detail/View.cpp | 102 +- src/xrpld/net/detail/InfoSub.cpp | 3 +- src/xrpld/net/detail/RPCCall.cpp | 4 +- src/xrpld/nodestore/Database.h | 4 +- src/xrpld/nodestore/backend/MemoryFactory.cpp | 12 +- src/xrpld/nodestore/backend/NuDBFactory.cpp | 6 +- .../nodestore/backend/RocksDBFactory.cpp | 17 +- src/xrpld/nodestore/detail/BatchWriter.cpp | 4 +- src/xrpld/nodestore/detail/Database.cpp | 21 +- src/xrpld/nodestore/detail/DatabaseNodeImp.h | 5 +- src/xrpld/nodestore/detail/DecodedBlob.cpp | 6 +- src/xrpld/nodestore/detail/EncodedBlob.h | 12 +- src/xrpld/nodestore/detail/ManagerImp.cpp | 4 +- src/xrpld/overlay/Compression.h | 8 +- src/xrpld/overlay/Slot.h | 4 +- src/xrpld/overlay/detail/ConnectAttempt.cpp | 4 +- src/xrpld/overlay/detail/Message.cpp | 8 +- src/xrpld/overlay/detail/OverlayImpl.cpp | 27 +- src/xrpld/overlay/detail/OverlayImpl.h | 6 +- src/xrpld/overlay/detail/PeerImp.cpp | 61 +- src/xrpld/overlay/detail/ProtocolMessage.h | 6 +- src/xrpld/overlay/detail/TrafficCount.h | 5 +- src/xrpld/overlay/detail/ZeroCopyStream.h | 5 +- src/xrpld/peerfinder/detail/Bootcache.cpp | 8 +- src/xrpld/peerfinder/detail/Counts.h | 16 +- src/xrpld/peerfinder/detail/Handouts.h | 6 +- src/xrpld/peerfinder/detail/Livecache.h | 12 +- src/xrpld/peerfinder/detail/Logic.h | 49 +- src/xrpld/peerfinder/detail/SlotImp.cpp | 27 +- src/xrpld/perflog/detail/PerfLogImp.cpp | 24 +- src/xrpld/rpc/Status.h | 8 +- src/xrpld/rpc/detail/Handler.cpp | 15 +- src/xrpld/rpc/detail/RPCHelpers.cpp | 25 +- src/xrpld/rpc/detail/RPCHelpers.h | 4 +- src/xrpld/rpc/detail/Role.cpp | 4 +- src/xrpld/rpc/detail/Status.cpp | 7 +- src/xrpld/rpc/detail/TransactionSign.cpp | 4 +- src/xrpld/rpc/handlers/AMMInfo.cpp | 14 +- src/xrpld/rpc/handlers/AccountChannels.cpp | 2 +- src/xrpld/rpc/handlers/AccountInfo.cpp | 8 +- src/xrpld/rpc/handlers/AccountLines.cpp | 2 +- src/xrpld/rpc/handlers/AccountOffers.cpp | 2 +- src/xrpld/rpc/handlers/AccountTx.cpp | 10 +- src/xrpld/rpc/handlers/Fee1.cpp | 2 +- src/xrpld/rpc/handlers/LedgerClosed.cpp | 3 +- src/xrpld/rpc/handlers/LedgerDiff.cpp | 4 +- src/xrpld/rpc/handlers/LedgerHandler.cpp | 8 +- src/xrpld/rpc/handlers/PayChanClaim.cpp | 4 +- src/xrpld/rpc/handlers/Tx.cpp | 2 +- src/xrpld/shamap/SHAMap.h | 15 +- src/xrpld/shamap/SHAMapItem.h | 6 +- src/xrpld/shamap/detail/SHAMap.cpp | 139 ++- src/xrpld/shamap/detail/SHAMapDelta.cpp | 12 +- src/xrpld/shamap/detail/SHAMapInnerNode.cpp | 103 +- src/xrpld/shamap/detail/SHAMapLeafNode.cpp | 19 +- src/xrpld/shamap/detail/SHAMapNodeID.cpp | 25 +- src/xrpld/shamap/detail/SHAMapSync.cpp | 24 +- src/xrpld/shamap/detail/TaggedPointer.ipp | 33 +- 261 files changed, 3852 insertions(+), 1038 deletions(-) create mode 100644 external/antithesis-sdk/.clang-format create mode 100644 external/antithesis-sdk/CMakeLists.txt create mode 100644 external/antithesis-sdk/LICENSE create mode 100644 external/antithesis-sdk/README.md create mode 100644 external/antithesis-sdk/antithesis_instrumentation.h create mode 100644 external/antithesis-sdk/antithesis_sdk.h create mode 100644 include/xrpl/beast/utility/instrumentation.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c34f89397d..49ecd192b7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,7 @@ set(SECP256K1_INSTALL TRUE) add_subdirectory(external/secp256k1) add_library(secp256k1::secp256k1 ALIAS secp256k1) add_subdirectory(external/ed25519-donna) +add_subdirectory(external/antithesis-sdk) find_package(gRPC REQUIRED) find_package(lz4 REQUIRED) # Target names with :: are not allowed in a generator expression. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ceca1eaa6fc..0609cd7f2e5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -343,6 +343,68 @@ pip3 install pre-commit pre-commit install ``` +## Contracts and instrumentation + +We are using [Antithesis](https://antithesis.com/) for continuous fuzzing, +and keep a copy of [Antithesis C++ SDK](https://github.com/antithesishq/antithesis-sdk-cpp/) +in `external/antithesis-sdk`. One of the aims of fuzzing is to identify bugs +by finding external conditions which cause contracts violations inside `rippled`. +The contracts are expressed as `ASSERT` or `UNREACHABLE` (defined in +`include/xrpl/beast/utility/instrumentation.h`), which are effectively (outside +of Antithesis) wrappers for `assert(...)` with added name. The purpose of name +is to provide contracts with stable identity which does not rely on line numbers. + +When `rippled` is built with the Antithesis instrumentation enabled +(using `voidstar` CMake option) and ran on the Antithesis platform, the +contracts become +[test properties](https://antithesis.com/docs/using_antithesis/properties.html); +otherwise they are just like a regular `assert`. +To learn more about Antithesis, see +[How Antithesis Works](https://antithesis.com/docs/introduction/how_antithesis_works.html) +and [C++ SDK](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html#) + +We continue to use the old style `assert` or `assert(false)` in certain +locations, where the reporting of contract violations on the Antithesis +platform is either not possible or not useful. + +For this reason: +* The locations where `assert` or `assert(false)` contracts should continue to be used: + * `constexpr` functions + * unit tests i.e. files under `src/test` + * unit tests-related modules (files under `beast/test` and `beast/unit_test`) +* Outside of the listed locations, do not use `assert`; use `ASSERT` instead, + giving it unique name, with the short description of the contract. +* Outside of the listed locations, do not use `assert(false)`; use + `UNREACHABLE` instead, giving it unique name, with the description of the + condition being violated +* The contract name should start with a full name (including scope) of the + function, optionally a named lambda, followed by a colon ` : ` and a brief + (typically at most five words) description. `UNREACHABLE` contracts + can use slightly longer descriptions. If there are multiple overloads of the + function, use common sense to balance both brevity and unambiguity of the + function name. NOTE: the purpose of name is to provide stable means of + unique identification of every contract; for this reason try to avoid elements + which can change in some obvious refactors or when reinforcing the condition. +* Contract description typically (except for `UNREACHABLE`) should describe the + _expected_ condition, as in "I assert that _expected_ is true". +* Contract description for `UNREACHABLE` should describe the _unexpected_ + situation which caused the line to have been reached. +* Example good name for an + `UNREACHABLE` macro `"Json::operator==(Value, Value) : invalid type"`; example + good name for an `ASSERT` macro `"Json::Value::asCString : valid type"`. +* Example **bad** name + `"RFC1751::insert(char* s, int x, int start, int length) : length is greater than or equal zero"` + (missing namespace, unnecessary full function signature, description too verbose). + Good name: `"ripple::RFC1751::insert : minimum length"`. +* In **few** well-justified cases a non-standard name can be used, in which case a + comment should be placed to explain the rationale (example in `contract.cpp`) +* Do **not** rename a contract without a good reason (e.g. the name no longer + reflects the location or the condition being checked) +* Do not use `std::unreachable` +* Do not put contracts where they can be violated by an external condition + (e.g. timing, data payload before mandatory validation etc.) as this creates + bogus bug reports (and causes crashes of Debug builds) + ## Unit Tests To execute all unit tests: diff --git a/cmake/RippledCompiler.cmake b/cmake/RippledCompiler.cmake index 43afc628bc3..7485605d950 100644 --- a/cmake/RippledCompiler.cmake +++ b/cmake/RippledCompiler.cmake @@ -120,7 +120,7 @@ else () target_link_libraries (common INTERFACE -rdynamic - $<$:-Wl,-z,relro,-z,now> + $<$:-Wl,-z,relro,-z,now,--build-id> # link to static libc/c++ iff: # * static option set and # * NOT APPLE (AppleClang does not support static libc/c++) and @@ -131,6 +131,17 @@ else () >) endif () +# Antithesis instrumentation will only be built and deployed using machines running Linux. +if (voidstar) + if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(FATAL_ERROR "Antithesis instrumentation requires Debug build type, aborting...") + elseif (NOT is_linux) + message(FATAL_ERROR "Antithesis instrumentation requires Linux, aborting...") + elseif (NOT (is_clang AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)) + message(FATAL_ERROR "Antithesis instrumentation requires Clang version 16 or later, aborting...") + endif () +endif () + if (use_mold) # use mold linker if available execute_process ( diff --git a/cmake/RippledCore.cmake b/cmake/RippledCore.cmake index 3b850354ed4..201384c3fcb 100644 --- a/cmake/RippledCore.cmake +++ b/cmake/RippledCore.cmake @@ -74,6 +74,7 @@ target_compile_definitions(xrpl.libxrpl target_compile_options(xrpl.libxrpl PUBLIC $<$:-Wno-maybe-uninitialized> + $<$:-DENABLE_VOIDSTAR> ) target_link_libraries(xrpl.libxrpl @@ -89,6 +90,7 @@ target_link_libraries(xrpl.libxrpl secp256k1::secp256k1 xrpl.libpb xxHash::xxhash + $<$:antithesis-sdk-cpp> ) if(xrpld) @@ -129,6 +131,19 @@ if(xrpld) target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI) endif () + if(voidstar) + target_compile_options(rippled + PRIVATE + -fsanitize-coverage=trace-pc-guard + ) + # rippled requires access to antithesis-sdk-cpp implementation file + # antithesis_instrumentation.h, which is not exported as INTERFACE + target_include_directories(rippled + PRIVATE + ${CMAKE_SOURCE_DIR}/external/antithesis-sdk + ) + endif() + # any files that don't play well with unity should be added here if(tests) set_source_files_properties( diff --git a/cmake/RippledInstall.cmake b/cmake/RippledInstall.cmake index 3199c9a19b8..229cc9b1c8a 100644 --- a/cmake/RippledInstall.cmake +++ b/cmake/RippledInstall.cmake @@ -10,6 +10,7 @@ install ( ripple_boost xrpl.libpb xrpl.libxrpl + antithesis-sdk-cpp EXPORT RippleExports LIBRARY DESTINATION lib ARCHIVE DESTINATION lib diff --git a/cmake/RippledSettings.cmake b/cmake/RippledSettings.cmake index b81843cd5b5..3eeebed428c 100644 --- a/cmake/RippledSettings.cmake +++ b/cmake/RippledSettings.cmake @@ -18,6 +18,9 @@ if(unity) set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "") endif() endif() +if(is_clang AND is_linux) + option(voidstar "Enable Antithesis instrumentation." OFF) +endif() if(is_gcc OR is_clang) option(coverage "Generates coverage info." OFF) option(profile "Add profiling flags" OFF) diff --git a/external/README.md b/external/README.md index 25ae577ba58..c810539fd7d 100644 --- a/external/README.md +++ b/external/README.md @@ -6,6 +6,7 @@ The Conan recipes include patches we have not yet pushed upstream. | Folder | Upstream | Description | |:----------------|:---------------------------------------------|:------------| +| `antithesis-sdk`| [Project](https://github.com/antithesishq/antithesis-sdk-cpp/) | [Antithesis](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html) SDK for C++ | | `ed25519-donna` | [Project](https://github.com/floodyberry/ed25519-donna) | [Ed25519](http://ed25519.cr.yp.to/) digital signatures | | `rocksdb` | [Recipe](https://github.com/conan-io/conan-center-index/tree/master/recipes/rocksdb) | Fast key/value database. (Supports rotational disks better than NuDB.) | | `secp256k1` | [Project](https://github.com/bitcoin-core/secp256k1) | ECDSA digital signatures using the **secp256k1** curve | diff --git a/external/antithesis-sdk/.clang-format b/external/antithesis-sdk/.clang-format new file mode 100644 index 00000000000..e871ed18b43 --- /dev/null +++ b/external/antithesis-sdk/.clang-format @@ -0,0 +1,3 @@ +--- +DisableFormat: true +SortIncludes: false diff --git a/external/antithesis-sdk/CMakeLists.txt b/external/antithesis-sdk/CMakeLists.txt new file mode 100644 index 00000000000..b7fa22de107 --- /dev/null +++ b/external/antithesis-sdk/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.25) + +# Note, version set explicitly by rippled project +project(antithesis-sdk-cpp VERSION 0.4.2 LANGUAGES CXX) + +add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h) + +# Note, both sections below created by rippled project +target_include_directories(antithesis-sdk-cpp INTERFACE + $ + $ +) + +install( + FILES antithesis_sdk.h + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) diff --git a/external/antithesis-sdk/LICENSE b/external/antithesis-sdk/LICENSE new file mode 100644 index 00000000000..90f1712ed1a --- /dev/null +++ b/external/antithesis-sdk/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Antithesis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/external/antithesis-sdk/README.md b/external/antithesis-sdk/README.md new file mode 100644 index 00000000000..ce512d7c6fd --- /dev/null +++ b/external/antithesis-sdk/README.md @@ -0,0 +1,8 @@ +# Antithesis C++ SDK + +This library provides methods for C++ programs to configure the [Antithesis](https://antithesis.com) platform. It contains three kinds of functionality: +* Assertion macros that allow you to define test properties about your software or workload. +* Randomness functions for requesting both structured and unstructured randomness from the Antithesis platform. +* Lifecycle functions that inform the Antithesis environment that particular test phases or milestones have been reached. + +For general usage guidance see the [Antithesis C++ SDK Documentation](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html) diff --git a/external/antithesis-sdk/antithesis_instrumentation.h b/external/antithesis-sdk/antithesis_instrumentation.h new file mode 100644 index 00000000000..a2e88dbef5d --- /dev/null +++ b/external/antithesis-sdk/antithesis_instrumentation.h @@ -0,0 +1,113 @@ +#pragma once + +/* +This header file enables code coverage instrumentation. It is distributed with the Antithesis C++ SDK. + +This header file can be used in both C and C++ programs. (The rest of the SDK works only for C++ programs.) + +You should include it in a single .cpp or .c file. + +The instructions (such as required compiler flags) and usage guidance are found at https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html. +*/ + +#include +#include +#include +#include +#include +#ifndef __cplusplus +#include +#include +#endif + +// If the libvoidstar(determ) library is present, +// pass thru trace_pc_guard related callbacks to it +typedef void (*trace_pc_guard_init_fn)(uint32_t *start, uint32_t *stop); +typedef void (*trace_pc_guard_fn)(uint32_t *guard, uint64_t edge); + +static trace_pc_guard_init_fn trace_pc_guard_init = NULL; +static trace_pc_guard_fn trace_pc_guard = NULL; +static bool did_check_libvoidstar = false; +static bool has_libvoidstar = false; + +static __attribute__((no_sanitize("coverage"))) void debug_message_out(const char *msg) { + (void)printf("%s\n", msg); + return; +} + +extern +#ifdef __cplusplus + "C" +#endif +__attribute__((no_sanitize("coverage"))) void antithesis_load_libvoidstar() { +#ifdef __cplusplus + constexpr +#endif + const char* LIB_PATH = "/usr/lib/libvoidstar.so"; + + if (did_check_libvoidstar) { + return; + } + debug_message_out("TRYING TO LOAD libvoidstar"); + did_check_libvoidstar = true; + void* shared_lib = dlopen(LIB_PATH, RTLD_NOW); + if (!shared_lib) { + debug_message_out("Can not load the Antithesis native library"); + return; + } + + void* trace_pc_guard_init_sym = dlsym(shared_lib, "__sanitizer_cov_trace_pc_guard_init"); + if (!trace_pc_guard_init_sym) { + debug_message_out("Can not forward calls to libvoidstar for __sanitizer_cov_trace_pc_guard_init"); + return; + } + + void* trace_pc_guard_sym = dlsym(shared_lib, "__sanitizer_cov_trace_pc_guard_internal"); + if (!trace_pc_guard_sym) { + debug_message_out("Can not forward calls to libvoidstar for __sanitizer_cov_trace_pc_guard"); + return; + } + + trace_pc_guard_init = (trace_pc_guard_init_fn)(trace_pc_guard_init_sym); + trace_pc_guard = (trace_pc_guard_fn)(trace_pc_guard_sym); + has_libvoidstar = true; + debug_message_out("LOADED libvoidstar"); +} + +// The following symbols are indeed reserved identifiers, since we're implementing functions defined +// in the compiler runtime. Not clear how to get Clang on board with that besides narrowly suppressing +// the warning in this case. The sample code on the CoverageSanitizer documentation page fails this +// warning! +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-identifier" +extern +#ifdef __cplusplus + "C" +#endif +void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { + debug_message_out("SDK forwarding to libvoidstar for __sanitizer_cov_trace_pc_guard_init()"); + if (!did_check_libvoidstar) { + antithesis_load_libvoidstar(); + } + if (has_libvoidstar) { + trace_pc_guard_init(start, stop); + } + return; +} + +extern +#ifdef __cplusplus + "C" +#endif +void __sanitizer_cov_trace_pc_guard( uint32_t *guard ) { + if (has_libvoidstar) { + uint64_t edge = (uint64_t)(__builtin_return_address(0)); + trace_pc_guard(guard, edge); + } else { + if (guard) { + *guard = 0; + } + } + return; +} +#pragma clang diagnostic pop diff --git a/external/antithesis-sdk/antithesis_sdk.h b/external/antithesis-sdk/antithesis_sdk.h new file mode 100644 index 00000000000..f6ed8e52d33 --- /dev/null +++ b/external/antithesis-sdk/antithesis_sdk.h @@ -0,0 +1,1093 @@ +#pragma once + +// This header file contains the Antithesis C++ SDK, which enables C++ applications to integrate with the [Antithesis platform]. +// +// Documentation for the SDK is found at https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html. + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace antithesis { + inline const char* SDK_VERSION = "0.4.0"; + inline const char* PROTOCOL_VERSION = "1.1.0"; + + struct LocalRandom { + std::random_device device; + std::mt19937_64 gen; + std::uniform_int_distribution distribution; + + LocalRandom() : device(), gen(device()), distribution() {} + + uint64_t random() { +#ifdef ANTITHESIS_RANDOM_OVERRIDE + return ANTITHESIS_RANDOM_OVERRIDE(); +#else + return distribution(gen); +#endif + } + }; + + struct JSON; struct JSONArray; + typedef std::variant JSONValue; + + struct JSONArray : std::vector { + using std::vector::vector; + + template::value, bool>::type = true> + JSONArray(std::vector vals) : std::vector(vals.begin(), vals.end()) {} + }; + + struct JSON : std::map { + JSON() : std::map() {} + JSON( std::initializer_list> args) : std::map(args) {} + + JSON( std::initializer_list> args, std::vector> more_args ) : std::map(args) { + for (auto& pair : more_args) { + (*this)[pair.first] = pair.second; + } + } + }; + + // Declarations that we expose + uint64_t get_random(); +} + +#if defined(NO_ANTITHESIS_SDK) || __cplusplus < 202000L || (defined(__clang__) && __clang_major__ < 16) + +#if __cplusplus < 202000L + #error "The Antithesis C++ API requires C++20 or higher" +#endif +#if defined(__clang__) && __clang_major__ < 16 + #error "The Antithesis C++ API requires clang version 16 or higher" +#endif + +#define ALWAYS(cond, message, ...) +#define ALWAYS_OR_UNREACHABLE(cond, message, ...) +#define SOMETIMES(cond, message, ...) +#define REACHABLE(message, ...) +#define UNREACHABLE(message, ...) +#define ALWAYS_GREATER_THAN(val, threshold, message, ...) +#define ALWAYS_GREATER_THAN_OR_EQUAL_TO(val, threshold, message, ...) +#define SOMETIMES_GREATER_THAN(val, threshold, message, ...) +#define SOMETIMES_GREATER_THAN_OR_EQUAL_TO(val, threshold, message, ...) +#define ALWAYS_LESS_THAN(val, threshold, message, ...) +#define ALWAYS_LESS_THAN_OR_EQUAL_TO(val, threshold, message, ...) +#define SOMETIMES_LESS_THAN(val, threshold, message, ...) +#define SOMETIMES_LESS_THAN_OR_EQUAL_TO(val, threshold, message, ...) +#define ALWAYS_SOME(pairs, message, ...) +#define SOMETIMES_ALL(pairs, message, ...) + +namespace antithesis { + inline uint64_t get_random() { + static LocalRandom random_gen; + return random_gen.random(); + } + + inline void setup_complete(const JSON& details) { + } + + inline void send_event(const char* name, const JSON& details) { + } +} + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace antithesis { + constexpr const char* const ERROR_LOG_LINE_PREFIX = "[* antithesis-sdk-cpp *]"; + constexpr const char* LIB_PATH = "/usr/lib/libvoidstar.so"; + constexpr const char* LOCAL_OUTPUT_ENVIRONMENT_VARIABLE = "ANTITHESIS_SDK_LOCAL_OUTPUT"; + + static std::ostream& operator<<(std::ostream& out, const JSON& details); + + struct LibHandler { + virtual ~LibHandler() = default; + virtual void output(const char* message) const = 0; + virtual uint64_t random() = 0; + + void output(const JSON& json) const { + std::ostringstream out; + out << json; + output(out.str().c_str()); + } + }; + + struct AntithesisHandler : LibHandler { + void output(const char* message) const override { + if (message != nullptr) { + fuzz_json_data(message, strlen(message)); + fuzz_flush(); + } + } + + uint64_t random() override { + return fuzz_get_random(); + } + + static std::unique_ptr create() { + void* shared_lib = dlopen(LIB_PATH, RTLD_NOW); + if (!shared_lib) { + error("Can not load the Antithesis native library"); + return nullptr; + } + + void* fuzz_json_data = dlsym(shared_lib, "fuzz_json_data"); + if (!fuzz_json_data) { + error("Can not access symbol fuzz_json_data"); + return nullptr; + } + + void* fuzz_flush = dlsym(shared_lib, "fuzz_flush"); + if (!fuzz_flush) { + error("Can not access symbol fuzz_flush"); + return nullptr; + } + + void* fuzz_get_random = dlsym(shared_lib, "fuzz_get_random"); + if (!fuzz_get_random) { + error("Can not access symbol fuzz_get_random"); + return nullptr; + } + + return std::unique_ptr(new AntithesisHandler( + reinterpret_cast(fuzz_json_data), + reinterpret_cast(fuzz_flush), + reinterpret_cast(fuzz_get_random))); + } + + private: + typedef void (*fuzz_json_data_t)( const char* message, size_t length ); + typedef void (*fuzz_flush_t)(); + typedef uint64_t (*fuzz_get_random_t)(); + + + fuzz_json_data_t fuzz_json_data; + fuzz_flush_t fuzz_flush; + fuzz_get_random_t fuzz_get_random; + + AntithesisHandler(fuzz_json_data_t fuzz_json_data, fuzz_flush_t fuzz_flush, fuzz_get_random_t fuzz_get_random) : + fuzz_json_data(fuzz_json_data), fuzz_flush(fuzz_flush), fuzz_get_random(fuzz_get_random) {} + + static void error(const char* message) { + fprintf(stderr, "%s %s: %s\n", ERROR_LOG_LINE_PREFIX, message, dlerror()); + } + }; + + struct LocalHandler : LibHandler{ + ~LocalHandler() override { + if (file != nullptr) { + fclose(file); + } + } + + void output(const char* message) const override { + if (file != nullptr && message != nullptr) { + fprintf(file, "%s\n", message); + } + } + + uint64_t random() override { + return random_gen.random(); + } + + static std::unique_ptr create() { + return std::unique_ptr(new LocalHandler(create_internal())); + } + private: + FILE* file; + LocalRandom random_gen; + + LocalHandler(FILE* file): file(file), random_gen() { + } + + // If `localOutputEnvVar` is set to a non-empty path, attempt to open that path and truncate the file + // to serve as the log file of the local handler. + // Otherwise, we don't have a log file, and logging is a no-op in the local handler. + static FILE* create_internal() { + const char* path = std::getenv(LOCAL_OUTPUT_ENVIRONMENT_VARIABLE); + if (!path || !path[0]) { + return nullptr; + } + + // Open the file for writing (create if needed and possible) and truncate it + FILE* file = fopen(path, "w"); + if (file == nullptr) { + fprintf(stderr, "%s Failed to open path %s: %s\n", ERROR_LOG_LINE_PREFIX, path, strerror(errno)); + return nullptr; + } + int ret = fchmod(fileno(file), 0644); + if (ret != 0) { + fprintf(stderr, "%s Failed to set permissions for path %s: %s\n", ERROR_LOG_LINE_PREFIX, path, strerror(errno)); + fclose(file); + return nullptr; + } + + return file; + } + }; + + static std::unique_ptr init() { + struct stat stat_buf; + if (stat(LIB_PATH, &stat_buf) == 0) { + std::unique_ptr tmp = AntithesisHandler::create(); + if (!tmp) { + fprintf(stderr, "%s Failed to create handler for Antithesis library\n", ERROR_LOG_LINE_PREFIX); + exit(-1); + } + return tmp; + } else { + return LocalHandler::create(); + } + } + + struct AssertionState { + uint8_t false_not_seen : 1; + uint8_t true_not_seen : 1; + uint8_t rest : 6; + + AssertionState() : false_not_seen(true), true_not_seen(true), rest(0) {} + }; + + template + inline constexpr bool always_false_v = false; + + static std::ostream& operator<<(std::ostream& out, const JSONValue& json) { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) { + out << std::quoted(arg); + } else if constexpr (std::is_same_v) { + out << (arg ? "true" : "false"); + } else if constexpr (std::is_same_v) { + char tmp[2] = {arg, '\0'}; + out << std::quoted(tmp); + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << std::quoted(arg); + } else if constexpr (std::is_same_v) { + out << "null"; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << '['; + bool first = true; + for (auto &item : arg) { + if (!first) { + out << ','; + } + first = false; + out << item; + } + out << ']'; + } else { + static_assert(always_false_v, "non-exhaustive JSONValue visitor!"); + } + }, json); + + return out; + } + + static std::ostream& operator<<(std::ostream& out, const JSON& details) { + out << '{'; + + bool first = true; + for (auto [key, value] : details) { + if (!first) { + out << ','; + } + out << std::quoted(key) << ':' << value; + first = false; + } + + out << '}'; + return out; + } + + enum AssertionType { + ALWAYS_ASSERTION, + ALWAYS_OR_UNREACHABLE_ASSERTION, + SOMETIMES_ASSERTION, + REACHABLE_ASSERTION, + UNREACHABLE_ASSERTION, + }; + + inline constexpr bool get_must_hit(AssertionType type) { + switch (type) { + case ALWAYS_ASSERTION: + case SOMETIMES_ASSERTION: + case REACHABLE_ASSERTION: + return true; + case ALWAYS_OR_UNREACHABLE_ASSERTION: + case UNREACHABLE_ASSERTION: + return false; + } + } + + inline constexpr const char* get_assert_type_string(AssertionType type) { + switch (type) { + case ALWAYS_ASSERTION: + case ALWAYS_OR_UNREACHABLE_ASSERTION: + return "always"; + case SOMETIMES_ASSERTION: + return "sometimes"; + case REACHABLE_ASSERTION: + case UNREACHABLE_ASSERTION: + return "reachability"; + } + } + + inline constexpr const char* get_display_type_string(AssertionType type) { + switch (type) { + case ALWAYS_ASSERTION: return "Always"; + case ALWAYS_OR_UNREACHABLE_ASSERTION: return "AlwaysOrUnreachable"; + case SOMETIMES_ASSERTION: return "Sometimes"; + case REACHABLE_ASSERTION: return "Reachable"; + case UNREACHABLE_ASSERTION: return "Unreachable"; + } + } + + struct LocationInfo { + const char* class_name; + const char* function_name; + const char* file_name; + const int line; + const int column; + + JSON to_json() const { + return JSON{ + {"class", class_name}, + {"function", function_name}, + {"file", file_name}, + {"begin_line", line}, + {"begin_column", column}, + }; + } + }; + + inline std::string make_key([[maybe_unused]] const char* message, const LocationInfo& location_info) { + return message; + } + + inline LibHandler& get_lib_handler() { + static LibHandler* lib_handler = nullptr; + if (lib_handler == nullptr) { + lib_handler = init().release(); // Leak on exit, rather than exit-time-destructor + + JSON language_block{ + {"name", "C++"}, + {"version", __VERSION__} + }; + + JSON version_message{ + {"antithesis_sdk", JSON{ + {"language", language_block}, + {"sdk_version", SDK_VERSION}, + {"protocol_version", PROTOCOL_VERSION} + } + }}; + lib_handler->output(version_message); + } + + return *lib_handler; + } + + inline void assert_impl(bool cond, const char* message, const JSON& details, const LocationInfo& location_info, + bool hit, bool must_hit, const char* assert_type, const char* display_type, const char* id) { + JSON assertion{ + {"antithesis_assert", JSON{ + {"hit", hit}, + {"must_hit", must_hit}, + {"assert_type", assert_type}, + {"display_type", display_type}, + {"message", message}, + {"condition", cond}, + {"id", id}, + {"location", location_info.to_json()}, + {"details", details}, + }} + }; + get_lib_handler().output(assertion); + } + + inline void assert_raw(bool cond, const char* message, const JSON& details, + const char* class_name, const char* function_name, const char* file_name, const int line, const int column, + bool hit, bool must_hit, const char* assert_type, const char* display_type, const char* id) { + LocationInfo location_info{ class_name, function_name, file_name, line, column }; + assert_impl(cond, message, details, location_info, hit, must_hit, assert_type, display_type, id); + } + + typedef std::set CatalogEntryTracker; + + inline CatalogEntryTracker& get_catalog_entry_tracker() { + static CatalogEntryTracker catalog_entry_tracker; + return catalog_entry_tracker; + } + + struct Assertion { + AssertionState state; + AssertionType type; + const char* message; + LocationInfo location; + + Assertion(const char* message, AssertionType type, LocationInfo&& location) : + state(), type(type), message(message), location(std::move(location)) { + this->add_to_catalog(); + } + + void add_to_catalog() const { + std::string id = make_key(message, location); + CatalogEntryTracker& tracker = get_catalog_entry_tracker(); + if (!tracker.contains(id)) { + tracker.insert(id); + const bool condition = (type == REACHABLE_ASSERTION ? true : false); + const bool hit = false; + const char* assert_type = get_assert_type_string(type); + const bool must_hit = get_must_hit(type); + const char* display_type = get_display_type_string(type); + assert_impl(condition, message, {}, location, hit, must_hit, assert_type, display_type, id.c_str()); + } + } + + [[clang::always_inline]] inline void check_assertion(bool cond, const JSON& details) { + #if defined(NO_ANTITHESIS_SDK) + #error "Antithesis SDK has been disabled" + #endif + if (__builtin_expect(state.false_not_seen || state.true_not_seen, false)) { + check_assertion_internal(cond, details); + } + } + + private: + void check_assertion_internal(bool cond, const JSON& details) { + bool emit = false; + if (!cond && state.false_not_seen) { + emit = true; + state.false_not_seen = false; // TODO: is the race OK? + } + + if (cond && state.true_not_seen) { + emit = true; + state.true_not_seen = false; // TODO: is the race OK? + } + + if (emit) { + const bool hit = true; + const char* assert_type = get_assert_type_string(type); + const bool must_hit = get_must_hit(type); + const char* display_type = get_display_type_string(type); + std::string id = make_key(message, location); + assert_impl(cond, message, details, location, hit, must_hit, assert_type, display_type, id.c_str()); + } + } + }; + + inline uint64_t get_random() { + return get_lib_handler().random(); + } + + inline void setup_complete(const JSON& details) { + JSON json{ + { "antithesis_setup", JSON{ + {"status", "complete"}, + {"details", details} + }} + }; + get_lib_handler().output(json); + } + + inline void send_event(const char* name, const JSON& details) { + JSON json = { { name, details } }; + get_lib_handler().output(json); + } + + enum GuidepostType { + GUIDEPOST_MAXIMIZE, + GUIDEPOST_MINIMIZE, + GUIDEPOST_EXPLORE, + GUIDEPOST_ALL, + GUIDEPOST_NONE + }; + + inline constexpr const char* get_guidance_type_string(GuidepostType type) { + switch (type) { + case GUIDEPOST_MAXIMIZE: + case GUIDEPOST_MINIMIZE: + return "numeric"; + case GUIDEPOST_ALL: + case GUIDEPOST_NONE: + return "boolean"; + case GUIDEPOST_EXPLORE: + return "json"; + } + } + + inline constexpr bool does_guidance_maximize(GuidepostType type) { + switch (type) { + case GUIDEPOST_MAXIMIZE: + case GUIDEPOST_ALL: + return true; + case GUIDEPOST_EXPLORE: + case GUIDEPOST_MINIMIZE: + case GUIDEPOST_NONE: + return false; + } + } + + template > + struct NumericGuidepost { + const char* message; + LocationInfo location; + GuidepostType type; + // an approximation of (left - right) / 2; contains an absolute value and a sign bit + std::pair extreme_half_gap; + + NumericGuidepost(const char* message, LocationInfo&& location, GuidepostType type) : + message(message), location(std::move(location)), type(type) { + this->add_to_catalog(); + if (type == GUIDEPOST_MAXIMIZE) { + extreme_half_gap = { std::numeric_limits::max(), false }; + } else { + extreme_half_gap = { std::numeric_limits::max(), true }; + } + } + + inline void add_to_catalog() { + std::string id = make_key(message, location); + JSON catalog{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(type)}, + {"message", message}, + {"id", id}, + {"location", location.to_json()}, + {"maximize", does_guidance_maximize(type)}, + {"hit", false} + }} + }; + get_lib_handler().output(catalog); + } + + std::pair compute_half_gap(NumericValue left, NumericValue right) { + // An extremely baroque way to compute (left - right) / 2, rounded toward 0, without overflowing or underflowing + if (std::is_integral_v) { + // If both numbers are odd then the gap doesn't change if we subtract 1 from both sides + // Also subtracting 1 from both sides won't underflow + if (left % 2 == 1 && right % 2 == 1) + return compute_half_gap( left - 1, right - 1); + // If one number is odd then we subtract 1 from the larger number + // This rounds the computation toward 0 but again won't underflow + if (left % 2 == 1 || right % 2 == 1) { + if (left > right) { + return compute_half_gap( left - 1, right ); + } else { + return compute_half_gap( left, right - 1 ); + } + } + // At this point both numbers are even, so the midpoint calculation is exact + NumericValue half_left = left / 2; + NumericValue half_right = right / 2; + NumericValue midpoint = half_left + half_right; + // This won't overflow or underflow because we're subtracting the midpoint + // We compute a positive value and a sign so that we don't have to do weird things with unsigned types + if (left > right) { + return { midpoint - right, true }; + } else { + return { right - midpoint, false }; + } + } else { + // If it's floating point we don't need to worry about overflowing, just do the arithmetic + return { left > right ? (left - right) / 2 : (right - left) / 2, left > right }; + } + } + + bool should_send_value(std::pair half_gap) { + if (this->type == GUIDEPOST_MAXIMIZE) { + if (half_gap.second && !extreme_half_gap.second) { + // we're positive and the extreme value isn't; always send back + return true; + } else if (!half_gap.second && extreme_half_gap.second) { + // we're negative and the extreme value is positive; never send back + return false; + } else if (half_gap.second && extreme_half_gap.second) { + // both positive; send back if our absolute value is at least as large + return half_gap.first >= extreme_half_gap.first; + } else { + // both negative; send back if our absolute value is at least as small + return half_gap.first <= extreme_half_gap.first; + } + } else { + if (half_gap.second && !extreme_half_gap.second) { + // we're positive and the extreme value isn't; never send back + return false; + } else if (!half_gap.second && extreme_half_gap.second) { + // we're negative and the extreme value is positive; always send back + return true; + } else if (half_gap.second && extreme_half_gap.second) { + // both positive; send back if our absolute value is at least as small + return half_gap.first <= extreme_half_gap.first; + } else { + // both negative; send back if our absolute value is at least as large + return half_gap.first >= extreme_half_gap.first; + } + } + } + + [[clang::always_inline]] inline void send_guidance(Value value) { + std::pair half_gap = compute_half_gap(value.first, value.second); + if (should_send_value(half_gap)) { + extreme_half_gap = half_gap; + std::string id = make_key(this->message, this->location); + JSON guidance{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(this->type)}, + {"message", this->message}, + {"id", id}, + {"location", this->location.to_json()}, + {"maximize", does_guidance_maximize(this->type)}, + {"guidance_data", JSON{ + { "left", value.first }, + { "right", value.second } }}, + {"hit", true} + }} + }; + get_lib_handler().output(guidance); + } + } + }; + + template + struct BooleanGuidepost { + const char* message; + LocationInfo location; + GuidepostType type; + + BooleanGuidepost(const char* message, LocationInfo&& location, GuidepostType type) : + message(message), location(std::move(location)), type(type) { + this->add_to_catalog(); + } + + inline void add_to_catalog() { + std::string id = make_key(message, location); + JSON catalog{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(type)}, + {"message", message}, + {"id", id}, + {"location", location.to_json()}, + {"maximize", does_guidance_maximize(type)}, + {"hit", false} + }} + }; + get_lib_handler().output(catalog); + } + + inline virtual void send_guidance(GuidanceType data) { + std::string id = make_key(this->message, this->location); + JSON guidance{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(this->type)}, + {"message", this->message}, + {"id", id}, + {"location", location.to_json()}, + {"maximize", does_guidance_maximize(this->type)}, + {"guidance_data", data}, + {"hit", true} + }} + }; + get_lib_handler().output(guidance); + } + }; +} + +namespace { + template + struct fixed_string { + std::array contents; + constexpr fixed_string() { + for(unsigned int i=0; i from_c_str( const char* s ) { + fixed_string it; + for(unsigned int i=0; i + fixed_string( const char (&arr)[N] ) -> fixed_string; + + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" + static constexpr size_t string_length( const char * s ) { + for(int l = 0; ; l++) + if (!s[l]) + return l; + } + #pragma clang diagnostic pop + + template + struct CatalogEntry { + [[clang::always_inline]] static inline antithesis::Assertion create() { + antithesis::LocationInfo location{ "", function_name.c_str(), file_name.c_str(), line, column }; + return antithesis::Assertion(message.c_str(), type, std::move(location)); + } + + static inline antithesis::Assertion assertion = create(); + }; + + template + struct BooleanGuidanceCatalogEntry { + [[clang::always_inline]] static inline antithesis::BooleanGuidepost create() { + antithesis::LocationInfo location{ "", function_name.c_str(), file_name.c_str(), line, column }; + switch (type) { + case antithesis::GUIDEPOST_ALL: + case antithesis::GUIDEPOST_NONE: + return antithesis::BooleanGuidepost(message.c_str(), std::move(location), type); + default: + throw std::runtime_error("Can't create boolean guidepost with non-boolean type"); + } + } + + static inline antithesis::BooleanGuidepost guidepost = create(); + }; + + template + struct NumericGuidanceCatalogEntry { + [[clang::always_inline]] static inline antithesis::NumericGuidepost create() { + antithesis::LocationInfo location{ "", function_name.c_str(), file_name.c_str(), line, column }; + switch (type) { + case antithesis::GUIDEPOST_MAXIMIZE: + case antithesis::GUIDEPOST_MINIMIZE: + return antithesis::NumericGuidepost(message.c_str(), std::move(location), type); + default: + throw std::runtime_error("Can't create numeric guidepost with non-numeric type"); + } + } + + static inline antithesis::NumericGuidepost guidepost = create(); + }; +} + +#define FIXED_STRING_FROM_C_STR(s) (fixed_string::from_c_str(s)) + +#define _NL_1(foo) { #foo, foo } +#define _NL_2(foo, ...) { #foo, foo }, _NL_1(__VA_ARGS__) +#define _NL_3(foo, ...) { #foo, foo }, _NL_2(__VA_ARGS__) +#define _NL_4(foo, ...) { #foo, foo }, _NL_3(__VA_ARGS__) +#define _NL_5(foo, ...) { #foo, foo }, _NL_4(__VA_ARGS__) +#define _NL_6(foo, ...) { #foo, foo }, _NL_5(__VA_ARGS__) +#define _NL_7(foo, ...) { #foo, foo }, _NL_6(__VA_ARGS__) +#define _NL_8(foo, ...) { #foo, foo }, _NL_7(__VA_ARGS__) +#define _NL_9(foo, ...) { #foo, foo }, _NL_8(__VA_ARGS__) +#define _NL_10(foo, ...) { #foo, foo }, _NL_9(__VA_ARGS__) + +#define _ELEVENTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define _GET_NL(...) \ + _ELEVENTH_ARG(__VA_ARGS__, _NL_10, _NL_9, _NL_8, _NL_7, _NL_6, _NL_5, _NL_4, _NL_3, _NL_2, _NL_1) + +#define NAMED_LIST(...) { _GET_NL(__VA_ARGS__)(__VA_ARGS__) } + +#define ANTITHESIS_ASSERT_RAW(type, cond, message, ...) ( \ + CatalogEntry< \ + type, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(cond, (antithesis::JSON(__VA_ARGS__)) ) ) + +#define ALWAYS(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::ALWAYS_ASSERTION, cond, message, __VA_ARGS__) +#define ALWAYS_OR_UNREACHABLE(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::ALWAYS_OR_UNREACHABLE_ASSERTION, cond, message, __VA_ARGS__) +#define SOMETIMES(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::SOMETIMES_ASSERTION, cond, message, __VA_ARGS__) +#define REACHABLE(message, ...) ANTITHESIS_ASSERT_RAW(antithesis::REACHABLE_ASSERTION, true, message, __VA_ARGS__) +#define UNREACHABLE(message, ...) ANTITHESIS_ASSERT_RAW(antithesis::UNREACHABLE_ASSERTION, false, message, __VA_ARGS__) + +#define ALWAYS_GREATER_THAN(left, right, message, ...) \ +do { \ + static_assert(std::is_same_v, "Values compared in ALWAYS_GREATER_THAN must be of same type"); \ + CatalogEntry< \ + antithesis::ALWAYS_ASSERTION, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(left > right, (antithesis::JSON(__VA_ARGS__, {{ "left", left }, { "right", right }})) ); \ + NumericGuidanceCatalogEntry< \ + decltype(left), \ + antithesis::GUIDEPOST_MINIMIZE, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance({ left, right }); \ +} while (0) + +#define ALWAYS_GREATER_THAN_OR_EQUAL_TO(left, right, message, ...) \ +do { \ + static_assert(std::is_same_v, "Values compared in ALWAYS_GREATER_THAN_OR_EQUAL_TO must be of same type"); \ + CatalogEntry< \ + antithesis::ALWAYS_ASSERTION, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(left >= right, (antithesis::JSON(__VA_ARGS__, {{ "left", left }, { "right", right }})) ); \ + NumericGuidanceCatalogEntry< \ + decltype(left), \ + antithesis::GUIDEPOST_MINIMIZE, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance({ left, right }); \ +} while (0) + +#define SOMETIMES_GREATER_THAN(left, right, message, ...) \ +do { \ + static_assert(std::is_same_v, "Values compared in SOMETIMES_GREATER_THAN must be of same type"); \ + CatalogEntry< \ + antithesis::SOMETIMES_ASSERTION, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(left > right, (antithesis::JSON(__VA_ARGS__, {{ "left", left }, { "right", right }})) ); \ + NumericGuidanceCatalogEntry< \ + decltype(left), \ + antithesis::GUIDEPOST_MAXIMIZE, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance({ left, right }); \ +} while (0) + +#define SOMETIMES_GREATER_THAN_OR_EQUAL_TO(left, right, message, ...) \ +do { \ + static_assert(std::is_same_v, "Values compared in SOMETIMES_GREATER_THAN_OR_EQUAL_TO must be of same type"); \ + CatalogEntry< \ + antithesis::SOMETIMES_ASSERTION, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(left >= right, (antithesis::JSON(__VA_ARGS__, {{ "left", left }, { "right", right }})) ); \ + NumericGuidanceCatalogEntry< \ + decltype(left), \ + antithesis::GUIDEPOST_MAXIMIZE, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance({ left, right }); \ +} while (0) + +#define ALWAYS_LESS_THAN(left, right, message, ...) \ +do { \ + static_assert(std::is_same_v, "Values compared in ALWAYS_LESS_THAN must be of same type"); \ + CatalogEntry< \ + antithesis::ALWAYS_ASSERTION, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(left < right, (antithesis::JSON(__VA_ARGS__, {{ "left", left }, { "right", right }})) ); \ + NumericGuidanceCatalogEntry< \ + decltype(left), \ + antithesis::GUIDEPOST_MAXIMIZE, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance({ left, right }); \ +} while (0) + +#define ALWAYS_LESS_THAN_OR_EQUAL_TO(left, right, message, ...) \ +do { \ + static_assert(std::is_same_v, "Values compared in ALWAYS_LESS_THAN_OR_EQUAL_TO must be of same type"); \ + CatalogEntry< \ + antithesis::ALWAYS_ASSERTION, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(left <= right, (antithesis::JSON(__VA_ARGS__, {{ "left", left }, { "right", right }})) ); \ + NumericGuidanceCatalogEntry< \ + decltype(left), \ + antithesis::GUIDEPOST_MAXIMIZE, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance({ left, right }); \ +} while (0) + +#define SOMETIMES_LESS_THAN(left, right, message, ...) \ +do { \ + static_assert(std::is_same_v, "Values compared in SOMETIMES_LESS_THAN must be of same type"); \ + CatalogEntry< \ + antithesis::SOMETIMES_ASSERTION, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(left < right, (antithesis::JSON(__VA_ARGS__, {{ "left", left }, { "right", right }})) ); \ + NumericGuidanceCatalogEntry< \ + decltype(left), \ + antithesis::GUIDEPOST_MINIMIZE, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance({ left, right }); \ +} while (0) + +#define SOMETIMES_LESS_THAN_OR_EQUAL_TO(left, right, message, ...) \ +do { \ + static_assert(std::is_same_v, "Values compared in SOMETIMES_LESS_THAN_OR_EQUAL_TO must be of same type"); \ + CatalogEntry< \ + antithesis::SOMETIMES_ASSERTION, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(left <= right, (antithesis::JSON(__VA_ARGS__, {{ "left", left }, { "right", right }})) ); \ + NumericGuidanceCatalogEntry< \ + decltype(left), \ + antithesis::GUIDEPOST_MINIMIZE, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance({ left, right }); \ +} while (0) + +#define ALWAYS_SOME(pairs, message, ...) \ +do { \ + bool disjunction = false; \ + for (std::pair pair : pairs) { \ + if (pair.second) { \ + disjunction = true; \ + break; \ + } \ + } \ + CatalogEntry< \ + antithesis::ALWAYS_ASSERTION, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(disjunction, (antithesis::JSON(__VA_ARGS__, pairs)) ); \ + antithesis::json json_pairs = antithesis::json(pairs); \ + BooleanGuidanceCatalogEntry< \ + decltype(json_pairs), \ + antithesis::GUIDEPOST_NONE, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance(json_pairs); \ +} while (0) + +#define SOMETIMES_ALL(pairs, message, ...) \ +do { \ + bool conjunction = true; \ + for (std::pair pair : pairs) { \ + if (!pair.second) { \ + conjunction = false; \ + break; \ + } \ + } \ + CatalogEntry< \ + antithesis::SOMETIMES_ASSERTION, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(conjunction, (antithesis::JSON(__VA_ARGS__, pairs)) ); \ + antithesis::json json_pairs = antithesis::json(pairs); \ + BooleanGuidanceCatalogEntry< \ + decltype(json_pairs), \ + antithesis::GUIDEPOST_ALL, \ + fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance(json_pairs); \ +} while (0) + +#endif + +namespace antithesis { + template + Iter random_choice(Iter begin, Iter end) { + ssize_t num_things = end - begin; + if (num_things == 0) { + return end; + } + + uint64_t uval = get_random(); + ssize_t index = uval % num_things; + return begin + index; + } +} diff --git a/include/xrpl/basics/Buffer.h b/include/xrpl/basics/Buffer.h index 25ae8ca315c..733db0bdb72 100644 --- a/include/xrpl/basics/Buffer.h +++ b/include/xrpl/basics/Buffer.h @@ -21,7 +21,7 @@ #define RIPPLE_BASICS_BUFFER_H_INCLUDED #include -#include +#include #include #include #include @@ -112,9 +112,10 @@ class Buffer operator=(Slice s) { // Ensure the slice isn't a subset of the buffer. - assert( + ASSERT( s.size() == 0 || size_ == 0 || s.data() < p_.get() || - s.data() >= p_.get() + size_); + s.data() >= p_.get() + size_, + "ripple::Buffer::operator=(Slice) : input not a subset"); if (auto p = alloc(s.size())) std::memcpy(p, s.data(), s.size()); diff --git a/include/xrpl/basics/FeeUnits.h b/include/xrpl/basics/FeeUnits.h index c63a169f00e..70f2fc9fa89 100644 --- a/include/xrpl/basics/FeeUnits.h +++ b/include/xrpl/basics/FeeUnits.h @@ -20,16 +20,16 @@ #define BASICS_FEES_H_INCLUDED #include +#include #include -#include -#include -#include #include #include #include +#include #include #include +#include namespace ripple { @@ -419,9 +419,13 @@ mulDivU(Source1 value, Dest mul, Source2 div) { // split the asserts so if one hits, the user can tell which // without a debugger. - assert(value.value() >= 0); - assert(mul.value() >= 0); - assert(div.value() >= 0); + ASSERT( + value.value() >= 0, + "ripple::feeunit::mulDivU : minimum value input"); + ASSERT( + mul.value() >= 0, "ripple::feeunit::mulDivU : minimum mul input"); + ASSERT( + div.value() >= 0, "ripple::feeunit::mulDivU : minimum div input"); return std::nullopt; } diff --git a/include/xrpl/basics/MathUtilities.h b/include/xrpl/basics/MathUtilities.h index 4e8e3751cd8..45b8fc485cc 100644 --- a/include/xrpl/basics/MathUtilities.h +++ b/include/xrpl/basics/MathUtilities.h @@ -43,7 +43,7 @@ namespace ripple { constexpr std::size_t calculatePercent(std::size_t count, std::size_t total) { - assert(total != 0); + assert(total != 0); // NOTE No ASSERT here, because constexpr return ((std::min(count, total) * 100) + total - 1) / total; } diff --git a/include/xrpl/basics/SlabAllocator.h b/include/xrpl/basics/SlabAllocator.h index 5c4cba343cf..147231299e7 100644 --- a/include/xrpl/basics/SlabAllocator.h +++ b/include/xrpl/basics/SlabAllocator.h @@ -20,7 +20,9 @@ #ifndef RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED #define RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED +#include #include +#include #include #include @@ -28,10 +30,10 @@ #include #include -#include #include #include #include +#include #if BOOST_OS_LINUX #include @@ -141,7 +143,9 @@ class SlabAllocator void deallocate(std::uint8_t* ptr) noexcept { - assert(own(ptr)); + ASSERT( + own(ptr), + "ripple::SlabAllocator::SlabBlock::deallocate : own input"); std::lock_guard l(m_); @@ -184,7 +188,9 @@ class SlabAllocator boost::alignment::align_up(sizeof(Type) + extra, itemAlignment_)) , slabSize_(alloc) { - assert((itemAlignment_ & (itemAlignment_ - 1)) == 0); + ASSERT( + (itemAlignment_ & (itemAlignment_ - 1)) == 0, + "ripple::SlabAllocator::SlabAllocator : valid alignment"); } SlabAllocator(SlabAllocator const& other) = delete; @@ -294,7 +300,10 @@ class SlabAllocator bool deallocate(std::uint8_t* ptr) noexcept { - assert(ptr); + ASSERT( + ptr != nullptr, + "ripple::SlabAllocator::SlabAllocator::deallocate : non-null " + "input"); for (auto slab = slabs_.load(); slab != nullptr; slab = slab->next_) { diff --git a/include/xrpl/basics/Slice.h b/include/xrpl/basics/Slice.h index 00126f8882d..c10ca0b0e96 100644 --- a/include/xrpl/basics/Slice.h +++ b/include/xrpl/basics/Slice.h @@ -22,9 +22,9 @@ #include #include +#include #include #include -#include #include #include #include @@ -103,7 +103,9 @@ class Slice std::uint8_t operator[](std::size_t i) const noexcept { - assert(i < size_); + ASSERT( + i < size_, + "ripple::Slice::operator[](std::size_t) const : valid input"); return data_[i]; } diff --git a/include/xrpl/basics/base_uint.h b/include/xrpl/basics/base_uint.h index ae5aa17a63e..9adb3b394c4 100644 --- a/include/xrpl/basics/base_uint.h +++ b/include/xrpl/basics/base_uint.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -289,7 +290,9 @@ class base_uint std::is_trivially_copyable::value>> explicit base_uint(Container const& c) { - assert(c.size() * sizeof(typename Container::value_type) == size()); + ASSERT( + c.size() * sizeof(typename Container::value_type) == size(), + "ripple::base_uint::base_uint(Container auto) : input size match"); std::memcpy(data_.data(), c.data(), size()); } @@ -300,7 +303,9 @@ class base_uint base_uint&> operator=(Container const& c) { - assert(c.size() * sizeof(typename Container::value_type) == size()); + ASSERT( + c.size() * sizeof(typename Container::value_type) == size(), + "ripple::base_uint::operator=(Container auto) : input size match"); std::memcpy(data_.data(), c.data(), size()); return *this; } diff --git a/include/xrpl/basics/partitioned_unordered_map.h b/include/xrpl/basics/partitioned_unordered_map.h index 08f4cba9d3e..c8e31906dc4 100644 --- a/include/xrpl/basics/partitioned_unordered_map.h +++ b/include/xrpl/basics/partitioned_unordered_map.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H #define RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H -#include +#include #include #include #include @@ -246,7 +246,10 @@ class partitioned_unordered_map ? *partitions : std::thread::hardware_concurrency(); map_.resize(partitions_); - assert(partitions_); + ASSERT( + partitions_ != 0, + "ripple::partitioned_unordered_map::partitioned_unordered_map : " + "nonzero partitions"); } std::size_t diff --git a/include/xrpl/basics/random.h b/include/xrpl/basics/random.h index 87b303bf6d5..41369d2a454 100644 --- a/include/xrpl/basics/random.h +++ b/include/xrpl/basics/random.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_BASICS_RANDOM_H_INCLUDED #define RIPPLE_BASICS_RANDOM_H_INCLUDED +#include #include -#include #include #include #include @@ -114,7 +114,7 @@ std::enable_if_t< Integral> rand_int(Engine& engine, Integral min, Integral max) { - assert(max > min); + ASSERT(max > min, "ripple::rand_int : max over min inputs"); // This should have no state and constructing it should // be very cheap. If that turns out not to be the case diff --git a/include/xrpl/basics/scope.h b/include/xrpl/basics/scope.h index b1d13eae8ce..a38184041c6 100644 --- a/include/xrpl/basics/scope.h +++ b/include/xrpl/basics/scope.h @@ -20,6 +20,8 @@ #ifndef RIPPLE_BASICS_SCOPE_H_INCLUDED #define RIPPLE_BASICS_SCOPE_H_INCLUDED +#include + #include #include #include @@ -233,7 +235,9 @@ class scope_unlock explicit scope_unlock(std::unique_lock& lock) noexcept(true) : plock(&lock) { - assert(plock->owns_lock()); + ASSERT( + plock->owns_lock(), + "ripple::scope_unlock::scope_unlock : mutex must be locked"); plock->unlock(); } diff --git a/include/xrpl/basics/spinlock.h b/include/xrpl/basics/spinlock.h index 85a2ac41d51..92514478c4f 100644 --- a/include/xrpl/basics/spinlock.h +++ b/include/xrpl/basics/spinlock.h @@ -18,8 +18,8 @@ #ifndef RIPPLE_BASICS_SPINLOCK_H_INCLUDED #define RIPPLE_BASICS_SPINLOCK_H_INCLUDED +#include #include -#include #include #include @@ -117,7 +117,9 @@ class packed_spinlock packed_spinlock(std::atomic& lock, int index) : bits_(lock), mask_(static_cast(1) << index) { - assert(index >= 0 && (mask_ != 0)); + ASSERT( + index >= 0 && (mask_ != 0), + "ripple::packed_spinlock::packed_spinlock : valid index and mask"); } [[nodiscard]] bool diff --git a/include/xrpl/beast/asio/io_latency_probe.h b/include/xrpl/beast/asio/io_latency_probe.h index bbde13af687..fb4f5f9f6a2 100644 --- a/include/xrpl/beast/asio/io_latency_probe.h +++ b/include/xrpl/beast/asio/io_latency_probe.h @@ -20,8 +20,10 @@ #ifndef BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED #define BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED +#include #include #include + #include #include #include @@ -172,7 +174,10 @@ class io_latency_probe , m_repeat(repeat) , m_probe(probe) { - assert(m_probe); + ASSERT( + m_probe != nullptr, + "beast::io_latency_probe::sample_op::sample_op : non-null " + "probe input"); m_probe->addref(); } @@ -182,7 +187,10 @@ class io_latency_probe , m_repeat(from.m_repeat) , m_probe(from.m_probe) { - assert(m_probe); + ASSERT( + m_probe != nullptr, + "beast::io_latency_probe::sample_op::sample_op(sample_op&&) : " + "non-null probe input"); from.m_probe = nullptr; } diff --git a/include/xrpl/beast/clock/manual_clock.h b/include/xrpl/beast/clock/manual_clock.h index 97be8e79b90..505cbe27208 100644 --- a/include/xrpl/beast/clock/manual_clock.h +++ b/include/xrpl/beast/clock/manual_clock.h @@ -21,7 +21,7 @@ #define BEAST_CHRONO_MANUAL_CLOCK_H_INCLUDED #include -#include +#include namespace beast { @@ -61,7 +61,9 @@ class manual_clock : public abstract_clock void set(time_point const& when) { - assert(!Clock::is_steady || when >= now_); + ASSERT( + !Clock::is_steady || when >= now_, + "beast::manual_clock::set(time_point) : forward input"); now_ = when; } @@ -78,7 +80,9 @@ class manual_clock : public abstract_clock void advance(std::chrono::duration const& elapsed) { - assert(!Clock::is_steady || (now_ + elapsed) >= now_); + ASSERT( + !Clock::is_steady || (now_ + elapsed) >= now_, + "beast::manual_clock::advance(duration) : forward input"); now_ += elapsed; } diff --git a/include/xrpl/beast/container/detail/aged_unordered_container.h b/include/xrpl/beast/container/detail/aged_unordered_container.h index 72e3334801b..30c8489693e 100644 --- a/include/xrpl/beast/container/detail/aged_unordered_container.h +++ b/include/xrpl/beast/container/detail/aged_unordered_container.h @@ -1330,7 +1330,10 @@ class aged_unordered_container size_type bucket(Key const& k) const { - assert(bucket_count() != 0); + ASSERT( + bucket_count() != 0, + "beast::detail::aged_unordered_container::bucket : nonzero bucket " + "count"); return m_cont.bucket(k, std::cref(m_config.hash_function())); } @@ -1471,7 +1474,10 @@ class aged_unordered_container { if (would_exceed(additional)) m_buck.resize(size() + additional, m_cont); - assert(load_factor() <= max_load_factor()); + ASSERT( + load_factor() <= max_load_factor(), + "beast::detail::aged_unordered_container::maybe_rehash : maximum " + "load factor"); } // map, set diff --git a/include/xrpl/beast/core/LexicalCast.h b/include/xrpl/beast/core/LexicalCast.h index e0fa24ca9f5..0a7f2379daf 100644 --- a/include/xrpl/beast/core/LexicalCast.h +++ b/include/xrpl/beast/core/LexicalCast.h @@ -20,9 +20,10 @@ #ifndef BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED #define BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED +#include + #include #include -#include #include #include #include @@ -159,7 +160,9 @@ struct LexicalCast bool operator()(Out& out, char const* in) const { - assert(in); + ASSERT( + in != nullptr, + "beast::detail::LexicalCast(char const*) : non-null input"); return LexicalCast()(out, in); } }; @@ -174,7 +177,9 @@ struct LexicalCast bool operator()(Out& out, char* in) const { - assert(in); + ASSERT( + in != nullptr, + "beast::detail::LexicalCast(char*) : non-null input"); return LexicalCast()(out, in); } }; diff --git a/include/xrpl/beast/net/IPAddress.h b/include/xrpl/beast/net/IPAddress.h index f3a1a7348f2..cdac4abbd9c 100644 --- a/include/xrpl/beast/net/IPAddress.h +++ b/include/xrpl/beast/net/IPAddress.h @@ -24,9 +24,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -96,7 +96,7 @@ hash_append(Hasher& h, beast::IP::Address const& addr) noexcept else if (addr.is_v6()) hash_append(h, addr.to_v6().to_bytes()); else - assert(false); + UNREACHABLE("beast::hash_append : invalid address type"); } } // namespace beast diff --git a/include/xrpl/beast/net/IPAddressV6.h b/include/xrpl/beast/net/IPAddressV6.h index 74eb6b96d8e..83e4d6f8a32 100644 --- a/include/xrpl/beast/net/IPAddressV6.h +++ b/include/xrpl/beast/net/IPAddressV6.h @@ -20,8 +20,8 @@ #ifndef BEAST_NET_IPADDRESSV6_H_INCLUDED #define BEAST_NET_IPADDRESSV6_H_INCLUDED +#include #include -#include #include #include #include diff --git a/include/xrpl/beast/utility/Journal.h b/include/xrpl/beast/utility/Journal.h index 059355ccae7..aaa53a3515d 100644 --- a/include/xrpl/beast/utility/Journal.h +++ b/include/xrpl/beast/utility/Journal.h @@ -20,7 +20,7 @@ #ifndef BEAST_UTILITY_JOURNAL_H_INCLUDED #define BEAST_UTILITY_JOURNAL_H_INCLUDED -#include +#include #include namespace beast { @@ -205,7 +205,9 @@ class Journal */ Stream(Sink& sink, Severity level) : m_sink(sink), m_level(level) { - assert(m_level < severities::kDisabled); + ASSERT( + m_level < severities::kDisabled, + "beast::Journal::Stream::Stream : maximum level"); } /** Construct or copy another Stream. */ diff --git a/include/xrpl/beast/utility/instrumentation.h b/include/xrpl/beast/utility/instrumentation.h new file mode 100644 index 00000000000..f3f8987242e --- /dev/null +++ b/include/xrpl/beast/utility/instrumentation.h @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +/* +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 BEAST_UTILITY_INSTRUMENTATION_H_INCLUDED +#define BEAST_UTILITY_INSTRUMENTATION_H_INCLUDED + +#include + +#ifdef ENABLE_VOIDSTAR +#ifdef NDEBUG +#error "Antithesis instrumentation requires Debug build" +#endif +#include +#else +#define ALWAYS(cond, name, ...) assert((name) && (cond)) +#define ALWAYS_OR_UNREACHABLE(cond, name, ...) assert((name) && (cond)) +#define SOMETIMES(cond, name, ...) +#define REACHABLE(name, ...) +#define UNREACHABLE(name, ...) assert((name) && false) +#endif + +#define ASSERT ALWAYS_OR_UNREACHABLE + +// How to use the instrumentation macros: +// +// ALWAYS if cond must be true and the line must be reached during fuzzing +// ASSERT if cond must be true but the line might not be reached during fuzzing +// REACHABLE if the line must be reached during fuzzing +// SOMETIMES a hint for the fuzzer to try to make the cond true +// UNREACHABLE if the line must not be reached (in fuzzing or in normal use) +// +// NOTE: ASSERT has similar semantics as C assert macro, with minor differences: +// * ASSERT must have an unique name (naming convention in CONTRIBUTING.md) +// * the condition (which comes first) must be *implicitly* convertible to bool +// * during fuzzing, the program will continue execution past a failed ASSERT +// +// We continue to use regular C assert inside unit tests and inside constexpr +// functions. +// +// NOTE: UNREACHABLE does *not* have the same semantics as std::unreachable. +// The program will continue execution past an UNREACHABLE in a Release build +// and during fuzzing (similar to ASSERT). +// Also, the naming convention in UNREACHABLE is subtly different from other +// instrumentation macros - its name describes the condition which was *not* +// meant to happen, while name in other macros describe the condition that is +// meant to happen (e.g. as in "assert that this happens"). + +#endif diff --git a/include/xrpl/beast/utility/rngfill.h b/include/xrpl/beast/utility/rngfill.h index 71f434bdaf9..3be6aa307b3 100644 --- a/include/xrpl/beast/utility/rngfill.h +++ b/include/xrpl/beast/utility/rngfill.h @@ -20,8 +20,8 @@ #ifndef BEAST_RANDOM_RNGFILL_H_INCLUDED #define BEAST_RANDOM_RNGFILL_H_INCLUDED +#include #include -#include #include #include #include @@ -42,7 +42,8 @@ rngfill(void* buffer, std::size_t bytes, Generator& g) bytes -= sizeof(v); } - assert(bytes < sizeof(result_type)); + ASSERT( + bytes < sizeof(result_type), "beast::rngfill(void*) : maximum bytes"); #ifdef __GNUC__ // gcc 11.1 (falsely) warns about an array-bounds overflow in release mode. diff --git a/include/xrpl/json/detail/json_assert.h b/include/xrpl/json/detail/json_assert.h index c401ccf7200..264bcd90f3d 100644 --- a/include/xrpl/json/detail/json_assert.h +++ b/include/xrpl/json/detail/json_assert.h @@ -22,9 +22,6 @@ #include -#define JSON_ASSERT_UNREACHABLE assert(false) -#define JSON_ASSERT(condition) \ - assert(condition); // @todo <= change this into an exception throw #define JSON_ASSERT_MESSAGE(condition, message) \ if (!(condition)) \ ripple::Throw(message); diff --git a/include/xrpl/protocol/AmountConversions.h b/include/xrpl/protocol/AmountConversions.h index 270d009b916..20a985d1190 100644 --- a/include/xrpl/protocol/AmountConversions.h +++ b/include/xrpl/protocol/AmountConversions.h @@ -53,7 +53,9 @@ toSTAmount(XRPAmount const& xrp) inline STAmount toSTAmount(XRPAmount const& xrp, Issue const& iss) { - assert(isXRP(iss.account) && isXRP(iss.currency)); + ASSERT( + isXRP(iss.account) && isXRP(iss.currency), + "ripple::toSTAmount : is XRP"); return toSTAmount(xrp); } @@ -72,12 +74,14 @@ template <> inline IOUAmount toAmount(STAmount const& amt) { - assert(amt.mantissa() < std::numeric_limits::max()); + ASSERT( + amt.mantissa() < std::numeric_limits::max(), + "ripple::toAmount : maximum mantissa"); bool const isNeg = amt.negative(); std::int64_t const sMant = isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); - assert(!isXRP(amt)); + ASSERT(!isXRP(amt), "ripple::toAmount : is not XRP"); return IOUAmount(sMant, amt.exponent()); } @@ -85,12 +89,14 @@ template <> inline XRPAmount toAmount(STAmount const& amt) { - assert(amt.mantissa() < std::numeric_limits::max()); + ASSERT( + amt.mantissa() < std::numeric_limits::max(), + "ripple::toAmount : maximum mantissa"); bool const isNeg = amt.negative(); std::int64_t const sMant = isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); - assert(isXRP(amt)); + ASSERT(isXRP(amt), "ripple::toAmount : is XRP"); return XRPAmount(sMant); } diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index 90a81c55ef4..219230e69a1 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -151,14 +151,19 @@ class FeatureBitset : private std::bitset explicit FeatureBitset(base const& b) : base(b) { - assert(b.count() == count()); + ASSERT( + b.count() == count(), + "ripple::FeatureBitset::FeatureBitset(base) : count match"); } template explicit FeatureBitset(uint256 const& f, Fs&&... fs) { initFromFeatures(f, std::forward(fs)...); - assert(count() == (sizeof...(fs) + 1)); + ASSERT( + count() == (sizeof...(fs) + 1), + "ripple::FeatureBitset::FeatureBitset(uint256) : count and " + "sizeof... do match"); } template @@ -166,7 +171,10 @@ class FeatureBitset : private std::bitset { for (auto const& f : fs) set(featureToBitsetIndex(f)); - assert(fs.size() == count()); + ASSERT( + fs.size() == count(), + "ripple::FeatureBitset::FeatureBitset(Container auto) : count and " + "size do match"); } auto diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index 72cf0b527b1..6b5024a1f03 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -220,7 +220,7 @@ page(uint256 const& root, std::uint64_t index = 0) noexcept; inline Keylet page(Keylet const& root, std::uint64_t index = 0) noexcept { - assert(root.type == ltDIR_NODE); + ASSERT(root.type == ltDIR_NODE, "ripple::keylet::page : valid root type"); return page(root.key, index); } /** @} */ diff --git a/include/xrpl/protocol/Issue.h b/include/xrpl/protocol/Issue.h index 335dd91354a..60182698ee6 100644 --- a/include/xrpl/protocol/Issue.h +++ b/include/xrpl/protocol/Issue.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_ISSUE_H_INCLUDED #define RIPPLE_PROTOCOL_ISSUE_H_INCLUDED +#include #include #include -#include #include #include diff --git a/include/xrpl/protocol/MultiApiJson.h b/include/xrpl/protocol/MultiApiJson.h index 73c274ff7f7..e1f65199617 100644 --- a/include/xrpl/protocol/MultiApiJson.h +++ b/include/xrpl/protocol/MultiApiJson.h @@ -23,8 +23,8 @@ #include #include +#include #include -#include #include #include #include @@ -159,8 +159,10 @@ struct MultiApiJson -> std:: invoke_result_t { - assert( - valid(version) && index(version) >= 0 && index(version) < size); + ASSERT( + valid(version) && index(version) >= 0 && index(version) < size, + "ripple::detail::MultiApiJson::operator() : valid " + "version"); return std::invoke( fn, json.val[index(version)], @@ -177,8 +179,9 @@ struct MultiApiJson operator()(Json& json, Version version, Fn fn) const -> std::invoke_result_t { - assert( - valid(version) && index(version) >= 0 && index(version) < size); + ASSERT( + valid(version) && index(version) >= 0 && index(version) < size, + "ripple::detail::MultiApiJson::operator() : valid version"); return std::invoke(fn, json.val[index(version)]); } } visitor = {}; diff --git a/include/xrpl/protocol/Quality.h b/include/xrpl/protocol/Quality.h index 1ee2cc9f686..fac9dd29a43 100644 --- a/include/xrpl/protocol/Quality.h +++ b/include/xrpl/protocol/Quality.h @@ -298,7 +298,9 @@ class Quality friend double relativeDistance(Quality const& q1, Quality const& q2) { - assert(q1.m_value > 0 && q2.m_value > 0); + ASSERT( + q1.m_value > 0 && q2.m_value > 0, + "ripple::Quality::relativeDistance : minimum inputs"); if (q1.m_value == q2.m_value) // make expected common case fast return 0; diff --git a/include/xrpl/protocol/Rate.h b/include/xrpl/protocol/Rate.h index 6970d9c16a8..2872a5809de 100644 --- a/include/xrpl/protocol/Rate.h +++ b/include/xrpl/protocol/Rate.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_RATE_H_INCLUDED #define RIPPLE_PROTOCOL_RATE_H_INCLUDED +#include #include #include -#include #include #include diff --git a/include/xrpl/protocol/STAmount.h b/include/xrpl/protocol/STAmount.h index e0a6c1eca08..f3dde91cf7e 100644 --- a/include/xrpl/protocol/STAmount.h +++ b/include/xrpl/protocol/STAmount.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -353,7 +354,10 @@ STAmount::STAmount( , mIsNegative(negative) { // mValue is uint64, but needs to fit in the range of int64 - assert(mValue <= std::numeric_limits::max()); + ASSERT( + mValue <= std::numeric_limits::max(), + "ripple::STAmount::STAmount(SField, A, std::uint64_t, int, bool) : " + "maximum mantissa input"); canonicalize(); } diff --git a/include/xrpl/protocol/STBitString.h b/include/xrpl/protocol/STBitString.h index f3a74f2fc54..a80c3c2c253 100644 --- a/include/xrpl/protocol/STBitString.h +++ b/include/xrpl/protocol/STBitString.h @@ -170,8 +170,10 @@ template void STBitString::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == getSType()); + ASSERT(getFName().isBinary(), "ripple::STBitString::add : field is binary"); + ASSERT( + getFName().fieldType == getSType(), + "ripple::STBitString::add : field type match"); s.addBitString(value_); } diff --git a/include/xrpl/protocol/STBlob.h b/include/xrpl/protocol/STBlob.h index bdedbd92105..cfe4ab5af58 100644 --- a/include/xrpl/protocol/STBlob.h +++ b/include/xrpl/protocol/STBlob.h @@ -23,9 +23,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/include/xrpl/protocol/STInteger.h b/include/xrpl/protocol/STInteger.h index 6bae2cc3152..8dc6b7ff1a3 100644 --- a/include/xrpl/protocol/STInteger.h +++ b/include/xrpl/protocol/STInteger.h @@ -110,8 +110,10 @@ template inline void STInteger::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == getSType()); + ASSERT(getFName().isBinary(), "ripple::STInteger::add : field is binary"); + ASSERT( + getFName().fieldType == getSType(), + "ripple::STInteger::add : field type match"); s.addInteger(value_); } diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index 748a2b5d685..a31058413f0 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -737,7 +737,8 @@ STObject::Proxy::assign(U&& u) t = dynamic_cast(st_->getPField(*f_, true)); else t = dynamic_cast(st_->makeFieldPresent(*f_)); - assert(t); + ASSERT( + t != nullptr, "ripple::STObject::Proxy::assign : type cast succeeded"); *t = std::forward(u); } @@ -1033,13 +1034,19 @@ STObject::at(TypedField const& f) const if (auto const u = dynamic_cast(b)) return u->value(); - assert(mType); - assert(b->getSType() == STI_NOTPRESENT); + ASSERT( + mType != nullptr, + "ripple::STObject::at(TypedField auto) : field template non-null"); + ASSERT( + b->getSType() == STI_NOTPRESENT, + "ripple::STObject::at(TypedField auto) : type not present"); if (mType->style(f) == soeOPTIONAL) Throw("Missing optional field: " + f.getName()); - assert(mType->style(f) == soeDEFAULT); + ASSERT( + mType->style(f) == soeDEFAULT, + "ripple::STObject::at(TypedField auto) : template style is default"); // Used to help handle the case where value_type is a const reference, // otherwise we would return the address of a temporary. @@ -1057,11 +1064,19 @@ STObject::at(OptionaledField const& of) const auto const u = dynamic_cast(b); if (!u) { - assert(mType); - assert(b->getSType() == STI_NOTPRESENT); + ASSERT( + mType != nullptr, + "ripple::STObject::at(OptionaledField auto) : field template " + "non-null"); + ASSERT( + b->getSType() == STI_NOTPRESENT, + "ripple::STObject::at(OptionaledField auto) : type not present"); if (mType->style(*of.f) == soeOPTIONAL) return std::nullopt; - assert(mType->style(*of.f) == soeDEFAULT); + ASSERT( + mType->style(*of.f) == soeDEFAULT, + "ripple::STObject::at(OptionaledField auto) : template style is " + "default"); return typename T::value_type{}; } return u->value(); diff --git a/include/xrpl/protocol/STPathSet.h b/include/xrpl/protocol/STPathSet.h index 473086368fb..754bb279238 100644 --- a/include/xrpl/protocol/STPathSet.h +++ b/include/xrpl/protocol/STPathSet.h @@ -21,11 +21,11 @@ #define RIPPLE_PROTOCOL_STPATHSET_H_INCLUDED #include +#include #include #include #include #include -#include #include #include @@ -257,7 +257,9 @@ inline STPathElement::STPathElement( is_offer_ = false; mAccountID = *account; mType |= typeAccount; - assert(mAccountID != noAccount()); + ASSERT( + mAccountID != noAccount(), + "ripple::STPathElement::STPathElement : account is set"); } if (currency) @@ -270,7 +272,9 @@ inline STPathElement::STPathElement( { mIssuerID = *issuer; mType |= typeIssuer; - assert(mIssuerID != noAccount()); + ASSERT( + mIssuerID != noAccount(), + "ripple::STPathElement::STPathElement : issuer is set"); } hash_value_ = get_hash(*this); diff --git a/include/xrpl/protocol/STValidation.h b/include/xrpl/protocol/STValidation.h index 6cae0971f51..69472f84e6d 100644 --- a/include/xrpl/protocol/STValidation.h +++ b/include/xrpl/protocol/STValidation.h @@ -22,10 +22,10 @@ #include #include +#include #include #include #include -#include #include #include #include @@ -176,7 +176,9 @@ STValidation::STValidation( Throw("Invalid signature in validation"); } - assert(nodeID_.isNonZero()); + ASSERT( + nodeID_.isNonZero(), + "ripple::STValidation::STValidation(SerialIter) : nonzero node"); } /** Construct, sign and trust a new STValidation issued by this node. @@ -199,7 +201,10 @@ STValidation::STValidation( , nodeID_(nodeID) , seenTime_(signTime) { - assert(nodeID_.isNonZero()); + ASSERT( + nodeID_.isNonZero(), + "ripple::STValidation::STValidation(PublicKey, SecretKey) : nonzero " + "node"); // First, set our own public key: if (publicKeyType(pk) != KeyType::secp256k1) diff --git a/include/xrpl/protocol/Serializer.h b/include/xrpl/protocol/Serializer.h index 0e96078ed14..e5e3907101d 100644 --- a/include/xrpl/protocol/Serializer.h +++ b/include/xrpl/protocol/Serializer.h @@ -27,9 +27,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -55,7 +55,9 @@ class Serializer if (size) { - assert(data != nullptr); + ASSERT( + data != nullptr, + "ripple::Serializer::Serializer(void const*) : non-null input"); std::memcpy(mData.data(), data, size); } } @@ -331,7 +333,7 @@ Serializer::addVL(Iter begin, Iter end, int len) len -= begin->size(); #endif } - assert(len == 0); + ASSERT(len == 0, "ripple::Serializer::addVL : length matches distance"); return ret; } diff --git a/include/xrpl/protocol/TxMeta.h b/include/xrpl/protocol/TxMeta.h index 7932a4c55a3..868efd854ff 100644 --- a/include/xrpl/protocol/TxMeta.h +++ b/include/xrpl/protocol/TxMeta.h @@ -116,7 +116,9 @@ class TxMeta STAmount getDeliveredAmount() const { - assert(hasDeliveredAmount()); + ASSERT( + hasDeliveredAmount(), + "ripple::TxMeta::getDeliveredAmount : non-null delivered amount"); return *mDelivered; } diff --git a/include/xrpl/protocol/detail/b58_utils.h b/include/xrpl/protocol/detail/b58_utils.h index b060fc7e166..960b3d8dcb6 100644 --- a/include/xrpl/protocol/detail/b58_utils.h +++ b/include/xrpl/protocol/detail/b58_utils.h @@ -21,12 +21,12 @@ #define RIPPLE_PROTOCOL_B58_UTILS_H_INCLUDED #include +#include #include #include #include -#include #include #include #include @@ -130,7 +130,9 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) { // should never happen, but if it does then it seems natural to define // the a null set of numbers to be zero, so the remainder is also zero. - assert(0); + UNREACHABLE( + "ripple::b58_fast::detail::inplace_bigint_div_rem : empty " + "numerator"); return 0; } @@ -146,8 +148,14 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) unsigned __int128 const denom128 = denom; unsigned __int128 const d = num / denom128; unsigned __int128 const r = num - (denom128 * d); - assert(d >> 64 == 0); - assert(r >> 64 == 0); + ASSERT( + d >> 64 == 0, + "ripple::b58_fast::detail::inplace_bigint_div_rem::div_rem_64 : " + "valid division result"); + ASSERT( + r >> 64 == 0, + "ripple::b58_fast::detail::inplace_bigint_div_rem::div_rem_64 : " + "valid remainder"); return {static_cast(d), static_cast(r)}; }; @@ -170,7 +178,9 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) b58_10_to_b58_be(std::uint64_t input) { constexpr std::uint64_t B_58_10 = 430804206899405824; // 58^10; - assert(input < B_58_10); + ASSERT( + input < B_58_10, + "ripple::b58_fast::detail::b58_10_to_b58_be : valid input"); constexpr std::size_t resultSize = 10; std::array result{}; int i = 0; diff --git a/include/xrpl/resource/detail/Entry.h b/include/xrpl/resource/detail/Entry.h index d4f32080d9d..32ba77c6d35 100644 --- a/include/xrpl/resource/detail/Entry.h +++ b/include/xrpl/resource/detail/Entry.h @@ -23,9 +23,9 @@ #include #include #include +#include #include #include -#include namespace ripple { namespace Resource { diff --git a/include/xrpl/resource/detail/Key.h b/include/xrpl/resource/detail/Key.h index 3df2dce039d..f953d5103eb 100644 --- a/include/xrpl/resource/detail/Key.h +++ b/include/xrpl/resource/detail/Key.h @@ -21,8 +21,8 @@ #define RIPPLE_RESOURCE_KEY_H_INCLUDED #include +#include #include -#include namespace ripple { namespace Resource { diff --git a/include/xrpl/resource/detail/Logic.h b/include/xrpl/resource/detail/Logic.h index a57e529e0a2..6b7830c07cd 100644 --- a/include/xrpl/resource/detail/Logic.h +++ b/include/xrpl/resource/detail/Logic.h @@ -26,12 +26,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include namespace ripple { @@ -401,7 +401,9 @@ class Logic { std::lock_guard _(lock_); Entry& entry(iter->second); - assert(entry.refcount == 0); + ASSERT( + entry.refcount == 0, + "ripple::Resource::Logic::erase : entry not used"); inactive_.erase(inactive_.iterator_to(entry)); table_.erase(iter); } @@ -433,7 +435,9 @@ class Logic admin_.erase(admin_.iterator_to(entry)); break; default: - assert(false); + UNREACHABLE( + "ripple::Resource::Logic::release : invalid entry " + "kind"); break; } inactive_.push_back(entry); diff --git a/include/xrpl/server/detail/BaseHTTPPeer.h b/include/xrpl/server/detail/BaseHTTPPeer.h index 32ec4d3009d..bcdddcc711d 100644 --- a/include/xrpl/server/detail/BaseHTTPPeer.h +++ b/include/xrpl/server/detail/BaseHTTPPeer.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -34,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/include/xrpl/server/detail/BasePeer.h b/include/xrpl/server/detail/BasePeer.h index a90eaabf6e4..97ad77f7f22 100644 --- a/include/xrpl/server/detail/BasePeer.h +++ b/include/xrpl/server/detail/BasePeer.h @@ -21,12 +21,12 @@ #define RIPPLE_SERVER_BASEPEER_H_INCLUDED #include +#include #include #include #include #include #include -#include #include #include diff --git a/include/xrpl/server/detail/BaseWSPeer.h b/include/xrpl/server/detail/BaseWSPeer.h index 4c4049a8b9b..8f3022bdf32 100644 --- a/include/xrpl/server/detail/BaseWSPeer.h +++ b/include/xrpl/server/detail/BaseWSPeer.h @@ -21,17 +21,21 @@ #define RIPPLE_SERVER_BASEWSPEER_H_INCLUDED #include +#include #include #include #include +#include #include #include + #include #include #include +#include -#include #include +#include namespace ripple { @@ -508,7 +512,9 @@ template void BaseWSPeer::fail(error_code ec, String const& what) { - assert(strand_.running_in_this_thread()); + ASSERT( + strand_.running_in_this_thread(), + "ripple::BaseWSPeer::fail : strand in this thread"); cancel_timer(); if (!ec_ && ec != boost::asio::error::operation_aborted) diff --git a/src/libxrpl/basics/Log.cpp b/src/libxrpl/basics/Log.cpp index 3d5963cc266..873087bd217 100644 --- a/src/libxrpl/basics/Log.cpp +++ b/src/libxrpl/basics/Log.cpp @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -224,7 +224,7 @@ Logs::fromSeverity(beast::severities::Severity level) return lsERROR; default: - assert(false); + UNREACHABLE("ripple::Logs::fromSeverity : invalid severity"); [[fallthrough]]; case kFatal: break; @@ -250,7 +250,7 @@ Logs::toSeverity(LogSeverity level) case lsERROR: return kError; default: - assert(false); + UNREACHABLE("ripple::Logs::toSeverity : invalid severity"); [[fallthrough]]; case lsFATAL: break; @@ -277,7 +277,7 @@ Logs::toString(LogSeverity s) case lsFATAL: return "Fatal"; default: - assert(false); + UNREACHABLE("ripple::Logs::toString : invalid severity"); return "Unknown"; } } @@ -341,7 +341,7 @@ Logs::format( output += "ERR "; break; default: - assert(false); + UNREACHABLE("ripple::Logs::format : invalid severity"); [[fallthrough]]; case kFatal: output += "FTL "; diff --git a/src/libxrpl/basics/Number.cpp b/src/libxrpl/basics/Number.cpp index ebbfa0023c9..f9d10ec14e5 100644 --- a/src/libxrpl/basics/Number.cpp +++ b/src/libxrpl/basics/Number.cpp @@ -18,9 +18,9 @@ //============================================================================== #include +#include #include #include -#include #include #include #include @@ -235,7 +235,9 @@ Number::operator+=(Number const& y) *this = Number{}; return *this; } - assert(isnormal() && y.isnormal()); + ASSERT( + isnormal() && y.isnormal(), + "ripple::Number::operator+=(Number) : is normal"); auto xm = mantissa(); auto xe = exponent(); int xn = 1; @@ -374,7 +376,9 @@ Number::operator*=(Number const& y) *this = y; return *this; } - assert(isnormal() && y.isnormal()); + ASSERT( + isnormal() && y.isnormal(), + "ripple::Number::operator*=(Number) : is normal"); auto xm = mantissa(); auto xe = exponent(); int xn = 1; @@ -428,7 +432,9 @@ Number::operator*=(Number const& y) std::to_string(xe)); mantissa_ = xm * zn; exponent_ = xe; - assert(isnormal() || *this == Number{}); + ASSERT( + isnormal() || *this == Number{}, + "ripple::Number::operator*=(Number) : result is normal"); return *this; } @@ -536,7 +542,7 @@ to_string(Number const& amount) negative = true; } - assert(exponent + 43 > 0); + ASSERT(exponent + 43 > 0, "ripple::to_string(Number) : minimum exponent"); ptrdiff_t const pad_prefix = 27; ptrdiff_t const pad_suffix = 23; @@ -562,7 +568,9 @@ to_string(Number const& amount) if (std::distance(pre_from, pre_to) > pad_prefix) pre_from += pad_prefix; - assert(post_to >= post_from); + ASSERT( + post_to >= post_from, + "ripple::to_string(Number) : first distance check"); pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; }); @@ -571,7 +579,9 @@ to_string(Number const& amount) if (std::distance(post_from, post_to) > pad_suffix) post_to -= pad_suffix; - assert(post_to >= post_from); + ASSERT( + post_to >= post_from, + "ripple::to_string(Number) : second distance check"); post_to = std::find_if( std::make_reverse_iterator(post_to), diff --git a/src/libxrpl/basics/ResolverAsio.cpp b/src/libxrpl/basics/ResolverAsio.cpp index 7105eb12a74..efaaf80b5af 100644 --- a/src/libxrpl/basics/ResolverAsio.cpp +++ b/src/libxrpl/basics/ResolverAsio.cpp @@ -21,9 +21,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -48,7 +48,9 @@ class AsyncObject ~AsyncObject() { // Destroying the object with I/O pending? Not a clean exit! - assert(m_pending.load() == 0); + ASSERT( + m_pending.load() == 0, + "ripple::AsyncObject::~AsyncObject : nothing pending"); } /** RAII container that maintains the count of pending I/O. @@ -153,8 +155,11 @@ class ResolverAsioImpl : public ResolverAsio, ~ResolverAsioImpl() override { - assert(m_work.empty()); - assert(m_stopped); + ASSERT( + m_work.empty(), + "ripple::ResolverAsioImpl::~ResolverAsioImpl : no pending work"); + ASSERT( + m_stopped, "ripple::ResolverAsioImpl::~ResolverAsioImpl : stopped"); } //------------------------------------------------------------------------- @@ -176,8 +181,10 @@ class ResolverAsioImpl : public ResolverAsio, void start() override { - assert(m_stopped == true); - assert(m_stop_called == false); + ASSERT(m_stopped == true, "ripple::ResolverAsioImpl::start : stopped"); + ASSERT( + m_stop_called == false, + "ripple::ResolverAsioImpl::start : not stopping"); if (m_stopped.exchange(false) == true) { @@ -217,8 +224,12 @@ class ResolverAsioImpl : public ResolverAsio, resolve(std::vector const& names, HandlerType const& handler) override { - assert(m_stop_called == false); - assert(!names.empty()); + ASSERT( + m_stop_called == false, + "ripple::ResolverAsioImpl::resolve : not stopping"); + ASSERT( + !names.empty(), + "ripple::ResolverAsioImpl::resolve : names non-empty"); // TODO NIKB use rvalue references to construct and move // reducing cost. @@ -235,7 +246,9 @@ class ResolverAsioImpl : public ResolverAsio, void do_stop(CompletionCounter) { - assert(m_stop_called == true); + ASSERT( + m_stop_called == true, + "ripple::ResolverAsioImpl::do_stop : stopping"); if (m_stopped.exchange(true) == false) { @@ -381,7 +394,9 @@ class ResolverAsioImpl : public ResolverAsio, HandlerType const& handler, CompletionCounter) { - assert(!names.empty()); + ASSERT( + !names.empty(), + "ripple::ResolverAsioImpl::do_resolve : names non-empty"); if (m_stop_called == false) { diff --git a/src/libxrpl/basics/contract.cpp b/src/libxrpl/basics/contract.cpp index fbda83c7a63..4f0a74644af 100644 --- a/src/libxrpl/basics/contract.cpp +++ b/src/libxrpl/basics/contract.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -48,6 +49,12 @@ LogicError(std::string const& s) noexcept { JLOG(debugLog().fatal()) << s; std::cerr << "Logic error: " << s << std::endl; + // Use a non-standard contract naming here (without namespace) because + // it's the only location where various unrelated execution paths may + // register an error; this is also why the "message" parameter is passed + // here. + // For the above reasons, we want this contract to stand out. + UNREACHABLE("LogicError", {{"message", s}}); detail::accessViolation(); } diff --git a/src/libxrpl/beast/clock/basic_seconds_clock.cpp b/src/libxrpl/beast/clock/basic_seconds_clock.cpp index f5af8bd16ec..fa9a8725df5 100644 --- a/src/libxrpl/beast/clock/basic_seconds_clock.cpp +++ b/src/libxrpl/beast/clock/basic_seconds_clock.cpp @@ -18,9 +18,9 @@ //============================================================================== #include +#include #include -#include #include #include #include @@ -57,7 +57,9 @@ static_assert(std::atomic::is_always_lock_free); seconds_clock_thread::~seconds_clock_thread() { - assert(thread_.joinable()); + ASSERT( + thread_.joinable(), + "beast::seconds_clock_thread::~seconds_clock_thread : thread joinable"); { std::lock_guard lock(mut_); stop_ = true; diff --git a/src/libxrpl/beast/core/SemanticVersion.cpp b/src/libxrpl/beast/core/SemanticVersion.cpp index b33ed2f48f4..e4a5aee486a 100644 --- a/src/libxrpl/beast/core/SemanticVersion.cpp +++ b/src/libxrpl/beast/core/SemanticVersion.cpp @@ -19,9 +19,9 @@ #include #include +#include #include -#include #include namespace beast { @@ -304,7 +304,8 @@ compare(SemanticVersion const& lhs, SemanticVersion const& rhs) if (isNumeric(left)) { - assert(isNumeric(right)); + ASSERT( + isNumeric(right), "beast::compare : both inputs numeric"); int const iLeft(lexicalCastThrow(left)); int const iRight(lexicalCastThrow(right)); @@ -316,7 +317,9 @@ compare(SemanticVersion const& lhs, SemanticVersion const& rhs) } else { - assert(!isNumeric(right)); + ASSERT( + !isNumeric(right), + "beast::compare : both inputs non-numeric"); int result = left.compare(right); diff --git a/src/libxrpl/beast/insight/StatsDCollector.cpp b/src/libxrpl/beast/insight/StatsDCollector.cpp index 76ae15b82d5..58322fc95ed 100644 --- a/src/libxrpl/beast/insight/StatsDCollector.cpp +++ b/src/libxrpl/beast/insight/StatsDCollector.cpp @@ -25,8 +25,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -400,7 +400,10 @@ class StatsDCollectorImp for (auto const& s : *keepAlive) { std::size_t const length(s.size()); - assert(!s.empty()); + ASSERT( + !s.empty(), + "beast::insight::detail::StatsDCollectorImp::send_buffers : " + "non-empty payload"); if (!buffers.empty() && (size + length) > max_packet_size) { log(buffers); diff --git a/src/libxrpl/beast/utility/src/beast_Journal.cpp b/src/libxrpl/beast/utility/src/beast_Journal.cpp index 8ce7ea8d47c..449f474739c 100644 --- a/src/libxrpl/beast/utility/src/beast_Journal.cpp +++ b/src/libxrpl/beast/utility/src/beast_Journal.cpp @@ -18,7 +18,7 @@ //============================================================================== #include -#include +#include namespace beast { diff --git a/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp b/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp index 56e862ca8c0..46c17ea4644 100644 --- a/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp +++ b/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp @@ -18,8 +18,8 @@ //============================================================================== #include +#include #include -#include #include #include @@ -199,7 +199,9 @@ PropertyStream::Source::add(Source& source) std::lock_guard lk1(lock_, std::adopt_lock); std::lock_guard lk2(source.lock_, std::adopt_lock); - assert(source.parent_ == nullptr); + ASSERT( + source.parent_ == nullptr, + "beast::PropertyStream::Source::add : null source parent"); children_.push_back(source.item_); source.parent_ = this; } @@ -211,7 +213,9 @@ PropertyStream::Source::remove(Source& child) std::lock_guard lk1(lock_, std::adopt_lock); std::lock_guard lk2(child.lock_, std::adopt_lock); - assert(child.parent_ == this); + ASSERT( + child.parent_ == this, + "beast::PropertyStream::Source::remove : child parent match"); children_.erase(children_.iterator_to(child.item_)); child.parent_ = nullptr; } diff --git a/src/libxrpl/crypto/RFC1751.cpp b/src/libxrpl/crypto/RFC1751.cpp index 1c6f28287b0..35363c862b5 100644 --- a/src/libxrpl/crypto/RFC1751.cpp +++ b/src/libxrpl/crypto/RFC1751.cpp @@ -17,10 +17,10 @@ */ //============================================================================== +#include #include #include #include -#include #include #include @@ -270,10 +270,12 @@ RFC1751::extract(char const* s, int start, int length) unsigned char cr; unsigned long x; - assert(length <= 11); - assert(start >= 0); - assert(length >= 0); - assert(start + length <= 66); + ASSERT(length <= 11, "ripple::RFC1751::extract : maximum length"); + ASSERT(start >= 0, "ripple::RFC1751::extract : minimum start"); + ASSERT(length >= 0, "ripple::RFC1751::extract : minimum length"); + ASSERT( + start + length <= 66, + "ripple::RFC1751::extract : maximum start + length"); int const shiftR = 24 - (length + (start % 8)); cl = s[start / 8]; // get components @@ -320,10 +322,12 @@ RFC1751::insert(char* s, int x, int start, int length) unsigned long y; int shift; - assert(length <= 11); - assert(start >= 0); - assert(length >= 0); - assert(start + length <= 66); + ASSERT(length <= 11, "ripple::RFC1751::insert : maximum length"); + ASSERT(start >= 0, "ripple::RFC1751::insert : minimum start"); + ASSERT(length >= 0, "ripple::RFC1751::insert : minimum length"); + ASSERT( + start + length <= 66, + "ripple::RFC1751::insert : maximum start + length"); shift = ((8 - ((start + length) % 8)) % 8); y = (long)x << shift; diff --git a/src/libxrpl/crypto/csprng.cpp b/src/libxrpl/crypto/csprng.cpp index 480d561eacf..948500734c0 100644 --- a/src/libxrpl/crypto/csprng.cpp +++ b/src/libxrpl/crypto/csprng.cpp @@ -18,9 +18,9 @@ //============================================================================== #include +#include #include #include -#include #include #include #include diff --git a/src/libxrpl/json/Object.cpp b/src/libxrpl/json/Object.cpp index 179b0e31ef2..d38132b1f21 100644 --- a/src/libxrpl/json/Object.cpp +++ b/src/libxrpl/json/Object.cpp @@ -18,8 +18,8 @@ //============================================================================== #include +#include #include -#include namespace Json { @@ -168,7 +168,7 @@ Array::append(Json::Value const& v) return; } } - assert(false); // Can't get here. + UNREACHABLE("Json::Array::append : invalid type"); } void @@ -203,7 +203,7 @@ Object::set(std::string const& k, Json::Value const& v) return; } } - assert(false); // Can't get here. + UNREACHABLE("Json::Object::set : invalid type"); } //------------------------------------------------------------------------------ @@ -214,7 +214,7 @@ template void doCopyFrom(Object& to, Json::Value const& from) { - assert(from.isObjectOrNull()); + ASSERT(from.isObjectOrNull(), "Json::doCopyFrom : valid input type"); auto members = from.getMemberNames(); for (auto& m : members) to[m] = from[m]; diff --git a/src/libxrpl/json/json_reader.cpp b/src/libxrpl/json/json_reader.cpp index 42488b3ec87..3e445ab5cc8 100644 --- a/src/libxrpl/json/json_reader.cpp +++ b/src/libxrpl/json/json_reader.cpp @@ -953,7 +953,7 @@ operator>>(std::istream& sin, Value& root) Json::Reader reader; bool ok = reader.parse(sin, root); - // JSON_ASSERT( ok ); + // ASSERT(ok, "Json::operator>>() : parse succeeded"); if (!ok) ripple::Throw(reader.getFormatedErrorMessages()); diff --git a/src/libxrpl/json/json_value.cpp b/src/libxrpl/json/json_value.cpp index 155c3e1e044..a2034f471c4 100644 --- a/src/libxrpl/json/json_value.cpp +++ b/src/libxrpl/json/json_value.cpp @@ -207,7 +207,7 @@ Value::Value(ValueType type) : type_(type), allocated_(0) break; default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::Value(ValueType) : invalid type"); } } @@ -277,7 +277,7 @@ Value::Value(const Value& other) : type_(other.type_) break; default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::Value(Value const&) : invalid type"); } } @@ -305,7 +305,7 @@ Value::~Value() break; default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::~Value : invalid type"); } } @@ -406,7 +406,7 @@ operator<(const Value& x, const Value& y) } default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::operator<(Value, Value) : invalid type"); } return 0; // unreachable @@ -452,7 +452,7 @@ operator==(const Value& x, const Value& y) *x.value_.map_ == *y.value_.map_; default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::operator==(Value, Value) : invalid type"); } return 0; // unreachable @@ -461,7 +461,7 @@ operator==(const Value& x, const Value& y) const char* Value::asCString() const { - JSON_ASSERT(type_ == stringValue); + ASSERT(type_ == stringValue, "Json::Value::asCString : valid type"); return value_.string_; } @@ -493,7 +493,7 @@ Value::asString() const JSON_ASSERT_MESSAGE(false, "Type is not convertible to string"); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::asString : invalid type"); } return ""; // unreachable @@ -535,7 +535,7 @@ Value::asInt() const JSON_ASSERT_MESSAGE(false, "Type is not convertible to int"); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::asInt : invalid type"); } return 0; // unreachable; @@ -577,7 +577,7 @@ Value::asUInt() const JSON_ASSERT_MESSAGE(false, "Type is not convertible to uint"); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::asUInt : invalid type"); } return 0; // unreachable; @@ -609,7 +609,7 @@ Value::asDouble() const JSON_ASSERT_MESSAGE(false, "Type is not convertible to double"); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::asDouble : invalid type"); } return 0; // unreachable; @@ -641,7 +641,7 @@ Value::asBool() const return value_.map_->size() != 0; default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::asBool : invalid type"); } return false; // unreachable; @@ -695,7 +695,7 @@ Value::isConvertibleTo(ValueType other) const (other == nullValue && value_.map_->size() == 0); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::isConvertible : invalid type"); } return false; // unreachable; @@ -729,7 +729,7 @@ Value::size() const return Int(value_.map_->size()); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::size : invalid type"); } return 0; // unreachable; @@ -752,8 +752,9 @@ Value::operator bool() const void Value::clear() { - JSON_ASSERT( - type_ == nullValue || type_ == arrayValue || type_ == objectValue); + ASSERT( + type_ == nullValue || type_ == arrayValue || type_ == objectValue, + "Json::Value::clear : valid type"); switch (type_) { @@ -770,7 +771,9 @@ Value::clear() Value& Value::operator[](UInt index) { - JSON_ASSERT(type_ == nullValue || type_ == arrayValue); + ASSERT( + type_ == nullValue || type_ == arrayValue, + "Json::Value::operator[](UInt) : valid type"); if (type_ == nullValue) *this = Value(arrayValue); @@ -789,7 +792,9 @@ Value::operator[](UInt index) const Value& Value::operator[](UInt index) const { - JSON_ASSERT(type_ == nullValue || type_ == arrayValue); + ASSERT( + type_ == nullValue || type_ == arrayValue, + "Json::Value::operator[](UInt) const : valid type"); if (type_ == nullValue) return null; @@ -812,7 +817,9 @@ Value::operator[](const char* key) Value& Value::resolveReference(const char* key, bool isStatic) { - JSON_ASSERT(type_ == nullValue || type_ == objectValue); + ASSERT( + type_ == nullValue || type_ == objectValue, + "Json::Value::resolveReference : valid type"); if (type_ == nullValue) *this = Value(objectValue); @@ -846,7 +853,9 @@ Value::isValidIndex(UInt index) const const Value& Value::operator[](const char* key) const { - JSON_ASSERT(type_ == nullValue || type_ == objectValue); + ASSERT( + type_ == nullValue || type_ == objectValue, + "Json::Value::operator[](const char*) const : valid type"); if (type_ == nullValue) return null; @@ -906,7 +915,9 @@ Value::get(std::string const& key, const Value& defaultValue) const Value Value::removeMember(const char* key) { - JSON_ASSERT(type_ == nullValue || type_ == objectValue); + ASSERT( + type_ == nullValue || type_ == objectValue, + "Json::Value::removeMember : valid type"); if (type_ == nullValue) return null; @@ -947,7 +958,9 @@ Value::isMember(std::string const& key) const Value::Members Value::getMemberNames() const { - JSON_ASSERT(type_ == nullValue || type_ == objectValue); + ASSERT( + type_ == nullValue || type_ == objectValue, + "Json::Value::getMemberNames : valid type"); if (type_ == nullValue) return Value::Members(); diff --git a/src/libxrpl/json/json_writer.cpp b/src/libxrpl/json/json_writer.cpp index 5459042cddb..3ae0dacfc2b 100644 --- a/src/libxrpl/json/json_writer.cpp +++ b/src/libxrpl/json/json_writer.cpp @@ -17,8 +17,8 @@ */ //============================================================================== +#include #include -#include #include #include #include @@ -70,7 +70,7 @@ valueToString(Int value) if (isNegative) *--current = '-'; - assert(current >= buffer); + ASSERT(current >= buffer, "Json::valueToString(Int) : buffer check"); return current; } @@ -80,7 +80,7 @@ valueToString(UInt value) char buffer[32]; char* current = buffer + sizeof(buffer); uintToString(value, current); - assert(current >= buffer); + ASSERT(current >= buffer, "Json::valueToString(UInt) : buffer check"); return current; } @@ -391,7 +391,9 @@ StyledWriter::writeArrayValue(const Value& value) } else // output on a single line { - assert(childValues_.size() == size); + ASSERT( + childValues_.size() == size, + "Json::StyledWriter::writeArrayValue : child size match"); document_ += "[ "; for (unsigned index = 0; index < size; ++index) @@ -483,7 +485,9 @@ StyledWriter::indent() void StyledWriter::unindent() { - assert(int(indentString_.size()) >= indentSize_); + ASSERT( + int(indentString_.size()) >= indentSize_, + "Json::StyledWriter::unindent : maximum indent size"); indentString_.resize(indentString_.size() - indentSize_); } @@ -613,7 +617,9 @@ StyledStreamWriter::writeArrayValue(const Value& value) } else // output on a single line { - assert(childValues_.size() == size); + ASSERT( + childValues_.size() == size, + "Json::StyledStreamWriter::writeArrayValue : child size match"); *document_ << "[ "; for (unsigned index = 0; index < size; ++index) @@ -706,7 +712,9 @@ StyledStreamWriter::indent() void StyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); + ASSERT( + indentString_.size() >= indentation_.size(), + "Json::StyledStreamWriter::unindent : maximum indent size"); indentString_.resize(indentString_.size() - indentation_.size()); } diff --git a/src/libxrpl/protocol/AMMCore.cpp b/src/libxrpl/protocol/AMMCore.cpp index 7ac27041e76..6661ab69a74 100644 --- a/src/libxrpl/protocol/AMMCore.cpp +++ b/src/libxrpl/protocol/AMMCore.cpp @@ -109,7 +109,9 @@ ammAuctionTimeSlot(std::uint64_t current, STObject const& auctionSlot) // It should be impossible for expiration to be < TOTAL_TIME_SLOT_SECS, // but check just to be safe auto const expiration = auctionSlot[sfExpiration]; - assert(expiration >= TOTAL_TIME_SLOT_SECS); + ASSERT( + expiration >= TOTAL_TIME_SLOT_SECS, + "ripple::ammAuctionTimeSlot : minimum expiration"); if (expiration >= TOTAL_TIME_SLOT_SECS) { if (auto const start = expiration - TOTAL_TIME_SLOT_SECS; diff --git a/src/libxrpl/protocol/AccountID.cpp b/src/libxrpl/protocol/AccountID.cpp index 5f0fa631851..8fe9ce115c4 100644 --- a/src/libxrpl/protocol/AccountID.cpp +++ b/src/libxrpl/protocol/AccountID.cpp @@ -77,7 +77,9 @@ class AccountIdCache auto ret = encodeBase58Token(TokenType::AccountID, id.data(), id.size()); - assert(ret.size() <= 38); + ASSERT( + ret.size() <= 38, + "ripple::detail::AccountIdCache : maximum result size"); { std::lock_guard lock(sl); diff --git a/src/libxrpl/protocol/ErrorCodes.cpp b/src/libxrpl/protocol/ErrorCodes.cpp index c157d9b296c..c9988eb589b 100644 --- a/src/libxrpl/protocol/ErrorCodes.cpp +++ b/src/libxrpl/protocol/ErrorCodes.cpp @@ -17,9 +17,9 @@ */ //============================================================================== +#include #include #include -#include #include namespace ripple { @@ -211,7 +211,9 @@ error_code_http_status(error_code_i code) std::string rpcErrorString(Json::Value const& jv) { - assert(RPC::contains_error(jv)); + ASSERT( + RPC::contains_error(jv), + "ripple::RPC::rpcErrorString : input contains an error"); return jv[jss::error].asString() + jv[jss::error_message].asString(); } diff --git a/src/libxrpl/protocol/Feature.cpp b/src/libxrpl/protocol/Feature.cpp index 3f6e760577a..47c495f9d62 100644 --- a/src/libxrpl/protocol/Feature.cpp +++ b/src/libxrpl/protocol/Feature.cpp @@ -221,7 +221,9 @@ FeatureCollections::FeatureCollections() std::optional FeatureCollections::getRegisteredFeature(std::string const& name) const { - assert(readOnly); + ASSERT( + readOnly.load(), + "ripple::FeatureCollections::getRegisteredFeature : startup completed"); Feature const* feature = getByName(name); if (feature) return feature->feature; @@ -303,7 +305,9 @@ FeatureCollections::registrationIsDone() size_t FeatureCollections::featureToBitsetIndex(uint256 const& f) const { - assert(readOnly); + ASSERT( + readOnly.load(), + "ripple::FeatureCollections::featureToBitsetIndex : startup completed"); Feature const* feature = getByFeature(f); if (!feature) @@ -315,7 +319,9 @@ FeatureCollections::featureToBitsetIndex(uint256 const& f) const uint256 const& FeatureCollections::bitsetIndexToFeature(size_t i) const { - assert(readOnly); + ASSERT( + readOnly.load(), + "ripple::FeatureCollections::bitsetIndexToFeature : startup completed"); Feature const& feature = getByIndex(i); return feature.feature; } @@ -323,7 +329,9 @@ FeatureCollections::bitsetIndexToFeature(size_t i) const std::string FeatureCollections::featureToName(uint256 const& f) const { - assert(readOnly); + ASSERT( + readOnly.load(), + "ripple::FeatureCollections::featureToName : startup completed"); Feature const* feature = getByFeature(f); return feature ? feature->name : to_string(f); } diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index 12142879ad5..1519673ad4a 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -17,6 +17,7 @@ */ //============================================================================== +#include #include #include #include @@ -26,7 +27,6 @@ #include #include -#include namespace ripple { @@ -95,7 +95,7 @@ indexHash(LedgerNameSpace space, Args const&... args) uint256 getBookBase(Book const& book) { - assert(isConsistent(book)); + ASSERT(isConsistent(book), "ripple::getBookBase : input is consistent"); auto const index = indexHash( LedgerNameSpace::BOOK_DIR, @@ -135,7 +135,7 @@ getTicketIndex(AccountID const& account, std::uint32_t ticketSeq) uint256 getTicketIndex(AccountID const& account, SeqProxy ticketSeq) { - assert(ticketSeq.isTicket()); + ASSERT(ticketSeq.isTicket(), "ripple::getTicketIndex : valid input"); return getTicketIndex(account, ticketSeq.value()); } @@ -222,7 +222,7 @@ line( // There is code in SetTrust that calls us with id0 == id1, to allow users // to locate and delete such "weird" trustlines. If we remove that code, we // could enable this assert: - // assert(id0 != id1); + // ASSERT(id0 != id1, "ripple::keylet::line : accounts must be different"); // A trust line is shared between two accounts; while we typically think // of this as an "issuer" and a "holder" the relationship is actually fully @@ -251,7 +251,7 @@ offer(AccountID const& id, std::uint32_t seq) noexcept Keylet quality(Keylet const& k, std::uint64_t q) noexcept { - assert(k.type == ltDIR_NODE); + ASSERT(k.type == ltDIR_NODE, "ripple::keylet::quality : valid input type"); // Indexes are stored in big endian format: they print as hex as stored. // Most significant bytes are first and the least significant bytes @@ -269,7 +269,9 @@ quality(Keylet const& k, std::uint64_t q) noexcept Keylet next_t::operator()(Keylet const& k) const { - assert(k.type == ltDIR_NODE); + ASSERT( + k.type == ltDIR_NODE, + "ripple::keylet::next_t::operator() : valid input type"); return {ltDIR_NODE, getQualityNext(k.key)}; } @@ -387,7 +389,8 @@ nftpage_max(AccountID const& owner) Keylet nftpage(Keylet const& k, uint256 const& token) { - assert(k.type == ltNFTOKEN_PAGE); + ASSERT( + k.type == ltNFTOKEN_PAGE, "ripple::keylet::nftpage : valid input type"); return {ltNFTOKEN_PAGE, (k.key & ~nft::pageMask) + (token & nft::pageMask)}; } diff --git a/src/libxrpl/protocol/Keylet.cpp b/src/libxrpl/protocol/Keylet.cpp index 23847811d3b..ab6b8ad0cf7 100644 --- a/src/libxrpl/protocol/Keylet.cpp +++ b/src/libxrpl/protocol/Keylet.cpp @@ -25,7 +25,9 @@ namespace ripple { bool Keylet::check(STLedgerEntry const& sle) const { - assert(sle.getType() != ltANY || sle.getType() != ltCHILD); + ASSERT( + sle.getType() != ltANY || sle.getType() != ltCHILD, + "ripple::Keylet::check : valid input type"); if (type == ltANY) return true; diff --git a/src/libxrpl/protocol/Quality.cpp b/src/libxrpl/protocol/Quality.cpp index c6464eba9d2..005e824760e 100644 --- a/src/libxrpl/protocol/Quality.cpp +++ b/src/libxrpl/protocol/Quality.cpp @@ -17,8 +17,8 @@ */ //============================================================================== +#include #include -#include #include namespace ripple { @@ -35,7 +35,7 @@ Quality::Quality(Amounts const& amount) Quality& Quality::operator++() { - assert(m_value > 0); + ASSERT(m_value > 0, "ripple::Quality::operator++() : minimum value"); --m_value; return *this; } @@ -51,7 +51,9 @@ Quality::operator++(int) Quality& Quality::operator--() { - assert(m_value < std::numeric_limits::max()); + ASSERT( + m_value < std::numeric_limits::max(), + "ripple::Quality::operator--() : maximum value"); ++m_value; return *this; } @@ -81,10 +83,11 @@ ceil_in_impl( // Clamp out if (result.out > amount.out) result.out = amount.out; - assert(result.in == limit); + ASSERT( + result.in == limit, "ripple::ceil_in_impl : result matches limit"); return result; } - assert(amount.in <= limit); + ASSERT(amount.in <= limit, "ripple::ceil_in_impl : result inside limit"); return amount; } @@ -120,10 +123,12 @@ ceil_out_impl( // Clamp in if (result.in > amount.in) result.in = amount.in; - assert(result.out == limit); + ASSERT( + result.out == limit, + "ripple::ceil_out_impl : result matches limit"); return result; } - assert(amount.out <= limit); + ASSERT(amount.out <= limit, "ripple::ceil_out_impl : result inside limit"); return amount; } @@ -146,17 +151,23 @@ Quality composed_quality(Quality const& lhs, Quality const& rhs) { STAmount const lhs_rate(lhs.rate()); - assert(lhs_rate != beast::zero); + ASSERT( + lhs_rate != beast::zero, + "ripple::composed_quality : nonzero left input"); STAmount const rhs_rate(rhs.rate()); - assert(rhs_rate != beast::zero); + ASSERT( + rhs_rate != beast::zero, + "ripple::composed_quality : nonzero right input"); STAmount const rate(mulRound(lhs_rate, rhs_rate, lhs_rate.asset(), true)); std::uint64_t const stored_exponent(rate.exponent() + 100); std::uint64_t const stored_mantissa(rate.mantissa()); - assert((stored_exponent > 0) && (stored_exponent <= 255)); + ASSERT( + (stored_exponent > 0) && (stored_exponent <= 255), + "ripple::composed_quality : valid exponent"); return Quality((stored_exponent << (64 - 8)) | stored_mantissa); } diff --git a/src/libxrpl/protocol/Rate2.cpp b/src/libxrpl/protocol/Rate2.cpp index 33bd9c5d0be..3e7d467e184 100644 --- a/src/libxrpl/protocol/Rate2.cpp +++ b/src/libxrpl/protocol/Rate2.cpp @@ -46,7 +46,7 @@ transferFeeAsRate(std::uint16_t fee) STAmount multiply(STAmount const& amount, Rate const& rate) { - assert(rate.value != 0); + ASSERT(rate.value != 0, "ripple::nft::multiply : nonzero rate input"); if (rate == parityRate) return amount; @@ -57,7 +57,7 @@ multiply(STAmount const& amount, Rate const& rate) STAmount multiplyRound(STAmount const& amount, Rate const& rate, bool roundUp) { - assert(rate.value != 0); + ASSERT(rate.value != 0, "ripple::nft::multiplyRound : nonzero rate input"); if (rate == parityRate) return amount; @@ -72,7 +72,9 @@ multiplyRound( Asset const& asset, bool roundUp) { - assert(rate.value != 0); + ASSERT( + rate.value != 0, + "ripple::nft::multiplyRound(Issue) : nonzero rate input"); if (rate == parityRate) { @@ -85,7 +87,7 @@ multiplyRound( STAmount divide(STAmount const& amount, Rate const& rate) { - assert(rate.value != 0); + ASSERT(rate.value != 0, "ripple::nft::divide : nonzero rate input"); if (rate == parityRate) return amount; @@ -96,7 +98,7 @@ divide(STAmount const& amount, Rate const& rate) STAmount divideRound(STAmount const& amount, Rate const& rate, bool roundUp) { - assert(rate.value != 0); + ASSERT(rate.value != 0, "ripple::nft::divideRound : nonzero rate input"); if (rate == parityRate) return amount; @@ -111,7 +113,9 @@ divideRound( Asset const& asset, bool roundUp) { - assert(rate.value != 0); + ASSERT( + rate.value != 0, + "ripple::nft::divideRound(Issue) : nonzero rate input"); if (rate == parityRate) return amount; diff --git a/src/libxrpl/protocol/Rules.cpp b/src/libxrpl/protocol/Rules.cpp index f47e966e138..3edc1448d00 100644 --- a/src/libxrpl/protocol/Rules.cpp +++ b/src/libxrpl/protocol/Rules.cpp @@ -91,7 +91,10 @@ class Rules::Impl return true; if (!digest_ || !other.digest_) return false; - assert(presets_ == other.presets_); + ASSERT( + presets_ == other.presets_, + "ripple::Rules::Impl::operator==(Impl) const : input presets do " + "match"); return *digest_ == *other.digest_; } }; @@ -118,7 +121,7 @@ Rules::presets() const bool Rules::enabled(uint256 const& feature) const { - assert(impl_); + ASSERT(impl_ != nullptr, "ripple::Rules::enabled : initialized"); // The functionality of the "NonFungibleTokensV1_1" amendment is // precisely the functionality of the following three amendments @@ -137,7 +140,9 @@ Rules::enabled(uint256 const& feature) const bool Rules::operator==(Rules const& other) const { - assert(impl_ && other.impl_); + ASSERT( + impl_ && other.impl_, + "ripple::Rules::operator==(Rules) const : both initialized"); if (impl_.get() == other.impl_.get()) return true; return *impl_ == *other.impl_; diff --git a/src/libxrpl/protocol/SField.cpp b/src/libxrpl/protocol/SField.cpp index 537fa557fcc..20e1e112655 100644 --- a/src/libxrpl/protocol/SField.cpp +++ b/src/libxrpl/protocol/SField.cpp @@ -17,8 +17,8 @@ */ //============================================================================== +#include #include -#include #include #include #include diff --git a/src/libxrpl/protocol/STAccount.cpp b/src/libxrpl/protocol/STAccount.cpp index 8ae43f76863..d3d93f75601 100644 --- a/src/libxrpl/protocol/STAccount.cpp +++ b/src/libxrpl/protocol/STAccount.cpp @@ -80,8 +80,10 @@ STAccount::getSType() const void STAccount::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == STI_ACCOUNT); + ASSERT(getFName().isBinary(), "ripple::STAccount::add : field is binary"); + ASSERT( + getFName().fieldType == STI_ACCOUNT, + "ripple::STAccount::add : valid field type"); // Preserve the serialization behavior of an STBlob: // o If we are default (all zeros) serialize as an empty blob. diff --git a/src/libxrpl/protocol/STAmount.cpp b/src/libxrpl/protocol/STAmount.cpp index fe13118d88c..c33b2b40aa3 100644 --- a/src/libxrpl/protocol/STAmount.cpp +++ b/src/libxrpl/protocol/STAmount.cpp @@ -29,7 +29,7 @@ #include #include #include -#include + #include #include @@ -68,11 +68,13 @@ getInt64Value(STAmount const& amount, bool valid, const char* error) { if (!valid) Throw(error); - assert(amount.exponent() == 0); + ASSERT(amount.exponent() == 0, "ripple::getInt64Value : exponent is zero"); auto ret = static_cast(amount.mantissa()); - assert(static_cast(ret) == amount.mantissa()); + ASSERT( + static_cast(ret) == amount.mantissa(), + "ripple::getInt64Value : mantissa must roundtrip"); if (amount.negative()) ret = -ret; @@ -199,7 +201,10 @@ STAmount::STAmount(SField const& name, std::uint64_t mantissa, bool negative) , mOffset(0) , mIsNegative(negative) { - assert(mValue <= std::numeric_limits::max()); + ASSERT( + mValue <= std::numeric_limits::max(), + "ripple::STAmount::STAmount(SField, std::uint64_t, bool) : maximum " + "mantissa input"); } STAmount::STAmount(SField const& name, STAmount const& from) @@ -209,7 +214,9 @@ STAmount::STAmount(SField const& name, STAmount const& from) , mOffset(from.mOffset) , mIsNegative(from.mIsNegative) { - assert(mValue <= std::numeric_limits::max()); + ASSERT( + mValue <= std::numeric_limits::max(), + "ripple::STAmount::STAmount(SField, STAmount) : maximum input"); canonicalize(); } @@ -221,7 +228,10 @@ STAmount::STAmount(std::uint64_t mantissa, bool negative) , mOffset(0) , mIsNegative(mantissa != 0 && negative) { - assert(mValue <= std::numeric_limits::max()); + ASSERT( + mValue <= std::numeric_limits::max(), + "ripple::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa " + "input"); } STAmount::STAmount(XRPAmount const& amount) @@ -305,7 +315,9 @@ STAmount::mpt() const STAmount& STAmount::operator=(IOUAmount const& iou) { - assert(native() == false); + ASSERT( + native() == false, + "ripple::STAmount::operator=(IOUAmount) : is not XRP"); mOffset = iou.exponent(); mIsNegative = iou < beast::zero; if (mIsNegative) @@ -444,7 +456,9 @@ getRate(STAmount const& offerOut, STAmount const& offerIn) STAmount r = divide(offerIn, offerOut, noIssue()); if (r == beast::zero) // offer is too good return 0; - assert((r.exponent() >= -100) && (r.exponent() <= 155)); + ASSERT( + (r.exponent() >= -100) && (r.exponent() <= 155), + "ripple::getRate : exponent inside range"); std::uint64_t ret = r.exponent() + 100; return (ret << (64 - 8)) | r.mantissa(); } @@ -525,7 +539,7 @@ STAmount::getText() const return ret; } - assert(mOffset + 43 > 0); + ASSERT(mOffset + 43 > 0, "ripple::STAmount::getText : minimum offset"); size_t const pad_prefix = 27; size_t const pad_suffix = 23; @@ -549,7 +563,9 @@ STAmount::getText() const if (std::distance(pre_from, pre_to) > pad_prefix) pre_from += pad_prefix; - assert(post_to >= post_from); + ASSERT( + post_to >= post_from, + "ripple::STAmount::getText : first distance check"); pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; }); @@ -558,7 +574,9 @@ STAmount::getText() const if (std::distance(post_from, post_to) > pad_suffix) post_to -= pad_suffix; - assert(post_to >= post_from); + ASSERT( + post_to >= post_from, + "ripple::STAmount::getText : second distance check"); post_to = std::find_if( std::make_reverse_iterator(post_to), @@ -594,7 +612,7 @@ STAmount::add(Serializer& s) const { if (native()) { - assert(mOffset == 0); + ASSERT(mOffset == 0, "ripple::STAmount::add : zero offset"); if (!mIsNegative) s.add64(mValue | cPositive); @@ -771,10 +789,15 @@ STAmount::canonicalize() if (mOffset > cMaxOffset) Throw("value overflow"); - assert((mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue))); - assert( - (mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset))); - assert((mValue != 0) || (mOffset != -100)); + ASSERT( + (mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue)), + "ripple::STAmount::canonicalize : value inside range"); + ASSERT( + (mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset)), + "ripple::STAmount::canonicalize : offset inside range"); + ASSERT( + (mValue != 0) || (mOffset != -100), + "ripple::STAmount::canonicalize : value or offset set"); } void diff --git a/src/libxrpl/protocol/STBase.cpp b/src/libxrpl/protocol/STBase.cpp index 73565cbf765..d93068bb053 100644 --- a/src/libxrpl/protocol/STBase.cpp +++ b/src/libxrpl/protocol/STBase.cpp @@ -17,10 +17,9 @@ */ //============================================================================== +#include #include #include -#include -#include namespace ripple { @@ -30,7 +29,7 @@ STBase::STBase() : fName(&sfGeneric) STBase::STBase(SField const& n) : fName(&n) { - assert(fName); + ASSERT(fName != nullptr, "ripple::STBase::STBase : field is set"); } STBase& @@ -106,13 +105,15 @@ void STBase::add(Serializer& s) const { // Should never be called - assert(false); + UNREACHABLE("ripple::STBase::add : not implemented"); } bool STBase::isEquivalent(const STBase& t) const { - assert(getSType() == STI_NOTPRESENT); + ASSERT( + getSType() == STI_NOTPRESENT, + "ripple::STBase::isEquivalent : type not present"); return t.getSType() == STI_NOTPRESENT; } @@ -126,7 +127,7 @@ void STBase::setFName(SField const& n) { fName = &n; - assert(fName); + ASSERT(fName != nullptr, "ripple::STBase::setFName : field is set"); } SField const& @@ -138,7 +139,7 @@ STBase::getFName() const void STBase::addFieldID(Serializer& s) const { - assert(fName->isBinary()); + ASSERT(fName->isBinary(), "ripple::STBase::addFieldID : field is binary"); s.addFieldID(fName->fieldType, fName->fieldValue); } diff --git a/src/libxrpl/protocol/STBlob.cpp b/src/libxrpl/protocol/STBlob.cpp index 63e7b4bf3da..755588138a2 100644 --- a/src/libxrpl/protocol/STBlob.cpp +++ b/src/libxrpl/protocol/STBlob.cpp @@ -54,10 +54,11 @@ STBlob::getText() const void STBlob::add(Serializer& s) const { - assert(getFName().isBinary()); - assert( + ASSERT(getFName().isBinary(), "ripple::STBlob::add : field is binary"); + ASSERT( (getFName().fieldType == STI_VL) || - (getFName().fieldType == STI_ACCOUNT)); + (getFName().fieldType == STI_ACCOUNT), + "ripple::STBlob::add : valid field type"); s.addVL(value_.data(), value_.size()); } diff --git a/src/libxrpl/protocol/STInteger.cpp b/src/libxrpl/protocol/STInteger.cpp index 7dfcc50dea0..5e8fc47d9da 100644 --- a/src/libxrpl/protocol/STInteger.cpp +++ b/src/libxrpl/protocol/STInteger.cpp @@ -199,12 +199,16 @@ Json::Value STUInt64::getJson(JsonOptions) const { auto convertToString = [](uint64_t const value, int const base) { - assert(base == 10 || base == 16); + ASSERT( + base == 10 || base == 16, + "ripple::STUInt64::getJson : base 10 or 16"); std::string str( base == 10 ? 20 : 16, 0); // Allocate space depending on base auto ret = std::to_chars(str.data(), str.data() + str.size(), value, base); - assert(ret.ec == std::errc()); + ASSERT( + ret.ec == std::errc(), + "ripple::STUInt64::getJson : to_chars succeeded"); str.resize(std::distance(str.data(), ret.ptr)); return str; }; diff --git a/src/libxrpl/protocol/STLedgerEntry.cpp b/src/libxrpl/protocol/STLedgerEntry.cpp index 1801149ab2a..b7579a04ca8 100644 --- a/src/libxrpl/protocol/STLedgerEntry.cpp +++ b/src/libxrpl/protocol/STLedgerEntry.cpp @@ -161,7 +161,9 @@ STLedgerEntry::thread( if (oldPrevTxID == txID) { // this transaction is already threaded - assert(getFieldU32(sfPreviousTxnLgrSeq) == ledgerSeq); + ASSERT( + getFieldU32(sfPreviousTxnLgrSeq) == ledgerSeq, + "ripple::STLedgerEntry::thread : ledger sequence match"); return false; } diff --git a/src/libxrpl/protocol/STNumber.cpp b/src/libxrpl/protocol/STNumber.cpp index 3a92bbb02f9..74bda0046cf 100644 --- a/src/libxrpl/protocol/STNumber.cpp +++ b/src/libxrpl/protocol/STNumber.cpp @@ -19,6 +19,7 @@ #include +#include #include namespace ripple { @@ -52,8 +53,10 @@ STNumber::getText() const void STNumber::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == getSType()); + ASSERT(getFName().isBinary(), "ripple::STNumber::add : field is binary"); + ASSERT( + getFName().fieldType == getSType(), + "ripple::STNumber::add : field type match"); s.add64(value_.mantissa()); s.add32(value_.exponent()); } @@ -85,7 +88,9 @@ STNumber::move(std::size_t n, void* buf) bool STNumber::isEquivalent(STBase const& t) const { - assert(t.getSType() == this->getSType()); + ASSERT( + t.getSType() == this->getSType(), + "ripple::STNumber::isEquivalent : field type match"); STNumber const& v = dynamic_cast(t); return value_ == v; } diff --git a/src/libxrpl/protocol/STObject.cpp b/src/libxrpl/protocol/STObject.cpp index c8fc88348e9..520dc53b0de 100644 --- a/src/libxrpl/protocol/STObject.cpp +++ b/src/libxrpl/protocol/STObject.cpp @@ -862,9 +862,10 @@ STObject::add(Serializer& s, WhichFields whichFields) const // the type associated by rule with this field name // must be OBJECT, or the object cannot be deserialized SerializedTypeID const sType{field->getSType()}; - assert( + ASSERT( (sType != STI_OBJECT) || - (field->getFName().fieldType == STI_OBJECT)); + (field->getFName().fieldType == STI_OBJECT), + "ripple::STObject::add : valid field type"); field->addFieldID(s); field->add(s); if (sType == STI_ARRAY || sType == STI_OBJECT) diff --git a/src/libxrpl/protocol/STParsedJSON.cpp b/src/libxrpl/protocol/STParsedJSON.cpp index 09b6b6679d7..7d08993a8ba 100644 --- a/src/libxrpl/protocol/STParsedJSON.cpp +++ b/src/libxrpl/protocol/STParsedJSON.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,6 @@ #include #include -#include #include #include diff --git a/src/libxrpl/protocol/STPathSet.cpp b/src/libxrpl/protocol/STPathSet.cpp index 78c47cadc66..3409299d7cb 100644 --- a/src/libxrpl/protocol/STPathSet.cpp +++ b/src/libxrpl/protocol/STPathSet.cpp @@ -209,8 +209,10 @@ STPathSet::getSType() const void STPathSet::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == STI_PATHSET); + ASSERT(getFName().isBinary(), "ripple::STPathSet::add : field is binary"); + ASSERT( + getFName().fieldType == STI_PATHSET, + "ripple::STPathSet::add : valid field type"); bool first = true; for (auto const& spPath : value) diff --git a/src/libxrpl/protocol/STTx.cpp b/src/libxrpl/protocol/STTx.cpp index 7bd25246c53..b530271080d 100644 --- a/src/libxrpl/protocol/STTx.cpp +++ b/src/libxrpl/protocol/STTx.cpp @@ -137,7 +137,9 @@ STTx::getMentionedAccounts() const { if (auto sacc = dynamic_cast(&it)) { - assert(!sacc->isDefault()); + ASSERT( + !sacc->isDefault(), + "ripple::STTx::getMentionedAccounts : account is set"); if (!sacc->isDefault()) list.insert(sacc->value()); } @@ -298,7 +300,8 @@ STTx::getMetaSQL( std::string rTxn = sqlBlobLiteral(rawTxn.peekData()); auto format = TxFormats::getInstance().findByType(tx_type_); - assert(format != nullptr); + ASSERT( + format != nullptr, "ripple::STTx::getMetaSQL : non-null type format"); return str( boost::format(bfTrans) % to_string(getTransactionID()) % diff --git a/src/libxrpl/protocol/STValidation.cpp b/src/libxrpl/protocol/STValidation.cpp index ca5ceb0d9ce..5820fc9f9b0 100644 --- a/src/libxrpl/protocol/STValidation.cpp +++ b/src/libxrpl/protocol/STValidation.cpp @@ -107,7 +107,9 @@ STValidation::isValid() const noexcept { if (!valid_) { - assert(publicKeyType(getSignerPublic()) == KeyType::secp256k1); + ASSERT( + publicKeyType(getSignerPublic()) == KeyType::secp256k1, + "ripple::STValidation::isValid : valid key type"); valid_ = verifyDigest( getSignerPublic(), diff --git a/src/libxrpl/protocol/STVar.cpp b/src/libxrpl/protocol/STVar.cpp index 55927cb33aa..4c9217328f6 100644 --- a/src/libxrpl/protocol/STVar.cpp +++ b/src/libxrpl/protocol/STVar.cpp @@ -121,7 +121,9 @@ STVar::STVar(SerialIter& sit, SField const& name, int depth) STVar::STVar(SerializedTypeID id, SField const& name) { - assert((id == STI_NOTPRESENT) || (id == name.fieldType)); + ASSERT( + (id == STI_NOTPRESENT) || (id == name.fieldType), + "ripple::detail::STVar::STVar(SerializedTypeID) : valid type input"); constructST(id, 0, name); } diff --git a/src/libxrpl/protocol/STVector256.cpp b/src/libxrpl/protocol/STVector256.cpp index 385c0ef76db..e9ea1e862de 100644 --- a/src/libxrpl/protocol/STVector256.cpp +++ b/src/libxrpl/protocol/STVector256.cpp @@ -68,8 +68,10 @@ STVector256::isDefault() const void STVector256::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == STI_VECTOR256); + ASSERT(getFName().isBinary(), "ripple::STVector256::add : field is binary"); + ASSERT( + getFName().fieldType == STI_VECTOR256, + "ripple::STVector256::add : valid field type"); s.addVL(mValue.begin(), mValue.end(), mValue.size() * (256 / 8)); } diff --git a/src/libxrpl/protocol/Serializer.cpp b/src/libxrpl/protocol/Serializer.cpp index ceaf76faf34..51fb94054e3 100644 --- a/src/libxrpl/protocol/Serializer.cpp +++ b/src/libxrpl/protocol/Serializer.cpp @@ -107,7 +107,9 @@ int Serializer::addFieldID(int type, int name) { int ret = mData.size(); - assert((type > 0) && (type < 256) && (name > 0) && (name < 256)); + ASSERT( + (type > 0) && (type < 256) && (name > 0) && (name < 256), + "ripple::Serializer::addFieldID : inputs inside range"); if (type < 16) { @@ -176,9 +178,10 @@ Serializer::addVL(Blob const& vector) { int ret = addEncoded(vector.size()); addRaw(vector); - assert( + ASSERT( mData.size() == - (ret + vector.size() + encodeLengthLength(vector.size()))); + (ret + vector.size() + encodeLengthLength(vector.size())), + "ripple::Serializer::addVL : size matches expected"); return ret; } @@ -482,7 +485,8 @@ SerialIter::getVLDataLength() } else { - assert(lenLen == 3); + ASSERT( + lenLen == 3, "ripple::SerialIter::getVLDataLength : lenLen is 3"); int b2 = get8(); int b3 = get8(); datLen = Serializer::decodeVLLength(b1, b2, b3); diff --git a/src/libxrpl/protocol/TxMeta.cpp b/src/libxrpl/protocol/TxMeta.cpp index 253d00e8414..ea3e43240ba 100644 --- a/src/libxrpl/protocol/TxMeta.cpp +++ b/src/libxrpl/protocol/TxMeta.cpp @@ -55,7 +55,9 @@ TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj) auto affectedNodes = dynamic_cast(obj.peekAtPField(sfAffectedNodes)); - assert(affectedNodes); + ASSERT( + affectedNodes != nullptr, + "ripple::TxMeta::TxMeta(STObject) : type cast succeeded"); if (affectedNodes) mNodes = *affectedNodes; @@ -106,7 +108,9 @@ TxMeta::setAffectedNode( mNodes.push_back(STObject(type)); STObject& obj = mNodes.back(); - assert(obj.getFName() == type); + ASSERT( + obj.getFName() == type, + "ripple::TxMeta::setAffectedNode : field type match"); obj.setFieldH256(sfLedgerIndex, node); obj.setFieldU16(sfLedgerEntryType, nodeType); } @@ -127,14 +131,18 @@ TxMeta::getAffectedAccounts() const if (index != -1) { auto inner = dynamic_cast(&it.peekAtIndex(index)); - assert(inner); + ASSERT( + inner != nullptr, + "ripple::getAffectedAccounts : STObject type cast succeeded"); if (inner) { for (auto const& field : *inner) { if (auto sa = dynamic_cast(&field)) { - assert(!sa->isDefault()); + ASSERT( + !sa->isDefault(), + "ripple::getAffectedAccounts : account is set"); if (!sa->isDefault()) list.insert(sa->value()); } @@ -145,7 +153,10 @@ TxMeta::getAffectedAccounts() const (field.getFName() == sfTakerGets)) { auto lim = dynamic_cast(&field); - assert(lim); + ASSERT( + lim != nullptr, + "ripple::getAffectedAccounts : STAmount type cast " + "succeeded"); if (lim != nullptr) { @@ -175,7 +186,9 @@ TxMeta::getAffectedNode(SLE::ref node, SField const& type) mNodes.push_back(STObject(type)); STObject& obj = mNodes.back(); - assert(obj.getFName() == type); + ASSERT( + obj.getFName() == type, + "ripple::TxMeta::getAffectedNode(SLE::ref) : field type match"); obj.setFieldH256(sfLedgerIndex, index); obj.setFieldU16(sfLedgerEntryType, node->getFieldU16(sfLedgerEntryType)); @@ -190,7 +203,7 @@ TxMeta::getAffectedNode(uint256 const& node) if (n.getFieldH256(sfLedgerIndex) == node) return n; } - assert(false); + UNREACHABLE("ripple::TxMeta::getAffectedNode(uint256) : node not found"); Throw("Affected node not found"); return *(mNodes.begin()); // Silence compiler warning. } @@ -199,7 +212,7 @@ STObject TxMeta::getAsObject() const { STObject metaData(sfTransactionMetaData); - assert(mResult != 255); + ASSERT(mResult != 255, "ripple::TxMeta::getAsObject : result is set"); metaData.setFieldU8(sfTransactionResult, mResult); metaData.setFieldU32(sfTransactionIndex, mIndex); metaData.emplace_back(mNodes); @@ -213,7 +226,9 @@ TxMeta::addRaw(Serializer& s, TER result, std::uint32_t index) { mResult = TERtoInt(result); mIndex = index; - assert((mResult == 0) || ((mResult > 100) && (mResult <= 255))); + ASSERT( + (mResult == 0) || ((mResult > 100) && (mResult <= 255)), + "ripple::TxMeta::addRaw : valid TER input"); mNodes.sort([](STObject const& o1, STObject const& o2) { return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex); diff --git a/src/libxrpl/protocol/tokens.cpp b/src/libxrpl/protocol/tokens.cpp index ccae1fb8ed2..de3812637cf 100644 --- a/src/libxrpl/protocol/tokens.cpp +++ b/src/libxrpl/protocol/tokens.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -35,7 +36,6 @@ #include #include -#include #include #include #include @@ -248,7 +248,8 @@ encodeBase58( iter[-1] = carry % 58; carry /= 58; } - assert(carry == 0); + ASSERT( + carry == 0, "ripple::b58_ref::detail::encodeBase58 : zero carry"); pbegin++; } @@ -298,7 +299,8 @@ decodeBase58(std::string const& s) *iter = carry % 256; carry /= 256; } - assert(carry == 0); + ASSERT( + carry == 0, "ripple::b58_ref::detail::decodeBase58 : zero carry"); ++psz; --remain; } @@ -535,7 +537,9 @@ b58_to_b256_be(std::string_view input, std::span out) ripple::b58_fast::detail::div_rem(input.size(), 10); auto const num_partial_coeffs = partial_coeff_len ? 1 : 0; auto const num_b_58_10_coeffs = num_full_coeffs + num_partial_coeffs; - assert(num_b_58_10_coeffs <= b_58_10_coeff.size()); + ASSERT( + num_b_58_10_coeffs <= b_58_10_coeff.size(), + "ripple::b58_fast::detail::b58_to_b256_be : maximum coeff"); for (auto c : input.substr(0, partial_coeff_len)) { auto cur_val = ::ripple::alphabetReverse[c]; diff --git a/src/libxrpl/resource/Consumer.cpp b/src/libxrpl/resource/Consumer.cpp index b8652546841..adabd770964 100644 --- a/src/libxrpl/resource/Consumer.cpp +++ b/src/libxrpl/resource/Consumer.cpp @@ -17,10 +17,10 @@ */ //============================================================================== +#include #include #include #include -#include namespace ripple { namespace Resource { @@ -109,14 +109,18 @@ Consumer::charge(Charge const& what) bool Consumer::warn() { - assert(m_entry != nullptr); + ASSERT( + m_entry != nullptr, + "ripple::Resource::Consumer::warn : non-null entry"); return m_logic->warn(*m_entry); } bool Consumer::disconnect(beast::Journal const& j) { - assert(m_entry != nullptr); + ASSERT( + m_entry != nullptr, + "ripple::Resource::Consumer::disconnect : non-null entry"); bool const d = m_logic->disconnect(*m_entry); if (d) { @@ -128,14 +132,18 @@ Consumer::disconnect(beast::Journal const& j) int Consumer::balance() { - assert(m_entry != nullptr); + ASSERT( + m_entry != nullptr, + "ripple::Resource::Consumer::balance : non-null entry"); return m_logic->balance(*m_entry); } Entry& Consumer::entry() { - assert(m_entry != nullptr); + ASSERT( + m_entry != nullptr, + "ripple::Resource::Consumer::entry : non-null entry"); return *m_entry; } diff --git a/src/test/jtx/impl/amount.cpp b/src/test/jtx/impl/amount.cpp index 9f374c2cb58..5be53dc0a95 100644 --- a/src/test/jtx/impl/amount.cpp +++ b/src/test/jtx/impl/amount.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/src/test/overlay/short_read_test.cpp b/src/test/overlay/short_read_test.cpp index 6dd4f8c00b8..0efc49b84e3 100644 --- a/src/test/overlay/short_read_test.cpp +++ b/src/test/overlay/short_read_test.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include #include diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index 263d660d003..0be77c7de79 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -92,7 +93,9 @@ RCLConsensus::Adaptor::Adaptor( std::numeric_limits::max() - 1)) , nUnlVote_(validatorKeys_.nodeID, j_) { - assert(valCookie_ != 0); + ASSERT( + valCookie_ != 0, + "ripple::RCLConsensus::Adaptor::Adaptor : nonzero cookie"); JLOG(j_.info()) << "Consensus engine started (cookie: " + std::to_string(valCookie_) + ")"; @@ -146,8 +149,12 @@ RCLConsensus::Adaptor::acquireLedger(LedgerHash const& hash) return std::nullopt; } - assert(!built->open() && built->isImmutable()); - assert(built->info().hash == hash); + ASSERT( + !built->open() && built->isImmutable(), + "ripple::RCLConsensus::Adaptor::acquireLedger : valid ledger state"); + ASSERT( + built->info().hash == hash, + "ripple::RCLConsensus::Adaptor::acquireLedger : ledger hash match"); // Notify inbound transactions of the new ledger sequence number inboundTransactions_.newRound(built->info().seq); @@ -673,8 +680,12 @@ RCLConsensus::Adaptor::doAccept( ledgerMaster_.switchLCL(built.ledger_); // Do these need to exist? - assert(ledgerMaster_.getClosedLedger()->info().hash == built.id()); - assert(app_.openLedger().current()->info().parentHash == built.id()); + ASSERT( + ledgerMaster_.getClosedLedger()->info().hash == built.id(), + "ripple::RCLConsensus::Adaptor::doAccept : ledger hash match"); + ASSERT( + app_.openLedger().current()->info().parentHash == built.id(), + "ripple::RCLConsensus::Adaptor::doAccept : parent hash match"); } //------------------------------------------------------------------------- @@ -770,7 +781,9 @@ RCLConsensus::Adaptor::buildLCL( std::shared_ptr built = [&]() { if (auto const replayData = ledgerMaster_.releaseReplay()) { - assert(replayData->parent()->info().hash == previousLedger.id()); + ASSERT( + replayData->parent()->info().hash == previousLedger.id(), + "ripple::RCLConsensus::Adaptor::buildLCL : parent hash match"); return buildLedger(*replayData, tapNONE, app_, j_); } return buildLedger( diff --git a/src/xrpld/app/consensus/RCLCxPeerPos.cpp b/src/xrpld/app/consensus/RCLCxPeerPos.cpp index 74747853a2d..14a60a84182 100644 --- a/src/xrpld/app/consensus/RCLCxPeerPos.cpp +++ b/src/xrpld/app/consensus/RCLCxPeerPos.cpp @@ -38,7 +38,9 @@ RCLCxPeerPos::RCLCxPeerPos( { // The maximum allowed size of a signature is 72 bytes; we verify // this elsewhere, but we want to be extra careful here: - assert(signature.size() != 0 && signature.size() <= signature_.capacity()); + ASSERT( + signature.size() != 0 && signature.size() <= signature_.capacity(), + "ripple::RCLCxPeerPos::RCLCxPeerPos : valid signature size"); if (signature.size() != 0 && signature.size() <= signature_.capacity()) signature_.assign(signature.begin(), signature.end()); diff --git a/src/xrpld/app/consensus/RCLCxTx.h b/src/xrpld/app/consensus/RCLCxTx.h index 58e58ac3b7d..0181eb03c21 100644 --- a/src/xrpld/app/consensus/RCLCxTx.h +++ b/src/xrpld/app/consensus/RCLCxTx.h @@ -111,7 +111,9 @@ class RCLTxSet */ RCLTxSet(std::shared_ptr m) : map_{std::move(m)} { - assert(map_); + ASSERT( + map_ != nullptr, + "ripple::RCLTxSet::MutableTxSet::RCLTxSet : non-null input"); } /** Constructor from a previously created MutableTxSet @@ -177,7 +179,9 @@ class RCLTxSet std::map ret; for (auto const& [k, v] : delta) { - assert((v.first && !v.second) || (v.second && !v.first)); + ASSERT( + (v.first && !v.second) || (v.second && !v.first), + "ripple::RCLTxSet::compare : either side is set"); ret[k] = static_cast(v.first); } diff --git a/src/xrpld/app/consensus/RCLValidations.cpp b/src/xrpld/app/consensus/RCLValidations.cpp index 096ec56df6f..e620cd3de90 100644 --- a/src/xrpld/app/consensus/RCLValidations.cpp +++ b/src/xrpld/app/consensus/RCLValidations.cpp @@ -50,7 +50,10 @@ RCLValidatedLedger::RCLValidatedLedger( auto const hashIndex = ledger->read(keylet::skip()); if (hashIndex) { - assert(hashIndex->getFieldU32(sfLastLedgerSequence) == (seq() - 1)); + ASSERT( + hashIndex->getFieldU32(sfLastLedgerSequence) == (seq() - 1), + "ripple::RCLValidatedLedger::RCLValidatedLedger(Ledger) : valid " + "last ledger sequence"); ancestors_ = hashIndex->getFieldV256(sfHashes).value(); } else @@ -151,8 +154,12 @@ RCLValidationsAdaptor::acquire(LedgerHash const& hash) return std::nullopt; } - assert(!ledger->open() && ledger->isImmutable()); - assert(ledger->info().hash == hash); + ASSERT( + !ledger->open() && ledger->isImmutable(), + "ripple::RCLValidationsAdaptor::acquire : valid ledger state"); + ASSERT( + ledger->info().hash == hash, + "ripple::RCLValidationsAdaptor::acquire : ledger hash match"); return RCLValidatedLedger(std::move(ledger), j_); } @@ -191,7 +198,9 @@ handleNewValidation( { if (bypassAccept == BypassAccept::yes) { - assert(j.has_value()); + ASSERT( + j.has_value(), + "ripple::handleNewValidation : journal is available"); if (j.has_value()) { JLOG(j->trace()) << "Bypassing checkAccept for validation " diff --git a/src/xrpld/app/ledger/AcceptedLedgerTx.cpp b/src/xrpld/app/ledger/AcceptedLedgerTx.cpp index e1ad68dff37..620ab031762 100644 --- a/src/xrpld/app/ledger/AcceptedLedgerTx.cpp +++ b/src/xrpld/app/ledger/AcceptedLedgerTx.cpp @@ -33,7 +33,9 @@ AcceptedLedgerTx::AcceptedLedgerTx( , mMeta(txn->getTransactionID(), ledger->seq(), *met) , mAffected(mMeta.getAffectedAccounts()) { - assert(!ledger->open()); + ASSERT( + !ledger->open(), + "ripple::AcceptedLedgerTx::AcceptedLedgerTx : valid ledger state"); Serializer s; met->add(s); @@ -76,7 +78,9 @@ AcceptedLedgerTx::AcceptedLedgerTx( std::string AcceptedLedgerTx::getEscMeta() const { - assert(!mRawMeta.empty()); + ASSERT( + !mRawMeta.empty(), + "ripple::AcceptedLedgerTx::getEscMeta : metadata is set"); return sqlBlobLiteral(mRawMeta); } diff --git a/src/xrpld/app/ledger/ConsensusTransSetSF.cpp b/src/xrpld/app/ledger/ConsensusTransSetSF.cpp index 4aed7d94bf3..334b6d46dbd 100644 --- a/src/xrpld/app/ledger/ConsensusTransSetSF.cpp +++ b/src/xrpld/app/ledger/ConsensusTransSetSF.cpp @@ -60,7 +60,10 @@ ConsensusTransSetSF::gotNode( Serializer s(nodeData.data() + 4, nodeData.size() - 4); SerialIter sit(s.slice()); auto stx = std::make_shared(std::ref(sit)); - assert(stx->getTransactionID() == nodeHash.as_uint256()); + ASSERT( + stx->getTransactionID() == nodeHash.as_uint256(), + "ripple::ConsensusTransSetSF::gotNode : transaction hash " + "match"); auto const pap = &app_; app_.getJobQueue().addJob(jtTRANSACTION, "TXS->TXN", [pap, stx]() { pap->getOPs().submitTransaction(stx); @@ -92,7 +95,9 @@ ConsensusTransSetSF::getNode(SHAMapHash const& nodeHash) const Serializer s; s.add32(HashPrefix::transactionID); txn->getSTransaction()->add(s); - assert(sha512Half(s.slice()) == nodeHash.as_uint256()); + ASSERT( + sha512Half(s.slice()) == nodeHash.as_uint256(), + "ripple::ConsensusTransSetSF::getNode : transaction hash match"); nodeData = s.peekData(); return nodeData; } diff --git a/src/xrpld/app/ledger/Ledger.cpp b/src/xrpld/app/ledger/Ledger.cpp index 4991b551cd1..5fdc4811051 100644 --- a/src/xrpld/app/ledger/Ledger.cpp +++ b/src/xrpld/app/ledger/Ledger.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,6 @@ #include #include #include -#include #include #include @@ -369,7 +369,7 @@ Ledger::setAccepted( bool correctCloseTime) { // Used when we witnessed the consensus. - assert(!open()); + ASSERT(!open(), "ripple::Ledger::setAccepted : valid ledger state"); info_.closeTime = closeTime; info_.closeTimeResolution = closeResolution; @@ -442,7 +442,7 @@ Ledger::read(Keylet const& k) const { if (k.key == beast::zero) { - assert(false); + UNREACHABLE("ripple::Ledger::read : zero key"); return nullptr; } auto const& item = stateMap_.peekItem(k.key); @@ -562,7 +562,9 @@ Ledger::rawTxInsert( std::shared_ptr const& txn, std::shared_ptr const& metaData) { - assert(metaData); + ASSERT( + metaData != nullptr, + "ripple::Ledger::rawTxInsert : non-null metadata input"); // low-level - just add to table Serializer s(txn->getDataLength() + metaData->getDataLength() + 16); @@ -579,7 +581,9 @@ Ledger::rawTxInsertWithHash( std::shared_ptr const& txn, std::shared_ptr const& metaData) { - assert(metaData); + ASSERT( + metaData != nullptr, + "ripple::Ledger::rawTxInsertWithHash : non-null metadata input"); // low-level - just add to table Serializer s(txn->getDataLength() + metaData->getDataLength() + 16); @@ -675,7 +679,9 @@ Ledger::setup() void Ledger::defaultFees(Config const& config) { - assert(fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0); + ASSERT( + fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0, + "ripple::Ledger::defaultFees : zero fees"); if (fees_.base == 0) fees_.base = config.FEES.reference_fee; if (fees_.reserve == 0) @@ -871,7 +877,7 @@ Ledger::assertSensible(beast::Journal ledgerJ) const JLOG(ledgerJ.fatal()) << "ledger is not sensible" << j; - assert(false); + UNREACHABLE("ripple::Ledger::assertSensible : ledger is not sensible"); return false; } @@ -905,7 +911,9 @@ Ledger::updateSkipList() created = false; } - assert(hashes.size() <= 256); + ASSERT( + hashes.size() <= 256, + "ripple::Ledger::updateSkipList : first maximum hashes size"); hashes.push_back(info_.parentHash); sle->setFieldV256(sfHashes, STVector256(hashes)); sle->setFieldU32(sfLastLedgerSequence, prevIndex); @@ -930,7 +938,9 @@ Ledger::updateSkipList() hashes = static_cast(sle->getFieldV256(sfHashes)); created = false; } - assert(hashes.size() <= 256); + ASSERT( + hashes.size() <= 256, + "ripple::Ledger::updateSkipList : second maximum hashes size"); if (hashes.size() == 256) hashes.erase(hashes.begin()); hashes.push_back(info_.parentHash); @@ -1010,7 +1020,8 @@ pendSaveValidated( } } - assert(ledger->isImmutable()); + ASSERT( + ledger->isImmutable(), "ripple::pendSaveValidated : immutable ledger"); if (!app.pendingSaves().shouldWork(ledger->info().seq, isSynchronous)) { @@ -1087,9 +1098,10 @@ finishLoadByIndexOrHash( if (!ledger) return; - assert( + ASSERT( ledger->info().seq < XRP_LEDGER_EARLIEST_FEES || - ledger->read(keylet::fees())); + ledger->read(keylet::fees()), + "ripple::finishLoadByIndexOrHash : valid ledger fees"); ledger->setImmutable(); JLOG(j.trace()) << "Loaded ledger: " << to_string(ledger->info().hash); @@ -1128,7 +1140,9 @@ loadByHash(uint256 const& ledgerHash, Application& app, bool acquire) { std::shared_ptr ledger = loadLedgerHelper(*info, app, acquire); finishLoadByIndexOrHash(ledger, app.config(), app.journal("Ledger")); - assert(!ledger || ledger->info().hash == ledgerHash); + ASSERT( + !ledger || ledger->info().hash == ledgerHash, + "ripple::loadByHash : ledger hash match if loaded"); return ledger; } return {}; diff --git a/src/xrpld/app/ledger/LedgerHistory.cpp b/src/xrpld/app/ledger/LedgerHistory.cpp index b63cd84772a..b12a0da0fa3 100644 --- a/src/xrpld/app/ledger/LedgerHistory.cpp +++ b/src/xrpld/app/ledger/LedgerHistory.cpp @@ -58,7 +58,9 @@ LedgerHistory::insert( if (!ledger->isImmutable()) LogicError("mutable Ledger in insert"); - assert(ledger->stateMap().getHash().isNonZero()); + ASSERT( + ledger->stateMap().getHash().isNonZero(), + "ripple::LedgerHistory::insert : nonzero hash"); std::unique_lock sl(m_ledgers_by_hash.peekMutex()); @@ -99,13 +101,17 @@ LedgerHistory::getLedgerBySeq(LedgerIndex index) if (!ret) return ret; - assert(ret->info().seq == index); + ASSERT( + ret->info().seq == index, + "ripple::LedgerHistory::getLedgerBySeq : result sequence match"); { // Add this ledger to the local tracking by index std::unique_lock sl(m_ledgers_by_hash.peekMutex()); - assert(ret->isImmutable()); + ASSERT( + ret->isImmutable(), + "ripple::LedgerHistory::getLedgerBySeq : immutable result ledger"); m_ledgers_by_hash.canonicalize_replace_client(ret->info().hash, ret); mLedgersByIndex[ret->info().seq] = ret->info().hash; return (ret->info().seq == index) ? ret : nullptr; @@ -119,8 +125,14 @@ LedgerHistory::getLedgerByHash(LedgerHash const& hash) if (ret) { - assert(ret->isImmutable()); - assert(ret->info().hash == hash); + ASSERT( + ret->isImmutable(), + "ripple::LedgerHistory::getLedgerByHash : immutable fetched " + "ledger"); + ASSERT( + ret->info().hash == hash, + "ripple::LedgerHistory::getLedgerByHash : fetched ledger hash " + "match"); return ret; } @@ -129,10 +141,16 @@ LedgerHistory::getLedgerByHash(LedgerHash const& hash) if (!ret) return ret; - assert(ret->isImmutable()); - assert(ret->info().hash == hash); + ASSERT( + ret->isImmutable(), + "ripple::LedgerHistory::getLedgerByHash : immutable loaded ledger"); + ASSERT( + ret->info().hash == hash, + "ripple::LedgerHistory::getLedgerByHash : loaded ledger hash match"); m_ledgers_by_hash.canonicalize_replace_client(ret->info().hash, ret); - assert(ret->info().hash == hash); + ASSERT( + ret->info().hash == hash, + "ripple::LedgerHistory::getLedgerByHash : result hash match"); return ret; } @@ -176,7 +194,9 @@ log_metadata_difference( auto validMetaData = getMeta(validLedger, tx); auto builtMetaData = getMeta(builtLedger, tx); - assert(validMetaData || builtMetaData); + ASSERT( + validMetaData || builtMetaData, + "ripple::log_metadata_difference : some metadata present"); if (validMetaData && builtMetaData) { @@ -320,7 +340,9 @@ LedgerHistory::handleMismatch( std::optional const& validatedConsensusHash, Json::Value const& consensus) { - assert(built != valid); + ASSERT( + built != valid, + "ripple::LedgerHistory::handleMismatch : unequal hashes"); ++mismatch_counter_; auto builtLedger = getLedgerByHash(built); @@ -335,7 +357,9 @@ LedgerHistory::handleMismatch( return; } - assert(builtLedger->info().seq == validLedger->info().seq); + ASSERT( + builtLedger->info().seq == validLedger->info().seq, + "ripple::LedgerHistory::handleMismatch : sequence match"); if (auto stream = j_.debug()) { @@ -428,7 +452,7 @@ LedgerHistory::builtLedger( { LedgerIndex index = ledger->info().seq; LedgerHash hash = ledger->info().hash; - assert(!hash.isZero()); + ASSERT(!hash.isZero(), "ripple::LedgerHistory::builtLedger : nonzero hash"); std::unique_lock sl(m_consensus_validated.peekMutex()); @@ -468,7 +492,9 @@ LedgerHistory::validatedLedger( { LedgerIndex index = ledger->info().seq; LedgerHash hash = ledger->info().hash; - assert(!hash.isZero()); + ASSERT( + !hash.isZero(), + "ripple::LedgerHistory::validatedLedger : nonzero hash"); std::unique_lock sl(m_consensus_validated.peekMutex()); diff --git a/src/xrpld/app/ledger/OpenLedger.h b/src/xrpld/app/ledger/OpenLedger.h index b218b1d6e11..2ec355fd82f 100644 --- a/src/xrpld/app/ledger/OpenLedger.h +++ b/src/xrpld/app/ledger/OpenLedger.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include namespace ripple { @@ -263,7 +263,8 @@ OpenLedger::apply( // If there are any transactions left, we must have // tried them in at least one final pass - assert(retries.empty() || !retry); + ASSERT( + retries.empty() || !retry, "ripple::OpenLedger::apply : valid retries"); } //------------------------------------------------------------------------------ diff --git a/src/xrpld/app/ledger/OrderBookDB.cpp b/src/xrpld/app/ledger/OrderBookDB.cpp index d0eddadbacb..926728cbf4f 100644 --- a/src/xrpld/app/ledger/OrderBookDB.cpp +++ b/src/xrpld/app/ledger/OrderBookDB.cpp @@ -225,7 +225,9 @@ OrderBookDB::makeBookListeners(Book const& book) ret = std::make_shared(); mListeners[book] = ret; - assert(getBookListeners(book) == ret); + ASSERT( + getBookListeners(book) == ret, + "ripple::OrderBookDB::makeBookListeners : result roundtrip lookup"); } return ret; diff --git a/src/xrpld/app/ledger/TransactionStateSF.cpp b/src/xrpld/app/ledger/TransactionStateSF.cpp index fac28cd2aa8..fef622945c1 100644 --- a/src/xrpld/app/ledger/TransactionStateSF.cpp +++ b/src/xrpld/app/ledger/TransactionStateSF.cpp @@ -30,7 +30,9 @@ TransactionStateSF::gotNode( SHAMapNodeType type) const { - assert(type != SHAMapNodeType::tnTRANSACTION_NM); + ASSERT( + type != SHAMapNodeType::tnTRANSACTION_NM, + "ripple::TransactionStateSF::gotNode : valid input"); db_.store( hotTRANSACTION_NODE, std::move(nodeData), diff --git a/src/xrpld/app/ledger/detail/BuildLedger.cpp b/src/xrpld/app/ledger/detail/BuildLedger.cpp index 8c4a7a3f41d..812f9dbbc05 100644 --- a/src/xrpld/app/ledger/detail/BuildLedger.cpp +++ b/src/xrpld/app/ledger/detail/BuildLedger.cpp @@ -57,7 +57,7 @@ buildLedgerImpl( { OpenView accum(&*built); - assert(!accum.open()); + ASSERT(!accum.open(), "ripple::buildLedgerImpl : valid ledger state"); applyTxs(accum, built); accum.apply(*built); } @@ -75,9 +75,10 @@ buildLedgerImpl( built->unshare(); // Accept ledger - assert( + ASSERT( built->info().seq < XRP_LEDGER_EARLIEST_FEES || - built->read(keylet::fees())); + built->read(keylet::fees()), + "ripple::buildLedgerImpl : valid ledger fees"); built->setAccepted(closeTime, closeResolution, closeTimeCorrect); return built; @@ -169,7 +170,9 @@ applyTransactions( // If there are any transactions left, we must have // tried them in at least one final pass - assert(txns.empty() || !certainRetry); + ASSERT( + txns.empty() || !certainRetry, + "ripple::applyTransactions : retry transactions"); return count; } diff --git a/src/xrpld/app/ledger/detail/InboundLedger.cpp b/src/xrpld/app/ledger/detail/InboundLedger.cpp index 16b15c2fce7..add0726719a 100644 --- a/src/xrpld/app/ledger/detail/InboundLedger.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedger.cpp @@ -120,9 +120,10 @@ InboundLedger::init(ScopedLockType& collectionLock) JLOG(journal_.debug()) << "Acquiring ledger we already have in " << " local store. " << hash_; - assert( + ASSERT( mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - mLedger->read(keylet::fees())); + mLedger->read(keylet::fees()), + "ripple::InboundLedger::init : valid ledger fees"); mLedger->setImmutable(); if (mReason == Reason::HISTORY) @@ -351,9 +352,10 @@ InboundLedger::tryDB(NodeStore::Database& srcDB) { JLOG(journal_.debug()) << "Had everything locally"; complete_ = true; - assert( + ASSERT( mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - mLedger->read(keylet::fees())); + mLedger->read(keylet::fees()), + "ripple::InboundLedger::tryDB : valid ledger fees"); mLedger->setImmutable(); } } @@ -447,13 +449,16 @@ InboundLedger::done() std::to_string(timeouts_) + " ")) << mStats.get(); - assert(complete_ || failed_); + ASSERT( + complete_ || failed_, + "ripple::InboundLedger::done : complete or failed"); if (complete_ && !failed_ && mLedger) { - assert( + ASSERT( mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - mLedger->read(keylet::fees())); + mLedger->read(keylet::fees()), + "ripple::InboundLedger::done : valid ledger fees"); mLedger->setImmutable(); switch (mReason) { @@ -613,7 +618,10 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) // if we wind up abandoning this fetch. if (mHaveHeader && !mHaveState && !failed_) { - assert(mLedger); + ASSERT( + mLedger != nullptr, + "ripple::InboundLedger::trigger : non-null ledger to read state " + "from"); if (!mLedger->stateMap().isValid()) { @@ -685,7 +693,10 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) if (mHaveHeader && !mHaveTransactions && !failed_) { - assert(mLedger); + ASSERT( + mLedger != nullptr, + "ripple::InboundLedger::trigger : non-null ledger to read " + "transactions from"); if (!mLedger->txMap().isValid()) { @@ -950,7 +961,7 @@ InboundLedger::takeAsRootNode(Slice const& data, SHAMapAddNode& san) if (!mHaveHeader) { - assert(false); + UNREACHABLE("ripple::InboundLedger::takeAsRootNode : no ledger header"); return false; } @@ -975,7 +986,7 @@ InboundLedger::takeTxRootNode(Slice const& data, SHAMapAddNode& san) if (!mHaveHeader) { - assert(false); + UNREACHABLE("ripple::InboundLedger::takeTxRootNode : no ledger header"); return false; } diff --git a/src/xrpld/app/ledger/detail/InboundLedgers.cpp b/src/xrpld/app/ledger/detail/InboundLedgers.cpp index f6d86a4d737..3b492de5531 100644 --- a/src/xrpld/app/ledger/detail/InboundLedgers.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedgers.cpp @@ -73,7 +73,9 @@ class InboundLedgersImp : public InboundLedgers InboundLedger::Reason reason) override { auto doAcquire = [&, seq, reason]() -> std::shared_ptr { - assert(hash.isNonZero()); + ASSERT( + hash.isNonZero(), + "ripple::InboundLedgersImp::acquire::doAcquire : nonzero hash"); // probably not the right rule if (app_.getOPs().isNeedNetworkLedger() && @@ -162,7 +164,9 @@ class InboundLedgersImp : public InboundLedgers std::shared_ptr find(uint256 const& hash) override { - assert(hash.isNonZero()); + ASSERT( + hash.isNonZero(), + "ripple::InboundLedgersImp::find : nonzero input"); std::shared_ptr ret; @@ -324,7 +328,9 @@ class InboundLedgersImp : public InboundLedgers acqs.reserve(mLedgers.size()); for (auto const& it : mLedgers) { - assert(it.second); + ASSERT( + it.second != nullptr, + "ripple::InboundLedgersImp::getInfo : non-null ledger"); acqs.push_back(it); } for (auto const& it : mRecentFailures) @@ -359,7 +365,10 @@ class InboundLedgersImp : public InboundLedgers acquires.reserve(mLedgers.size()); for (auto const& it : mLedgers) { - assert(it.second); + ASSERT( + it.second != nullptr, + "ripple::InboundLedgersImp::gotFetchPack : non-null " + "ledger"); acquires.push_back(it.second); } } diff --git a/src/xrpld/app/ledger/detail/LedgerCleaner.cpp b/src/xrpld/app/ledger/detail/LedgerCleaner.cpp index 3021c691c53..7c9d0f9fd53 100644 --- a/src/xrpld/app/ledger/detail/LedgerCleaner.cpp +++ b/src/xrpld/app/ledger/detail/LedgerCleaner.cpp @@ -231,7 +231,9 @@ class LedgerCleanerImp : public LedgerCleaner }); if (shouldExit_) break; - assert(state_ == State::cleaning); + ASSERT( + state_ == State::cleaning, + "ripple::LedgerCleanerImp::run : is cleaning"); } doLedgerCleaner(); } @@ -353,7 +355,9 @@ class LedgerCleanerImp : public LedgerCleaner LedgerHash refHash = getLedgerHash(referenceLedger, refIndex); bool const nonzero(refHash.isNonZero()); - assert(nonzero); + ASSERT( + nonzero, + "ripple::LedgerCleanerImp::getHash : nonzero hash"); if (nonzero) { // We found the hash and sequence of a better reference diff --git a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp index e079fb3ee27..6c19f6da4ea 100644 --- a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp +++ b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp @@ -199,8 +199,12 @@ LedgerDeltaAcquire::tryBuild(std::shared_ptr const& parent) if (failed_ || !complete_ || !replayTemp_) return {}; - assert(parent->seq() + 1 == replayTemp_->seq()); - assert(parent->info().hash == replayTemp_->info().parentHash); + ASSERT( + parent->seq() + 1 == replayTemp_->seq(), + "ripple::LedgerDeltaAcquire::tryBuild : parent sequence match"); + ASSERT( + parent->info().hash == replayTemp_->info().parentHash, + "ripple::LedgerDeltaAcquire::tryBuild : parent hash match"); // build ledger LedgerReplay replayData(parent, replayTemp_, std::move(orderedTxns_)); fullLedger_ = buildLedger(replayData, tapNONE, app_, journal_); @@ -262,7 +266,7 @@ LedgerDeltaAcquire::onLedgerBuilt( void LedgerDeltaAcquire::notify(ScopedLockType& sl) { - assert(isDone()); + ASSERT(isDone(), "ripple::LedgerDeltaAcquire::notify : is done"); std::vector toCall; std::swap(toCall, dataReadyCallbacks_); auto const good = !failed_; diff --git a/src/xrpld/app/ledger/detail/LedgerMaster.cpp b/src/xrpld/app/ledger/detail/LedgerMaster.cpp index 53edef17d33..f5d55f6af23 100644 --- a/src/xrpld/app/ledger/detail/LedgerMaster.cpp +++ b/src/xrpld/app/ledger/detail/LedgerMaster.cpp @@ -47,13 +47,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -276,9 +276,11 @@ LedgerMaster::setValidLedger(std::shared_ptr const& l) mValidLedger.set(l); mValidLedgerSign = signTime.time_since_epoch().count(); - assert( + ASSERT( mValidLedgerSeq || !app_.getMaxDisallowedLedger() || - l->info().seq + max_ledger_difference_ > app_.getMaxDisallowedLedger()); + l->info().seq + max_ledger_difference_ > + app_.getMaxDisallowedLedger(), + "ripple::LedgerMaster::setValidLedger : valid ledger sequence"); (void)max_ledger_difference_; mValidLedgerSeq = l->info().seq; @@ -343,7 +345,9 @@ LedgerMaster::addHeldTransaction( bool LedgerMaster::canBeCurrent(std::shared_ptr const& ledger) { - assert(ledger); + ASSERT( + ledger != nullptr, + "ripple::LedgerMaster::canBeCurrent : non-null input"); // Never jump to a candidate ledger that precedes our // last validated ledger @@ -411,7 +415,9 @@ LedgerMaster::canBeCurrent(std::shared_ptr const& ledger) void LedgerMaster::switchLCL(std::shared_ptr const& lastClosed) { - assert(lastClosed); + ASSERT( + lastClosed != nullptr, + "ripple::LedgerMaster::switchLCL : non-null input"); if (!lastClosed->isImmutable()) LogicError("mutable ledger in switchLCL"); @@ -528,7 +534,9 @@ LedgerMaster::isValidated(ReadView const& ledger) // This ledger's hash is not the hash of the validated ledger if (hash) { - assert(hash->isNonZero()); + ASSERT( + hash->isNonZero(), + "ripple::LedgerMaster::isValidated : nonzero hash"); uint256 valHash = app_.getRelationalDatabase().getHashByIndex(seq); if (valHash == ledger.info().hash) @@ -818,7 +826,9 @@ LedgerMaster::setFullLedger( // A new ledger has been accepted as part of the trusted chain JLOG(m_journal.debug()) << "Ledger " << ledger->info().seq << " accepted :" << ledger->info().hash; - assert(ledger->stateMap().getHash().isNonZero()); + ASSERT( + ledger->stateMap().getHash().isNonZero(), + "ripple::LedgerMaster::setFullLedger : nonzero ledger state hash"); ledger->setValidated(); ledger->setFull(); @@ -1282,7 +1292,9 @@ LedgerMaster::findNewLedgersToPublish( { JLOG(m_journal.fatal()) << "Ledger: " << valSeq << " does not have hash for " << seq; - assert(false); + UNREACHABLE( + "ripple::LedgerMaster::findNewLedgersToPublish : ledger " + "not found"); } else { @@ -1369,7 +1381,9 @@ LedgerMaster::tryAdvance() app_.getJobQueue().addJob(jtADVANCE, "advanceLedger", [this]() { std::unique_lock sl(m_mutex); - assert(!mValidLedger.empty() && mAdvanceThread); + ASSERT( + !mValidLedger.empty() && mAdvanceThread, + "ripple::LedgerMaster::tryAdvance : has valid ledger"); JLOG(m_journal.trace()) << "advanceThread<"; @@ -1670,7 +1684,9 @@ LedgerMaster::walkHashBySeq( // be located easily and should contain the hash. LedgerIndex refIndex = getCandidateLedger(index); auto const refHash = hashOfSeq(*referenceLedger, refIndex, m_journal); - assert(refHash); + ASSERT( + refHash.has_value(), + "ripple::LedgerMaster::walkHashBySeq : found ledger"); if (refHash) { // Try the hash and sequence of a better reference ledger just found @@ -1695,7 +1711,10 @@ LedgerMaster::walkHashBySeq( *refHash, refIndex, reason)) { ledgerHash = hashOfSeq(*l, index, m_journal); - assert(ledgerHash); + ASSERT( + ledgerHash.has_value(), + "ripple::LedgerMaster::walkHashBySeq : has complete " + "ledger"); } } } @@ -1807,7 +1826,9 @@ LedgerMaster::fetchForHistory( scope_unlock sul{sl}; if (auto hash = getLedgerHashForHistory(missing, reason)) { - assert(hash->isNonZero()); + ASSERT( + hash->isNonZero(), + "ripple::LedgerMaster::fetchForHistory : found ledger"); auto ledger = getLedgerByHash(*hash); if (!ledger) { @@ -1834,7 +1855,9 @@ LedgerMaster::fetchForHistory( if (ledger) { auto seq = ledger->info().seq; - assert(seq == missing); + ASSERT( + seq == missing, + "ripple::LedgerMaster::fetchForHistory : sequence match"); JLOG(m_journal.trace()) << "fetchForHistory acquired " << seq; setFullLedger(ledger, false, false); int fillInProgress; @@ -1875,7 +1898,10 @@ LedgerMaster::fetchForHistory( std::uint32_t seq = missing - i; if (auto h = getLedgerHashForHistory(seq, reason)) { - assert(h->isNonZero()); + ASSERT( + h->isNonZero(), + "ripple::LedgerMaster::fetchForHistory : " + "prefetched ledger"); app_.getInboundLedgers().acquire(*h, seq, reason); } } @@ -2061,7 +2087,7 @@ populateFetchPack( std::uint32_t seq, bool withLeaves = true) { - assert(cnt != 0); + ASSERT(cnt != 0, "ripple::populateFetchPack : nonzero count input"); Serializer s(1024); diff --git a/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp b/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp index d7f29e33b3b..e03137a8b09 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp @@ -32,7 +32,10 @@ LedgerReplayTask::TaskParameter::TaskParameter( std::uint32_t totalNumLedgers) : reason_(r), finishHash_(finishLedgerHash), totalLedgers_(totalNumLedgers) { - assert(finishLedgerHash.isNonZero() && totalNumLedgers > 0); + ASSERT( + finishLedgerHash.isNonZero() && totalNumLedgers > 0, + "ripple::LedgerReplayTask::TaskParameter::TaskParameter : valid " + "inputs"); } bool @@ -48,7 +51,9 @@ LedgerReplayTask::TaskParameter::update( skipList_ = sList; skipList_.emplace_back(finishHash_); startHash_ = skipList_[skipList_.size() - totalLedgers_]; - assert(startHash_.isNonZero()); + ASSERT( + startHash_.isNonZero(), + "ripple::LedgerReplayTask::TaskParameter::update : nonzero start hash"); startSeq_ = finishSeq_ - totalLedgers_ + 1; full_ = true; return true; @@ -200,7 +205,9 @@ LedgerReplayTask::tryAdvance(ScopedLockType& sl) for (; deltaToBuild_ < deltas_.size(); ++deltaToBuild_) { auto& delta = deltas_[deltaToBuild_]; - assert(parent_->seq() + 1 == delta->ledgerSeq_); + ASSERT( + parent_->seq() + 1 == delta->ledgerSeq_, + "ripple::LedgerReplayTask::tryAdvance : consecutive sequence"); if (auto l = delta->tryBuild(parent_); l) { JLOG(journal_.debug()) @@ -289,9 +296,11 @@ LedgerReplayTask::addDelta(std::shared_ptr const& delta) JLOG(journal_.trace()) << "addDelta task " << hash_ << " deltaIndex=" << deltaToBuild_ << " totalDeltas=" << deltas_.size(); - assert( + ASSERT( deltas_.empty() || - deltas_.back()->ledgerSeq_ + 1 == delta->ledgerSeq_); + deltas_.back()->ledgerSeq_ + 1 == delta->ledgerSeq_, + "ripple::LedgerReplayTask::addDelta : no deltas or consecutive " + "sequence", ); deltas_.push_back(delta); } } diff --git a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp index 4aa0e4beb79..7557d9ed344 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp @@ -47,9 +47,10 @@ LedgerReplayer::replay( uint256 const& finishLedgerHash, std::uint32_t totalNumLedgers) { - assert( + ASSERT( finishLedgerHash.isNonZero() && totalNumLedgers > 0 && - totalNumLedgers <= LedgerReplayParameters::MAX_TASK_SIZE); + totalNumLedgers <= LedgerReplayParameters::MAX_TASK_SIZE, + "ripple::LedgerReplayer::replay : valid inputs"); LedgerReplayTask::TaskParameter parameter( r, finishLedgerHash, totalNumLedgers); diff --git a/src/xrpld/app/ledger/detail/SkipListAcquire.cpp b/src/xrpld/app/ledger/detail/SkipListAcquire.cpp index 1d1de62b61b..3b3952a5557 100644 --- a/src/xrpld/app/ledger/detail/SkipListAcquire.cpp +++ b/src/xrpld/app/ledger/detail/SkipListAcquire.cpp @@ -139,7 +139,9 @@ SkipListAcquire::processData( std::uint32_t ledgerSeq, boost::intrusive_ptr const& item) { - assert(ledgerSeq != 0 && item); + ASSERT( + ledgerSeq != 0 && item, + "ripple::SkipListAcquire::processData : valid inputs"); ScopedLockType sl(mtx_); if (isDone()) return; @@ -224,7 +226,7 @@ SkipListAcquire::onSkipListAcquired( void SkipListAcquire::notify(ScopedLockType& sl) { - assert(isDone()); + ASSERT(isDone(), "ripple::SkipListAcquire::notify : is done"); std::vector toCall; std::swap(toCall, dataReadyCallbacks_); auto const good = !failed_; diff --git a/src/xrpld/app/ledger/detail/TimeoutCounter.cpp b/src/xrpld/app/ledger/detail/TimeoutCounter.cpp index f70e54f8cd4..1d8efca37f9 100644 --- a/src/xrpld/app/ledger/detail/TimeoutCounter.cpp +++ b/src/xrpld/app/ledger/detail/TimeoutCounter.cpp @@ -43,7 +43,9 @@ TimeoutCounter::TimeoutCounter( , queueJobParameter_(std::move(jobParameter)) , timer_(app_.getIOService()) { - assert((timerInterval_ > 10ms) && (timerInterval_ < 30s)); + ASSERT( + (timerInterval_ > 10ms) && (timerInterval_ < 30s), + "ripple::TimeoutCounter::TimeoutCounter : interval input inside range"); } void diff --git a/src/xrpld/app/main/Application.cpp b/src/xrpld/app/main/Application.cpp index a9d66679010..c10862d8217 100644 --- a/src/xrpld/app/main/Application.cpp +++ b/src/xrpld/app/main/Application.cpp @@ -586,7 +586,10 @@ class ApplicationImp : public Application, public BasicApp virtual ServerHandler& getServerHandler() override { - assert(serverHandler_); + ASSERT( + serverHandler_ != nullptr, + "ripple::ApplicationImp::getServerHandler : non-null server " + "handle"); return *serverHandler_; } @@ -792,28 +795,37 @@ class ApplicationImp : public Application, public BasicApp Overlay& overlay() override { - assert(overlay_); + ASSERT( + overlay_ != nullptr, + "ripple::ApplicationImp::overlay : non-null overlay"); return *overlay_; } TxQ& getTxQ() override { - assert(txQ_.get() != nullptr); + ASSERT( + txQ_.get() != nullptr, + "ripple::ApplicationImp::getTxQ : non-null transaction queue"); return *txQ_; } RelationalDatabase& getRelationalDatabase() override { - assert(mRelationalDatabase.get() != nullptr); + ASSERT( + mRelationalDatabase.get() != nullptr, + "ripple::ApplicationImp::getRelationalDatabase : non-null " + "relational database"); return *mRelationalDatabase; } DatabaseCon& getWalletDB() override { - assert(mWalletDB.get() != nullptr); + ASSERT( + mWalletDB.get() != nullptr, + "ripple::ApplicationImp::getWalletDB : non-null wallet database"); return *mWalletDB; } @@ -828,7 +840,10 @@ class ApplicationImp : public Application, public BasicApp bool initRelationalDatabase() { - assert(mWalletDB.get() == nullptr); + ASSERT( + mWalletDB.get() == nullptr, + "ripple::ApplicationImp::initRelationalDatabase : null wallet " + "database"); try { @@ -1230,7 +1245,9 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) for (auto const& [a, vote] : amendments) { auto const f = ripple::getRegisteredFeature(a); - assert(f); + ASSERT( + f.has_value(), + "ripple::ApplicationImp::setup : registered feature"); if (f) supported.emplace_back(a, *f, vote); } @@ -1693,9 +1710,10 @@ ApplicationImp::startGenesisLedger() auto const next = std::make_shared(*genesis, timeKeeper().closeTime()); next->updateSkipList(); - assert( + ASSERT( next->info().seq < XRP_LEDGER_EARLIEST_FEES || - next->read(keylet::fees())); + next->read(keylet::fees()), + "ripple::ApplicationImp::startGenesisLedger : valid ledger fees"); next->setImmutable(); openLedger_.emplace(next, cachedSLEs_, logs_->journal("OpenLedger")); m_ledgerMaster->storeLedger(next); @@ -1714,9 +1732,10 @@ ApplicationImp::getLastFullLedger() if (!ledger) return ledger; - assert( + ASSERT( ledger->info().seq < XRP_LEDGER_EARLIEST_FEES || - ledger->read(keylet::fees())); + ledger->read(keylet::fees()), + "ripple::ApplicationImp::getLastFullLedger : valid ledger fees"); ledger->setImmutable(); if (getLedgerMaster().haveLedger(seq)) @@ -1868,9 +1887,10 @@ ApplicationImp::loadLedgerFromFile(std::string const& name) loadLedger->stateMap().flushDirty(hotACCOUNT_NODE); - assert( + ASSERT( loadLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - loadLedger->read(keylet::fees())); + loadLedger->read(keylet::fees()), + "ripple::ApplicationImp::loadLedgerFromFile : valid ledger fees"); loadLedger->setAccepted( closeTime, closeTimeResolution, !closeTimeEstimated); @@ -1968,7 +1988,9 @@ ApplicationImp::loadOldLedger( if (!loadLedger) { JLOG(m_journal.fatal()) << "Replay ledger missing/damaged"; - assert(false); + UNREACHABLE( + "ripple::ApplicationImp::loadOldLedger : replay ledger " + "missing/damaged"); return false; } } @@ -1997,21 +2019,26 @@ ApplicationImp::loadOldLedger( if (loadLedger->info().accountHash.isZero()) { JLOG(m_journal.fatal()) << "Ledger is empty."; - assert(false); + UNREACHABLE( + "ripple::ApplicationImp::loadOldLedger : ledger is empty"); return false; } if (!loadLedger->walkLedger(journal("Ledger"), true)) { JLOG(m_journal.fatal()) << "Ledger is missing nodes."; - assert(false); + UNREACHABLE( + "ripple::ApplicationImp::loadOldLedger : ledger is missing " + "nodes"); return false; } if (!loadLedger->assertSensible(journal("Ledger"))) { JLOG(m_journal.fatal()) << "Ledger is not sensible."; - assert(false); + UNREACHABLE( + "ripple::ApplicationImp::loadOldLedger : ledger is not " + "sensible"); return false; } diff --git a/src/xrpld/app/main/GRPCServer.cpp b/src/xrpld/app/main/GRPCServer.cpp index 5a231dfc9e6..c4a1b2458c9 100644 --- a/src/xrpld/app/main/GRPCServer.cpp +++ b/src/xrpld/app/main/GRPCServer.cpp @@ -606,7 +606,7 @@ GRPCServer::stop() GRPCServer::~GRPCServer() { - assert(!running_); + ASSERT(!running_, "ripple::GRPCServer::~GRPCServer : is not running"); } } // namespace ripple diff --git a/src/xrpld/app/main/LoadManager.cpp b/src/xrpld/app/main/LoadManager.cpp index f5dd8719470..181007305ef 100644 --- a/src/xrpld/app/main/LoadManager.cpp +++ b/src/xrpld/app/main/LoadManager.cpp @@ -73,7 +73,9 @@ void LoadManager::start() { JLOG(journal_.debug()) << "Starting"; - assert(!thread_.joinable()); + ASSERT( + !thread_.joinable(), + "ripple::LoadManager::start : thread not joinable"); thread_ = std::thread{&LoadManager::run, this}; } diff --git a/src/xrpld/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp index 169a6dad912..2b47ac9795b 100644 --- a/src/xrpld/app/main/Main.cpp +++ b/src/xrpld/app/main/Main.cpp @@ -69,6 +69,10 @@ #error Multiple supported platforms appear active at once #endif +#ifdef ENABLE_VOIDSTAR +#include "antithesis_instrumentation.h" +#endif + namespace po = boost::program_options; namespace ripple { diff --git a/src/xrpld/app/main/NodeStoreScheduler.cpp b/src/xrpld/app/main/NodeStoreScheduler.cpp index bf07e559fd3..f2dce5421f0 100644 --- a/src/xrpld/app/main/NodeStoreScheduler.cpp +++ b/src/xrpld/app/main/NodeStoreScheduler.cpp @@ -18,7 +18,7 @@ //============================================================================== #include -#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/FeeVoteImpl.cpp b/src/xrpld/app/misc/FeeVoteImpl.cpp index cb4e57b0f73..7943bbe97a7 100644 --- a/src/xrpld/app/misc/FeeVoteImpl.cpp +++ b/src/xrpld/app/misc/FeeVoteImpl.cpp @@ -200,7 +200,9 @@ FeeVoteImpl::doVoting( std::shared_ptr const& initialPosition) { // LCL must be flag ledger - assert(lastClosedLedger && isFlagLedger(lastClosedLedger->seq())); + ASSERT( + lastClosedLedger && isFlagLedger(lastClosedLedger->seq()), + "ripple::FeeVoteImpl::doVoting : has a flag ledger"); detail::VotableValue baseFeeVote( lastClosedLedger->fees().base, target_.reference_fee); diff --git a/src/xrpld/app/misc/HashRouter.cpp b/src/xrpld/app/misc/HashRouter.cpp index c117d20fe2b..44133dddf9b 100644 --- a/src/xrpld/app/misc/HashRouter.cpp +++ b/src/xrpld/app/misc/HashRouter.cpp @@ -101,7 +101,7 @@ HashRouter::getFlags(uint256 const& key) bool HashRouter::setFlags(uint256 const& key, int flags) { - assert(flags != 0); + ASSERT(flags != 0, "ripple::HashRouter::setFlags : valid input"); std::lock_guard lock(mutex_); diff --git a/src/xrpld/app/misc/NegativeUNLVote.cpp b/src/xrpld/app/misc/NegativeUNLVote.cpp index 45d72bcd2b3..b8f485c3dc0 100644 --- a/src/xrpld/app/misc/NegativeUNLVote.cpp +++ b/src/xrpld/app/misc/NegativeUNLVote.cpp @@ -89,7 +89,9 @@ NegativeUNLVote::doVoting( { auto n = choose(prevLedger->info().hash, candidates.toDisableCandidates); - assert(nidToKeyMap.count(n)); + ASSERT( + nidToKeyMap.count(n) != 0, + "ripple::NegativeUNLVote::doVoting : found node to disable"); addTx(seq, nidToKeyMap.at(n), ToDisable, initialSet); } @@ -97,7 +99,9 @@ NegativeUNLVote::doVoting( { auto n = choose( prevLedger->info().hash, candidates.toReEnableCandidates); - assert(nidToKeyMap.count(n)); + ASSERT( + nidToKeyMap.count(n) != 0, + "ripple::NegativeUNLVote::doVoting : found node to enable"); addTx(seq, nidToKeyMap.at(n), ToReEnable, initialSet); } } @@ -140,7 +144,9 @@ NegativeUNLVote::choose( uint256 const& randomPadData, std::vector const& candidates) { - assert(!candidates.empty()); + ASSERT( + !candidates.empty(), + "ripple::NegativeUNLVote::choose : non-empty input"); static_assert(NodeID::bytes <= uint256::bytes); NodeID randomPad = NodeID::fromVoid(randomPadData.data()); NodeID txNodeID = candidates[0]; diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index d647df91f1e..e7432b4de0c 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -105,7 +105,10 @@ class NetworkOPsImp final : public NetworkOPs FailHard f) : transaction(t), admin(a), local(l), failType(f) { - assert(local || failType == FailHard::no); + ASSERT( + local || failType == FailHard::no, + "ripple::NetworkOPsImp::TransactionStatus::TransactionStatus : " + "valid inputs"); } }; @@ -1210,7 +1213,9 @@ NetworkOPsImp::processTransaction( *transaction->getSTransaction(), view->rules(), app_.config()); - assert(validity == Validity::Valid); + ASSERT( + validity == Validity::Valid, + "ripple::NetworkOPsImp::processTransaction : valid validity"); // Not concerned with local checks at this point. if (validity == Validity::SigBad) @@ -1316,9 +1321,13 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) std::vector submit_held; std::vector transactions; mTransactions.swap(transactions); - assert(!transactions.empty()); + ASSERT( + !transactions.empty(), + "ripple::NetworkOPsImp::apply : non-empty transactions"); + ASSERT( + mDispatchState != DispatchState::running, + "ripple::NetworkOPsImp::apply : is not running"); - assert(mDispatchState != DispatchState::running); mDispatchState = DispatchState::running; batchLock.unlock(); @@ -1534,7 +1543,9 @@ NetworkOPsImp::getOwnerInfo( for (auto const& uDirEntry : sleNode->getFieldV256(sfIndexes)) { auto sleCur = lpLedger->read(keylet::child(uDirEntry)); - assert(sleCur); + ASSERT( + sleCur != nullptr, + "ripple::NetworkOPsImp::getOwnerInfo : non-null child SLE"); switch (sleCur->getType()) { @@ -1561,7 +1572,9 @@ NetworkOPsImp::getOwnerInfo( case ltACCOUNT_ROOT: case ltDIR_NODE: default: - assert(false); + UNREACHABLE( + "ripple::NetworkOPsImp::getOwnerInfo : invalid " + "type"); break; } } @@ -1571,7 +1584,9 @@ NetworkOPsImp::getOwnerInfo( if (uNodeDir) { sleNode = lpLedger->read(keylet::page(root, uNodeDir)); - assert(sleNode); + ASSERT( + sleNode != nullptr, + "ripple::NetworkOPsImp::getOwnerInfo : read next page"); } } while (uNodeDir); } @@ -1802,7 +1817,9 @@ NetworkOPsImp::switchLastClosedLedger( bool NetworkOPsImp::beginConsensus(uint256 const& networkClosed) { - assert(networkClosed.isNonZero()); + ASSERT( + networkClosed.isNonZero(), + "ripple::NetworkOPsImp::beginConsensus : nonzero input"); auto closingInfo = m_ledgerMaster.getCurrentLedger()->info(); @@ -1823,10 +1840,14 @@ NetworkOPsImp::beginConsensus(uint256 const& networkClosed) return false; } - assert(prevLedger->info().hash == closingInfo.parentHash); - assert( - closingInfo.parentHash == - m_ledgerMaster.getClosedLedger()->info().hash); + ASSERT( + prevLedger->info().hash == closingInfo.parentHash, + "ripple::NetworkOPsImp::beginConsensus : prevLedger hash matches " + "parent"); + ASSERT( + closingInfo.parentHash == m_ledgerMaster.getClosedLedger()->info().hash, + "ripple::NetworkOPsImp::beginConsensus : closedLedger parent matches " + "hash"); if (prevLedger->rules().enabled(featureNegativeUNL)) app_.validators().setNegativeUNL(prevLedger->negativeUNL()); @@ -2799,7 +2820,9 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) lpAccepted->info().hash, alpAccepted); } - assert(alpAccepted->getLedger().get() == lpAccepted.get()); + ASSERT( + alpAccepted->getLedger().get() == lpAccepted.get(), + "ripple::NetworkOPsImp::pubLedger : accepted input"); { JLOG(m_journal.debug()) @@ -3202,9 +3225,11 @@ NetworkOPsImp::pubAccountTransaction( if (last) jvObj.set(jss::account_history_boundary, true); - assert( + ASSERT( jvObj.isMember(jss::account_history_tx_stream) == - MultiApiJson::none); + MultiApiJson::none, + "ripple::NetworkOPsImp::pubAccountTransaction : " + "account_history_tx_stream not set"); for (auto& info : accountHistoryNotify) { auto& index = info.index_; @@ -3277,9 +3302,11 @@ NetworkOPsImp::pubProposedAccountTransaction( isrListener->getApiVersion(), // [&](Json::Value const& jv) { isrListener->send(jv, true); }); - assert( + ASSERT( jvObj.isMember(jss::account_history_tx_stream) == - MultiApiJson::none); + MultiApiJson::none, + "ripple::NetworkOPs::pubProposedAccountTransaction : " + "account_history_tx_stream not set"); for (auto& info : accountHistoryNotify) { auto& index = info.index_; @@ -3500,7 +3527,9 @@ NetworkOPsImp::addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo) return db->newestAccountTxPage(options); } default: { - assert(false); + UNREACHABLE( + "ripple::NetworkOPsImp::addAccountHistoryJob::" + "getMoreTxns : invalid database type"); return {}; } } @@ -3696,7 +3725,9 @@ NetworkOPsImp::subAccountHistoryStart( } else { - assert(false); + UNREACHABLE( + "ripple::NetworkOPsImp::subAccountHistoryStart : failed to " + "access genesis account"); return; } } @@ -3804,7 +3835,7 @@ NetworkOPsImp::subBook(InfoSub::ref isrListener, Book const& book) if (auto listeners = app_.getOrderBookDB().makeBookListeners(book)) listeners->addSubscriber(isrListener); else - assert(false); + UNREACHABLE("ripple::NetworkOPsImp::subBook : null book listeners"); return true; } @@ -3823,7 +3854,7 @@ NetworkOPsImp::acceptLedger( { // This code-path is exclusively used when the server is in standalone // mode via `ledger_accept` - assert(m_standalone); + ASSERT(m_standalone, "ripple::NetworkOPsImp::acceptLedger : is standalone"); if (!m_standalone) Throw( diff --git a/src/xrpld/app/misc/SHAMapStoreImp.cpp b/src/xrpld/app/misc/SHAMapStoreImp.cpp index 1ce862b095f..2913ebb857f 100644 --- a/src/xrpld/app/misc/SHAMapStoreImp.cpp +++ b/src/xrpld/app/misc/SHAMapStoreImp.cpp @@ -513,7 +513,9 @@ SHAMapStoreImp::clearSql( std::function()> const& getMinSeq, std::function const& deleteBeforeSeq) { - assert(deleteInterval_); + ASSERT( + deleteInterval_ != 0, + "ripple::SHAMapStoreImp::clearSql : nonzero delete interval"); LedgerIndex min = std::numeric_limits::max(); { diff --git a/src/xrpld/app/misc/detail/AMMHelpers.cpp b/src/xrpld/app/misc/detail/AMMHelpers.cpp index f10b4c15eb0..4e23a607502 100644 --- a/src/xrpld/app/misc/detail/AMMHelpers.cpp +++ b/src/xrpld/app/misc/detail/AMMHelpers.cpp @@ -209,7 +209,9 @@ adjustAmountsByLPTokens( return std::make_tuple(amountActual, std::nullopt, lpTokensActual); } - assert(lpTokensActual == lpTokens); + ASSERT( + lpTokensActual == lpTokens, + "ripple::adjustAmountsByLPTokens : LP tokens match actual"); return {amount, amount2, lpTokensActual}; } diff --git a/src/xrpld/app/misc/detail/AMMUtils.cpp b/src/xrpld/app/misc/detail/AMMUtils.cpp index efc80cf17b6..c91f0c56642 100644 --- a/src/xrpld/app/misc/detail/AMMUtils.cpp +++ b/src/xrpld/app/misc/detail/AMMUtils.cpp @@ -145,9 +145,10 @@ std::uint16_t getTradingFee(ReadView const& view, SLE const& ammSle, AccountID const& account) { using namespace std::chrono; - assert( + ASSERT( !view.rules().enabled(fixInnerObjTemplate) || - ammSle.isFieldPresent(sfAuctionSlot)); + ammSle.isFieldPresent(sfAuctionSlot), + "ripple::getTradingFee : auction present"); if (ammSle.isFieldPresent(sfAuctionSlot)) { auto const& auctionSlot = diff --git a/src/xrpld/app/misc/detail/AmendmentTable.cpp b/src/xrpld/app/misc/detail/AmendmentTable.cpp index 62b80890821..a35eb72efeb 100644 --- a/src/xrpld/app/misc/detail/AmendmentTable.cpp +++ b/src/xrpld/app/misc/detail/AmendmentTable.cpp @@ -656,7 +656,9 @@ AmendmentTableImpl::persistVote( std::string const& name, AmendmentVote vote) const { - assert(vote != AmendmentVote::obsolete); + ASSERT( + vote != AmendmentVote::obsolete, + "ripple::AmendmentTableImpl::persistVote : valid vote input"); auto db = db_.checkoutDb(); voteAmendment(*db, amendment, name, vote); } diff --git a/src/xrpld/app/misc/detail/Manifest.cpp b/src/xrpld/app/misc/detail/Manifest.cpp index a17858ceb39..bf3b58cc9d9 100644 --- a/src/xrpld/app/misc/detail/Manifest.cpp +++ b/src/xrpld/app/misc/detail/Manifest.cpp @@ -390,7 +390,9 @@ ManifestCache::applyManifest(Manifest m) auto prewriteCheck = [this, &m](auto const& iter, bool checkSignature, auto const& lock) -> std::optional { - assert(lock.owns_lock()); + ASSERT( + lock.owns_lock(), + "ripple::ManifestCache::applyManifest::prewriteCheck : locked"); (void)lock; // not used. parameter is present to ensure the mutex is // locked when the lambda is called. if (iter != map_.end() && m.sequence <= iter->second.sequence) diff --git a/src/xrpld/app/misc/detail/Transaction.cpp b/src/xrpld/app/misc/detail/Transaction.cpp index c8f9df232e0..27cb785eb78 100644 --- a/src/xrpld/app/misc/detail/Transaction.cpp +++ b/src/xrpld/app/misc/detail/Transaction.cpp @@ -82,7 +82,10 @@ Transaction::sqlTransactionStatus(boost::optional const& status) return INCLUDED; } - assert(c == txnSqlUnknown); + ASSERT( + c == txnSqlUnknown, + "ripple::Transaction::sqlTransactionStatus : unknown transaction " + "status"); return INVALID; } diff --git a/src/xrpld/app/misc/detail/TxQ.cpp b/src/xrpld/app/misc/detail/TxQ.cpp index a4e62b382a7..9f886fd2977 100644 --- a/src/xrpld/app/misc/detail/TxQ.cpp +++ b/src/xrpld/app/misc/detail/TxQ.cpp @@ -52,7 +52,7 @@ getFeeLevelPaid(ReadView const& view, STTx const& tx) return std::pair{baseFee + mod, feePaid + mod}; }(); - assert(baseFee.signum() > 0); + ASSERT(baseFee.signum() > 0, "ripple::getFeeLevelPaid : positive fee"); if (effectiveFeePaid.signum() <= 0 || baseFee.signum() <= 0) { return FeeLevel64(0); @@ -95,7 +95,9 @@ TxQ::FeeMetrics::update( feeLevels.push_back(getFeeLevelPaid(view, *tx.first)); }); std::sort(feeLevels.begin(), feeLevels.end()); - assert(size == feeLevels.size()); + ASSERT( + size == feeLevels.size(), + "ripple::TxQ::FeeMetrics::update : fee levels size"); JLOG((timeLeap ? j_.warn() : j_.debug())) << "Ledger " << view.info().seq << " has " << size << " transactions. " @@ -247,7 +249,10 @@ TxQ::FeeMetrics::escalatedSeriesFeeLevel( auto const target = snapshot.txnsExpected; auto const multiplier = snapshot.escalationMultiplier; - assert(current > target); + ASSERT( + current > target, + "ripple::TxQ::FeeMetrics::escalatedSeriesFeeLevel : current over " + "target"); /* Calculate (apologies for the terrible notation) sum(n = current -> last) : multiplier * n * n / (target * target) @@ -292,7 +297,9 @@ std::pair TxQ::MaybeTx::apply(Application& app, OpenView& view, beast::Journal j) { // If the rules or flags change, preflight again - assert(pfresult); + ASSERT( + pfresult.has_value(), + "ripple::TxQ::MaybeTx::apply : preflight result is set"); STAmountSO stAmountSO{view.rules().enabled(fixSTAmountCanonicalize)}; NumberSO stNumberSO{view.rules().enabled(fixUniversalNumber)}; @@ -337,8 +344,10 @@ TxQ::TxQAccount::add(MaybeTx&& txn) auto const seqProx = txn.seqProxy; auto result = transactions.emplace(seqProx, std::move(txn)); - assert(result.second); - assert(&result.first->second != &txn); + ASSERT(result.second, "ripple::TxQ::TxQAccount::add : emplace succeeded"); + ASSERT( + &result.first->second != &txn, + "ripple::TxQ::TxQAccount::add : transaction moved"); return result.first->second; } @@ -446,9 +455,8 @@ TxQ::erase(TxQ::FeeMultiSet::const_iterator_type candidateIter) // Now that the candidate has been removed from the // intrusive list remove it from the TxQAccount // so the memory can be freed. - auto const found = txQAccount.remove(seqProx); - (void)found; - assert(found); + [[maybe_unused]] auto const found = txQAccount.remove(seqProx); + ASSERT(found, "ripple::TxQ::erase : account removed"); return newCandidateIter; } @@ -460,15 +468,20 @@ TxQ::eraseAndAdvance(TxQ::FeeMultiSet::const_iterator_type candidateIter) auto& txQAccount = byAccount_.at(candidateIter->account); auto const accountIter = txQAccount.transactions.find(candidateIter->seqProxy); - assert(accountIter != txQAccount.transactions.end()); + ASSERT( + accountIter != txQAccount.transactions.end(), + "ripple::TxQ::eraseAndAdvance : account found"); // Note that sequence-based transactions must be applied in sequence order // from smallest to largest. But ticket-based transactions can be // applied in any order. - assert( + ASSERT( candidateIter->seqProxy.isTicket() || - accountIter == txQAccount.transactions.begin()); - assert(byFee_.iterator_to(accountIter->second) == candidateIter); + accountIter == txQAccount.transactions.begin(), + "ripple::TxQ::eraseAndAdvance : ticket or sequence"); + ASSERT( + byFee_.iterator_to(accountIter->second) == candidateIter, + "ripple::TxQ::eraseAndAdvance : found in byFee"); auto const accountNextIter = std::next(accountIter); // Check if the next transaction for this account is earlier in the queue, @@ -515,7 +528,9 @@ TxQ::tryClearAccountQueueUpThruTx( beast::Journal j) { SeqProxy const tSeqProx{tx.getSeqProxy()}; - assert(beginTxIter != accountIter->second.transactions.end()); + ASSERT( + beginTxIter != accountIter->second.transactions.end(), + "ripple::TxQ::tryClearAccountQueueUpThruTx : non-empty accounts input"); // This check is only concerned with the range from // [aSeqProxy, tSeqProxy) @@ -998,7 +1013,7 @@ TxQ::apply( // o The current first thing in the queue has a Ticket and // * The tx has a Ticket that precedes it or // * txSeqProx == acctSeqProx. - assert(prevIter != txIter->end); + ASSERT(prevIter != txIter->end, "ripple::TxQ::apply : not end"); if (prevIter == txIter->end || txSeqProx < prevIter->first) { // The first Sequence number in the queue must be the @@ -1119,10 +1134,11 @@ TxQ::apply( // inserted in the middle from fouling up later transactions. auto const potentialTotalSpend = totalFee + std::min(balance - std::min(balance, reserve), potentialSpend); - assert( + ASSERT( potentialTotalSpend > XRPAmount{0} || - (potentialTotalSpend == XRPAmount{0} && - multiTxn->applyView.fees().base == 0)); + (potentialTotalSpend == XRPAmount{0} && + multiTxn->applyView.fees().base == 0), + "ripple::TxQ::apply : total spend check"); sleBump->setFieldAmount(sfBalance, balance - potentialTotalSpend); // The transaction's sequence/ticket will be valid when the other // transactions in the queue have been processed. If the tx has a @@ -1152,7 +1168,7 @@ TxQ::apply( return {pcresult.ter, false}; // Too low of a fee should get caught by preclaim - assert(feeLevelPaid >= baseLevel); + ASSERT(feeLevelPaid >= baseLevel, "ripple::TxQ::apply : minimum fee"); JLOG(j_.trace()) << "Transaction " << transactionID << " from account " << account << " has fee level of " << feeLevelPaid @@ -1277,7 +1293,9 @@ TxQ::apply( // The queue is full, and this transaction is more // valuable, so kick out the cheapest transaction. auto dropRIter = endAccount.transactions.rbegin(); - assert(dropRIter->second.account == lastRIter->account); + ASSERT( + dropRIter->second.account == lastRIter->account, + "ripple::TxQ::apply : cheapest transaction found"); JLOG(j_.info()) << "Removing last item of account " << lastRIter->account << " from queue with average fee of " << endEffectiveFeeLevel @@ -1303,11 +1321,10 @@ TxQ::apply( if (!accountIsInQueue) { // Create a new TxQAccount object and add the byAccount lookup. - bool created; + [[maybe_unused]] bool created = false; std::tie(accountIter, created) = byAccount_.emplace(account, TxQAccount(tx)); - (void)created; - assert(created); + ASSERT(created, "ripple::TxQ::apply : account created"); } // Modify the flags for use when coming out of the queue. // These changes _may_ cause an extra `preflight`, but as long as @@ -1520,9 +1537,9 @@ TxQ::accept(Application& app, OpenView& view) // making things worse, drop the _last_ transaction for // this account. auto dropRIter = account.transactions.rbegin(); - assert( - dropRIter->second.account == - candidateIter->account); + ASSERT( + dropRIter->second.account == candidateIter->account, + "ripple::TxQ::accept : account check"); JLOG(j_.info()) << "Queue is nearly full, and transaction " @@ -1553,7 +1570,7 @@ TxQ::accept(Application& app, OpenView& view) LedgerHash const& parentHash = view.info().parentHash; #if !NDEBUG auto const startingSize = byFee_.size(); - assert(parentHash != parentHash_); + ASSERT(parentHash != parentHash_, "ripple::TxQ::accept : new parent hash"); parentHash_ = parentHash; #endif // byFee_ doesn't "own" the candidate objects inside it, so it's @@ -1575,7 +1592,9 @@ TxQ::accept(Application& app, OpenView& view) byFee_.insert(candidate); } } - assert(byFee_.size() == startingSize); + ASSERT( + byFee_.size() == startingSize, + "ripple::TxQ::accept : byFee size match"); return ledgerChanged; } @@ -1734,10 +1753,18 @@ TxQ::removeFromByFee( // If the transaction we're holding replaces a transaction in the // queue, remove the transaction that is being replaced. auto deleteIter = byFee_.iterator_to((*replacedTxIter)->second); - assert(deleteIter != byFee_.end()); - assert(&(*replacedTxIter)->second == &*deleteIter); - assert(deleteIter->seqProxy == tx->getSeqProxy()); - assert(deleteIter->account == (*tx)[sfAccount]); + ASSERT( + deleteIter != byFee_.end(), + "ripple::TxQ::removeFromByFee : found in byFee"); + ASSERT( + &(*replacedTxIter)->second == &*deleteIter, + "ripple::TxQ::removeFromByFee : matching transaction"); + ASSERT( + deleteIter->seqProxy == tx->getSeqProxy(), + "ripple::TxQ::removeFromByFee : matching sequence"); + ASSERT( + deleteIter->account == (*tx)[sfAccount], + "ripple::TxQ::removeFromByFee : matching account"); erase(deleteIter); } diff --git a/src/xrpld/app/misc/detail/ValidatorList.cpp b/src/xrpld/app/misc/detail/ValidatorList.cpp index 9a323e0116b..052cecb80b1 100644 --- a/src/xrpld/app/misc/detail/ValidatorList.cpp +++ b/src/xrpld/app/misc/detail/ValidatorList.cpp @@ -276,7 +276,9 @@ ValidatorList::buildFileData( { Json::Value value(Json::objectValue); - assert(pubCollection.rawVersion == 2 || pubCollection.remaining.empty()); + ASSERT( + pubCollection.rawVersion == 2 || pubCollection.remaining.empty(), + "ripple::ValidatorList::buildFileData : valid publisher list input"); auto const effectiveVersion = forceVersion ? *forceVersion : pubCollection.rawVersion; @@ -376,7 +378,9 @@ ValidatorList::parseBlobs(std::uint32_t version, Json::Value const& body) ValidatorBlobInfo& info = result.emplace_back(); info.blob = body[jss::blob].asString(); info.signature = body[jss::signature].asString(); - assert(result.size() == 1); + ASSERT( + result.size() == 1, + "ripple::ValidatorList::parseBlobs : single element result"); return result; } // Treat unknown versions as if they're the latest version. This @@ -411,7 +415,10 @@ ValidatorList::parseBlobs(std::uint32_t version, Json::Value const& body) info.manifest = blobInfo[jss::manifest].asString(); } } - assert(result.size() == blobs.size()); + ASSERT( + result.size() == blobs.size(), + "ripple::ValidatorList::parseBlobs(version, Jason::Value) : " + "result size matches"); return result; } } @@ -442,7 +449,10 @@ ValidatorList::parseBlobs(protocol::TMValidatorListCollection const& body) info.manifest = blob.manifest(); } } - assert(result.size() == body.blobs_size()); + ASSERT( + result.size() == body.blobs_size(), + "ripple::ValidatorList::parseBlobs(TMValidatorList) : result size " + "match"); return result; } @@ -464,7 +474,7 @@ splitMessage( { if (begin == 0 && end == 0) end = largeMsg.blobs_size(); - assert(begin < end); + ASSERT(begin < end, "ripple::splitMessage : valid inputs"); if (end <= begin) return 0; @@ -498,7 +508,9 @@ splitMessageParts( if (blob.has_manifest()) smallMsg.set_manifest(blob.manifest()); - assert(Message::totalSize(smallMsg) <= maximiumMessageSize); + ASSERT( + Message::totalSize(smallMsg) <= maximiumMessageSize, + "ripple::splitMessageParts : maximum message size"); messages.emplace_back( std::make_shared(smallMsg, protocol::mtVALIDATORLIST), @@ -546,7 +558,10 @@ buildValidatorListMessage( ValidatorBlobInfo const& currentBlob, std::size_t maxSize) { - assert(messages.empty()); + ASSERT( + messages.empty(), + "ripple::buildValidatorListMessage(ValidatorBlobInfo) : empty messages " + "input"); protocol::TMValidatorList msg; auto const manifest = currentBlob.manifest ? *currentBlob.manifest : rawManifest; @@ -557,7 +572,10 @@ buildValidatorListMessage( // Override the version msg.set_version(version); - assert(Message::totalSize(msg) <= maximiumMessageSize); + ASSERT( + Message::totalSize(msg) <= maximiumMessageSize, + "ripple::buildValidatorListMessage(ValidatorBlobInfo) : maximum " + "message size"); messages.emplace_back( std::make_shared(msg, protocol::mtVALIDATORLIST), sha512Half(msg), @@ -576,7 +594,10 @@ buildValidatorListMessage( std::map const& blobInfos, std::size_t maxSize) { - assert(messages.empty()); + ASSERT( + messages.empty(), + "ripple::buildValidatorListMessage(std::map) : empty messages input"); protocol::TMValidatorListCollection msg; auto const version = rawVersion < 2 ? 2 : rawVersion; msg.set_version(version); @@ -592,7 +613,10 @@ buildValidatorListMessage( if (blobInfo.manifest) blob.set_manifest(*blobInfo.manifest); } - assert(msg.blobs_size() > 0); + ASSERT( + msg.blobs_size() > 0, + "ripple::buildValidatorListMessage(std::map) : minimum message blobs"); if (Message::totalSize(msg) > maxSize) { // split into smaller messages @@ -621,7 +645,10 @@ ValidatorList::buildValidatorListMessages( std::vector& messages, std::size_t maxSize /*= maximiumMessageSize*/) { - assert(!blobInfos.empty()); + ASSERT( + !blobInfos.empty(), + "ripple::ValidatorList::buildValidatorListMessages : empty messages " + "input"); auto const& [currentSeq, currentBlob] = *blobInfos.begin(); auto numVLs = std::accumulate( messages.begin(), @@ -704,7 +731,10 @@ ValidatorList::sendValidatorList( messages); if (newPeerSequence) { - assert(!messages.empty()); + ASSERT( + !messages.empty(), + "ripple::ValidatorList::sendValidatorList : non-empty messages " + "input"); // Don't send it next time. peer.setPublisherListSequence(publisherKey, newPeerSequence); @@ -720,7 +750,9 @@ ValidatorList::sendValidatorList( } // The only way sent wil be false is if the messages was too big, and // thus there will only be one entry without a message - assert(sent || messages.size() == 1); + ASSERT( + sent || messages.size() == 1, + "ripple::ValidatorList::sendValidatorList : sent or one message"); if (sent) { if (messageVersion > 1) @@ -734,7 +766,10 @@ ValidatorList::sendValidatorList( << "]"; else { - assert(numVLs == 1); + ASSERT( + numVLs == 1, + "ripple::ValidatorList::sendValidatorList : one validator " + "list"); JLOG(j.debug()) << "Sent validator list for " << strHex(publisherKey) << " with sequence " << newPeerSequence << " to " @@ -829,9 +864,10 @@ ValidatorList::broadcastBlobs( // be built to hold info for all of the valid VLs. std::map blobInfos; - assert( + ASSERT( lists.current.sequence == maxSequence || - lists.remaining.count(maxSequence) == 1); + lists.remaining.count(maxSequence) == 1, + "ripple::ValidatorList::broadcastBlobs : valid sequence"); // Can't use overlay.foreach here because we need to modify // the peer, and foreach provides a const& for (auto& peer : overlay.getActivePeers()) @@ -975,7 +1011,9 @@ ValidatorList::applyLists( for (auto iter = remaining.begin(); iter != remaining.end();) { auto next = std::next(iter); - assert(next == remaining.end() || next->first > iter->first); + ASSERT( + next == remaining.end() || next->first > iter->first, + "ripple::ValidatorList::applyLists : next is valid"); if (iter->first <= current.sequence || (next != remaining.end() && next->second.validFrom <= iter->second.validFrom)) @@ -1147,7 +1185,9 @@ ValidatorList::applyList( // Remove the entry in "remaining" pubCollection.remaining.erase(sequence); // Done - assert(publisher.sequence == sequence); + ASSERT( + publisher.sequence == sequence, + "ripple::ValidatorList::applyList : publisher sequence match"); } else { @@ -1441,9 +1481,10 @@ ValidatorList::removePublisherList( PublicKey const& publisherKey, PublisherStatus reason) { - assert( + ASSERT( reason != PublisherStatus::available && - reason != PublisherStatus::unavailable); + reason != PublisherStatus::unavailable, + "ripple::ValidatorList::removePublisherList : valid reason input"); auto const iList = publisherLists_.find(publisherKey); if (iList == publisherLists_.end()) return false; @@ -1628,7 +1669,9 @@ ValidatorList::getJson() const Json::Value& r = remaining.append(Json::objectValue); appendList(future, r); // Race conditions can happen, so make this check "fuzzy" - assert(future.validFrom > timeKeeper_.now() + 600s); + ASSERT( + future.validFrom > timeKeeper_.now() + 600s, + "ripple::ValidatorList::getJson : minimum valid from"); } if (remaining.size()) curr[jss::remaining] = std::move(remaining); @@ -1693,7 +1736,9 @@ ValidatorList::for_each_available( { if (plCollection.status != PublisherStatus::available) continue; - assert(plCollection.maxSequence); + ASSERT( + plCollection.maxSequence != 0, + "ripple::ValidatorList::for_each_available : nonzero maxSequence"); func( plCollection.rawManifest, plCollection.rawVersion, @@ -1827,21 +1872,31 @@ ValidatorList::updateTrusted( next->second.validFrom <= closeTime; ++iter, ++next) { - assert(std::next(iter) == next); + ASSERT( + std::next(iter) == next, + "ripple::ValidatorList::updateTrusted : sequential " + "remaining"); } - assert(iter != remaining.end()); + ASSERT( + iter != remaining.end(), + "ripple::ValidatorList::updateTrusted : non-end of " + "remaining"); // Rotate the pending list in to current auto sequence = iter->first; auto& candidate = iter->second; auto& current = collection.current; - assert(candidate.validFrom <= closeTime); + ASSERT( + candidate.validFrom <= closeTime, + "ripple::ValidatorList::updateTrusted : maximum time"); auto const oldList = current.list; current = std::move(candidate); if (collection.status != PublisherStatus::available) collection.status = PublisherStatus::available; - assert(current.sequence == sequence); + ASSERT( + current.sequence == sequence, + "ripple::ValidatorList::updateTrusted : sequence match"); // If the list is expired, remove the validators so they don't // get processed in. The expiration check below will do the rest // of the work @@ -1918,7 +1973,9 @@ ValidatorList::updateTrusted( { std::optional const signingKey = validatorManifests_.getSigningKey(k); - assert(signingKey); + ASSERT( + signingKey.has_value(), + "ripple::ValidatorList::updateTrusted : found signing key"); trustedSigningKeys_.insert(*signingKey); } } diff --git a/src/xrpld/app/misc/detail/ValidatorSite.cpp b/src/xrpld/app/misc/detail/ValidatorSite.cpp index 0c12816c1b8..fd775fc9251 100644 --- a/src/xrpld/app/misc/detail/ValidatorSite.cpp +++ b/src/xrpld/app/misc/detail/ValidatorSite.cpp @@ -411,7 +411,9 @@ ValidatorSite::parseJsonResponse( } auto const manifest = body[jss::manifest].asString(); - assert(version == body[jss::version].asUInt()); + ASSERT( + version == body[jss::version].asUInt(), + "ripple::ValidatorSite::parseJsonResponse : version match"); auto const& uri = sites_[siteIdx].activeResource->uri; auto const hash = sha512Half(manifest, blobs, version); auto const applyResult = app_.validators().applyListsAndBroadcast( @@ -586,7 +588,10 @@ ValidatorSite::onSiteFetch( case status::temporary_redirect: { auto newLocation = processRedirect(res, siteIdx, lock_sites); - assert(newLocation); + ASSERT( + newLocation != nullptr, + "ripple::ValidatorSite::onSiteFetch : non-null " + "validator"); // for perm redirects, also update our starting URI if (res.result() == status::moved_permanently || res.result() == status::permanent_redirect) diff --git a/src/xrpld/app/misc/detail/WorkBase.h b/src/xrpld/app/misc/detail/WorkBase.h index d7795af8bf0..8fece4703f5 100644 --- a/src/xrpld/app/misc/detail/WorkBase.h +++ b/src/xrpld/app/misc/detail/WorkBase.h @@ -282,7 +282,9 @@ WorkBase::onResponse(error_code const& ec) return fail(ec); close(); - assert(cb_); + ASSERT( + cb_ != nullptr, + "ripple::detail::WorkBase::onResponse : callback is set"); cb_(ec, lastEndpoint_, std::move(res_)); cb_ = nullptr; } diff --git a/src/xrpld/app/misc/detail/WorkFile.h b/src/xrpld/app/misc/detail/WorkFile.h index 266e5098cb6..1f08cacac68 100644 --- a/src/xrpld/app/misc/detail/WorkFile.h +++ b/src/xrpld/app/misc/detail/WorkFile.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include namespace ripple { @@ -88,7 +88,7 @@ WorkFile::run() error_code ec; auto const fileContents = getFileContents(ec, path_, megabytes(1)); - assert(cb_); + ASSERT(cb_ != nullptr, "ripple::detail::WorkFile::run : callback is set"); cb_(ec, fileContents); cb_ = nullptr; } diff --git a/src/xrpld/app/paths/Credit.cpp b/src/xrpld/app/paths/Credit.cpp index b3870937367..dbf0db45c4b 100644 --- a/src/xrpld/app/paths/Credit.cpp +++ b/src/xrpld/app/paths/Credit.cpp @@ -42,8 +42,12 @@ creditLimit( result.setIssuer(account); } - assert(result.getIssuer() == account); - assert(result.getCurrency() == currency); + ASSERT( + result.getIssuer() == account, + "ripple::creditLimit : result issuer match"); + ASSERT( + result.getCurrency() == currency, + "ripple::creditLimit : result currency match"); return result; } @@ -76,8 +80,12 @@ creditBalance( result.setIssuer(account); } - assert(result.getIssuer() == account); - assert(result.getCurrency() == currency); + ASSERT( + result.getIssuer() == account, + "ripple::creditBalance : result issuer match"); + ASSERT( + result.getCurrency() == currency, + "ripple::creditBalance : result currency match"); return result; } diff --git a/src/xrpld/app/paths/Flow.cpp b/src/xrpld/app/paths/Flow.cpp index c21d40c33b5..23d9da64150 100644 --- a/src/xrpld/app/paths/Flow.cpp +++ b/src/xrpld/app/paths/Flow.cpp @@ -193,7 +193,7 @@ flow( flowDebugInfo)); } - assert(!srcIsXRP && !dstIsXRP); + ASSERT(!srcIsXRP && !dstIsXRP, "ripple::flow : neither is XRP"); return finishFlow( sb, srcIssue, diff --git a/src/xrpld/app/paths/PathRequest.cpp b/src/xrpld/app/paths/PathRequest.cpp index bb6a104bca2..28ade441c2d 100644 --- a/src/xrpld/app/paths/PathRequest.cpp +++ b/src/xrpld/app/paths/PathRequest.cpp @@ -158,7 +158,7 @@ PathRequest::updateComplete() { std::lock_guard sl(mIndexLock); - assert(mInProgress); + ASSERT(mInProgress, "ripple::PathRequest::updateComplete : in progress"); mInProgress = false; if (fCompletion) diff --git a/src/xrpld/app/paths/Pathfinder.cpp b/src/xrpld/app/paths/Pathfinder.cpp index 5122bc7d6b8..3f506809887 100644 --- a/src/xrpld/app/paths/Pathfinder.cpp +++ b/src/xrpld/app/paths/Pathfinder.cpp @@ -189,7 +189,9 @@ Pathfinder::Pathfinder( , app_(app) , j_(app.journal("Pathfinder")) { - assert(!uSrcIssuer || isXRP(uSrcCurrency) == isXRP(uSrcIssuer.value())); + ASSERT( + !uSrcIssuer || isXRP(uSrcCurrency) == isXRP(uSrcIssuer.value()), + "ripple::Pathfinder::Pathfinder : valid inputs"); } bool @@ -577,7 +579,9 @@ Pathfinder::getBestPaths( if (mCompletePaths.empty() && extraPaths.empty()) return mCompletePaths; - assert(fullLiquidityPath.empty()); + ASSERT( + fullLiquidityPath.empty(), + "ripple::Pathfinder::getBestPaths : first empty path result"); const bool issuerIsSender = isXRP(mSrcCurrency) || (srcIssuer == mSrcAccount); @@ -638,7 +642,7 @@ Pathfinder::getBestPaths( if (path.empty()) { - assert(false); + UNREACHABLE("ripple::Pathfinder::getBestPaths : path not found"); continue; } @@ -681,7 +685,9 @@ Pathfinder::getBestPaths( if (remaining > beast::zero) { - assert(fullLiquidityPath.empty()); + ASSERT( + fullLiquidityPath.empty(), + "ripple::Pathfinder::getBestPaths : second empty path result"); JLOG(j_.info()) << "Paths could not send " << remaining << " of " << mDstAmount; } @@ -830,7 +836,9 @@ Pathfinder::addPathsForType( { case nt_SOURCE: // Source must always be at the start, so pathsOut has to be empty. - assert(pathsOut.empty()); + ASSERT( + pathsOut.empty(), + "ripple::Pathfinder::addPathsForType : empty paths"); pathsOut.push_back(STPath()); break; @@ -1282,7 +1290,7 @@ void fillPaths(Pathfinder::PaymentType type, PathCostList const& costs) { auto& list = mPathTable[type]; - assert(list.empty()); + ASSERT(list.empty(), "ripple::fillPaths : empty paths"); for (auto& cost : costs) list.push_back({cost.cost, makePath(cost.path)}); } diff --git a/src/xrpld/app/paths/RippleLineCache.cpp b/src/xrpld/app/paths/RippleLineCache.cpp index 0ff967c0821..053546ce0be 100644 --- a/src/xrpld/app/paths/RippleLineCache.cpp +++ b/src/xrpld/app/paths/RippleLineCache.cpp @@ -79,7 +79,9 @@ RippleLineCache::getRippleLines( // to be replaced by the full set. The full set will be built // below, and will be returned, if needed, on subsequent calls // for either value of outgoing. - assert(size <= totalLineCount_); + ASSERT( + size <= totalLineCount_, + "ripple::RippleLineCache::getRippleLines : maximum lines"); totalLineCount_ -= size; lines_.erase(otheriter); } @@ -99,7 +101,9 @@ RippleLineCache::getRippleLines( if (inserted) { - assert(it->second == nullptr); + ASSERT( + it->second == nullptr, + "ripple::RippleLineCache::getRippleLines : null lines"); auto lines = PathFindTrustLine::getItems(accountID, *ledger_, direction); if (lines.size()) @@ -110,7 +114,9 @@ RippleLineCache::getRippleLines( } } - assert(!it->second || (it->second->size() > 0)); + ASSERT( + !it->second || (it->second->size() > 0), + "ripple::RippleLineCache::getRippleLines : null or nonempty lines"); auto const size = it->second ? it->second->size() : 0; JLOG(journal_.trace()) << "getRippleLines for ledger " << ledger_->info().seq << " found " << size diff --git a/src/xrpld/app/paths/detail/AMMLiquidity.cpp b/src/xrpld/app/paths/detail/AMMLiquidity.cpp index 7b1649c649e..88600e2cc66 100644 --- a/src/xrpld/app/paths/detail/AMMLiquidity.cpp +++ b/src/xrpld/app/paths/detail/AMMLiquidity.cpp @@ -77,7 +77,9 @@ AMMLiquidity::generateFibSeqOffer( 196418, 317811, 514229, 832040, 1346269}; // clang-format on - assert(!ammContext_.maxItersReached()); + ASSERT( + !ammContext_.maxItersReached(), + "ripple::AMMLiquidity::generateFibSeqOffer : maximum iterations"); cur.out = toAmount( getIssue(balances.out), diff --git a/src/xrpld/app/paths/detail/AmountSpec.h b/src/xrpld/app/paths/detail/AmountSpec.h index 8a1117f9920..59ca5f5d29b 100644 --- a/src/xrpld/app/paths/detail/AmountSpec.h +++ b/src/xrpld/app/paths/detail/AmountSpec.h @@ -125,7 +125,7 @@ template <> inline IOUAmount& get(EitherAmount& amt) { - assert(!amt.native); + ASSERT(!amt.native, "ripple::get(EitherAmount&) : is not XRP"); return amt.iou; } @@ -133,7 +133,7 @@ template <> inline XRPAmount& get(EitherAmount& amt) { - assert(amt.native); + ASSERT(amt.native, "ripple::get(EitherAmount&) : is XRP"); return amt.xrp; } @@ -149,7 +149,9 @@ template <> inline IOUAmount const& get(EitherAmount const& amt) { - assert(!amt.native); + ASSERT( + !amt.native, + "ripple::get(EitherAmount const&) : is not XRP"); return amt.iou; } @@ -157,14 +159,16 @@ template <> inline XRPAmount const& get(EitherAmount const& amt) { - assert(amt.native); + ASSERT(amt.native, "ripple::get(EitherAmount const&) : is XRP"); return amt.xrp; } inline AmountSpec toAmountSpec(STAmount const& amt) { - assert(amt.mantissa() < std::numeric_limits::max()); + ASSERT( + amt.mantissa() < std::numeric_limits::max(), + "ripple::toAmountSpec(STAmount const&) : maximum mantissa"); bool const isNeg = amt.negative(); std::int64_t const sMant = isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); @@ -199,7 +203,10 @@ toAmountSpec(EitherAmount const& ea, std::optional const& c) AmountSpec r; r.native = (!c || isXRP(*c)); r.currency = c; - assert(ea.native == r.native); + ASSERT( + ea.native == r.native, + "ripple::toAmountSpec(EitherAmount const&&, std::optional) : " + "matching native"); if (r.native) { r.xrp = ea.xrp; diff --git a/src/xrpld/app/paths/detail/BookStep.cpp b/src/xrpld/app/paths/detail/BookStep.cpp index b22102119df..df05cc41864 100644 --- a/src/xrpld/app/paths/detail/BookStep.cpp +++ b/src/xrpld/app/paths/detail/BookStep.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -379,7 +380,9 @@ class BookOfferCrossingStep getQuality(std::optional const& limitQuality) { // It's really a programming error if the quality is missing. - assert(limitQuality); + ASSERT( + limitQuality.has_value(), + "ripple::BookOfferCrossingStep::getQuality : nonzero quality"); if (!limitQuality) Throw(tefINTERNAL, "Offer requires quality."); return *limitQuality; @@ -1107,7 +1110,7 @@ BookStep::revImp( // something went very wrong JLOG(j_.error()) << "BookStep remainingOut < 0 " << to_string(remainingOut); - assert(0); + UNREACHABLE("ripple::BookStep::revImp : remaining less than zero"); cache_.emplace(beast::zero, beast::zero); return {beast::zero, beast::zero}; } @@ -1130,7 +1133,7 @@ BookStep::fwdImp( boost::container::flat_set& ofrsToRm, TIn const& in) { - assert(cache_); + ASSERT(cache_.has_value(), "ripple::BookStep::fwdImp : cache is set"); TAmounts result(beast::zero, beast::zero); @@ -1149,7 +1152,9 @@ BookStep::fwdImp( TOut const& ownerGives, std::uint32_t transferRateIn, std::uint32_t transferRateOut) mutable -> bool { - assert(cache_); + ASSERT( + cache_.has_value(), + "ripple::BookStep::fwdImp::eachOffer : cache is set"); if (remainingIn <= beast::zero) return false; @@ -1277,7 +1282,7 @@ BookStep::fwdImp( // something went very wrong JLOG(j_.error()) << "BookStep remainingIn < 0 " << to_string(remainingIn); - assert(0); + UNREACHABLE("ripple::BookStep::fwdImp : remaining less than zero"); cache_.emplace(beast::zero, beast::zero); return {beast::zero, beast::zero}; } @@ -1412,7 +1417,7 @@ bookStepEqual(Step const& step, ripple::Book const& book) bool const outXRP = isXRP(book.out.currency); if (inXRP && outXRP) { - assert(0); + UNREACHABLE("ripple::test::bookStepEqual : no XRP to XRP book step"); return false; // no such thing as xrp/xrp book step } if (inXRP && !outXRP) diff --git a/src/xrpld/app/paths/detail/DirectStep.cpp b/src/xrpld/app/paths/detail/DirectStep.cpp index 7df06751140..194e77edc2c 100644 --- a/src/xrpld/app/paths/detail/DirectStep.cpp +++ b/src/xrpld/app/paths/detail/DirectStep.cpp @@ -514,7 +514,9 @@ DirectStepI::revImp( auto const [srcQOut, dstQIn] = qualities(sb, srcDebtDir, StrandDirection::reverse); - assert(static_cast(this)->verifyDstQualityIn(dstQIn)); + ASSERT( + static_cast(this)->verifyDstQualityIn(dstQIn), + "ripple::DirectStepI : valid destination quality"); Issue const srcToDstIss(currency_, redeems(srcDebtDir) ? dst_ : src_); @@ -633,7 +635,7 @@ DirectStepI::fwdImp( boost::container::flat_set& /*ofrsToRm*/, IOUAmount const& in) { - assert(cache_); + ASSERT(cache_.has_value(), "ripple::DirectStepI::fwdImp : cache is set"); auto const [maxSrcToDst, srcDebtDir] = static_cast(this)->maxFlow(sb, cache_->srcToDst); @@ -720,7 +722,7 @@ DirectStepI::validFwd( auto const savCache = *cache_; - assert(!in.native); + ASSERT(!in.native, "ripple::DirectStepI::validFwd : input is not XRP"); auto const [maxSrcToDst, srcDebtDir] = static_cast(this)->maxFlow(sb, cache_->srcToDst); @@ -784,8 +786,11 @@ DirectStepI::qualitiesSrcIssues( { // Charge a transfer rate when issuing and previous step redeems - assert(static_cast(this)->verifyPrevStepDebtDirection( - prevStepDebtDirection)); + ASSERT( + static_cast(this)->verifyPrevStepDebtDirection( + prevStepDebtDirection), + "ripple::DirectStepI::qualitiesSrcIssues : will prevStepDebtDirection " + "issue"); std::uint32_t const srcQOut = redeems(prevStepDebtDirection) ? transferRate(sb, src_).value @@ -924,7 +929,9 @@ DirectStepI::check(StrandContext const& ctx) const { if (!ctx.prevStep) { - assert(0); // prev seen book without a prev step!?! + UNREACHABLE( + "ripple::DirectStepI::check : prev seen book without a " + "prev step"); return temBAD_PATH_LOOP; } diff --git a/src/xrpld/app/paths/detail/FlowDebugInfo.h b/src/xrpld/app/paths/detail/FlowDebugInfo.h index 000db4e5714..38e1a8cff5e 100644 --- a/src/xrpld/app/paths/detail/FlowDebugInfo.h +++ b/src/xrpld/app/paths/detail/FlowDebugInfo.h @@ -89,7 +89,10 @@ struct FlowDebugInfo void pushLiquiditySrc(EitherAmount const& eIn, EitherAmount const& eOut) { - assert(!liquiditySrcIn.empty()); + ASSERT( + !liquiditySrcIn.empty(), + "ripple::path::detail::FlowDebugInfo::pushLiquiditySrc : " + "non-empty liquidity source"); liquiditySrcIn.back().push_back(eIn); liquiditySrcOut.back().push_back(eOut); } @@ -122,7 +125,9 @@ struct FlowDebugInfo auto i = timePoints.find(tag); if (i == timePoints.end()) { - assert(0); + UNREACHABLE( + "ripple::path::detail::FlowDebugInfo::duration : timepoint not " + "found"); return std::chrono::duration(0); } auto const& t = i->second; diff --git a/src/xrpld/app/paths/detail/PaySteps.cpp b/src/xrpld/app/paths/detail/PaySteps.cpp index f28c1b96a7c..56eae0aab3d 100644 --- a/src/xrpld/app/paths/detail/PaySteps.cpp +++ b/src/xrpld/app/paths/detail/PaySteps.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -100,13 +101,14 @@ toStep( // should already be taken care of JLOG(j.error()) << "Found offer/account payment step. Aborting payment strand."; - assert(0); + UNREACHABLE("ripple::toStep : offer/account payment payment strand"); return {temBAD_PATH, std::unique_ptr{}}; } - assert( + ASSERT( (e2->getNodeType() & STPathElement::typeCurrency) || - (e2->getNodeType() & STPathElement::typeIssuer)); + (e2->getNodeType() & STPathElement::typeIssuer), + "ripple::toStep : currency or issuer"); auto const outCurrency = e2->getNodeType() & STPathElement::typeCurrency ? e2->getCurrency() : curIssue.currency; @@ -120,7 +122,7 @@ toStep( return {temBAD_PATH, std::unique_ptr{}}; } - assert(e2->isOffer()); + ASSERT(e2->isOffer(), "ripple::toStep : is offer"); if (isXRP(outCurrency)) return make_BookStepIX(ctx, curIssue); @@ -391,7 +393,7 @@ toStrand( next->getCurrency() != curIssue.currency) { // Should never happen - assert(0); + UNREACHABLE("ripple::toStrand : offer currency mismatch"); return {temBAD_PATH, Strand{}}; } @@ -457,7 +459,7 @@ toStrand( if (!checkStrand()) { JLOG(j.warn()) << "Flow check strand failed"; - assert(0); + UNREACHABLE("ripple::toStrand : invalid strand"); return {temBAD_PATH, Strand{}}; } diff --git a/src/xrpld/app/paths/detail/StepChecks.h b/src/xrpld/app/paths/detail/StepChecks.h index 140c9d1fe46..3c1c883ebf6 100644 --- a/src/xrpld/app/paths/detail/StepChecks.h +++ b/src/xrpld/app/paths/detail/StepChecks.h @@ -35,7 +35,7 @@ checkFreeze( AccountID const& dst, Currency const& currency) { - assert(src != dst); + ASSERT(src != dst, "ripple::checkFreeze : unequal input accounts"); // check freeze if (auto sle = view.read(keylet::account(dst))) diff --git a/src/xrpld/app/paths/detail/StrandFlow.h b/src/xrpld/app/paths/detail/StrandFlow.h index 329a4cc643f..72ca97a42ac 100644 --- a/src/xrpld/app/paths/detail/StrandFlow.h +++ b/src/xrpld/app/paths/detail/StrandFlow.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -171,7 +172,9 @@ flow( << "Re-executed limiting step failed. r.first: " << to_string(get(r.first)) << " maxIn: " << to_string(*maxIn); - assert(0); + UNREACHABLE( + "ripple::flow : first step re-executing the " + "limiting step failed"); return Result{strand, std::move(ofrsToRm)}; } } @@ -207,7 +210,9 @@ flow( #else JLOG(j.fatal()) << "Re-executed limiting step failed"; #endif - assert(0); + UNREACHABLE( + "ripple::flow : limiting step re-executing the " + "limiting step failed"); return Result{strand, std::move(ofrsToRm)}; } } @@ -241,7 +246,9 @@ flow( #else JLOG(j.fatal()) << "Re-executed forward pass failed"; #endif - assert(0); + UNREACHABLE( + "ripple::flow : non-limiting step re-executing the " + "forward pass failed"); return Result{strand, std::move(ofrsToRm)}; } stepIn = r.second; @@ -493,7 +500,7 @@ class ActiveStrands { if (i >= cur_.size()) { - assert(0); + UNREACHABLE("ripple::ActiveStrands::get : input out of range"); return nullptr; } return cur_[i]; @@ -700,9 +707,10 @@ flow( flowDebugInfo->pushLiquiditySrc( EitherAmount(f.in), EitherAmount(f.out)); - assert( + ASSERT( f.out <= remainingOut && f.sandbox && - (!remainingIn || f.in <= *remainingIn)); + (!remainingIn || f.in <= *remainingIn), + "ripple::flow : remaining constraints"); Quality const q(f.out, f.in); @@ -725,7 +733,7 @@ flow( if (baseView.rules().enabled(featureFlowSortStrands)) { - assert(!best); + ASSERT(!best, "ripple::flow : best is unset"); if (!f.inactive) activeStrands.push(strand); best.emplace(f.in, f.out, std::move(*f.sandbox), *strand, q); @@ -839,7 +847,7 @@ flow( // running debug builds of rippled. While this issue still needs to // be resolved, the assert is causing more harm than good at this // point. - // assert(0); + // UNREACHABLE("ripple::flow : rounding error"); return {tefEXCEPTION, std::move(ofrsToRmOnFail)}; } @@ -876,7 +884,7 @@ flow( // Handles both cases 1. and 2. // fixFillOrKill amendment: // Handles 2. 1. is handled above and falls through for tfSell. - assert(remainingIn); + ASSERT(remainingIn.has_value(), "ripple::flow : nonzero remainingIn"); if (remainingIn && *remainingIn != beast::zero) return { tecPATH_PARTIAL, diff --git a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp index ac178cbe2f2..ebc9510f4b2 100644 --- a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp +++ b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp @@ -281,7 +281,8 @@ XRPEndpointStep::fwdImp( boost::container::flat_set& ofrsToRm, XRPAmount const& in) { - assert(cache_); + ASSERT( + cache_.has_value(), "ripple::XRPEndpointStep::fwdImp : cache is set"); auto const balance = static_cast(this)->xrpLiquid(sb); auto const result = isLast_ ? in : std::min(balance, in); @@ -309,7 +310,7 @@ XRPEndpointStep::validFwd( return {false, EitherAmount(XRPAmount(beast::zero))}; } - assert(in.native); + ASSERT(in.native, "ripple::XRPEndpointStep::validFwd : input is XRP"); auto const& xrpIn = in.xrp; auto const balance = static_cast(this)->xrpLiquid(sb); diff --git a/src/xrpld/app/rdb/RelationalDatabase.h b/src/xrpld/app/rdb/RelationalDatabase.h index 5b06aa24d0e..a7528e2370d 100644 --- a/src/xrpld/app/rdb/RelationalDatabase.h +++ b/src/xrpld/app/rdb/RelationalDatabase.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -235,7 +236,7 @@ rangeCheckedCast(C c) c < std::numeric_limits::lowest())) { /* This should never happen */ - assert(0); + UNREACHABLE("ripple::rangeCheckedCast : domain error"); JLOG(debugLog().error()) << "rangeCheckedCast domain error:" << " value = " << c << " min = " << std::numeric_limits::lowest() diff --git a/src/xrpld/app/rdb/backend/detail/Node.cpp b/src/xrpld/app/rdb/backend/detail/Node.cpp index 2ea6bd12c62..cd7bab3782a 100644 --- a/src/xrpld/app/rdb/backend/detail/Node.cpp +++ b/src/xrpld/app/rdb/backend/detail/Node.cpp @@ -58,7 +58,7 @@ to_string(TableType type) case TableType::AccountTransactions: return "AccountTransactions"; default: - assert(false); + UNREACHABLE("ripple::detail::to_string : invalid TableType"); return "Unknown"; } } @@ -202,7 +202,7 @@ saveValidatedLedger( if (!ledger->info().accountHash.isNonZero()) { JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}}); - assert(false); + UNREACHABLE("ripple::detail::saveValidatedLedger : zero account hash"); } if (ledger->info().accountHash != ledger->stateMap().getHash().as_uint256()) @@ -211,10 +211,13 @@ saveValidatedLedger( << " != " << ledger->stateMap().getHash(); JLOG(j.fatal()) << "saveAcceptedLedger: seq=" << seq << ", current=" << current; - assert(false); + UNREACHABLE( + "ripple::detail::saveValidatedLedger : mismatched account hash"); } - assert(ledger->info().txHash == ledger->txMap().getHash().as_uint256()); + ASSERT( + ledger->info().txHash == ledger->txMap().getHash().as_uint256(), + "ripple::detail::saveValidatedLedger : transaction hash match"); // Save the ledger header in the hashed object store { diff --git a/src/xrpld/app/rdb/detail/Vacuum.cpp b/src/xrpld/app/rdb/detail/Vacuum.cpp index cc7f01a8409..10bd95177ed 100644 --- a/src/xrpld/app/rdb/detail/Vacuum.cpp +++ b/src/xrpld/app/rdb/detail/Vacuum.cpp @@ -28,7 +28,9 @@ doVacuumDB(DatabaseCon::Setup const& setup, beast::Journal j) boost::filesystem::path dbPath = setup.dataDir / TxDBName; uintmax_t const dbSize = file_size(dbPath); - assert(dbSize != static_cast(-1)); + ASSERT( + dbSize != static_cast(-1), + "ripple:doVacuumDB : file_size succeeded"); if (auto available = space(dbPath.parent_path()).available; available < dbSize) @@ -54,7 +56,9 @@ doVacuumDB(DatabaseCon::Setup const& setup, beast::Journal j) std::cout << "VACUUM beginning. page_size: " << pageSize << std::endl; session << "VACUUM;"; - assert(setup.globalPragma); + ASSERT( + setup.globalPragma != nullptr, + "ripple:doVacuumDB : non-null global pragma"); for (auto const& p : *setup.globalPragma) session << p; session << "PRAGMA page_size;", soci::into(pageSize); diff --git a/src/xrpld/app/tx/detail/AMMBid.cpp b/src/xrpld/app/tx/detail/AMMBid.cpp index 9de3762d2e3..29ac826a5de 100644 --- a/src/xrpld/app/tx/detail/AMMBid.cpp +++ b/src/xrpld/app/tx/detail/AMMBid.cpp @@ -181,7 +181,9 @@ applyBid( } else { - assert(ammSle->isFieldPresent(sfAuctionSlot)); + ASSERT( + ammSle->isFieldPresent(sfAuctionSlot), + "ripple::applyBid : has auction slot"); if (!ammSle->isFieldPresent(sfAuctionSlot)) return {tecINTERNAL, false}; } @@ -304,7 +306,7 @@ applyBid( { // Price the slot was purchased at. STAmount const pricePurchased = auctionSlot[sfPrice]; - assert(timeSlot); + ASSERT(timeSlot.has_value(), "ripple::applyBid : timeSlot is set"); auto const fractionUsed = (Number(*timeSlot) + 1) / AUCTION_SLOT_TIME_INTERVALS; auto const fractionRemaining = Number(1) - fractionUsed; diff --git a/src/xrpld/app/tx/detail/AMMDeposit.cpp b/src/xrpld/app/tx/detail/AMMDeposit.cpp index 3448401eb79..21d48d42c9a 100644 --- a/src/xrpld/app/tx/detail/AMMDeposit.cpp +++ b/src/xrpld/app/tx/detail/AMMDeposit.cpp @@ -466,7 +466,9 @@ AMMDeposit::applyGuts(Sandbox& sb) if (result == tesSUCCESS) { - assert(newLPTokenBalance > beast::zero); + ASSERT( + newLPTokenBalance > beast::zero, + "ripple::AMMDeposit::applyGuts : valid new LP token balance"); ammSle->setFieldAmount(sfLPTokenBalance, newLPTokenBalance); // LP depositing into AMM empty state gets the auction slot // and the voting diff --git a/src/xrpld/app/tx/detail/AMMVote.cpp b/src/xrpld/app/tx/detail/AMMVote.cpp index c4b6c612c63..1269bf4c383 100644 --- a/src/xrpld/app/tx/detail/AMMVote.cpp +++ b/src/xrpld/app/tx/detail/AMMVote.cpp @@ -200,9 +200,10 @@ applyVote( } } - assert( + ASSERT( !ctx_.view().rules().enabled(fixInnerObjTemplate) || - ammSle->isFieldPresent(sfAuctionSlot)); + ammSle->isFieldPresent(sfAuctionSlot), + "ripple::applyVote : has auction slot"); // Update the vote entries and the trading/discounted fee. ammSle->setFieldArray(sfVoteSlots, updatedVoteSlots); diff --git a/src/xrpld/app/tx/detail/AMMWithdraw.cpp b/src/xrpld/app/tx/detail/AMMWithdraw.cpp index 118262905c1..d1cfebe0639 100644 --- a/src/xrpld/app/tx/detail/AMMWithdraw.cpp +++ b/src/xrpld/app/tx/detail/AMMWithdraw.cpp @@ -877,7 +877,9 @@ AMMWithdraw::equalWithdrawLimit( frac = Number{amount2} / amount2Balance; auto const amountWithdraw = amountBalance * frac; - assert(amountWithdraw <= amount); + ASSERT( + amountWithdraw <= amount, + "ripple::AMMWithdraw::equalWithdrawLimit : maximum amountWithdraw"); return withdraw( view, ammSle, diff --git a/src/xrpld/app/tx/detail/ApplyContext.cpp b/src/xrpld/app/tx/detail/ApplyContext.cpp index 969af7960eb..925da7aaf48 100644 --- a/src/xrpld/app/tx/detail/ApplyContext.cpp +++ b/src/xrpld/app/tx/detail/ApplyContext.cpp @@ -21,10 +21,10 @@ #include #include #include +#include #include #include #include -#include namespace ripple { @@ -146,7 +146,9 @@ ApplyContext::checkInvariantsHelper( TER ApplyContext::checkInvariants(TER const result, XRPAmount const fee) { - assert(isTesSuccess(result) || isTecClaim(result)); + ASSERT( + isTesSuccess(result) || isTecClaim(result), + "ripple::ApplyContext::checkInvariants : is tesSUCCESS or tecCLAIM"); return checkInvariantsHelper( result, diff --git a/src/xrpld/app/tx/detail/Change.cpp b/src/xrpld/app/tx/detail/Change.cpp index 909f35fc799..d2772d6966e 100644 --- a/src/xrpld/app/tx/detail/Change.cpp +++ b/src/xrpld/app/tx/detail/Change.cpp @@ -149,7 +149,7 @@ Change::doApply() case ttUNL_MODIFY: return applyUNLModify(); default: - assert(0); + UNREACHABLE("ripple::Change::doApply : invalid transaction type"); return tefFAILURE; } } @@ -157,7 +157,8 @@ Change::doApply() void Change::preCompute() { - assert(account_ == beast::zero); + ASSERT( + account_ == beast::zero, "ripple::Change::preCompute : zero account"); } void diff --git a/src/xrpld/app/tx/detail/CreateOffer.cpp b/src/xrpld/app/tx/detail/CreateOffer.cpp index 2a5145594a1..578600621f2 100644 --- a/src/xrpld/app/tx/detail/CreateOffer.cpp +++ b/src/xrpld/app/tx/detail/CreateOffer.cpp @@ -210,7 +210,9 @@ CreateOffer::checkAcceptAsset( Issue const& issue) { // Only valid for custom currencies - assert(!isXRP(issue.currency)); + ASSERT( + !isXRP(issue.currency), + "ripple::CreateOffer::checkAcceptAsset : input is not XRP"); auto const issuerAccount = view.read(keylet::account(issue.account)); @@ -283,7 +285,9 @@ CreateOffer::select_path( OfferStream const& leg2) { // If we don't have any viable path, why are we here?! - assert(have_direct || have_bridge); + ASSERT( + have_direct || have_bridge, + "ripple::CreateOffer::select_path : valid inputs"); // If there's no bridged path, the direct is the best by default. if (!have_bridge) @@ -327,7 +331,9 @@ CreateOffer::bridged_cross( { auto const& takerAmount = taker.original_offer(); - assert(!isXRP(takerAmount.in) && !isXRP(takerAmount.out)); + ASSERT( + !isXRP(takerAmount.in) && !isXRP(takerAmount.out), + "ripple::CreateOffer::bridged_cross : neither is XRP"); if (isXRP(takerAmount.in) || isXRP(takerAmount.out)) Throw("Bridging with XRP and an endpoint."); @@ -497,7 +503,9 @@ CreateOffer::bridged_cross( // Postcondition: If we aren't done, then we *must* have consumed at // least one offer fully. - assert(direct_consumed || leg1_consumed || leg2_consumed); + ASSERT( + direct_consumed || leg1_consumed || leg2_consumed, + "ripple::CreateOffer::bridged_cross : consumed an offer"); if (!direct_consumed && !leg1_consumed && !leg2_consumed) Throw( @@ -587,7 +595,9 @@ CreateOffer::direct_cross( // Postcondition: If we aren't done, then we *must* have consumed the // offer on the books fully! - assert(direct_consumed); + ASSERT( + direct_consumed, + "ripple::CreateOffer::direct_cross : consumed an offer"); if (!direct_consumed) Throw( @@ -849,7 +859,9 @@ CreateOffer::flowCross( // remaining output. This too preserves the offer // Quality. afterCross.out -= result.actualAmountOut; - assert(afterCross.out >= beast::zero); + ASSERT( + afterCross.out >= beast::zero, + "ripple::CreateOffer::flowCross : minimum offer"); if (afterCross.out < beast::zero) afterCross.out.clear(); afterCross.in = mulRound( @@ -1046,7 +1058,10 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) // We expect the implementation of cross to succeed // or give a tec. - assert(result == tesSUCCESS || isTecClaim(result)); + ASSERT( + result == tesSUCCESS || isTecClaim(result), + "ripple::CreateOffer::applyGuts : result is tesSUCCESS or " + "tecCLAIM"); if (auto stream = j_.trace()) { @@ -1064,8 +1079,12 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) return {result, true}; } - assert(saTakerGets.issue() == place_offer.in.issue()); - assert(saTakerPays.issue() == place_offer.out.issue()); + ASSERT( + saTakerGets.issue() == place_offer.in.issue(), + "ripple::CreateOffer::applyGuts : taker gets issue match"); + ASSERT( + saTakerPays.issue() == place_offer.out.issue(), + "ripple::CreateOffer::applyGuts : taker pays issue match"); if (takerAmount != place_offer) crossed = true; @@ -1093,7 +1112,9 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) saTakerGets = place_offer.in; } - assert(saTakerPays > zero && saTakerGets > zero); + ASSERT( + saTakerPays > zero && saTakerGets > zero, + "ripple::CreateOffer::applyGuts : taker pays and gets positive"); if (result != tesSUCCESS) { diff --git a/src/xrpld/app/tx/detail/DeleteAccount.cpp b/src/xrpld/app/tx/detail/DeleteAccount.cpp index a7f33a3d8dd..44addd3de52 100644 --- a/src/xrpld/app/tx/detail/DeleteAccount.cpp +++ b/src/xrpld/app/tx/detail/DeleteAccount.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -242,7 +243,9 @@ DeleteAccount::preclaim(PreclaimContext const& ctx) } auto sleAccount = ctx.view.read(keylet::account(account)); - assert(sleAccount); + ASSERT( + sleAccount != nullptr, + "ripple::DeleteAccount::preclaim : non-null account"); if (!sleAccount) return terNO_ACCOUNT; @@ -345,11 +348,15 @@ TER DeleteAccount::doApply() { auto src = view().peek(keylet::account(account_)); - assert(src); + ASSERT( + src != nullptr, + "ripple::DeleteAccount::doApply : non-null source account"); auto const dstID = ctx_.tx[sfDestination]; auto dst = view().peek(keylet::account(dstID)); - assert(dst); + ASSERT( + dst != nullptr, + "ripple::DeleteAccount::doApply : non-null destination account"); if (!src || !dst) return tefBAD_LEDGER; @@ -377,7 +384,9 @@ DeleteAccount::doApply() return {result, SkipEntry::No}; } - assert(!"Undeletable entry should be found in preclaim."); + UNREACHABLE( + "ripple::DeleteAccount::doApply : undeletable item not found " + "in preclaim"); JLOG(j_.error()) << "DeleteAccount undeletable item not " "found in preclaim."; return {tecHAS_OBLIGATIONS, SkipEntry::No}; @@ -391,7 +400,9 @@ DeleteAccount::doApply() (*src)[sfBalance] = (*src)[sfBalance] - mSourceBalance; ctx_.deliver(mSourceBalance); - assert((*src)[sfBalance] == XRPAmount(0)); + ASSERT( + (*src)[sfBalance] == XRPAmount(0), + "ripple::DeleteAccount::doApply : source balance is zero"); // If there's still an owner directory associated with the source account // delete it. diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index 90fc399b344..5101eba60aa 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -381,7 +381,8 @@ AccountRootsDeletedClean::finalize( // transaction processing results, however unlikely, only fail if the // feature is enabled. Enabled, or not, though, a fatal-level message will // be logged - bool const enforce = view.rules().enabled(featureInvariantsV1_1); + [[maybe_unused]] bool const enforce = + view.rules().enabled(featureInvariantsV1_1); auto const objectExists = [&view, enforce, &j](auto const& keylet) { if (auto const sle = view.read(keylet)) @@ -399,8 +400,10 @@ AccountRootsDeletedClean::finalize( JLOG(j.fatal()) << "Invariant failed: account deletion left behind a " << typeName << " object"; - (void)enforce; - assert(enforce); + ASSERT( + enforce, + "ripple::AccountRootsDeletedClean::finalize::objectExists : " + "account deletion left no objects behind"); return true; } return false; diff --git a/src/xrpld/app/tx/detail/NFTokenMint.cpp b/src/xrpld/app/tx/detail/NFTokenMint.cpp index d5c3a8707c2..b903563dff7 100644 --- a/src/xrpld/app/tx/detail/NFTokenMint.cpp +++ b/src/xrpld/app/tx/detail/NFTokenMint.cpp @@ -160,7 +160,9 @@ NFTokenMint::createNFTokenID( std::memcpy(ptr, &tokenSeq, sizeof(tokenSeq)); ptr += sizeof(tokenSeq); - assert(std::distance(buf.data(), ptr) == buf.size()); + ASSERT( + std::distance(buf.data(), ptr) == buf.size(), + "ripple::NFTokenMint::createNFTokenID : data size matches the buffer"); return uint256::fromVoid(buf.data()); } diff --git a/src/xrpld/app/tx/detail/NFTokenUtils.cpp b/src/xrpld/app/tx/detail/NFTokenUtils.cpp index 61ff8e200b3..38378b7ff9e 100644 --- a/src/xrpld/app/tx/detail/NFTokenUtils.cpp +++ b/src/xrpld/app/tx/detail/NFTokenUtils.cpp @@ -191,7 +191,9 @@ getPageForToken( : carr[0].getFieldH256(sfNFTokenID); auto np = std::make_shared(keylet::nftpage(base, tokenIDForNewPage)); - assert(np->key() > base.key); + ASSERT( + np->key() > base.key, + "ripple::nft::getPageForToken : valid NFT page index"); np->setFieldArray(sfNFTokens, narr); np->setFieldH256(sfNextPageMin, cp->key()); @@ -243,7 +245,9 @@ compareTokens(uint256 const& a, uint256 const& b) TER insertToken(ApplyView& view, AccountID owner, STObject&& nft) { - assert(nft.isFieldPresent(sfNFTokenID)); + ASSERT( + nft.isFieldPresent(sfNFTokenID), + "ripple::nft::insertToken : has NFT token"); // First, we need to locate the page the NFT belongs to, creating it // if necessary. This operation may fail if it is impossible to insert @@ -783,7 +787,9 @@ repairNFTokenDirectoryLinks(ApplyView& view, AccountID const& owner) return didRepair; } - assert(nextPage); + ASSERT( + nextPage != nullptr, + "ripple::nft::repairNFTokenDirectoryLinks : next page is available"); if (nextPage->isFieldPresent(sfNextPageMin)) { didRepair = true; @@ -891,7 +897,9 @@ tokenOfferCreatePreclaim( if (nftIssuer != acctID && !(nftFlags & nft::flagTransferable)) { auto const root = view.read(keylet::account(nftIssuer)); - assert(root); + ASSERT( + root != nullptr, + "ripple::nft::tokenOfferCreatePreclaim : non-null account"); if (auto minter = (*root)[~sfNFTokenMinter]; minter != acctID) return tefNFTOKEN_IS_NOT_TRANSFERABLE; diff --git a/src/xrpld/app/tx/detail/Offer.h b/src/xrpld/app/tx/detail/Offer.h index a6f707ba561..23129952c3d 100644 --- a/src/xrpld/app/tx/detail/Offer.h +++ b/src/xrpld/app/tx/detail/Offer.h @@ -209,7 +209,7 @@ void TOffer::setFieldAmounts() { #ifdef _MSC_VER - assert(0); + UNREACHABLE("ripple::TOffer::setFieldAmounts : must be specialized"); #else static_assert(sizeof(TOut) == -1, "Must be specialized"); #endif diff --git a/src/xrpld/app/tx/detail/OfferStream.cpp b/src/xrpld/app/tx/detail/OfferStream.cpp index b963195259a..2fb9ad6a143 100644 --- a/src/xrpld/app/tx/detail/OfferStream.cpp +++ b/src/xrpld/app/tx/detail/OfferStream.cpp @@ -51,7 +51,8 @@ TOfferStreamBase::TOfferStreamBase( , tip_(view, book_) , counter_(counter) { - assert(validBook_); + ASSERT( + validBook_, "ripple::TOfferStreamBase::TOfferStreamBase : valid book"); } // Handle the case where a directory item with no corresponding ledger entry @@ -339,7 +340,9 @@ TOfferStreamBase::step() std::is_same_v)) return shouldRmSmallIncreasedQOffer(); } - assert(0); // xrp/xrp offer!?! should never happen + UNREACHABLE( + "rippls::TOfferStreamBase::step::rmSmallIncreasedQOffer : XRP " + "vs XRP offer"); return false; }(); diff --git a/src/xrpld/app/tx/detail/PayChan.cpp b/src/xrpld/app/tx/detail/PayChan.cpp index b2d4c0c9449..c313feff43f 100644 --- a/src/xrpld/app/tx/detail/PayChan.cpp +++ b/src/xrpld/app/tx/detail/PayChan.cpp @@ -150,7 +150,9 @@ closeChannel( if (!sle) return tefINTERNAL; - assert((*slep)[sfAmount] >= (*slep)[sfBalance]); + ASSERT( + (*slep)[sfAmount] >= (*slep)[sfBalance], + "ripple::closeChannel : minimum channel amount"); (*sle)[sfBalance] = (*sle)[sfBalance] + (*slep)[sfAmount] - (*slep)[sfBalance]; adjustOwnerCount(view, sle, -1, j); @@ -546,7 +548,9 @@ PayChanClaim::doApply() (*slep)[sfBalance] = ctx_.tx[sfBalance]; XRPAmount const reqDelta = reqBalance - chanBalance; - assert(reqDelta >= beast::zero); + ASSERT( + reqDelta >= beast::zero, + "ripple::PayChanClaim::doApply : minimum balance delta"); (*sled)[sfBalance] = (*sled)[sfBalance] + reqDelta; ctx_.view().update(sled); ctx_.view().update(slep); diff --git a/src/xrpld/app/tx/detail/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp index 2be784306cd..d6f7c60fabc 100644 --- a/src/xrpld/app/tx/detail/Payment.cpp +++ b/src/xrpld/app/tx/detail/Payment.cpp @@ -525,7 +525,7 @@ Payment::doApply() return res; } - assert(dstAmount.native()); + ASSERT(dstAmount.native(), "ripple::Payment::doApply : amount is XRP"); // Direct XRP payment. diff --git a/src/xrpld/app/tx/detail/SetSignerList.cpp b/src/xrpld/app/tx/detail/SetSignerList.cpp index 0949fbbe775..9c4fcd0e6c1 100644 --- a/src/xrpld/app/tx/detail/SetSignerList.cpp +++ b/src/xrpld/app/tx/detail/SetSignerList.cpp @@ -128,7 +128,7 @@ SetSignerList::doApply() default: break; } - assert(false); // Should not be possible to get here. + UNREACHABLE("ripple::SetSignerList::doApply : invalid operation"); return temMALFORMED; } @@ -137,8 +137,12 @@ SetSignerList::preCompute() { // Get the quorum and operation info. auto result = determineOperation(ctx_.tx, view().flags(), j_); - assert(std::get<0>(result) == tesSUCCESS); - assert(std::get<3>(result) != unknown); + ASSERT( + std::get<0>(result) == tesSUCCESS, + "ripple::SetSignerList::preCompute : result is tesSUCCESS"); + ASSERT( + std::get<3>(result) != unknown, + "ripple::SetSignerList::preCompute : result is known operation"); quorum_ = std::get<1>(result); signers_ = std::get<2>(result); @@ -171,8 +175,12 @@ signerCountBasedOwnerCountDelta(std::size_t entryCount, Rules const& rules) // The static_cast should always be safe since entryCount should always // be in the range from 1 to 8 (or 32 if ExpandedSignerList is enabled). // We've got a lot of room to grow. - assert(entryCount >= STTx::minMultiSigners); - assert(entryCount <= STTx::maxMultiSigners(&rules)); + ASSERT( + entryCount >= STTx::minMultiSigners, + "ripple::signerCountBasedOwnerCountDelta : minimum signers"); + ASSERT( + entryCount <= STTx::maxMultiSigners(&rules), + "ripple::signerCountBasedOwnerCountDelta : maximum signers"); return 2 + static_cast(entryCount); } @@ -260,7 +268,10 @@ SetSignerList::validateQuorumAndSignerEntries( } // Make sure there are no duplicate signers. - assert(std::is_sorted(signers.begin(), signers.end())); + ASSERT( + std::is_sorted(signers.begin(), signers.end()), + "ripple::SetSignerList::validateQuorumAndSignerEntries : sorted " + "signers"); if (std::adjacent_find(signers.begin(), signers.end()) != signers.end()) { JLOG(j.trace()) << "Duplicate signers in signer list"; diff --git a/src/xrpld/app/tx/detail/Taker.cpp b/src/xrpld/app/tx/detail/Taker.cpp index 9d335de2846..6e4b7f5cd57 100644 --- a/src/xrpld/app/tx/detail/Taker.cpp +++ b/src/xrpld/app/tx/detail/Taker.cpp @@ -54,24 +54,36 @@ BasicTaker::BasicTaker( , cross_type_(cross_type) , journal_(journal) { - assert(remaining_.in > beast::zero); - assert(remaining_.out > beast::zero); - - assert(m_rate_in.value != 0); - assert(m_rate_out.value != 0); + ASSERT( + remaining_.in > beast::zero, + "ripple::BasicTaker::BasicTaker : positive remaining in"); + ASSERT( + remaining_.out > beast::zero, + "ripple::BasicTaker::BasicTaker : positive remaining out"); + + ASSERT( + m_rate_in.value != 0, + "ripple::BasicTaker::BasicTaker : nonzero rate in"); + ASSERT( + m_rate_out.value != 0, + "ripple::BasicTaker::BasicTaker : nonzero rate out"); // If we are dealing with a particular flavor, make sure that it's the // flavor we expect: - assert( + ASSERT( cross_type != CrossType::XrpToIou || - (isXRP(issue_in()) && !isXRP(issue_out()))); + (isXRP(issue_in()) && !isXRP(issue_out())), + "ripple::BasicTaker::BasicTaker : valid cross to IOU"); - assert( + ASSERT( cross_type != CrossType::IouToXrp || - (!isXRP(issue_in()) && isXRP(issue_out()))); + (!isXRP(issue_in()) && isXRP(issue_out())), + "ripple::BasicTaker::BasicTaker : valid cross to XRP"); // And make sure we're not crossing XRP for XRP - assert(!isXRP(issue_in()) || !isXRP(issue_out())); + ASSERT( + !isXRP(issue_in()) || !isXRP(issue_out()), + "ripple::BasicTaker::BasicTaker : not crossing XRP for XRP"); // If this is a passive order, we adjust the quality so as to prevent offers // at the same quality level from being consumed. @@ -150,7 +162,9 @@ BasicTaker::remaining_offer() const if (sell_) { - assert(remaining_.in > beast::zero); + ASSERT( + remaining_.in > beast::zero, + "ripple::BasicTaker::remaining_offer : positive remaining in"); // We scale the output based on the remaining input: return Amounts( @@ -158,7 +172,9 @@ BasicTaker::remaining_offer() const divRound(remaining_.in, quality_.rate(), issue_out_, true)); } - assert(remaining_.out > beast::zero); + ASSERT( + remaining_.out > beast::zero, + "ripple::BasicTaker::remaining_offer : positive remaining out"); // We scale the input based on the remaining output: return Amounts( @@ -424,7 +440,9 @@ BasicTaker::do_cross(Amounts offer, Quality quality, AccountID const& owner) remaining_.out -= result.order.out; remaining_.in -= result.order.in; - assert(remaining_.in >= beast::zero); + ASSERT( + remaining_.in >= beast::zero, + "ripple::BasicTaker::do_cross : minimum remaining in"); return result; } @@ -439,10 +457,17 @@ BasicTaker::do_cross( Quality quality2, AccountID const& owner2) { - assert(!offer1.in.native()); - assert(offer1.out.native()); - assert(offer2.in.native()); - assert(!offer2.out.native()); + ASSERT( + !offer1.in.native(), + "ripple::BasicTaker::do_cross : offer1 in is not XRP"); + ASSERT( + offer1.out.native(), + "ripple::BasicTaker::do_cross : offer1 out is XRP"); + ASSERT( + offer2.in.native(), "ripple::BasicTaker::do_cross : offer2 in is XRP"); + ASSERT( + !offer2.out.native(), + "ripple::BasicTaker::do_cross : offer2 out is not XRP"); // If the taker owns the first leg of the offer, then the taker's available // funds aren't the limiting factor for the input - the offer itself is. @@ -559,8 +584,12 @@ Taker::Taker( , direct_crossings_(0) , bridge_crossings_(0) { - assert(issue_in() == offer.in.issue()); - assert(issue_out() == offer.out.issue()); + ASSERT( + issue_in() == offer.in.issue(), + "ripple::Taker::Taker : issue in is a match"); + ASSERT( + issue_out() == offer.out.issue(), + "ripple::Taker::Taker : issue out is a match"); if (auto stream = journal_.debug()) { @@ -689,7 +718,8 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer) if (cross_type() != CrossType::XrpToIou) { - assert(!isXRP(flow.order.in)); + ASSERT( + !isXRP(flow.order.in), "ripple::Taker::fill : order in is not XRP"); if (result == tesSUCCESS) result = @@ -701,7 +731,7 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer) } else { - assert(isXRP(flow.order.in)); + ASSERT(isXRP(flow.order.in), "ripple::Taker::fill : order in is XRP"); if (result == tesSUCCESS) result = transferXRP(account(), offer.owner(), flow.order.in); @@ -710,7 +740,9 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer) // Now send funds from the account whose offer we're taking if (cross_type() != CrossType::IouToXrp) { - assert(!isXRP(flow.order.out)); + ASSERT( + !isXRP(flow.order.out), + "ripple::Taker::fill : order out is not XRP"); if (result == tesSUCCESS) result = redeemIOU( @@ -722,7 +754,7 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer) } else { - assert(isXRP(flow.order.out)); + ASSERT(isXRP(flow.order.out), "ripple::Taker::fill : order out is XRP"); if (result == tesSUCCESS) result = transferXRP(offer.owner(), account(), flow.order.out); diff --git a/src/xrpld/app/tx/detail/Transactor.cpp b/src/xrpld/app/tx/detail/Transactor.cpp index 052a735a2fd..8352dbc7800 100644 --- a/src/xrpld/app/tx/detail/Transactor.cpp +++ b/src/xrpld/app/tx/detail/Transactor.cpp @@ -368,7 +368,9 @@ Transactor::checkPriorTxAndLastLedger(PreclaimContext const& ctx) TER Transactor::consumeSeqProxy(SLE::pointer const& sleAccount) { - assert(sleAccount); + ASSERT( + sleAccount != nullptr, + "ripple::Transactor::consumeSeqProxy : non-null account"); SeqProxy const seqProx = ctx_.tx.getSeqProxy(); if (seqProx.isSeq()) { @@ -440,7 +442,9 @@ Transactor::ticketDelete( void Transactor::preCompute() { - assert(account_ != beast::zero); + ASSERT( + account_ != beast::zero, + "ripple::Transactor::preCompute : nonzero account"); } TER @@ -454,7 +458,9 @@ Transactor::apply() // sle must exist except for transactions // that allow zero account. - assert(sle != nullptr || account_ == beast::zero); + ASSERT( + sle != nullptr || account_ == beast::zero, + "ripple::Transactor::apply : non-null SLE or zero account"); if (sle) { @@ -579,8 +585,12 @@ Transactor::checkMultiSign(PreclaimContext const& ctx) // We have plans to support multiple SignerLists in the future. The // presence and defaulted value of the SignerListID field will enable that. - assert(sleAccountSigners->isFieldPresent(sfSignerListID)); - assert(sleAccountSigners->getFieldU32(sfSignerListID) == 0); + ASSERT( + sleAccountSigners->isFieldPresent(sfSignerListID), + "ripple::Transactor::checkMultiSign : has signer list ID"); + ASSERT( + sleAccountSigners->getFieldU32(sfSignerListID) == 0, + "ripple::Transactor::checkMultiSign : signer list ID is 0"); auto accountSigners = SignerEntries::deserialize(*sleAccountSigners, ctx.j, "ledger"); @@ -816,7 +826,9 @@ Transactor::reset(XRPAmount fee) auto const balance = txnAcct->getFieldAmount(sfBalance).xrp(); // balance should have already been checked in checkFee / preFlight. - assert(balance != beast::zero && (!view().open() || balance >= fee)); + ASSERT( + balance != beast::zero && (!view().open() || balance >= fee), + "ripple::Transactor::reset : valid balance"); // We retry/reject the transaction if the account balance is zero or we're // applying against an open ledger and the balance is less than the fee @@ -831,7 +843,8 @@ Transactor::reset(XRPAmount fee) // reject the transaction. txnAcct->setFieldAmount(sfBalance, balance - fee); TER const ter{consumeSeqProxy(txnAcct)}; - assert(isTesSuccess(ter)); + ASSERT( + isTesSuccess(ter), "ripple::Transactor::reset : result is tesSUCCESS"); if (isTesSuccess(ter)) view().update(txnAcct); @@ -871,7 +884,8 @@ Transactor::operator()() JLOG(j_.fatal()) << "Transaction serdes mismatch"; JLOG(j_.info()) << to_string(ctx_.tx.getJson(JsonOptions::none)); JLOG(j_.fatal()) << s2.getJson(JsonOptions::none); - assert(false); + UNREACHABLE( + "ripple::Transactor::operator() : transaction serdes mismatch"); } } #endif @@ -888,7 +902,9 @@ Transactor::operator()() // No transaction can return temUNKNOWN from apply, // and it can't be passed in from a preclaim. - assert(result != temUNKNOWN); + ASSERT( + result != temUNKNOWN, + "ripple::Transactor::operator() : result is not temUNKNOWN"); if (auto stream = j_.trace()) stream << "preclaim result: " << transToken(result); @@ -944,7 +960,10 @@ Transactor::operator()() std::shared_ptr const& after) { if (isDelete) { - assert(before && after); + ASSERT( + before && after, + "ripple::Transactor::operator()::visit : non-null SLE " + "inputs"); if (doOffers && before && after && (before->getType() == ltOFFER) && (before->getFieldAmount(sfTakerPays) == diff --git a/src/xrpld/app/tx/detail/XChainBridge.cpp b/src/xrpld/app/tx/detail/XChainBridge.cpp index f5633903567..7485ff6c4b0 100644 --- a/src/xrpld/app/tx/detail/XChainBridge.cpp +++ b/src/xrpld/app/tx/detail/XChainBridge.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -222,7 +223,9 @@ claimHelper( auto i = signersList.find(a.keyAccount); if (i == signersList.end()) { - assert(0); // should have already been checked + UNREACHABLE( + "ripple::claimHelper : invalid inputs"); // should have already + // been checked continue; } weight += i->second; @@ -437,7 +440,9 @@ transferHelper( if (amt.native()) { auto const sleSrc = psb.peek(keylet::account(src)); - assert(sleSrc); + ASSERT( + sleSrc != nullptr, + "ripple::transferHelper : non-null source account"); if (!sleSrc) return tecINTERNAL; diff --git a/src/xrpld/app/tx/detail/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp index b3c711084dc..24d6d6bb61f 100644 --- a/src/xrpld/app/tx/detail/applySteps.cpp +++ b/src/xrpld/app/tx/detail/applySteps.cpp @@ -157,7 +157,7 @@ invoke_preflight(PreflightContext const& ctx) // Should never happen JLOG(ctx.j.fatal()) << "Unknown transaction type in preflight: " << e.txnType; - assert(false); + UNREACHABLE("ripple::invoke_preflight : unknown transaction type"); return {temUNKNOWN, TxConsequences{temUNKNOWN}}; } } @@ -206,7 +206,7 @@ invoke_preclaim(PreclaimContext const& ctx) // Should never happen JLOG(ctx.j.fatal()) << "Unknown transaction type in preclaim: " << e.txnType; - assert(false); + UNREACHABLE("ripple::invoke_preclaim : unknown transaction type"); return temUNKNOWN; } } @@ -222,7 +222,8 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx) } catch (UnknownTxnType const& e) { - assert(false); + UNREACHABLE( + "ripple::invoke_calculateBaseFee : unknown transaction type"); return XRPAmount{0}; } } @@ -234,7 +235,9 @@ TxConsequences::TxConsequences(NotTEC pfresult) , seqProx_(SeqProxy::sequence(0)) , sequencesConsumed_(0) { - assert(!isTesSuccess(pfresult)); + ASSERT( + !isTesSuccess(pfresult), + "ripple::TxConsequences::TxConsequences : is not tesSUCCESS"); } TxConsequences::TxConsequences(STTx const& tx) @@ -281,7 +284,7 @@ invoke_apply(ApplyContext& ctx) // Should never happen JLOG(ctx.journal.fatal()) << "Unknown transaction type in apply: " << e.txnType; - assert(false); + UNREACHABLE("ripple::invoke_apply : unknown transaction type"); return {temUNKNOWN, false}; } } diff --git a/src/xrpld/consensus/Consensus.h b/src/xrpld/consensus/Consensus.h index 06c12b4f150..7b8d03f48a7 100644 --- a/src/xrpld/consensus/Consensus.h +++ b/src/xrpld/consensus/Consensus.h @@ -863,7 +863,9 @@ Consensus::gotTxSet( { // Our position is added to acquired_ as soon as we create it, // so this txSet must differ - assert(id != result_->position.position()); + ASSERT( + id != result_->position.position(), + "ripple::Consensus::gotTxSet : updated transaction set"); bool any = false; for (auto const& [nodeId, peerPos] : currPeerPositions_) { @@ -1008,7 +1010,9 @@ template void Consensus::handleWrongLedger(typename Ledger_t::ID const& lgrId) { - assert(lgrId != prevLedgerID_ || previousLedger_.id() != lgrId); + ASSERT( + lgrId != prevLedgerID_ || previousLedger_.id() != lgrId, + "ripple::Consensus::handleWrongLedger : have wrong ledger"); // Stop proposing because we are out of sync leaveConsensus(); @@ -1259,7 +1263,9 @@ void Consensus::phaseEstablish() { // can only establish consensus if we already took a stance - assert(result_); + ASSERT( + result_.has_value(), + "ripple::Consensus::phaseEstablish : result is set"); using namespace std::chrono; ConsensusParms const& parms = adaptor_.parms(); @@ -1307,7 +1313,7 @@ void Consensus::closeLedger() { // We should not be closing if we already have a position - assert(!result_); + ASSERT(!result_, "ripple::Consensus::closeLedger : result is not set"); phase_ = ConsensusPhase::establish; JLOG(j_.debug()) << "transitioned to ConsensusPhase::establish"; @@ -1360,7 +1366,9 @@ void Consensus::updateOurPositions() { // We must have a position if we are updating it - assert(result_); + ASSERT( + result_.has_value(), + "ripple::Consensus::updateOurPositions : result is set"); ConsensusParms const& parms = adaptor_.parms(); // Compute a cutoff time @@ -1544,7 +1552,8 @@ bool Consensus::haveConsensus() { // Must have a stance if we are checking for consensus - assert(result_); + ASSERT( + result_.has_value(), "ripple::Consensus::haveConsensus : has result"); // CHECKME: should possibly count unacquired TX sets as disagreeing int agree = 0, disagree = 0; @@ -1619,7 +1628,9 @@ void Consensus::createDisputes(TxSet_t const& o) { // Cannot create disputes without our stance - assert(result_); + ASSERT( + result_.has_value(), + "ripple::Consensus::createDisputes : result is set"); // Only create disputes if this is a new set if (!result_->compares.emplace(o.id()).second) @@ -1640,9 +1651,10 @@ Consensus::createDisputes(TxSet_t const& o) { ++dc; // create disputed transactions (from the ledger that has them) - assert( + ASSERT( (inThisSet && result_->txns.find(txId) && !o.find(txId)) || - (!inThisSet && !result_->txns.find(txId) && o.find(txId))); + (!inThisSet && !result_->txns.find(txId) && o.find(txId)), + "ripple::Consensus::createDisputes : has disputed transactions"); Tx_t tx = inThisSet ? result_->txns.find(txId) : o.find(txId); auto txID = tx.id(); @@ -1678,7 +1690,9 @@ void Consensus::updateDisputes(NodeID_t const& node, TxSet_t const& other) { // Cannot updateDisputes without our stance - assert(result_); + ASSERT( + result_.has_value(), + "ripple::Consensus::updateDisputes : result is set"); // Ensure we have created disputes against this set if we haven't seen // it before diff --git a/src/xrpld/consensus/ConsensusTypes.h b/src/xrpld/consensus/ConsensusTypes.h index da03fc4875a..15bc858848d 100644 --- a/src/xrpld/consensus/ConsensusTypes.h +++ b/src/xrpld/consensus/ConsensusTypes.h @@ -214,7 +214,9 @@ struct ConsensusResult ConsensusResult(TxSet_t&& s, Proposal_t&& p) : txns{std::move(s)}, position{std::move(p)} { - assert(txns.id() == position.position()); + ASSERT( + txns.id() == position.position(), + "ripple::ConsensusResult : valid inputs"); } //! The set of transactions consensus agrees go in the ledger diff --git a/src/xrpld/consensus/LedgerTiming.h b/src/xrpld/consensus/LedgerTiming.h index 1bb5bfd730f..57247abe968 100644 --- a/src/xrpld/consensus/LedgerTiming.h +++ b/src/xrpld/consensus/LedgerTiming.h @@ -82,7 +82,9 @@ getNextLedgerTimeResolution( bool previousAgree, Seq ledgerSeq) { - assert(ledgerSeq != Seq{0}); + ASSERT( + ledgerSeq != Seq{0}, + "ripple:getNextLedgerTimeResolution : valid ledger sequence"); using namespace std::chrono; // Find the current resolution: @@ -90,7 +92,9 @@ getNextLedgerTimeResolution( std::begin(ledgerPossibleTimeResolutions), std::end(ledgerPossibleTimeResolutions), previousResolution); - assert(iter != std::end(ledgerPossibleTimeResolutions)); + ASSERT( + iter != std::end(ledgerPossibleTimeResolutions), + "ripple:getNextLedgerTimeResolution : found time resolution"); // This should never happen, but just as a precaution if (iter == std::end(ledgerPossibleTimeResolutions)) diff --git a/src/xrpld/consensus/LedgerTrie.h b/src/xrpld/consensus/LedgerTrie.h index 32bae28cc07..ad1797d51fe 100644 --- a/src/xrpld/consensus/LedgerTrie.h +++ b/src/xrpld/consensus/LedgerTrie.h @@ -21,7 +21,9 @@ #define RIPPLE_APP_CONSENSUS_LEDGERS_TRIE_H_INCLUDED #include +#include #include + #include #include #include @@ -62,7 +64,7 @@ class SpanTip ID ancestor(Seq const& s) const { - assert(s <= seq); + ASSERT(s <= seq, "ripple::SpanTip::ancestor : valid input"); return ledger[s]; } @@ -88,7 +90,8 @@ class Span Span() : ledger_{typename Ledger::MakeGenesis{}} { // Require default ledger to be genesis seq - assert(ledger_.seq() == start_); + ASSERT( + ledger_.seq() == start_, "ripple::Span::Span : ledger is genesis"); } Span(Ledger ledger) @@ -157,7 +160,7 @@ class Span : start_{start}, end_{end}, ledger_{l} { // Spans cannot be empty - assert(start < end); + ASSERT(start < end, "ripple::Span::Span : non-empty span input"); } Seq @@ -230,7 +233,7 @@ struct Node [child](std::unique_ptr const& curr) { return curr.get() == child; }); - assert(it != children.end()); + ASSERT(it != children.end(), "ripple::Node::erase : valid input"); std::swap(*it, children.back()); children.pop_back(); } @@ -371,7 +374,7 @@ class LedgerTrie Node* curr = root.get(); // Root is always defined and is in common with all ledgers - assert(curr); + ASSERT(curr != nullptr, "ripple::LedgerTrie::find : non-null root"); Seq pos = curr->span.diff(ledger); bool done = false; @@ -452,7 +455,8 @@ class LedgerTrie auto const [loc, diffSeq] = find(ledger); // There is always a place to insert - assert(loc); + ASSERT( + loc != nullptr, "ripple::LedgerTrie::insert : valid input ledger"); // Node from which to start incrementing branchSupport Node* incNode = loc; @@ -487,12 +491,16 @@ class LedgerTrie newNode->tipSupport = loc->tipSupport; newNode->branchSupport = loc->branchSupport; newNode->children = std::move(loc->children); - assert(loc->children.empty()); + ASSERT( + loc->children.empty(), + "ripple::LedgerTrie::insert : moved-from children"); for (std::unique_ptr& child : newNode->children) child->parent = newNode.get(); // Loc truncates to prefix and newNode is its child - assert(prefix); + ASSERT( + prefix.has_value(), + "ripple::LedgerTrie::insert : prefix is set"); loc->span = *prefix; newNode->parent = loc; loc->children.emplace_back(std::move(newNode)); @@ -545,7 +553,9 @@ class LedgerTrie loc->tipSupport -= count; auto const it = seqSupport.find(ledger.seq()); - assert(it != seqSupport.end() && it->second >= count); + ASSERT( + it != seqSupport.end() && it->second >= count, + "ripple::LedgerTrie::remove : valid input ledger"); it->second -= count; if (it->second == 0) seqSupport.erase(it->first); diff --git a/src/xrpld/consensus/Validations.h b/src/xrpld/consensus/Validations.h index a1171effb56..765298d897a 100644 --- a/src/xrpld/consensus/Validations.h +++ b/src/xrpld/consensus/Validations.h @@ -434,7 +434,9 @@ class Validations Validation const& val, std::optional> prior) { - assert(val.trusted()); + ASSERT( + val.trusted(), + "ripple::Validations::updateTrie : trusted input validation"); // Clear any prior acquiring ledger for this node if (prior) @@ -713,7 +715,7 @@ class Validations setSeqToKeep(Seq const& low, Seq const& high) { std::lock_guard lock{mutex_}; - assert(low < high); + ASSERT(low < high, "ripple::Validations::setSeqToKeep : valid inputs"); toKeep_ = {low, high}; } diff --git a/src/xrpld/core/Coro.ipp b/src/xrpld/core/Coro.ipp index a936dd896ae..a046971015e 100644 --- a/src/xrpld/core/Coro.ipp +++ b/src/xrpld/core/Coro.ipp @@ -53,7 +53,7 @@ JobQueue::Coro::Coro( inline JobQueue::Coro::~Coro() { #ifndef NDEBUG - assert(finished_); + ASSERT(finished_, "ripple::JobQueue::Coro::~Coro : is finished"); #endif } @@ -103,7 +103,9 @@ JobQueue::Coro::resume() auto saved = detail::getLocalValues().release(); detail::getLocalValues().reset(&lvs_); std::lock_guard lock(mutex_); - assert(coro_); + ASSERT( + static_cast(coro_), + "ripple::JobQueue::Coro::resume : is runnable"); coro_(); detail::getLocalValues().release(); detail::getLocalValues().reset(saved); diff --git a/src/xrpld/core/DatabaseCon.h b/src/xrpld/core/DatabaseCon.h index c8c40dec662..bb6f36d4d56 100644 --- a/src/xrpld/core/DatabaseCon.h +++ b/src/xrpld/core/DatabaseCon.h @@ -97,7 +97,10 @@ class DatabaseCon std::vector const* commonPragma() const { - assert(!useGlobalPragma || globalPragma); + ASSERT( + !useGlobalPragma || globalPragma, + "ripple::DatabaseCon::Setup::commonPragma : consistent global " + "pragma"); return useGlobalPragma && globalPragma ? globalPragma.get() : nullptr; } diff --git a/src/xrpld/core/JobTypes.h b/src/xrpld/core/JobTypes.h index 3b41ce7ff47..5963446cd43 100644 --- a/src/xrpld/core/JobTypes.h +++ b/src/xrpld/core/JobTypes.h @@ -53,17 +53,22 @@ class JobTypes int limit, std::chrono::milliseconds avgLatency, std::chrono::milliseconds peakLatency) { - assert(m_map.find(jt) == m_map.end()); - - auto const [_, inserted] = m_map.emplace( - std::piecewise_construct, - std::forward_as_tuple(jt), - std::forward_as_tuple( - jt, name, limit, avgLatency, peakLatency)); - - assert(inserted == true); - (void)_; - (void)inserted; + ASSERT( + m_map.find(jt) == m_map.end(), + "ripple::JobTypes::JobTypes::add : unique job type input"); + + [[maybe_unused]] auto const inserted = + m_map + .emplace( + std::piecewise_construct, + std::forward_as_tuple(jt), + std::forward_as_tuple( + jt, name, limit, avgLatency, peakLatency)) + .second; + + ASSERT( + inserted == true, + "ripple::JobTypes::JobTypes::add : input is inserted"); }; // clang-format off @@ -137,7 +142,7 @@ class JobTypes get(JobType jt) const { Map::const_iterator const iter(m_map.find(jt)); - assert(iter != m_map.end()); + ASSERT(iter != m_map.end(), "ripple::JobTypes::get : valid input"); if (iter != m_map.end()) return iter->second; diff --git a/src/xrpld/core/detail/Config.cpp b/src/xrpld/core/detail/Config.cpp index 885951111c0..b37a931bca0 100644 --- a/src/xrpld/core/detail/Config.cpp +++ b/src/xrpld/core/detail/Config.cpp @@ -266,7 +266,7 @@ Config::Config() void Config::setupControl(bool bQuiet, bool bSilent, bool bStandalone) { - assert(NODE_SIZE == 0); + ASSERT(NODE_SIZE == 0, "ripple::Config::setupControl : node size not set"); QUIET = bQuiet || bSilent; SILENT = bSilent; @@ -287,7 +287,9 @@ Config::setupControl(bool bQuiet, bool bSilent, bool bStandalone) return (limit == 0) || (ramSize_ < limit); }); - assert(ns != threshold.second.end()); + ASSERT( + ns != threshold.second.end(), + "ripple::Config::setupControl : valid node size"); if (ns != threshold.second.end()) NODE_SIZE = std::distance(threshold.second.begin(), ns); @@ -298,7 +300,7 @@ Config::setupControl(bool bQuiet, bool bSilent, bool bStandalone) NODE_SIZE = std::min(hc / 2, NODE_SIZE); } - assert(NODE_SIZE <= 4); + ASSERT(NODE_SIZE <= 4, "ripple::Config::setupControl : node size is set"); } void @@ -1004,8 +1006,12 @@ int Config::getValueFor(SizedItem item, std::optional node) const { auto const index = static_cast>(item); - assert(index < sizedItems.size()); - assert(!node || *node <= 4); + ASSERT( + index < sizedItems.size(), + "ripple::Config::getValueFor : valid index input"); + ASSERT( + !node || *node <= 4, + "ripple::Config::getValueFor : unset or valid node"); return sizedItems.at(index).second.at(node.value_or(NODE_SIZE)); } diff --git a/src/xrpld/core/detail/DatabaseCon.cpp b/src/xrpld/core/detail/DatabaseCon.cpp index 7000899b1f6..d93a66cfb83 100644 --- a/src/xrpld/core/detail/DatabaseCon.cpp +++ b/src/xrpld/core/detail/DatabaseCon.cpp @@ -231,7 +231,9 @@ setup_DatabaseCon(Config const& c, std::optional j) "nodes storing large amounts of history, because of the " "difficulty inherent in rebuilding corrupted data."; } - assert(result->size() == 3); + ASSERT( + result->size() == 3, + "ripple::setup_DatabaseCon::globalPragma : result size is 3"); return result; }(); } diff --git a/src/xrpld/core/detail/Job.cpp b/src/xrpld/core/detail/Job.cpp index 0782fd05a66..17f600a4f41 100644 --- a/src/xrpld/core/detail/Job.cpp +++ b/src/xrpld/core/detail/Job.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include namespace ripple { diff --git a/src/xrpld/core/detail/JobQueue.cpp b/src/xrpld/core/detail/JobQueue.cpp index 1c859d724f4..3e87dd22212 100644 --- a/src/xrpld/core/detail/JobQueue.cpp +++ b/src/xrpld/core/detail/JobQueue.cpp @@ -55,7 +55,9 @@ JobQueue::JobQueue( std::piecewise_construct, std::forward_as_tuple(jt.type()), std::forward_as_tuple(jt, m_collector, logs))); - assert(result.second == true); + ASSERT( + result.second == true, + "ripple::JobQueue::JobQueue : jobs added"); (void)result.second; } } @@ -80,10 +82,14 @@ JobQueue::addRefCountedJob( std::string const& name, JobFunction const& func) { - assert(type != jtINVALID); + ASSERT( + type != jtINVALID, + "ripple::JobQueue::addRefCountedJob : valid input job type"); auto iter(m_jobData.find(type)); - assert(iter != m_jobData.end()); + ASSERT( + iter != m_jobData.end(), + "ripple::JobQueue::addRefCountedJob : job type found in jobs"); if (iter == m_jobData.end()) return false; @@ -93,9 +99,11 @@ JobQueue::addRefCountedJob( // FIXME: Workaround incorrect client shutdown ordering // do not add jobs to a queue with no threads - assert( + ASSERT( (type >= jtCLIENT && type <= jtCLIENT_WEBSOCKET) || - m_workers.getNumberOfThreads() > 0); + m_workers.getNumberOfThreads() > 0, + "ripple::JobQueue::addRefCountedJob : threads available or job " + "requires no threads"); { std::lock_guard lock(m_mutex); @@ -104,8 +112,12 @@ JobQueue::addRefCountedJob( auto const& job = *result.first; JobType const type(job.getType()); - assert(type != jtINVALID); - assert(m_jobSet.find(job) != m_jobSet.end()); + ASSERT( + type != jtINVALID, + "ripple::JobQueue::addRefCountedJob : has valid job type"); + ASSERT( + m_jobSet.find(job) != m_jobSet.end(), + "ripple::JobQueue::addRefCountedJob : job found"); perfLog_.jobQueue(type); JobTypeData& data(getJobTypeData(type)); @@ -165,7 +177,9 @@ std::unique_ptr JobQueue::makeLoadEvent(JobType t, std::string const& name) { JobDataMap::iterator iter(m_jobData.find(t)); - assert(iter != m_jobData.end()); + ASSERT( + iter != m_jobData.end(), + "ripple::JobQueue::makeLoadEvent : valid job type input"); if (iter == m_jobData.end()) return {}; @@ -180,7 +194,9 @@ JobQueue::addLoadEvents(JobType t, int count, std::chrono::milliseconds elapsed) LogicError("JobQueue::addLoadEvents() called after JobQueue stopped"); JobDataMap::iterator iter(m_jobData.find(t)); - assert(iter != m_jobData.end()); + ASSERT( + iter != m_jobData.end(), + "ripple::JobQueue::addLoadEvents : valid job type input"); iter->second.load().addSamples(count, elapsed); } @@ -206,7 +222,8 @@ JobQueue::getJson(int c) for (auto& x : m_jobData) { - assert(x.first != jtINVALID); + ASSERT( + x.first != jtINVALID, "ripple::JobQueue::getJson : valid job type"); if (x.first == jtGENERIC) continue; @@ -261,7 +278,9 @@ JobTypeData& JobQueue::getJobTypeData(JobType type) { JobDataMap::iterator c(m_jobData.find(type)); - assert(c != m_jobData.end()); + ASSERT( + c != m_jobData.end(), + "ripple::JobQueue::getJobTypeData : valid job type input"); // NIKB: This is ugly and I hate it. We must remove jtINVALID completely // and use something sane. @@ -286,9 +305,11 @@ JobQueue::stop() std::unique_lock lock(m_mutex); cv_.wait( lock, [this] { return m_processCount == 0 && m_jobSet.empty(); }); - assert(m_processCount == 0); - assert(m_jobSet.empty()); - assert(nSuspend_ == 0); + ASSERT( + m_processCount == 0, + "ripple::JobQueue::stop : all processes completed"); + ASSERT(m_jobSet.empty(), "ripple::JobQueue::stop : all jobs completed"); + ASSERT(nSuspend_ == 0, "ripple::JobQueue::stop : no coros suspended"); stopped_ = true; } } @@ -302,28 +323,35 @@ JobQueue::isStopped() const void JobQueue::getNextJob(Job& job) { - assert(!m_jobSet.empty()); + ASSERT(!m_jobSet.empty(), "ripple::JobQueue::getNextJob : non-empty jobs"); std::set::const_iterator iter; for (iter = m_jobSet.begin(); iter != m_jobSet.end(); ++iter) { JobType const type = iter->getType(); - assert(type != jtINVALID); + ASSERT( + type != jtINVALID, "ripple::JobQueue::getNextJob : valid job type"); JobTypeData& data(getJobTypeData(type)); - assert(data.running <= getJobLimit(type)); + ASSERT( + data.running <= getJobLimit(type), + "ripple::JobQueue::getNextJob : maximum jobs running"); // Run this job if we're running below the limit. if (data.running < getJobLimit(data.type())) { - assert(data.waiting > 0); + ASSERT( + data.waiting > 0, + "ripple::JobQueue::getNextJob : positive data waiting"); --data.waiting; ++data.running; break; } } - assert(iter != m_jobSet.end()); + ASSERT( + iter != m_jobSet.end(), + "ripple::JobQueue::getNextJob : found next job"); job = *iter; m_jobSet.erase(iter); } @@ -331,14 +359,18 @@ JobQueue::getNextJob(Job& job) void JobQueue::finishJob(JobType type) { - assert(type != jtINVALID); + ASSERT( + type != jtINVALID, + "ripple::JobQueue::finishJob : valid input job type"); JobTypeData& data = getJobTypeData(type); // Queue a deferred task if possible if (data.deferred > 0) { - assert(data.running + data.waiting >= getJobLimit(type)); + ASSERT( + data.running + data.waiting >= getJobLimit(type), + "ripple::JobQueue::finishJob : job limit"); --data.deferred; m_workers.addTask(); @@ -404,7 +436,9 @@ int JobQueue::getJobLimit(JobType type) { JobTypeInfo const& j(JobTypes::instance().get(type)); - assert(j.type() != jtINVALID); + ASSERT( + j.type() != jtINVALID, + "ripple::JobQueue::getJobLimit : valid job type"); return j.limit(); } diff --git a/src/xrpld/core/detail/LoadEvent.cpp b/src/xrpld/core/detail/LoadEvent.cpp index ca78fdb19cc..b9c1de79a33 100644 --- a/src/xrpld/core/detail/LoadEvent.cpp +++ b/src/xrpld/core/detail/LoadEvent.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include namespace ripple { @@ -83,7 +83,7 @@ LoadEvent::start() void LoadEvent::stop() { - assert(running_); + ASSERT(running_, "ripple::LoadEvent::stop : is running"); auto const now = std::chrono::steady_clock::now(); diff --git a/src/xrpld/core/detail/Workers.cpp b/src/xrpld/core/detail/Workers.cpp index ff861010d95..32e6ace4402 100644 --- a/src/xrpld/core/detail/Workers.cpp +++ b/src/xrpld/core/detail/Workers.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include namespace ripple { @@ -119,7 +119,9 @@ Workers::stop() m_cv.wait(lk, [this] { return m_allPaused; }); lk.unlock(); - assert(numberOfCurrentlyRunningTasks() == 0); + ASSERT( + numberOfCurrentlyRunningTasks() == 0, + "ripple::Workers::stop : zero running tasks"); } void diff --git a/src/xrpld/ledger/ApplyView.h b/src/xrpld/ledger/ApplyView.h index f0166cd0b38..12626824308 100644 --- a/src/xrpld/ledger/ApplyView.h +++ b/src/xrpld/ledger/ApplyView.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace ripple { @@ -276,8 +277,11 @@ class ApplyView : public ReadView { if (key.type != ltOFFER) { - assert(!"Only Offers are appended to book directories. " - "Call dirInsert() instead."); + UNREACHABLE( + "ripple::ApplyView::dirAppend : only Offers are appended to " + "book directories"); + // Only Offers are appended to book directories. Call dirInsert() + // instead return std::nullopt; } return dirAdd(true, directory, key.key, describe); diff --git a/src/xrpld/ledger/ReadView.h b/src/xrpld/ledger/ReadView.h index 50f1a7d98c1..efe920805ad 100644 --- a/src/xrpld/ledger/ReadView.h +++ b/src/xrpld/ledger/ReadView.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/src/xrpld/ledger/detail/ApplyStateTable.cpp b/src/xrpld/ledger/detail/ApplyStateTable.cpp index b849365c83f..2649ac2e207 100644 --- a/src/xrpld/ledger/detail/ApplyStateTable.cpp +++ b/src/xrpld/ledger/detail/ApplyStateTable.cpp @@ -19,10 +19,10 @@ #include #include +#include #include #include #include -#include namespace ripple { namespace detail { @@ -155,7 +155,10 @@ ApplyStateTable::apply( meta.setAffectedNode(item.first, *type, nodeType); if (type == &sfDeletedNode) { - assert(origNode && curNode); + ASSERT( + origNode && curNode, + "ripple::detail::ApplyStateTable::apply : valid nodes for " + "deletion"); threadOwners(to, meta, origNode, newMod, j); STObject prevs(sfPreviousFields); @@ -187,7 +190,10 @@ ApplyStateTable::apply( } else if (type == &sfModifiedNode) { - assert(curNode && origNode); + ASSERT( + curNode && origNode, + "ripple::detail::ApplyStateTable::apply : valid nodes for " + "modification"); if (curNode->isThreadedType( to.rules())) // thread transaction to node @@ -222,7 +228,10 @@ ApplyStateTable::apply( } else if (type == &sfCreatedNode) // if created, thread to owner(s) { - assert(curNode && !origNode); + ASSERT( + curNode && !origNode, + "ripple::detail::ApplyStateTable::apply : valid nodes for " + "creation"); threadOwners(to, meta, curNode, newMod, j); if (curNode->isThreadedType( @@ -245,7 +254,9 @@ ApplyStateTable::apply( } else { - assert(false); + UNREACHABLE( + "ripple::detail::ApplyStateTable::apply : unsupported " + "operation type"); } } @@ -536,13 +547,21 @@ ApplyStateTable::threadItem(TxMeta& meta, std::shared_ptr const& sle) if (node.getFieldIndex(sfPreviousTxnID) == -1) { - assert(node.getFieldIndex(sfPreviousTxnLgrSeq) == -1); + ASSERT( + node.getFieldIndex(sfPreviousTxnLgrSeq) == -1, + "ripple::ApplyStateTable::threadItem : previous ledger is not " + "set"); node.setFieldH256(sfPreviousTxnID, prevTxID); node.setFieldU32(sfPreviousTxnLgrSeq, prevLgrID); } - assert(node.getFieldH256(sfPreviousTxnID) == prevTxID); - assert(node.getFieldU32(sfPreviousTxnLgrSeq) == prevLgrID); + ASSERT( + node.getFieldH256(sfPreviousTxnID) == prevTxID, + "ripple::ApplyStateTable::threadItem : previous transaction is a " + "match"); + ASSERT( + node.getFieldU32(sfPreviousTxnLgrSeq) == prevLgrID, + "ripple::ApplyStateTable::threadItem : previous ledger is a match"); } } @@ -557,7 +576,9 @@ ApplyStateTable::getForMod( auto miter = mods.find(key); if (miter != mods.end()) { - assert(miter->second); + ASSERT( + miter->second != nullptr, + "ripple::ApplyStateTable::getForMod : non-null result"); return miter->second; } } @@ -613,7 +634,9 @@ ApplyStateTable::threadTx( return; } // threadItem only applied to AccountRoot - assert(sle->isThreadedType(base.rules())); + ASSERT( + sle->isThreadedType(base.rules()), + "ripple::ApplyStateTable::threadTx : SLE is threaded"); threadItem(meta, sle); } diff --git a/src/xrpld/ledger/detail/ApplyView.cpp b/src/xrpld/ledger/detail/ApplyView.cpp index 735aa9906e0..8b491bdcb2b 100644 --- a/src/xrpld/ledger/detail/ApplyView.cpp +++ b/src/xrpld/ledger/detail/ApplyView.cpp @@ -19,8 +19,8 @@ #include #include +#include #include -#include namespace ripple { @@ -133,7 +133,7 @@ ApplyView::emptyDirDelete(Keylet const& directory) if (directory.type != ltDIR_NODE || node->getFieldH256(sfRootIndex) != directory.key) { - assert(!"emptyDirDelete() called with wrong node type"); + UNREACHABLE("ripple::ApplyView::emptyDirDelete : invalid node type"); return false; } diff --git a/src/xrpld/ledger/detail/ApplyViewImpl.cpp b/src/xrpld/ledger/detail/ApplyViewImpl.cpp index ffbf681cd20..e01b8bfe3ba 100644 --- a/src/xrpld/ledger/detail/ApplyViewImpl.cpp +++ b/src/xrpld/ledger/detail/ApplyViewImpl.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include namespace ripple { diff --git a/src/xrpld/ledger/detail/BookDirs.cpp b/src/xrpld/ledger/detail/BookDirs.cpp index 58527b02ff2..4561aa2df18 100644 --- a/src/xrpld/ledger/detail/BookDirs.cpp +++ b/src/xrpld/ledger/detail/BookDirs.cpp @@ -30,12 +30,12 @@ BookDirs::BookDirs(ReadView const& view, Book const& book) , next_quality_(getQualityNext(root_)) , key_(view_->succ(root_, next_quality_).value_or(beast::zero)) { - assert(root_ != beast::zero); + ASSERT(root_ != beast::zero, "ripple::BookDirs::BookDirs : nonzero root"); if (key_ != beast::zero) { if (!cdirFirst(*view_, key_, sle_, entry_, index_)) { - assert(false); + UNREACHABLE("ripple::BookDirs::BookDirs : directory is empty"); } } } @@ -70,7 +70,10 @@ BookDirs::const_iterator::operator==( if (view_ == nullptr || other.view_ == nullptr) return false; - assert(view_ == other.view_ && root_ == other.root_); + ASSERT( + view_ == other.view_ && root_ == other.root_, + "ripple::BookDirs::const_iterator::operator== : views and roots are " + "matching"); return entry_ == other.entry_ && cur_key_ == other.cur_key_ && index_ == other.index_; } @@ -78,7 +81,9 @@ BookDirs::const_iterator::operator==( BookDirs::const_iterator::reference BookDirs::const_iterator::operator*() const { - assert(index_ != beast::zero); + ASSERT( + index_ != beast::zero, + "ripple::BookDirs::const_iterator::operator* : nonzero index"); if (!cache_) cache_ = view_->read(keylet::offer(index_)); return *cache_; @@ -89,7 +94,9 @@ BookDirs::const_iterator::operator++() { using beast::zero; - assert(index_ != zero); + ASSERT( + index_ != zero, + "ripple::BookDirs::const_iterator::operator++ : nonzero index"); if (!cdirNext(*view_, cur_key_, sle_, entry_, index_)) { if (index_ != 0 || @@ -102,7 +109,9 @@ BookDirs::const_iterator::operator++() } else if (!cdirFirst(*view_, cur_key_, sle_, entry_, index_)) { - assert(false); + UNREACHABLE( + "ripple::BookDirs::const_iterator::operator++ : directory is " + "empty"); } } @@ -113,7 +122,9 @@ BookDirs::const_iterator::operator++() BookDirs::const_iterator BookDirs::const_iterator::operator++(int) { - assert(index_ != beast::zero); + ASSERT( + index_ != beast::zero, + "ripple::BookDirs::const_iterator::operator++(int) : nonzero index"); const_iterator tmp(*this); ++(*this); return tmp; diff --git a/src/xrpld/ledger/detail/Dir.cpp b/src/xrpld/ledger/detail/Dir.cpp index 6004a73095c..24c88a52f09 100644 --- a/src/xrpld/ledger/detail/Dir.cpp +++ b/src/xrpld/ledger/detail/Dir.cpp @@ -60,14 +60,18 @@ const_iterator::operator==(const_iterator const& other) const if (view_ == nullptr || other.view_ == nullptr) return false; - assert(view_ == other.view_ && root_.key == other.root_.key); + ASSERT( + view_ == other.view_ && root_.key == other.root_.key, + "ripple::const_iterator::operator== : views and roots are matching"); return page_.key == other.page_.key && index_ == other.index_; } const_iterator::reference const_iterator::operator*() const { - assert(index_ != beast::zero); + ASSERT( + index_ != beast::zero, + "ripple::const_iterator::operator* : nonzero index"); if (!cache_) cache_ = view_->read(keylet::child(index_)); return *cache_; @@ -76,7 +80,9 @@ const_iterator::operator*() const const_iterator& const_iterator::operator++() { - assert(index_ != beast::zero); + ASSERT( + index_ != beast::zero, + "ripple::const_iterator::operator++ : nonzero index"); if (++it_ != std::end(*indexes_)) { index_ = *it_; @@ -90,7 +96,9 @@ const_iterator::operator++() const_iterator const_iterator::operator++(int) { - assert(index_ != beast::zero); + ASSERT( + index_ != beast::zero, + "ripple::const_iterator::operator++(int) : nonzero index"); const_iterator tmp(*this); ++(*this); return tmp; @@ -109,7 +117,9 @@ const_iterator::next_page() { page_ = keylet::page(root_, next); sle_ = view_->read(page_); - assert(sle_); + ASSERT( + sle_ != nullptr, + "ripple::const_iterator::next_page : non-null SLE"); indexes_ = &sle_->getFieldV256(sfIndexes); if (indexes_->empty()) { diff --git a/src/xrpld/ledger/detail/PaymentSandbox.cpp b/src/xrpld/ledger/detail/PaymentSandbox.cpp index d182d22b56c..3400427448d 100644 --- a/src/xrpld/ledger/detail/PaymentSandbox.cpp +++ b/src/xrpld/ledger/detail/PaymentSandbox.cpp @@ -20,12 +20,11 @@ #include #include #include +#include #include #include #include -#include - namespace ripple { namespace detail { @@ -49,8 +48,12 @@ DeferredCredits::credit( STAmount const& amount, STAmount const& preCreditSenderBalance) { - assert(sender != receiver); - assert(!amount.negative()); + ASSERT( + sender != receiver, + "ripple::detail::DeferredCredits::credit : sender is not receiver"); + ASSERT( + !amount.negative(), + "ripple::detail::DeferredCredits::credit : positive amount"); auto const k = makeKey(sender, receiver, amount.getCurrency()); auto i = credits_.find(k); @@ -253,14 +256,14 @@ PaymentSandbox::adjustOwnerCountHook( void PaymentSandbox::apply(RawView& to) { - assert(!ps_); + ASSERT(!ps_, "ripple::PaymentSandbox::apply : non-null sandbox"); items_.apply(to); } void PaymentSandbox::apply(PaymentSandbox& to) { - assert(ps_ == &to); + ASSERT(ps_ == &to, "ripple::PaymentSandbox::apply : matching sandbox"); items_.apply(to); tab_.apply(to.tab_); } @@ -344,7 +347,10 @@ PaymentSandbox::balanceChanges(ReadView const& view) const { // modify auto const at = after->getType(); - assert(at == before->getType()); + ASSERT( + at == before->getType(), + "ripple::PaymentSandbox::balanceChanges : after and before " + "types matching"); switch (at) { case ltACCOUNT_ROOT: diff --git a/src/xrpld/ledger/detail/RawStateTable.cpp b/src/xrpld/ledger/detail/RawStateTable.cpp index 4d3732f8a45..f8c575fc520 100644 --- a/src/xrpld/ledger/detail/RawStateTable.cpp +++ b/src/xrpld/ledger/detail/RawStateTable.cpp @@ -63,7 +63,10 @@ class RawStateTable::sles_iter_impl : public ReadView::sles_type::iter_base { if (auto const p = dynamic_cast(&impl)) { - assert(end1_ == p->end1_ && end0_ == p->end0_); + ASSERT( + end1_ == p->end1_ && end0_ == p->end0_, + "ripple::detail::RawStateTable::equal : matching end " + "iterators"); return iter1_ == p->iter1_ && iter0_ == p->iter0_; } @@ -73,7 +76,10 @@ class RawStateTable::sles_iter_impl : public ReadView::sles_type::iter_base void increment() override { - assert(sle1_ || sle0_); + ASSERT( + sle1_ || sle0_, + "ripple::detail::RawStateTable::increment : either SLE is " + "non-null"); if (sle1_ && !sle0_) { @@ -179,7 +185,9 @@ RawStateTable::apply(RawView& to) const bool RawStateTable::exists(ReadView const& base, Keylet const& k) const { - assert(k.key.isNonZero()); + ASSERT( + k.key.isNonZero(), + "ripple::detail::RawStateTable::exists : nonzero key"); auto const iter = items_.find(k.key); if (iter == items_.end()) return base.exists(k); diff --git a/src/xrpld/ledger/detail/ReadViewFwdRange.ipp b/src/xrpld/ledger/detail/ReadViewFwdRange.ipp index ae84259d7ce..844705a3f80 100644 --- a/src/xrpld/ledger/detail/ReadViewFwdRange.ipp +++ b/src/xrpld/ledger/detail/ReadViewFwdRange.ipp @@ -80,7 +80,10 @@ template bool ReadViewFwdRange::iterator::operator==(iterator const& other) const { - assert(view_ == other.view_); + ASSERT( + view_ == other.view_, + "ripple::detail::ReadViewFwdRange::iterator::operator==(iterator) " + "const : input view match"); if (impl_ != nullptr && other.impl_ != nullptr) return impl_->equal(*other.impl_); diff --git a/src/xrpld/ledger/detail/View.cpp b/src/xrpld/ledger/detail/View.cpp index ae4eb095017..23dbd81d5ad 100644 --- a/src/xrpld/ledger/detail/View.cpp +++ b/src/xrpld/ledger/detail/View.cpp @@ -22,11 +22,11 @@ #include #include #include +#include #include #include #include #include -#include #include namespace ripple { @@ -48,7 +48,9 @@ internalDirNext( uint256& entry) { auto const& svIndexes = page->getFieldV256(sfIndexes); - assert(index <= svIndexes.size()); + ASSERT( + index <= svIndexes.size(), + "ripple::detail::internalDirNext : index inside range"); if (index >= svIndexes.size()) { @@ -65,7 +67,8 @@ internalDirNext( else page = view.peek(keylet::page(root, next)); - assert(page); + ASSERT( + page != nullptr, "ripple::detail::internalDirNext : non-null root"); if (!page) return false; @@ -418,7 +421,7 @@ confineOwnerCount( << "Account " << *id << " owner count set below 0!"; } adjusted = 0; - assert(!id); + ASSERT(!id, "ripple::confineOwnerCount : id is not set"); } } return adjusted; @@ -467,7 +470,7 @@ forEachItem( Keylet const& root, std::function const&)> const& f) { - assert(root.type == ltDIR_NODE); + ASSERT(root.type == ltDIR_NODE, "ripple::forEachItem : valid root type"); if (root.type != ltDIR_NODE) return; @@ -497,7 +500,8 @@ forEachItemAfter( unsigned int limit, std::function const&)> const& f) { - assert(root.type == ltDIR_NODE); + ASSERT( + root.type == ltDIR_NODE, "ripple::forEachItemAfter : valid root type"); if (root.type != ltDIR_NODE) return false; @@ -772,9 +776,10 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal) auto const hashIndex = ledger.read(keylet::skip()); if (hashIndex) { - assert( + ASSERT( hashIndex->getFieldU32(sfLastLedgerSequence) == - (ledger.seq() - 1)); + (ledger.seq() - 1), + "ripple::hashOfSeq : matching ledger sequence"); STVector256 vec = hashIndex->getFieldV256(sfHashes); if (vec.size() >= diff) return vec[vec.size() - diff]; @@ -802,8 +807,8 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal) if (hashIndex) { auto const lastSeq = hashIndex->getFieldU32(sfLastLedgerSequence); - assert(lastSeq >= seq); - assert((lastSeq & 0xff) == 0); + ASSERT(lastSeq >= seq, "ripple::hashOfSeq : minimum last ledger"); + ASSERT((lastSeq & 0xff) == 0, "ripple::hashOfSeq : valid last ledger"); auto const diff = (lastSeq - seq) >> 8; STVector256 vec = hashIndex->getFieldV256(sfHashes); if (vec.size() > diff) @@ -829,7 +834,7 @@ adjustOwnerCount( { if (!sle) return; - assert(amount != 0); + ASSERT(amount != 0, "ripple::adjustOwnerCount : nonzero amount input"); std::uint32_t const current{sle->getFieldU32(sfOwnerCount)}; AccountID const id = (*sle)[sfAccount]; std::uint32_t const adjusted = confineOwnerCount(current, amount, id, j); @@ -894,13 +899,14 @@ trustCreate( const bool bSetDst = saLimit.getIssuer() == uDstAccountID; const bool bSetHigh = bSrcHigh ^ bSetDst; - assert(sleAccount); + ASSERT(sleAccount != nullptr, "ripple::trustCreate : non-null SLE"); if (!sleAccount) return tefINTERNAL; - assert( + ASSERT( sleAccount->getAccountID(sfAccount) == - (bSetHigh ? uHighAccountID : uLowAccountID)); + (bSetHigh ? uHighAccountID : uLowAccountID), + "ripple::trustCreate : matching account ID"); auto const slePeer = view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID)); if (!slePeer) @@ -1052,17 +1058,25 @@ rippleCreditIOU( Currency const& currency = saAmount.getCurrency(); // Make sure issuer is involved. - assert(!bCheckIssuer || uSenderID == issuer || uReceiverID == issuer); + ASSERT( + !bCheckIssuer || uSenderID == issuer || uReceiverID == issuer, + "ripple::rippleCreditIOU : matching issuer or don't care"); (void)issuer; // Disallow sending to self. - assert(uSenderID != uReceiverID); + ASSERT( + uSenderID != uReceiverID, + "ripple::rippleCreditIOU : sender is not receiver"); bool const bSenderHigh = uSenderID > uReceiverID; auto const index = keylet::line(uSenderID, uReceiverID, currency); - assert(!isXRP(uSenderID) && uSenderID != noAccount()); - assert(!isXRP(uReceiverID) && uReceiverID != noAccount()); + ASSERT( + !isXRP(uSenderID) && uSenderID != noAccount(), + "ripple::rippleCreditIOU : sender is not XRP"); + ASSERT( + !isXRP(uReceiverID) && uReceiverID != noAccount(), + "ripple::rippleCreditIOU : receiver is not XRP"); // If the line exists, modify it accordingly. if (auto const sleRippleState = view.peek(index)) @@ -1196,8 +1210,12 @@ rippleSendIOU( { auto const issuer = saAmount.getIssuer(); - assert(!isXRP(uSenderID) && !isXRP(uReceiverID)); - assert(uSenderID != uReceiverID); + ASSERT( + !isXRP(uSenderID) && !isXRP(uReceiverID), + "ripple::rippleSendIOU : neither sender nor receiver is XRP"); + ASSERT( + uSenderID != uReceiverID, + "ripple::rippleSendIOU : sender is not receiver"); if (uSenderID == issuer || uReceiverID == issuer || issuer == noAccount()) { @@ -1250,7 +1268,9 @@ accountSendIOU( } else { - assert(saAmount >= beast::zero && !saAmount.holds()); + ASSERT( + saAmount >= beast::zero && !saAmount.holds(), + "ripple::accountSendIOU : minimum amount and not MPT"); } /* If we aren't sending anything or if the sender is the same as the @@ -1420,7 +1440,9 @@ rippleSendMPT( beast::Journal j, WaiveTransferFee waiveFee) { - assert(uSenderID != uReceiverID); + ASSERT( + uSenderID != uReceiverID, + "ripple::rippleSendMPT : sender is not receiver"); // Safe to get MPT since rippleSendMPT is only called by accountSendMPT auto const issuer = saAmount.getIssuer(); @@ -1483,7 +1505,9 @@ accountSendMPT( beast::Journal j, WaiveTransferFee waiveFee) { - assert(saAmount >= beast::zero && saAmount.holds()); + ASSERT( + saAmount >= beast::zero && saAmount.holds(), + "ripple::accountSendMPT : minimum amount and MPT"); /* If we aren't sending anything or if the sender is the same as the * receiver then we don't need to do anything. @@ -1579,13 +1603,15 @@ issueIOU( Issue const& issue, beast::Journal j) { - assert(!isXRP(account) && !isXRP(issue.account)); + ASSERT( + !isXRP(account) && !isXRP(issue.account), + "ripple::issueIOU : neither account nor issuer is XRP"); // Consistency check - assert(issue == amount.issue()); + ASSERT(issue == amount.issue(), "ripple::issueIOU : matching issue"); // Can't send to self! - assert(issue.account != account); + ASSERT(issue.account != account, "ripple::issueIOU : not issuer account"); JLOG(j.trace()) << "issueIOU: " << to_string(account) << ": " << amount.getFullText(); @@ -1675,13 +1701,15 @@ redeemIOU( Issue const& issue, beast::Journal j) { - assert(!isXRP(account) && !isXRP(issue.account)); + ASSERT( + !isXRP(account) && !isXRP(issue.account), + "ripple::redeemIOU : neither account nor issuer is XRP"); // Consistency check - assert(issue == amount.issue()); + ASSERT(issue == amount.issue(), "ripple::redeemIOU : matching issue"); // Can't send to self! - assert(issue.account != account); + ASSERT(issue.account != account, "ripple::redeemIOU : not issuer account"); JLOG(j.trace()) << "redeemIOU: " << to_string(account) << ": " << amount.getFullText(); @@ -1745,10 +1773,10 @@ transferXRP( STAmount const& amount, beast::Journal j) { - assert(from != beast::zero); - assert(to != beast::zero); - assert(from != to); - assert(amount.native()); + ASSERT(from != beast::zero, "ripple::transferXRP : nonzero from account"); + ASSERT(to != beast::zero, "ripple::transferXRP : nonzero to account"); + ASSERT(from != to, "ripple::transferXRP : sender is not receiver"); + ASSERT(amount.native(), "ripple::transferXRP : amount is XRP"); SLE::pointer const sender = view.peek(keylet::account(from)); SLE::pointer const receiver = view.peek(keylet::account(to)); @@ -1911,7 +1939,9 @@ cleanupOnAccountDelete( // // 3. So we verify that uDirEntry is indeed 'it'+1. Then we jam it // back to 'it' to "un-invalidate" the iterator. - assert(uDirEntry >= 1); + ASSERT( + uDirEntry >= 1, + "ripple::cleanupOnAccountDelete : minimum dir entries"); if (uDirEntry == 0) { JLOG(j.error()) @@ -1995,7 +2025,9 @@ rippleCredit( } else { - assert(!bCheckIssuer); + ASSERT( + !bCheckIssuer, + "ripple::rippleCredit : not checking issuer"); return rippleCreditMPT( view, uSenderID, uReceiverID, saAmount, j); } diff --git a/src/xrpld/net/detail/InfoSub.cpp b/src/xrpld/net/detail/InfoSub.cpp index 3dc891cb5f9..4d18bf0b8fa 100644 --- a/src/xrpld/net/detail/InfoSub.cpp +++ b/src/xrpld/net/detail/InfoSub.cpp @@ -145,7 +145,8 @@ InfoSub::setApiVersion(unsigned int apiVersion) unsigned int InfoSub::getApiVersion() const noexcept { - assert(apiVersion_ > 0); + ASSERT( + apiVersion_ > 0, "ripple::InfoSub::getApiVersion : valid API version"); return apiVersion_; } diff --git a/src/xrpld/net/detail/RPCCall.cpp b/src/xrpld/net/detail/RPCCall.cpp index b92f4b1a205..06989765108 100644 --- a/src/xrpld/net/detail/RPCCall.cpp +++ b/src/xrpld/net/detail/RPCCall.cpp @@ -962,7 +962,9 @@ class RPCParser parseTransactionEntry(Json::Value const& jvParams) { // Parameter count should have already been verified. - assert(jvParams.size() == 2); + ASSERT( + jvParams.size() == 2, + "ripple::RPCParser::parseTransactionEntry : valid parameter count"); std::string const txHash = jvParams[0u].asString(); if (txHash.length() != 64) diff --git a/src/xrpld/nodestore/Database.h b/src/xrpld/nodestore/Database.h index bd25046fee2..04bd718104d 100644 --- a/src/xrpld/nodestore/Database.h +++ b/src/xrpld/nodestore/Database.h @@ -246,7 +246,9 @@ class Database void storeStats(std::uint64_t count, std::uint64_t sz) { - assert(count <= sz); + ASSERT( + count <= sz, + "ripple::NodeStore::Database::storeStats : valid inputs"); storeCount_ += count; storeSz_ += sz; } diff --git a/src/xrpld/nodestore/backend/MemoryFactory.cpp b/src/xrpld/nodestore/backend/MemoryFactory.cpp index 767db9d1695..1b7bf79c81e 100644 --- a/src/xrpld/nodestore/backend/MemoryFactory.cpp +++ b/src/xrpld/nodestore/backend/MemoryFactory.cpp @@ -131,7 +131,9 @@ class MemoryBackend : public Backend Status fetch(void const* key, std::shared_ptr* pObject) override { - assert(db_); + ASSERT( + db_ != nullptr, + "ripple::NodeStore::MemoryBackend::fetch : non-null database"); uint256 const hash(uint256::fromVoid(key)); std::lock_guard _(db_->mutex); @@ -167,7 +169,9 @@ class MemoryBackend : public Backend void store(std::shared_ptr const& object) override { - assert(db_); + ASSERT( + db_ != nullptr, + "ripple::NodeStore::MemoryBackend::store : non-null database"); std::lock_guard _(db_->mutex); db_->table.emplace(object->getHash(), object); } @@ -187,7 +191,9 @@ class MemoryBackend : public Backend void for_each(std::function)> f) override { - assert(db_); + ASSERT( + db_ != nullptr, + "ripple::NodeStore::MemoryBackend::for_each : non-null database"); for (auto const& e : db_->table) f(e.second); } diff --git a/src/xrpld/nodestore/backend/NuDBFactory.cpp b/src/xrpld/nodestore/backend/NuDBFactory.cpp index 14cd84a1ad7..24ebffd33a2 100644 --- a/src/xrpld/nodestore/backend/NuDBFactory.cpp +++ b/src/xrpld/nodestore/backend/NuDBFactory.cpp @@ -23,8 +23,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -117,7 +117,9 @@ class NuDBBackend : public Backend using namespace boost::filesystem; if (db_.is_open()) { - assert(false); + UNREACHABLE( + "ripple::NodeStore::NuDBBackend::open : database is already " + "open"); JLOG(j_.error()) << "database is already open"; return; } diff --git a/src/xrpld/nodestore/backend/RocksDBFactory.cpp b/src/xrpld/nodestore/backend/RocksDBFactory.cpp index 9ba9fffe1db..a4bb4ae5fb6 100644 --- a/src/xrpld/nodestore/backend/RocksDBFactory.cpp +++ b/src/xrpld/nodestore/backend/RocksDBFactory.cpp @@ -228,7 +228,9 @@ class RocksDBBackend : public Backend, public BatchWriter::Callback { if (m_db) { - assert(false); + UNREACHABLE( + "ripple::NodeStore::RocksDBBackend::open : database is already " + "open"); JLOG(m_journal.error()) << "database is already open"; return; } @@ -273,7 +275,9 @@ class RocksDBBackend : public Backend, public BatchWriter::Callback Status fetch(void const* key, std::shared_ptr* pObject) override { - assert(m_db); + ASSERT( + m_db != nullptr, + "ripple::NodeStore::RocksDBBackend::fetch : non-null database"); pObject->reset(); Status status(ok); @@ -349,7 +353,10 @@ class RocksDBBackend : public Backend, public BatchWriter::Callback void storeBatch(Batch const& batch) override { - assert(m_db); + ASSERT( + m_db != nullptr, + "ripple::NodeStore::RocksDBBackend::storeBatch : non-null " + "database"); rocksdb::WriteBatch wb; for (auto const& e : batch) @@ -381,7 +388,9 @@ class RocksDBBackend : public Backend, public BatchWriter::Callback void for_each(std::function)> f) override { - assert(m_db); + ASSERT( + m_db != nullptr, + "ripple::NodeStore::RocksDBBackend::for_each : non-null database"); rocksdb::ReadOptions const options; std::unique_ptr it(m_db->NewIterator(options)); diff --git a/src/xrpld/nodestore/detail/BatchWriter.cpp b/src/xrpld/nodestore/detail/BatchWriter.cpp index 1c5067d5bed..ec360f89f31 100644 --- a/src/xrpld/nodestore/detail/BatchWriter.cpp +++ b/src/xrpld/nodestore/detail/BatchWriter.cpp @@ -83,7 +83,9 @@ BatchWriter::writeBatch() std::lock_guard sl(mWriteMutex); mWriteSet.swap(set); - assert(mWriteSet.empty()); + ASSERT( + mWriteSet.empty(), + "ripple::NodeStore::BatchWriter::writeBatch : writes not set"); mWriteLoad = set.size(); if (set.empty()) diff --git a/src/xrpld/nodestore/detail/Database.cpp b/src/xrpld/nodestore/detail/Database.cpp index da15088e895..f9875d5062f 100644 --- a/src/xrpld/nodestore/detail/Database.cpp +++ b/src/xrpld/nodestore/detail/Database.cpp @@ -40,7 +40,9 @@ Database::Database( , requestBundle_(get(config, "rq_bundle", 4)) , readThreads_(std::max(1, readThreads)) { - assert(readThreads != 0); + ASSERT( + readThreads != 0, + "ripple::NodeStore::Database::Database : nonzero threads input"); if (earliestLedgerSeq_ < 1) Throw("Invalid earliest_seq"); @@ -87,7 +89,10 @@ Database::Database( for (auto it = read.begin(); it != read.end(); ++it) { - assert(!it->second.empty()); + ASSERT( + !it->second.empty(), + "ripple::NodeStore::Database::Database : non-empty " + "data"); auto const& hash = it->first; auto const& data = it->second; @@ -161,7 +166,9 @@ Database::stop() while (readThreads_.load() != 0) { - assert(steady_clock::now() - start < 30s); + ASSERT( + steady_clock::now() - start < 30s, + "ripple::NodeStore::Database::stop : maximum stop duration"); std::this_thread::yield(); } @@ -212,7 +219,9 @@ Database::importInternal(Backend& dstBackend, Database& srcDB) }; srcDB.for_each([&](std::shared_ptr nodeObject) { - assert(nodeObject); + ASSERT( + nodeObject != nullptr, + "ripple::NodeStore::Database::importInternal : non-null node"); if (!nodeObject) // This should never happen return; @@ -256,7 +265,9 @@ Database::fetchNodeObject( void Database::getCountsJson(Json::Value& obj) { - assert(obj.isObject()); + ASSERT( + obj.isObject(), + "ripple::NodeStore::Database::getCountsJson : valid input type"); { std::unique_lock lock(readLock_); diff --git a/src/xrpld/nodestore/detail/DatabaseNodeImp.h b/src/xrpld/nodestore/detail/DatabaseNodeImp.h index 326db38a661..2ed3443da92 100644 --- a/src/xrpld/nodestore/detail/DatabaseNodeImp.h +++ b/src/xrpld/nodestore/detail/DatabaseNodeImp.h @@ -76,7 +76,10 @@ class DatabaseNodeImp : public Database j); } - assert(backend_); + ASSERT( + backend_ != nullptr, + "ripple::NodeStore::DatabaseNodeImp::DatabaseNodeImp : non-null " + "backend"); } ~DatabaseNodeImp() diff --git a/src/xrpld/nodestore/detail/DecodedBlob.cpp b/src/xrpld/nodestore/detail/DecodedBlob.cpp index b71f2c543b1..49e1ff5e3bb 100644 --- a/src/xrpld/nodestore/detail/DecodedBlob.cpp +++ b/src/xrpld/nodestore/detail/DecodedBlob.cpp @@ -19,8 +19,8 @@ #include #include +#include #include -#include namespace ripple { namespace NodeStore { @@ -72,7 +72,9 @@ DecodedBlob::DecodedBlob(void const* key, void const* value, int valueBytes) std::shared_ptr DecodedBlob::createObject() { - assert(m_success); + ASSERT( + m_success, + "ripple::NodeStore::DecodedBlob::createObject : valid object type"); std::shared_ptr object; diff --git a/src/xrpld/nodestore/detail/EncodedBlob.h b/src/xrpld/nodestore/detail/EncodedBlob.h index 2b506a0df3f..d99908cf4f6 100644 --- a/src/xrpld/nodestore/detail/EncodedBlob.h +++ b/src/xrpld/nodestore/detail/EncodedBlob.h @@ -22,10 +22,10 @@ #include #include +#include #include #include #include -#include #include namespace ripple { @@ -80,7 +80,9 @@ class EncodedBlob public: explicit EncodedBlob(std::shared_ptr const& obj) : size_([&obj]() { - assert(obj); + ASSERT( + obj != nullptr, + "ripple::NodeStore::EncodedBlob::EncodedBlob : non-null input"); if (!obj) throw std::runtime_error( @@ -100,9 +102,11 @@ class EncodedBlob ~EncodedBlob() { - assert( + ASSERT( ((ptr_ == payload_.data()) && (size_ <= payload_.size())) || - ((ptr_ != payload_.data()) && (size_ > payload_.size()))); + ((ptr_ != payload_.data()) && (size_ > payload_.size())), + "ripple::NodeStore::EncodedBlob::~EncodedBlob : valid payload " + "pointer"); if (ptr_ != payload_.data()) delete[] ptr_; diff --git a/src/xrpld/nodestore/detail/ManagerImp.cpp b/src/xrpld/nodestore/detail/ManagerImp.cpp index 56dc66ee644..38f193a7d8a 100644 --- a/src/xrpld/nodestore/detail/ManagerImp.cpp +++ b/src/xrpld/nodestore/detail/ManagerImp.cpp @@ -91,7 +91,9 @@ ManagerImp::erase(Factory& factory) std::find_if(list_.begin(), list_.end(), [&factory](Factory* other) { return other == &factory; }); - assert(iter != list_.end()); + ASSERT( + iter != list_.end(), + "ripple::NodeStore::ManagerImp::erase : valid input"); list_.erase(iter); } diff --git a/src/xrpld/overlay/Compression.h b/src/xrpld/overlay/Compression.h index 1cf13fcb185..c7437badc4d 100644 --- a/src/xrpld/overlay/Compression.h +++ b/src/xrpld/overlay/Compression.h @@ -64,7 +64,9 @@ decompress( JLOG(debugLog().warn()) << "decompress: invalid compression algorithm " << static_cast(algorithm); - assert(0); + UNREACHABLE( + "ripple::compression::decompress : invalid compression " + "algorithm"); } } catch (...) @@ -99,7 +101,9 @@ compress( { JLOG(debugLog().warn()) << "compress: invalid compression algorithm" << static_cast(algorithm); - assert(0); + UNREACHABLE( + "ripple::compression::compress : invalid compression " + "algorithm"); } } catch (...) diff --git a/src/xrpld/overlay/Slot.h b/src/xrpld/overlay/Slot.h index 2a8b2146a02..fca6c621fa0 100644 --- a/src/xrpld/overlay/Slot.h +++ b/src/xrpld/overlay/Slot.h @@ -362,7 +362,9 @@ Slot::update( << consideredPoolSize << " selected " << *s << " " << *std::next(s, 1) << " " << *std::next(s, 2); - assert(peers_.size() >= MAX_SELECTED_PEERS); + ASSERT( + peers_.size() >= MAX_SELECTED_PEERS, + "ripple::reduce_relay::Slot::update : minimum peers"); // squelch peers which are not selected and // not already squelched diff --git a/src/xrpld/overlay/detail/ConnectAttempt.cpp b/src/xrpld/overlay/detail/ConnectAttempt.cpp index 6a3ebdd5b98..d65366560d5 100644 --- a/src/xrpld/overlay/detail/ConnectAttempt.cpp +++ b/src/xrpld/overlay/detail/ConnectAttempt.cpp @@ -90,7 +90,9 @@ ConnectAttempt::run() void ConnectAttempt::close() { - assert(strand_.running_in_this_thread()); + ASSERT( + strand_.running_in_this_thread(), + "ripple::ConnectAttempt::close : strand in this thread"); if (socket_.is_open()) { error_code ec; diff --git a/src/xrpld/overlay/detail/Message.cpp b/src/xrpld/overlay/detail/Message.cpp index 71917db0506..6e44f3e957c 100644 --- a/src/xrpld/overlay/detail/Message.cpp +++ b/src/xrpld/overlay/detail/Message.cpp @@ -34,7 +34,9 @@ Message::Message( auto const messageBytes = messageSize(message); - assert(messageBytes != 0); + ASSERT( + messageBytes != 0, + "ripple::Message::Message : non-empty message input"); buffer_.resize(headerBytes + messageBytes); @@ -43,7 +45,9 @@ Message::Message( if (messageBytes != 0) message.SerializeToArray(buffer_.data() + headerBytes, messageBytes); - assert(getBufferSize() == totalSize(message)); + ASSERT( + getBufferSize() == totalSize(message), + "ripple::Message::Message : message size matches the buffer"); } // static diff --git a/src/xrpld/overlay/detail/OverlayImpl.cpp b/src/xrpld/overlay/detail/OverlayImpl.cpp index e41a08a43d1..d5bd6e2ce68 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.cpp +++ b/src/xrpld/overlay/detail/OverlayImpl.cpp @@ -294,7 +294,9 @@ OverlayImpl::onHandoff( std::lock_guard lock(mutex_); { auto const result = m_peers.emplace(peer->slot(), peer); - assert(result.second); + ASSERT( + result.second, + "ripple::OverlayImpl::onHandoff : peer is inserted"); (void)result.second; } list_.emplace(peer.get(), peer); @@ -387,7 +389,7 @@ OverlayImpl::makeErrorResponse( void OverlayImpl::connect(beast::IP::Endpoint const& remote_endpoint) { - assert(work_); + ASSERT(work_.has_value(), "ripple::OverlayImpl::connect : work is set"); auto usage = resourceManager().newOutboundEndpoint(remote_endpoint); if (usage.disconnect(journal_)) @@ -429,7 +431,9 @@ OverlayImpl::add_active(std::shared_ptr const& peer) { auto const result = m_peers.emplace(peer->slot(), peer); - assert(result.second); + ASSERT( + result.second, + "ripple::OverlayImpl::add_active : peer is inserted"); (void)result.second; } @@ -438,7 +442,9 @@ OverlayImpl::add_active(std::shared_ptr const& peer) std::piecewise_construct, std::make_tuple(peer->id()), std::make_tuple(peer)); - assert(result.second); + ASSERT( + result.second, + "ripple::OverlayImpl::add_active : peer ID is inserted"); (void)result.second; } @@ -461,7 +467,7 @@ OverlayImpl::remove(std::shared_ptr const& slot) { std::lock_guard lock(mutex_); auto const iter = m_peers.find(slot); - assert(iter != m_peers.end()); + ASSERT(iter != m_peers.end(), "ripple::OverlayImpl::remove : valid input"); m_peers.erase(iter); } @@ -598,7 +604,9 @@ OverlayImpl::activate(std::shared_ptr const& peer) std::piecewise_construct, std::make_tuple(peer->id()), std::make_tuple(peer))); - assert(result.second); + ASSERT( + result.second, + "ripple::OverlayImpl::activate : peer ID is inserted"); (void)result.second; } @@ -609,7 +617,7 @@ OverlayImpl::activate(std::shared_ptr const& peer) << ")"; // We just accepted this peer so we have non-zero active peers - assert(size() != 0); + ASSERT(size() != 0, "ripple::OverlayImpl::activate : nonzero peers"); } void @@ -648,7 +656,10 @@ OverlayImpl::onManifests( // the loaded Manifest out of the optional so we need to // reload it here. mo = deserializeManifest(serialized); - assert(mo); + ASSERT( + mo.has_value(), + "ripple::OverlayImpl::onManifests : manifest " + "deserialization succeeded"); app_.getOPs().pubManifest(*mo); diff --git a/src/xrpld/overlay/detail/OverlayImpl.h b/src/xrpld/overlay/detail/OverlayImpl.h index a50dfc5e905..63e002ddf79 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.h +++ b/src/xrpld/overlay/detail/OverlayImpl.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -600,7 +600,9 @@ class OverlayImpl : public Overlay, public reduce_relay::SquelchHandler { auto counts = m_traffic.getCounts(); std::lock_guard lock(m_statsMutex); - assert(counts.size() == m_stats.trafficGauges.size()); + ASSERT( + counts.size() == m_stats.trafficGauges.size(), + "ripple::OverlayImpl::collect_metrics : counts size do match"); for (std::size_t i = 0; i < counts.size(); ++i) { diff --git a/src/xrpld/overlay/detail/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp index 4f5f1470f8e..5dd64c27ea5 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -565,7 +565,9 @@ PeerImp::hasRange(std::uint32_t uMin, std::uint32_t uMax) void PeerImp::close() { - assert(strand_.running_in_this_thread()); + ASSERT( + strand_.running_in_this_thread(), + "ripple::PeerImp::close : strand in this thread"); if (socket_.is_open()) { detaching_ = true; // DEPRECATED @@ -606,7 +608,9 @@ PeerImp::fail(std::string const& reason) void PeerImp::fail(std::string const& name, error_code ec) { - assert(strand_.running_in_this_thread()); + ASSERT( + strand_.running_in_this_thread(), + "ripple::PeerImp::fail : strand in this thread"); if (socket_.is_open()) { JLOG(journal_.warn()) @@ -619,9 +623,14 @@ PeerImp::fail(std::string const& name, error_code ec) void PeerImp::gracefulClose() { - assert(strand_.running_in_this_thread()); - assert(socket_.is_open()); - assert(!gracefulClose_); + ASSERT( + strand_.running_in_this_thread(), + "ripple::PeerImp::gracefulClose : strand in this thread"); + ASSERT( + socket_.is_open(), "ripple::PeerImp::gracefulClose : socket is open"); + ASSERT( + !gracefulClose_, + "ripple::PeerImp::gracefulClose : socket is not closing"); gracefulClose_ = true; if (send_queue_.size() > 0) return; @@ -747,7 +756,9 @@ PeerImp::onShutdown(error_code ec) void PeerImp::doAccept() { - assert(read_buffer_.size() == 0); + ASSERT( + read_buffer_.size() == 0, + "ripple::PeerImp::doAccept : empty read buffer"); JLOG(journal_.debug()) << "doAccept: " << remote_address_; @@ -948,7 +959,9 @@ PeerImp::onWriteMessage(error_code ec, std::size_t bytes_transferred) metrics_.sent.add_message(bytes_transferred); - assert(!send_queue_.empty()); + ASSERT( + !send_queue_.empty(), + "ripple::PeerImp::onWriteMessage : non-empty send buffer"); send_queue_.pop(); if (!send_queue_.empty()) { @@ -2002,13 +2015,18 @@ PeerImp::onValidatorListMessage( case ListDisposition::pending: { std::lock_guard sl(recentLock_); - assert(applyResult.publisherKey); + ASSERT( + applyResult.publisherKey.has_value(), + "ripple::PeerImp::onValidatorListMessage : publisher key is " + "set"); auto const& pubKey = *applyResult.publisherKey; #ifndef NDEBUG if (auto const iter = publisherListSequences_.find(pubKey); iter != publisherListSequences_.end()) { - assert(iter->second < applyResult.sequence); + ASSERT( + iter->second < applyResult.sequence, + "ripple::PeerImp::onValidatorListMessage : lower sequence"); } #endif publisherListSequences_[pubKey] = applyResult.sequence; @@ -2019,10 +2037,14 @@ PeerImp::onValidatorListMessage( #ifndef NDEBUG { std::lock_guard sl(recentLock_); - assert(applyResult.sequence && applyResult.publisherKey); - assert( + ASSERT( + applyResult.sequence && applyResult.publisherKey, + "ripple::PeerImp::onValidatorListMessage : nonzero sequence " + "and set publisher key"); + ASSERT( publisherListSequences_[*applyResult.publisherKey] <= - applyResult.sequence); + applyResult.sequence, + "ripple::PeerImp::onValidatorListMessage : maximum sequence"); } #endif // !NDEBUG @@ -2033,7 +2055,9 @@ PeerImp::onValidatorListMessage( case ListDisposition::unsupported_version: break; default: - assert(false); + UNREACHABLE( + "ripple::PeerImp::onValidatorListMessage : invalid best list " + "disposition"); } // Charge based on the worst result @@ -2072,7 +2096,9 @@ PeerImp::onValidatorListMessage( fee_ = Resource::feeBadData; break; default: - assert(false); + UNREACHABLE( + "ripple::PeerImp::onValidatorListMessage : invalid worst list " + "disposition"); } // Log based on all the results. @@ -2130,7 +2156,9 @@ PeerImp::onValidatorListMessage( << "(s) from peer " << remote_address_; break; default: - assert(false); + UNREACHABLE( + "ripple::PeerImp::onValidatorListMessage : invalid list " + "disposition"); } } } @@ -2805,7 +2833,8 @@ PeerImp::checkPropose( JLOG(p_journal_.trace()) << "Checking " << (isTrusted ? "trusted" : "UNTRUSTED") << " proposal"; - assert(packet); + ASSERT( + packet != nullptr, "ripple::PeerImp::checkPropose : non-null packet"); if (!cluster() && !peerPos.checkSign()) { diff --git a/src/xrpld/overlay/detail/ProtocolMessage.h b/src/xrpld/overlay/detail/ProtocolMessage.h index 8a7512afb31..b1e871437f3 100644 --- a/src/xrpld/overlay/detail/ProtocolMessage.h +++ b/src/xrpld/overlay/detail/ProtocolMessage.h @@ -24,11 +24,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -175,7 +175,9 @@ parseMessageHeader( MessageHeader hdr; auto iter = buffersBegin(bufs); - assert(iter != buffersEnd(bufs)); + ASSERT( + iter != buffersEnd(bufs), + "ripple::detail::parseMessageHeader : non-empty buffer"); // Check valid header compressed message: // - 4 bits are the compression algorithm, 1st bit is always set to 1 diff --git a/src/xrpld/overlay/detail/TrafficCount.h b/src/xrpld/overlay/detail/TrafficCount.h index 7dd5cbba901..754e2872b18 100644 --- a/src/xrpld/overlay/detail/TrafficCount.h +++ b/src/xrpld/overlay/detail/TrafficCount.h @@ -21,6 +21,7 @@ #define RIPPLE_OVERLAY_TRAFFIC_H_INCLUDED #include +#include #include #include @@ -171,7 +172,9 @@ class TrafficCount void addCount(category cat, bool inbound, int bytes) { - assert(cat <= category::unknown); + ASSERT( + cat <= category::unknown, + "ripple::TrafficCount::addCount : valid category input"); if (inbound) { diff --git a/src/xrpld/overlay/detail/ZeroCopyStream.h b/src/xrpld/overlay/detail/ZeroCopyStream.h index da0f0d380d8..44d8100952e 100644 --- a/src/xrpld/overlay/detail/ZeroCopyStream.h +++ b/src/xrpld/overlay/detail/ZeroCopyStream.h @@ -20,6 +20,8 @@ #ifndef RIPPLE_OVERLAY_ZEROCOPYSTREAM_H_INCLUDED #define RIPPLE_OVERLAY_ZEROCOPYSTREAM_H_INCLUDED +#include + #include #include #include @@ -204,7 +206,8 @@ template void ZeroCopyOutputStream::BackUp(int count) { - assert(count <= commit_); + ASSERT( + count <= commit_, "ripple::ZeroCopyOutputStream::BackUp : valid input"); auto const n = commit_ - count; streambuf_.commit(n); count_ += n; diff --git a/src/xrpld/peerfinder/detail/Bootcache.cpp b/src/xrpld/peerfinder/detail/Bootcache.cpp index 9e94a12e619..88fa4c6221a 100644 --- a/src/xrpld/peerfinder/detail/Bootcache.cpp +++ b/src/xrpld/peerfinder/detail/Bootcache.cpp @@ -159,7 +159,9 @@ Bootcache::on_success(beast::IP::Endpoint const& endpoint) ++entry.valence(); m_map.erase(result.first); result = m_map.insert(value_type(endpoint, entry)); - assert(result.second); + ASSERT( + result.second, + "ripple:PeerFinder::Bootcache::on_success : endpoint inserted"); } Entry const& entry(result.first->right); JLOG(m_journal.info()) << beast::leftw(18) << "Bootcache connect " @@ -185,7 +187,9 @@ Bootcache::on_failure(beast::IP::Endpoint const& endpoint) --entry.valence(); m_map.erase(result.first); result = m_map.insert(value_type(endpoint, entry)); - assert(result.second); + ASSERT( + result.second, + "ripple:PeerFinder::Bootcache::on_failure : endpoint inserted"); } Entry const& entry(result.first->right); auto const n(std::abs(entry.valence())); diff --git a/src/xrpld/peerfinder/detail/Counts.h b/src/xrpld/peerfinder/detail/Counts.h index 1ea6ff976de..d18aa858567 100644 --- a/src/xrpld/peerfinder/detail/Counts.h +++ b/src/xrpld/peerfinder/detail/Counts.h @@ -71,7 +71,9 @@ class Counts can_activate(Slot const& s) const { // Must be handshaked and in the right state - assert(s.state() == Slot::connected || s.state() == Slot::accept); + ASSERT( + s.state() == Slot::connected || s.state() == Slot::accept, + "ripple::PeerFinder::Counts::can_activate : valid input state"); if (s.fixed() || s.reserved()) return true; @@ -262,13 +264,18 @@ class Counts switch (s.state()) { case Slot::accept: - assert(s.inbound()); + ASSERT( + s.inbound(), + "ripple::PeerFinder::Counts::adjust : input is inbound"); m_acceptCount += n; break; case Slot::connect: case Slot::connected: - assert(!s.inbound()); + ASSERT( + !s.inbound(), + "ripple::PeerFinder::Counts::adjust : input is not " + "inbound"); m_attempts += n; break; @@ -290,7 +297,8 @@ class Counts break; default: - assert(false); + UNREACHABLE( + "ripple::PeerFinder::Counts::adjust : invalid input state"); break; }; } diff --git a/src/xrpld/peerfinder/detail/Handouts.h b/src/xrpld/peerfinder/detail/Handouts.h index 0b54dc205fa..aa397d79c6e 100644 --- a/src/xrpld/peerfinder/detail/Handouts.h +++ b/src/xrpld/peerfinder/detail/Handouts.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -43,7 +43,9 @@ template std::size_t handout_one(Target& t, HopContainer& h) { - assert(!t.full()); + ASSERT( + !t.full(), + "ripple::PeerFinder::detail::handout_one : target is not full"); for (auto it = h.begin(); it != h.end(); ++it) { auto const& e = *it; diff --git a/src/xrpld/peerfinder/detail/Livecache.h b/src/xrpld/peerfinder/detail/Livecache.h index 1583ccd96a3..bf1aca2eb9d 100644 --- a/src/xrpld/peerfinder/detail/Livecache.h +++ b/src/xrpld/peerfinder/detail/Livecache.h @@ -432,7 +432,9 @@ Livecache::insert(Endpoint const& ep) // but we will use it to make connections and hand it out // when redirecting. // - assert(ep.hops <= (Tuning::maxHops + 1)); + ASSERT( + ep.hops <= (Tuning::maxHops + 1), + "ripple::PeerFinder::Livecache::insert : maximum input hops"); auto result = m_cache.emplace(ep.address, ep); Element& e(result.first->second); if (result.second) @@ -530,7 +532,9 @@ template void Livecache::hops_t::insert(Element& e) { - assert(e.endpoint.hops <= Tuning::maxHops + 1); + ASSERT( + e.endpoint.hops <= Tuning::maxHops + 1, + "ripple::PeerFinder::Livecache::hops_t::insert : maximum input hops"); // This has security implications without a shuffle m_lists[e.endpoint.hops].push_front(e); ++m_hist[e.endpoint.hops]; @@ -540,7 +544,9 @@ template void Livecache::hops_t::reinsert(Element& e, std::uint32_t numHops) { - assert(numHops <= Tuning::maxHops + 1); + ASSERT( + numHops <= Tuning::maxHops + 1, + "ripple::PeerFinder::Livecache::hops_t::reinsert : maximum hops input"); auto& list = m_lists[e.endpoint.hops]; list.erase(list.iterator_to(e)); diff --git a/src/xrpld/peerfinder/detail/Logic.h b/src/xrpld/peerfinder/detail/Logic.h index 3bfb9942c3a..41bb6789a86 100644 --- a/src/xrpld/peerfinder/detail/Logic.h +++ b/src/xrpld/peerfinder/detail/Logic.h @@ -304,7 +304,10 @@ class Logic // Add slot to table auto const result(slots_.emplace(slot->remote_endpoint(), slot)); // Remote address must not already exist - assert(result.second); + ASSERT( + result.second, + "ripple::PeerFinder::Logic::new_inbound_slot : remote endpoint " + "inserted"); // Add to the connected address list connectedAddresses_.emplace(remote_endpoint.address()); @@ -339,7 +342,10 @@ class Logic // Add slot to table auto const result = slots_.emplace(slot->remote_endpoint(), slot); // Remote address must not already exist - assert(result.second); + ASSERT( + result.second, + "ripple::PeerFinder::Logic::new_outbound_slot : remote endpoint " + "inserted"); // Add to the connected address list connectedAddresses_.emplace(remote_endpoint.address()); @@ -362,7 +368,9 @@ class Logic std::lock_guard _(lock_); // The object must exist in our table - assert(slots_.find(slot->remote_endpoint()) != slots_.end()); + ASSERT( + slots_.find(slot->remote_endpoint()) != slots_.end(), + "ripple::PeerFinder::Logic::onConnected : valid slot input"); // Assign the local endpoint now that it's known slot->local_endpoint(local_endpoint); @@ -371,8 +379,10 @@ class Logic auto const iter(slots_.find(local_endpoint)); if (iter != slots_.end()) { - assert( - iter->second->local_endpoint() == slot->remote_endpoint()); + ASSERT( + iter->second->local_endpoint() == slot->remote_endpoint(), + "ripple::PeerFinder::Logic::onConnected : local and remote " + "endpoints do match"); JLOG(m_journal.warn()) << beast::leftw(18) << "Logic dropping " << slot->remote_endpoint() << " as self connect"; @@ -397,10 +407,13 @@ class Logic std::lock_guard _(lock_); // The object must exist in our table - assert(slots_.find(slot->remote_endpoint()) != slots_.end()); + ASSERT( + slots_.find(slot->remote_endpoint()) != slots_.end(), + "ripple::PeerFinder::Logic::activate : valid slot input"); // Must be accepted or connected - assert( - slot->state() == Slot::accept || slot->state() == Slot::connected); + ASSERT( + slot->state() == Slot::accept || slot->state() == Slot::connected, + "ripple::PeerFinder::Logic::activate : valid slot state"); // Check for duplicate connection by key if (keys_.find(key) != keys_.end()) @@ -426,7 +439,9 @@ class Logic { [[maybe_unused]] bool const inserted = keys_.insert(key).second; // Public key must not already exist - assert(inserted); + ASSERT( + inserted, + "ripple::PeerFinder::Logic::activate : public key inserted"); } // Change state and update counts @@ -788,10 +803,14 @@ class Logic std::lock_guard _(lock_); // The object must exist in our table - assert(slots_.find(slot->remote_endpoint()) != slots_.end()); + ASSERT( + slots_.find(slot->remote_endpoint()) != slots_.end(), + "ripple::PeerFinder::Logic::on_endpoints : valid slot input"); // Must be handshaked! - assert(slot->state() == Slot::active); + ASSERT( + slot->state() == Slot::active, + "ripple::PeerFinder::Logic::on_endpoints : valid slot state"); clock_type::time_point const now(m_clock.now()); @@ -803,7 +822,9 @@ class Logic for (auto const& ep : list) { - assert(ep.hops != 0); + ASSERT( + ep.hops != 0, + "ripple::PeerFinder::Logic::on_endpoints : nonzero hops"); slot->recent.insert(ep.address, ep.hops); @@ -956,7 +977,9 @@ class Logic break; default: - assert(false); + UNREACHABLE( + "ripple::PeerFinder::Logic::on_closed : invalid slot " + "state"); break; } } diff --git a/src/xrpld/peerfinder/detail/SlotImp.cpp b/src/xrpld/peerfinder/detail/SlotImp.cpp index a5d13aa729e..4cc3e577d66 100644 --- a/src/xrpld/peerfinder/detail/SlotImp.cpp +++ b/src/xrpld/peerfinder/detail/SlotImp.cpp @@ -64,19 +64,32 @@ void SlotImp::state(State state_) { // Must go through activate() to set active state - assert(state_ != active); + ASSERT( + state_ != active, + "ripple::PeerFinder::SlotImp::state : input state is not active"); // The state must be different - assert(state_ != m_state); + ASSERT( + state_ != m_state, + "ripple::PeerFinder::SlotImp::state : input state is different from " + "current"); // You can't transition into the initial states - assert(state_ != accept && state_ != connect); + ASSERT( + state_ != accept && state_ != connect, + "ripple::PeerFinder::SlotImp::state : input state is not an initial"); // Can only become connected from outbound connect state - assert(state_ != connected || (!m_inbound && m_state == connect)); + ASSERT( + state_ != connected || (!m_inbound && m_state == connect), + "ripple::PeerFinder::SlotImp::state : input state is not connected an " + "invalid state"); // Can't gracefully close on an outbound connection attempt - assert(state_ != closing || m_state != connect); + ASSERT( + state_ != closing || m_state != connect, + "ripple::PeerFinder::SlotImp::state : input state is not closing an " + "invalid state"); m_state = state_; } @@ -85,7 +98,9 @@ void SlotImp::activate(clock_type::time_point const& now) { // Can only become active from the accept or connected state - assert(m_state == accept || m_state == connected); + ASSERT( + m_state == accept || m_state == connected, + "ripple::PeerFinder::SlotImp::activate : valid state"); m_state = active; whenAcceptEndpoints = now; diff --git a/src/xrpld/perflog/detail/PerfLogImp.cpp b/src/xrpld/perflog/detail/PerfLogImp.cpp index a4773b33e10..559bdb1743c 100644 --- a/src/xrpld/perflog/detail/PerfLogImp.cpp +++ b/src/xrpld/perflog/detail/PerfLogImp.cpp @@ -54,7 +54,9 @@ PerfLogImp::Counters::Counters( if (!inserted) { // Ensure that no other function populates this entry. - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::Counters::Counters : failed to " + "insert label"); } } } @@ -67,7 +69,9 @@ PerfLogImp::Counters::Counters( if (!inserted) { // Ensure that no other function populates this entry. - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::Counters::Counters : failed to " + "insert job type"); } } } @@ -326,7 +330,7 @@ PerfLogImp::rpcStart(std::string const& method, std::uint64_t const requestId) auto counter = counters_.rpc_.find(method); if (counter == counters_.rpc_.end()) { - assert(false); + UNREACHABLE("ripple::perf::PerfLogImp::rpcStart : valid method input"); return; } @@ -348,7 +352,7 @@ PerfLogImp::rpcEnd( auto counter = counters_.rpc_.find(method); if (counter == counters_.rpc_.end()) { - assert(false); + UNREACHABLE("ripple::perf::PerfLogImp::rpcEnd : valid method input"); return; } steady_time_point startTime; @@ -362,7 +366,8 @@ PerfLogImp::rpcEnd( } else { - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::rpcEnd : valid requestId input"); } } std::lock_guard lock(counter->second.mutex); @@ -380,7 +385,8 @@ PerfLogImp::jobQueue(JobType const type) auto counter = counters_.jq_.find(type); if (counter == counters_.jq_.end()) { - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::jobQueue : valid job type input"); return; } std::lock_guard lock(counter->second.mutex); @@ -397,7 +403,8 @@ PerfLogImp::jobStart( auto counter = counters_.jq_.find(type); if (counter == counters_.jq_.end()) { - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::jobStart : valid job type input"); return; } { @@ -416,7 +423,8 @@ PerfLogImp::jobFinish(JobType const type, microseconds dur, int instance) auto counter = counters_.jq_.find(type); if (counter == counters_.jq_.end()) { - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::jobFinish : valid job type input"); return; } { diff --git a/src/xrpld/rpc/Status.h b/src/xrpld/rpc/Status.h index 1d94a6837a8..34ca69e9576 100644 --- a/src/xrpld/rpc/Status.h +++ b/src/xrpld/rpc/Status.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_RPC_STATUS_H_INCLUDED #define RIPPLE_RPC_STATUS_H_INCLUDED +#include #include #include -#include namespace ripple { namespace RPC { @@ -95,7 +95,7 @@ struct Status : public std::exception TER toTER() const { - assert(type_ == Type::TER); + ASSERT(type_ == Type::TER, "ripple::RPC::Status::toTER : type is TER"); return TER::fromInt(code_); } @@ -104,7 +104,9 @@ struct Status : public std::exception error_code_i toErrorCode() const { - assert(type_ == Type::error_code_i); + ASSERT( + type_ == Type::error_code_i, + "ripple::RPC::Status::toTER : type is error code"); return error_code_i(code_); } diff --git a/src/xrpld/rpc/detail/Handler.cpp b/src/xrpld/rpc/detail/Handler.cpp index 90dee4475a1..f303f657172 100644 --- a/src/xrpld/rpc/detail/Handler.cpp +++ b/src/xrpld/rpc/detail/Handler.cpp @@ -38,7 +38,7 @@ byRef(Function const& f) result = f(context); if (result.type() != Json::objectValue) { - assert(false); + UNREACHABLE("ripple::RPC::byRef : result is object"); result = RPC::makeObjectValue(result); } @@ -50,9 +50,10 @@ template Status handle(JsonContext& context, Object& object) { - assert( + ASSERT( context.apiVersion >= HandlerImpl::minApiVer && - context.apiVersion <= HandlerImpl::maxApiVer); + context.apiVersion <= HandlerImpl::maxApiVer, + "ripple::RPC::handle : valid API version"); HandlerImpl handler(context); auto status = handler.check(); @@ -204,8 +205,12 @@ class HandlerTable unsigned minVer, unsigned maxVer) { - assert(minVer <= maxVer); - assert(maxVer <= RPC::apiMaximumValidVersion); + ASSERT( + minVer <= maxVer, + "ripple::RPC::HandlerTable : valid API version range"); + ASSERT( + maxVer <= RPC::apiMaximumValidVersion, + "ripple::RPC::HandlerTable : valid max API version"); return std::any_of( range.first, diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index af204eaedf7..6ab8cee27e2 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -544,19 +544,21 @@ getLedger(T& ledger, LedgerShortcut shortcut, Context& context) return {rpcNOT_SYNCED, "notSynced"}; } - assert(!ledger->open()); + ASSERT( + !ledger->open(), "ripple::RPC::getLedger : validated is not open"); } else { if (shortcut == LedgerShortcut::CURRENT) { ledger = context.ledgerMaster.getCurrentLedger(); - assert(ledger->open()); + ASSERT(ledger->open(), "ripple::RPC::getLedger : current is open"); } else if (shortcut == LedgerShortcut::CLOSED) { ledger = context.ledgerMaster.getClosedLedger(); - assert(!ledger->open()); + ASSERT( + !ledger->open(), "ripple::RPC::getLedger : closed is not open"); } else { @@ -965,7 +967,9 @@ chooseLedgerEntryType(Json::Value const& params) { result.first = RPC::Status{ rpcINVALID_PARAMS, "Invalid field 'type', not string."}; - assert(result.first.type() == RPC::Status::Type::error_code_i); + ASSERT( + result.first.type() == RPC::Status::Type::error_code_i, + "ripple::RPC::chooseLedgerEntryType : first valid result type"); return result; } @@ -978,7 +982,10 @@ chooseLedgerEntryType(Json::Value const& params) { result.first = RPC::Status{rpcINVALID_PARAMS, "Invalid field 'type'."}; - assert(result.first.type() == RPC::Status::Type::error_code_i); + ASSERT( + result.first.type() == RPC::Status::Type::error_code_i, + "ripple::RPC::chooseLedgerEntryType : second valid result " + "type"); return result; } result.second = iter->second; @@ -1084,7 +1091,9 @@ getLedgerByContext(RPC::JsonContext& context) // ledger auto const refIndex = getCandidateLedger(ledgerIndex); auto refHash = hashOfSeq(*ledger, refIndex, j); - assert(refHash); + ASSERT( + refHash.has_value(), + "ripple::RPC::getLedgerByContext : nonzero ledger hash"); ledger = ledgerMaster.getLedgerByHash(*refHash); if (!ledger) @@ -1118,7 +1127,9 @@ getLedgerByContext(RPC::JsonContext& context) neededHash = hashOfSeq(*ledger, ledgerIndex, j); } - assert(neededHash); + ASSERT( + neededHash.has_value(), + "ripple::RPC::getLedgerByContext : nonzero needed hash"); ledgerHash = neededHash ? *neededHash : beast::zero; // kludge } diff --git a/src/xrpld/rpc/detail/RPCHelpers.h b/src/xrpld/rpc/detail/RPCHelpers.h index 54c426b17c3..80ab9d6a5ec 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.h +++ b/src/xrpld/rpc/detail/RPCHelpers.h @@ -213,7 +213,9 @@ template void setVersion(Object& parent, unsigned int apiVersion, bool betaEnabled) { - assert(apiVersion != apiInvalidVersion); + ASSERT( + apiVersion != apiInvalidVersion, + "ripple::RPC::setVersion : input is valid"); auto&& object = addObject(parent, jss::version); if (apiVersion == apiVersionIfUnspecified) { diff --git a/src/xrpld/rpc/detail/Role.cpp b/src/xrpld/rpc/detail/Role.cpp index 5cfe30b26e6..739c8f58012 100644 --- a/src/xrpld/rpc/detail/Role.cpp +++ b/src/xrpld/rpc/detail/Role.cpp @@ -28,7 +28,9 @@ namespace ripple { bool passwordUnrequiredOrSentCorrect(Port const& port, Json::Value const& params) { - assert(!(port.admin_nets_v4.empty() && port.admin_nets_v6.empty())); + ASSERT( + !(port.admin_nets_v4.empty() && port.admin_nets_v6.empty()), + "ripple::passwordUnrequiredOrSentCorrect : non-empty admin nets"); bool const passwordRequired = (!port.admin_user.empty() || !port.admin_password.empty()); diff --git a/src/xrpld/rpc/detail/Status.cpp b/src/xrpld/rpc/detail/Status.cpp index af212d37f14..1773d3bc949 100644 --- a/src/xrpld/rpc/detail/Status.cpp +++ b/src/xrpld/rpc/detail/Status.cpp @@ -36,9 +36,8 @@ Status::codeString() const { std::string s1, s2; - auto success = transResultInfo(toTER(), s1, s2); - assert(success); - (void)success; + [[maybe_unused]] auto const success = transResultInfo(toTER(), s1, s2); + ASSERT(success, "ripple::RPC::codeString : valid TER result"); return s1 + ": " + s2; } @@ -51,7 +50,7 @@ Status::codeString() const return sStr.str(); } - assert(false); + UNREACHABLE("ripple::RPC::codeString : invalid type"); return ""; } diff --git a/src/xrpld/rpc/detail/TransactionSign.cpp b/src/xrpld/rpc/detail/TransactionSign.cpp index 2f10387bc81..3623b26d356 100644 --- a/src/xrpld/rpc/detail/TransactionSign.cpp +++ b/src/xrpld/rpc/detail/TransactionSign.cpp @@ -1031,7 +1031,9 @@ transactionSignFor( if (!preprocResult.second) return preprocResult.first; - assert(signForParams.validMultiSign()); + ASSERT( + signForParams.validMultiSign(), + "ripple::RPC::transactionSignFor : valid multi-signature"); { std::shared_ptr account_state = diff --git a/src/xrpld/rpc/handlers/AMMInfo.cpp b/src/xrpld/rpc/handlers/AMMInfo.cpp index 9d5b20f1d63..e6a1d713a4a 100644 --- a/src/xrpld/rpc/handlers/AMMInfo.cpp +++ b/src/xrpld/rpc/handlers/AMMInfo.cpp @@ -147,14 +147,17 @@ doAMMInfo(RPC::JsonContext& context) if (context.apiVersion >= 3 && invalid(params)) return Unexpected(rpcINVALID_PARAMS); - assert( + ASSERT( (issue1.has_value() == issue2.has_value()) && - (issue1.has_value() != ammID.has_value())); + (issue1.has_value() != ammID.has_value()), + "ripple::doAMMInfo : issue1 and issue2 do match"); auto const ammKeylet = [&]() { if (issue1 && issue2) return keylet::amm(*issue1, *issue2); - assert(ammID); + ASSERT( + ammID.has_value(), + "ripple::doAMMInfo::ammKeylet : ammID is set"); return keylet::amm(*ammID); }(); auto const amm = ledger->read(ammKeylet); @@ -213,9 +216,10 @@ doAMMInfo(RPC::JsonContext& context) } if (voteSlots.size() > 0) ammResult[jss::vote_slots] = std::move(voteSlots); - assert( + ASSERT( !ledger->rules().enabled(fixInnerObjTemplate) || - amm->isFieldPresent(sfAuctionSlot)); + amm->isFieldPresent(sfAuctionSlot), + "ripple::doAMMInfo : auction slot is set"); if (amm->isFieldPresent(sfAuctionSlot)) { auto const& auctionSlot = diff --git a/src/xrpld/rpc/handlers/AccountChannels.cpp b/src/xrpld/rpc/handlers/AccountChannels.cpp index ad591b04a1c..4b9ff7e43c5 100644 --- a/src/xrpld/rpc/handlers/AccountChannels.cpp +++ b/src/xrpld/rpc/handlers/AccountChannels.cpp @@ -169,7 +169,7 @@ doAccountChannels(RPC::JsonContext& context) std::shared_ptr const& sleCur) { if (!sleCur) { - assert(false); + UNREACHABLE("ripple::doAccountChannels : null SLE"); return false; } diff --git a/src/xrpld/rpc/handlers/AccountInfo.cpp b/src/xrpld/rpc/handlers/AccountInfo.cpp index dab0274e9dd..4f62eb5880a 100644 --- a/src/xrpld/rpc/handlers/AccountInfo.cpp +++ b/src/xrpld/rpc/handlers/AccountInfo.cpp @@ -214,7 +214,9 @@ doAccountInfo(RPC::JsonContext& context) if (tx.seqProxy.isSeq()) { - assert(prevSeqProxy < tx.seqProxy); + ASSERT( + prevSeqProxy < tx.seqProxy, + "rpple::doAccountInfo : first sorted proxy"); prevSeqProxy = tx.seqProxy; jvTx[jss::seq] = tx.seqProxy.value(); ++seqCount; @@ -224,7 +226,9 @@ doAccountInfo(RPC::JsonContext& context) } else { - assert(prevSeqProxy < tx.seqProxy); + ASSERT( + prevSeqProxy < tx.seqProxy, + "rpple::doAccountInfo : second sorted proxy"); prevSeqProxy = tx.seqProxy; jvTx[jss::ticket] = tx.seqProxy.value(); ++ticketCount; diff --git a/src/xrpld/rpc/handlers/AccountLines.cpp b/src/xrpld/rpc/handlers/AccountLines.cpp index 64ca95ebe56..e2e6ce19ded 100644 --- a/src/xrpld/rpc/handlers/AccountLines.cpp +++ b/src/xrpld/rpc/handlers/AccountLines.cpp @@ -189,7 +189,7 @@ doAccountLines(RPC::JsonContext& context) std::shared_ptr const& sleCur) { if (!sleCur) { - assert(false); + UNREACHABLE("ripple::doAccountLines : null SLE"); return false; } diff --git a/src/xrpld/rpc/handlers/AccountOffers.cpp b/src/xrpld/rpc/handlers/AccountOffers.cpp index 3c4a4404984..86559a79f4f 100644 --- a/src/xrpld/rpc/handlers/AccountOffers.cpp +++ b/src/xrpld/rpc/handlers/AccountOffers.cpp @@ -145,7 +145,7 @@ doAccountOffers(RPC::JsonContext& context) std::shared_ptr const& sle) { if (!sle) { - assert(false); + UNREACHABLE("ripple::doAccountOffers : null SLE"); return false; } diff --git a/src/xrpld/rpc/handlers/AccountTx.cpp b/src/xrpld/rpc/handlers/AccountTx.cpp index 887694daf21..5b391ebe3b6 100644 --- a/src/xrpld/rpc/handlers/AccountTx.cpp +++ b/src/xrpld/rpc/handlers/AccountTx.cpp @@ -307,7 +307,9 @@ populateJsonResponse( if (auto txnsData = std::get_if(&result.transactions)) { - assert(!args.binary); + ASSERT( + !args.binary, + "ripple::populateJsonResponse : binary is not set"); for (auto const& [txn, txnMeta] : *txnsData) { @@ -354,13 +356,15 @@ populateJsonResponse( jvObj[jss::meta], sttx, *txnMeta); } else - assert(false && "Missing transaction medatata"); + UNREACHABLE( + "ripple::populateJsonResponse : missing " + "transaction medatata"); } } } else { - assert(args.binary); + ASSERT(args.binary, "ripple::populateJsonResponse : binary is set"); for (auto const& binaryData : std::get(result.transactions)) diff --git a/src/xrpld/rpc/handlers/Fee1.cpp b/src/xrpld/rpc/handlers/Fee1.cpp index da766fdbb32..de5bdc4f6ca 100644 --- a/src/xrpld/rpc/handlers/Fee1.cpp +++ b/src/xrpld/rpc/handlers/Fee1.cpp @@ -32,7 +32,7 @@ doFee(RPC::JsonContext& context) auto result = context.app.getTxQ().doRPC(context.app); if (result.type() == Json::objectValue) return result; - assert(false); + UNREACHABLE("ripple::doFee : invalid result type"); RPC::inject_error(rpcINTERNAL, context.params); return context.params; } diff --git a/src/xrpld/rpc/handlers/LedgerClosed.cpp b/src/xrpld/rpc/handlers/LedgerClosed.cpp index 9bc9315f648..759f4aecd33 100644 --- a/src/xrpld/rpc/handlers/LedgerClosed.cpp +++ b/src/xrpld/rpc/handlers/LedgerClosed.cpp @@ -29,7 +29,8 @@ Json::Value doLedgerClosed(RPC::JsonContext& context) { auto ledger = context.ledgerMaster.getClosedLedger(); - assert(ledger); + ASSERT( + ledger != nullptr, "ripple::doLedgerClosed : non-null closed ledger"); Json::Value jvResult; jvResult[jss::ledger_index] = ledger->info().seq; diff --git a/src/xrpld/rpc/handlers/LedgerDiff.cpp b/src/xrpld/rpc/handlers/LedgerDiff.cpp index 6398be60973..e562197f4af 100644 --- a/src/xrpld/rpc/handlers/LedgerDiff.cpp +++ b/src/xrpld/rpc/handlers/LedgerDiff.cpp @@ -73,7 +73,9 @@ doLedgerDiffGrpc( } else { - assert(inDesired->size() > 0); + ASSERT( + inDesired->size() > 0, + "ripple::doLedgerDiffGrpc : non-empty desired"); diff->set_key(k.data(), k.size()); if (request.include_blobs()) { diff --git a/src/xrpld/rpc/handlers/LedgerHandler.cpp b/src/xrpld/rpc/handlers/LedgerHandler.cpp index 2bf4fb09f94..54f9a8b8459 100644 --- a/src/xrpld/rpc/handlers/LedgerHandler.cpp +++ b/src/xrpld/rpc/handlers/LedgerHandler.cpp @@ -135,7 +135,9 @@ doLedgerGrpc(RPC::GRPCContext& context) { for (auto& i : ledger->txs) { - assert(i.first); + ASSERT( + i.first != nullptr, + "ripple::doLedgerGrpc : non-null transaction"); if (request.expand()) { auto txn = response.mutable_transactions_list() @@ -211,7 +213,9 @@ doLedgerGrpc(RPC::GRPCContext& context) obj->set_key(k.data(), k.size()); if (inDesired) { - assert(inDesired->size() > 0); + ASSERT( + inDesired->size() > 0, + "ripple::doLedgerGrpc : non-empty desired"); obj->set_data(inDesired->data(), inDesired->size()); } if (inBase && inDesired) diff --git a/src/xrpld/rpc/handlers/PayChanClaim.cpp b/src/xrpld/rpc/handlers/PayChanClaim.cpp index 1fecd5f1449..e55191877ef 100644 --- a/src/xrpld/rpc/handlers/PayChanClaim.cpp +++ b/src/xrpld/rpc/handlers/PayChanClaim.cpp @@ -58,7 +58,9 @@ doChannelAuthorize(RPC::JsonContext& context) std::optional> const keyPair = RPC::keypairForSignature(params, result, context.apiVersion); - assert(keyPair || RPC::contains_error(result)); + ASSERT( + keyPair || RPC::contains_error(result), + "ripple::doChannelAuthorize : valid keyPair or an error"); if (!keyPair || RPC::contains_error(result)) return result; diff --git a/src/xrpld/rpc/handlers/Tx.cpp b/src/xrpld/rpc/handlers/Tx.cpp index 98af3a809bf..af08575bbd8 100644 --- a/src/xrpld/rpc/handlers/Tx.cpp +++ b/src/xrpld/rpc/handlers/Tx.cpp @@ -251,7 +251,7 @@ populateJsonResponse( // populate binary metadata if (auto blob = std::get_if(&result.meta)) { - assert(args.binary); + ASSERT(args.binary, "ripple::populateJsonResponse : binary is set"); auto json_meta = (context.apiVersion > 1 ? jss::meta_blob : jss::meta); response[json_meta] = strHex(makeSlice(*blob)); diff --git a/src/xrpld/shamap/SHAMap.h b/src/xrpld/shamap/SHAMap.h index a47f1c1c2bc..cc9a8d9e6ae 100644 --- a/src/xrpld/shamap/SHAMap.h +++ b/src/xrpld/shamap/SHAMap.h @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -599,7 +599,9 @@ SHAMap::setLedgerSeq(std::uint32_t lseq) inline void SHAMap::setImmutable() { - assert(state_ != SHAMapState::Invalid); + ASSERT( + state_ != SHAMapState::Invalid, + "ripple::SHAMap::setImmutable : state is valid"); state_ = SHAMapState::Immutable; } @@ -680,7 +682,9 @@ class SHAMap::const_iterator inline SHAMap::const_iterator::const_iterator(SHAMap const* map) : map_(map) { - assert(map_ != nullptr); + ASSERT( + map_ != nullptr, + "ripple::SHAMap::const_iterator::const_iterator : non-null input"); if (auto temp = map_->peekFirstItem(stack_)) item_ = temp->peekItem().get(); @@ -732,7 +736,10 @@ SHAMap::const_iterator::operator++(int) inline bool operator==(SHAMap::const_iterator const& x, SHAMap::const_iterator const& y) { - assert(x.map_ == y.map_); + ASSERT( + x.map_ == y.map_, + "ripple::operator==(SHAMap::const_iterator, SHAMap::const_iterator) : " + "inputs map do match"); return x.item_ == y.item_; } diff --git a/src/xrpld/shamap/SHAMapItem.h b/src/xrpld/shamap/SHAMapItem.h index 1a1822456e9..e49762a50b2 100644 --- a/src/xrpld/shamap/SHAMapItem.h +++ b/src/xrpld/shamap/SHAMapItem.h @@ -25,8 +25,8 @@ #include #include #include +#include #include -#include namespace ripple { @@ -159,7 +159,9 @@ intrusive_ptr_release(SHAMapItem const* x) inline boost::intrusive_ptr make_shamapitem(uint256 const& tag, Slice data) { - assert(data.size() <= megabytes(16)); + ASSERT( + data.size() <= megabytes(16), + "ripple::make_shamapitem : maximum input size"); std::uint8_t* raw = detail::slabber.allocate(data.size()); diff --git a/src/xrpld/shamap/detail/SHAMap.cpp b/src/xrpld/shamap/detail/SHAMap.cpp index d06ba2a153a..11cf079320f 100644 --- a/src/xrpld/shamap/detail/SHAMap.cpp +++ b/src/xrpld/shamap/detail/SHAMap.cpp @@ -101,10 +101,12 @@ SHAMap::dirtyUp( // stack is a path of inner nodes up to, but not including, child // child can be an inner node or a leaf - assert( - (state_ != SHAMapState::Synching) && - (state_ != SHAMapState::Immutable)); - assert(child && (child->cowid() == cowid_)); + ASSERT( + (state_ != SHAMapState::Synching) && (state_ != SHAMapState::Immutable), + "ripple::SHAMap::dirtyUp : valid state"); + ASSERT( + child && (child->cowid() == cowid_), + "ripple::SHAMap::dirtyUp : valid child input"); while (!stack.empty()) { @@ -112,10 +114,10 @@ SHAMap::dirtyUp( std::dynamic_pointer_cast(stack.top().first); SHAMapNodeID nodeID = stack.top().second; stack.pop(); - assert(node != nullptr); + ASSERT(node != nullptr, "ripple::SHAMap::dirtyUp : non-null node"); int branch = selectBranch(nodeID, target); - assert(branch >= 0); + ASSERT(branch >= 0, "ripple::SHAMap::dirtyUp : valid branch"); node = unshareNode(std::move(node), nodeID); node->setChild(branch, std::move(child)); @@ -127,7 +129,9 @@ SHAMap::dirtyUp( SHAMapLeafNode* SHAMap::walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack) const { - assert(stack == nullptr || stack->empty()); + ASSERT( + stack == nullptr || stack->empty(), + "ripple::SHAMap::walkTowardsKey : empty stack input"); auto inNode = root_; SHAMapNodeID nodeID; @@ -162,7 +166,7 @@ SHAMap::findKey(uint256 const& id) const std::shared_ptr SHAMap::fetchNodeFromDB(SHAMapHash const& hash) const { - assert(backed_); + ASSERT(backed_, "ripple::SHAMap::fetchNodeFromDB : is backed"); auto obj = f_.db().fetchNodeObject(hash.as_uint256(), ledgerSeq_); return finishFetch(hash, obj); } @@ -172,7 +176,7 @@ SHAMap::finishFetch( SHAMapHash const& hash, std::shared_ptr const& object) const { - assert(backed_); + ASSERT(backed_, "ripple::SHAMap::finishFetch : is backed"); try { @@ -360,9 +364,13 @@ SHAMap::descend( int branch, SHAMapSyncFilter* filter) const { - assert(parent->isInner()); - assert((branch >= 0) && (branch < branchFactor)); - assert(!parent->isEmptyBranch(branch)); + ASSERT(parent->isInner(), "ripple::SHAMap::descend : valid parent input"); + ASSERT( + (branch >= 0) && (branch < branchFactor), + "ripple::SHAMap::descend : valid branch input"); + ASSERT( + !parent->isEmptyBranch(branch), + "ripple::SHAMap::descend : parent branch is non-empty"); SHAMapTreeNode* child = parent->getChildPointer(branch); @@ -430,11 +438,15 @@ std::shared_ptr SHAMap::unshareNode(std::shared_ptr node, SHAMapNodeID const& nodeID) { // make sure the node is suitable for the intended operation (copy on write) - assert(node->cowid() <= cowid_); + ASSERT( + node->cowid() <= cowid_, + "ripple::SHAMap::unshareNode : node valid for cowid"); if (node->cowid() != cowid_) { // have a CoW - assert(state_ != SHAMapState::Immutable); + ASSERT( + state_ != SHAMapState::Immutable, + "ripple::SHAMap::unshareNode : not immutable"); node = std::static_pointer_cast(node->clone(cowid_)); if (nodeID.isRoot()) root_ = node; @@ -467,7 +479,9 @@ SHAMap::belowHelper( if (!inner->isEmptyBranch(i)) { node = descendThrow(inner, i); - assert(!stack.empty()); + ASSERT( + !stack.empty(), + "ripple::SHAMap::belowHelper : non-empty stack"); if (node->isLeaf()) { auto n = std::static_pointer_cast(node); @@ -531,7 +545,7 @@ SHAMap::onlyBelow(SHAMapTreeNode* node) const if (!nextNode) { - assert(false); + UNREACHABLE("ripple::SHAMap::onlyBelow : no next node"); return no_item; } @@ -541,14 +555,16 @@ SHAMap::onlyBelow(SHAMapTreeNode* node) const // An inner node must have at least one leaf // below it, unless it's the root_ auto const leaf = static_cast(node); - assert(leaf->peekItem() || (leaf == root_.get())); + ASSERT( + leaf->peekItem() || (leaf == root_.get()), + "ripple::SHAMap::onlyBelow : valid inner node"); return leaf->peekItem(); } SHAMapLeafNode const* SHAMap::peekFirstItem(SharedPtrNodeStack& stack) const { - assert(stack.empty()); + ASSERT(stack.empty(), "ripple::SHAMap::peekFirstItem : empty stack input"); SHAMapLeafNode* node = firstBelow(root_, stack); if (!node) { @@ -562,13 +578,18 @@ SHAMap::peekFirstItem(SharedPtrNodeStack& stack) const SHAMapLeafNode const* SHAMap::peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const { - assert(!stack.empty()); - assert(stack.top().first->isLeaf()); + ASSERT( + !stack.empty(), "ripple::SHAMap::peekNextItem : non-empty stack input"); + ASSERT( + stack.top().first->isLeaf(), + "ripple::SHAMap::peekNextItem : stack starts with leaf"); stack.pop(); while (!stack.empty()) { auto [node, nodeID] = stack.top(); - assert(!node->isLeaf()); + ASSERT( + !node->isLeaf(), + "ripple::SHAMap::peekNextItem : another node is not leaf"); auto inner = std::static_pointer_cast(node); for (auto i = selectBranch(nodeID, id) + 1; i < branchFactor; ++i) { @@ -578,7 +599,9 @@ SHAMap::peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const auto leaf = firstBelow(node, stack, i); if (!leaf) Throw(type_, id); - assert(leaf->isLeaf()); + ASSERT( + leaf->isLeaf(), + "ripple::SHAMap::peekNextItem : leaf is valid"); return leaf; } } @@ -696,7 +719,9 @@ bool SHAMap::delItem(uint256 const& id) { // delete the item with this ID - assert(state_ != SHAMapState::Immutable); + ASSERT( + state_ != SHAMapState::Immutable, + "ripple::SHAMap::delItem : not immutable"); SharedPtrNodeStack stack; walkTowardsKey(id, &stack); @@ -775,8 +800,12 @@ SHAMap::addGiveItem( SHAMapNodeType type, boost::intrusive_ptr item) { - assert(state_ != SHAMapState::Immutable); - assert(type != SHAMapNodeType::tnINNER); + ASSERT( + state_ != SHAMapState::Immutable, + "ripple::SHAMap::addGiveItem : not immutable"); + ASSERT( + type != SHAMapNodeType::tnINNER, + "ripple::SHAMap::addGiveItem : valid type input"); // add the specified item, does not update uint256 tag = item->key(); @@ -802,7 +831,9 @@ SHAMap::addGiveItem( // easy case, we end on an inner node auto inner = std::static_pointer_cast(node); int branch = selectBranch(nodeID, tag); - assert(inner->isEmptyBranch(branch)); + ASSERT( + inner->isEmptyBranch(branch), + "ripple::SHAMap::addGiveItem : inner branch is empty"); inner->setChild(branch, makeTypedLeaf(type, std::move(item), cowid_)); } else @@ -811,7 +842,9 @@ SHAMap::addGiveItem( // items auto leaf = std::static_pointer_cast(node); auto otherItem = leaf->peekItem(); - assert(otherItem && (tag != otherItem->key())); + ASSERT( + otherItem && (tag != otherItem->key()), + "ripple::SHAMap::addGiveItem : non-null item"); node = std::make_shared(node->cowid()); @@ -829,7 +862,7 @@ SHAMap::addGiveItem( } // we can add the two leaf nodes here - assert(node->isInner()); + ASSERT(node->isInner(), "ripple::SHAMap::addGiveItem : node is inner"); auto inner = static_cast(node.get()); inner->setChild(b1, makeTypedLeaf(type, std::move(item), cowid_)); @@ -868,7 +901,9 @@ SHAMap::updateGiveItem( // can't change the tag but can change the hash uint256 tag = item->key(); - assert(state_ != SHAMapState::Immutable); + ASSERT( + state_ != SHAMapState::Immutable, + "ripple::SHAMap::updateGiveItem : not immutable"); SharedPtrNodeStack stack; walkTowardsKey(tag, &stack); @@ -882,7 +917,7 @@ SHAMap::updateGiveItem( if (!node || (node->peekItem()->key() != tag)) { - assert(false); + UNREACHABLE("ripple::SHAMap::updateGiveItem : invalid node"); return false; } @@ -927,7 +962,9 @@ SHAMap::fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter) if (newRoot) { root_ = newRoot; - assert(root_->getHash() == hash); + ASSERT( + root_->getHash() == hash, + "ripple::SHAMap::fetchRoot : root hash do match"); return true; } @@ -949,8 +986,8 @@ SHAMap::fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter) std::shared_ptr SHAMap::writeNode(NodeObjectType t, std::shared_ptr node) const { - assert(node->cowid() == 0); - assert(backed_); + ASSERT(node->cowid() == 0, "ripple::SHAMap::writeNode : valid input node"); + ASSERT(backed_, "ripple::SHAMap::writeNode : is backed"); canonicalize(node->getHash(), node); @@ -970,7 +1007,8 @@ SHAMap::preFlushNode(std::shared_ptr node) const { // A shared node should never need to be flushed // because that would imply someone modified it - assert(node->cowid() != 0); + ASSERT( + node->cowid() != 0, "ripple::SHAMap::preFlushNode : valid input node"); if (node->cowid() != cowid_) { @@ -998,7 +1036,7 @@ SHAMap::flushDirty(NodeObjectType t) int SHAMap::walkSubTree(bool doWrite, NodeObjectType t) { - assert(!doWrite || backed_); + ASSERT(!doWrite || backed_, "ripple::SHAMap::walkSubTree : valid input"); int flushed = 0; @@ -1073,7 +1111,10 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t) // flush this leaf ++flushed; - assert(node->cowid() == cowid_); + ASSERT( + node->cowid() == cowid_, + "ripple::SHAMap::walkSubTree : node cowid do " + "match"); child->updateHash(); child->unshare(); @@ -1106,7 +1147,9 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t) stack.pop(); // Hook this inner node to its parent - assert(parent->cowid() == cowid_); + ASSERT( + parent->cowid() == cowid_, + "ripple::SHAMap::walkSubTree : parent cowid do match"); parent->shareChild(pos, node); // Continue with parent's next child, if any @@ -1150,7 +1193,9 @@ SHAMap::dump(bool hash) const auto child = inner->getChildPointer(i); if (child) { - assert(child->getHash() == inner->getChildHash(i)); + ASSERT( + child->getHash() == inner->getChildHash(i), + "ripple::SHAMap::dump : child hash do match"); stack.push({child, nodeID.getChildNodeID(i)}); } } @@ -1167,7 +1212,9 @@ std::shared_ptr SHAMap::cacheLookup(SHAMapHash const& hash) const { auto ret = f_.getTreeNodeCache()->fetch(hash.as_uint256()); - assert(!ret || !ret->cowid()); + ASSERT( + !ret || !ret->cowid(), + "ripple::SHAMap::cacheLookup : not found or zero cowid"); return ret; } @@ -1176,9 +1223,12 @@ SHAMap::canonicalize( SHAMapHash const& hash, std::shared_ptr& node) const { - assert(backed_); - assert(node->cowid() == 0); - assert(node->getHash() == hash); + ASSERT(backed_, "ripple::SHAMap::canonicalize : is backed"); + ASSERT( + node->cowid() == 0, "ripple::SHAMap::canonicalize : valid node input"); + ASSERT( + node->getHash() == hash, + "ripple::SHAMap::canonicalize : node hash do match"); f_.getTreeNodeCache()->canonicalize_replace_client(hash.as_uint256(), node); } @@ -1188,8 +1238,9 @@ SHAMap::invariants() const { (void)getHash(); // update node hashes auto node = root_.get(); - assert(node != nullptr); - assert(!node->isLeaf()); + ASSERT(node != nullptr, "ripple::SHAMap::invariants : non-null root node"); + ASSERT( + !node->isLeaf(), "ripple::SHAMap::invariants : root node is not leaf"); SharedPtrNodeStack stack; for (auto leaf = peekFirstItem(stack); leaf != nullptr; leaf = peekNextItem(leaf->peekItem()->key(), stack)) diff --git a/src/xrpld/shamap/detail/SHAMapDelta.cpp b/src/xrpld/shamap/detail/SHAMapDelta.cpp index 0dcb861a63f..b2f62685829 100644 --- a/src/xrpld/shamap/detail/SHAMapDelta.cpp +++ b/src/xrpld/shamap/detail/SHAMapDelta.cpp @@ -128,7 +128,9 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const // many differences throws on corrupt tables or missing nodes CAUTION: // otherMap is not locked and must be immutable - assert(isValid() && otherMap.isValid()); + ASSERT( + isValid() && otherMap.isValid(), + "ripple::SHAMap::compare : valid state and valid input"); if (getHash() == otherMap.getHash()) return true; @@ -145,7 +147,7 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const if (!ourNode || !otherNode) { - assert(false); + UNREACHABLE("ripple::SHAMap::compare : missing a node"); Throw(type_, uint256()); } @@ -226,7 +228,7 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const } } else - assert(false); + UNREACHABLE("ripple::SHAMap::compare : invalid node"); } return true; @@ -323,7 +325,9 @@ SHAMap::walkMapParallel( { std::shared_ptr node = std::move(nodeStack.top()); - assert(node); + ASSERT( + node != nullptr, + "ripple::SHAMap::walkMapParallel : non-null node"); nodeStack.pop(); for (int i = 0; i < 16; ++i) diff --git a/src/xrpld/shamap/detail/SHAMapInnerNode.cpp b/src/xrpld/shamap/detail/SHAMapInnerNode.cpp index 99155a6401f..2f8448d7edc 100644 --- a/src/xrpld/shamap/detail/SHAMapInnerNode.cpp +++ b/src/xrpld/shamap/detail/SHAMapInnerNode.cpp @@ -225,7 +225,8 @@ SHAMapInnerNode::updateHashDeep() void SHAMapInnerNode::serializeForWire(Serializer& s) const { - assert(!isEmpty()); + ASSERT( + !isEmpty(), "ripple::SHAMapInnerNode::serializeForWire : is non-empty"); // If the node is sparse, then only send non-empty branches: if (getBranchCount() < 12) @@ -249,7 +250,9 @@ SHAMapInnerNode::serializeForWire(Serializer& s) const void SHAMapInnerNode::serializeWithPrefix(Serializer& s) const { - assert(!isEmpty()); + ASSERT( + !isEmpty(), + "ripple::SHAMapInnerNode::serializeWithPrefix : is non-empty"); s.add32(HashPrefix::innerNode); iterChildren( @@ -274,9 +277,13 @@ SHAMapInnerNode::getString(const SHAMapNodeID& id) const void SHAMapInnerNode::setChild(int m, std::shared_ptr child) { - assert((m >= 0) && (m < branchFactor)); - assert(cowid_ != 0); - assert(child.get() != this); + ASSERT( + (m >= 0) && (m < branchFactor), + "ripple::SHAMapInnerNode::setChild : valid branch input"); + ASSERT(cowid_ != 0, "ripple::SHAMapInnerNode::setChild : nonzero cowid"); + ASSERT( + child.get() != this, + "ripple::SHAMapInnerNode::setChild : valid child input"); auto const dstIsBranch = [&] { if (child) @@ -303,27 +310,41 @@ SHAMapInnerNode::setChild(int m, std::shared_ptr child) hash_.zero(); - assert(getBranchCount() <= hashesAndChildren_.capacity()); + ASSERT( + getBranchCount() <= hashesAndChildren_.capacity(), + "ripple::SHAMapInnerNode::setChild : maximum branch count"); } // finished modifying, now make shareable void SHAMapInnerNode::shareChild(int m, std::shared_ptr const& child) { - assert((m >= 0) && (m < branchFactor)); - assert(cowid_ != 0); - assert(child); - assert(child.get() != this); - - assert(!isEmptyBranch(m)); + ASSERT( + (m >= 0) && (m < branchFactor), + "ripple::SHAMapInnerNode::shareChild : valid branch input"); + ASSERT(cowid_ != 0, "ripple::SHAMapInnerNode::shareChild : nonzero cowid"); + ASSERT( + child != nullptr, + "ripple::SHAMapInnerNode::shareChild : non-null child input"); + ASSERT( + child.get() != this, + "ripple::SHAMapInnerNode::shareChild : valid child input"); + + ASSERT( + !isEmptyBranch(m), + "ripple::SHAMapInnerNode::shareChild : non-empty branch input"); hashesAndChildren_.getChildren()[*getChildIndex(m)] = child; } SHAMapTreeNode* SHAMapInnerNode::getChildPointer(int branch) { - assert(branch >= 0 && branch < branchFactor); - assert(!isEmptyBranch(branch)); + ASSERT( + branch >= 0 && branch < branchFactor, + "ripple::SHAMapInnerNode::getChildPointer : valid branch input"); + ASSERT( + !isEmptyBranch(branch), + "ripple::SHAMapInnerNode::getChildPointer : non-empty branch input"); auto const index = *getChildIndex(branch); @@ -335,8 +356,12 @@ SHAMapInnerNode::getChildPointer(int branch) std::shared_ptr SHAMapInnerNode::getChild(int branch) { - assert(branch >= 0 && branch < branchFactor); - assert(!isEmptyBranch(branch)); + ASSERT( + branch >= 0 && branch < branchFactor, + "ripple::SHAMapInnerNode::getChild : valid branch input"); + ASSERT( + !isEmptyBranch(branch), + "ripple::SHAMapInnerNode::getChild : non-empty branch input"); auto const index = *getChildIndex(branch); @@ -348,7 +373,9 @@ SHAMapInnerNode::getChild(int branch) SHAMapHash const& SHAMapInnerNode::getChildHash(int m) const { - assert((m >= 0) && (m < branchFactor)); + ASSERT( + (m >= 0) && (m < branchFactor), + "ripple::SHAMapInnerNode::getChildHash : valid branch input"); if (auto const i = getChildIndex(m)) return hashesAndChildren_.getHashes()[*i]; @@ -360,12 +387,21 @@ SHAMapInnerNode::canonicalizeChild( int branch, std::shared_ptr node) { - assert(branch >= 0 && branch < branchFactor); - assert(node); - assert(!isEmptyBranch(branch)); + ASSERT( + branch >= 0 && branch < branchFactor, + "ripple::SHAMapInnerNode::canonicalizeChild : valid branch input"); + ASSERT( + node != nullptr, + "ripple::SHAMapInnerNode::canonicalizeChild : valid node input"); + ASSERT( + !isEmptyBranch(branch), + "ripple::SHAMapInnerNode::canonicalizeChild : non-empty branch input"); auto const childIndex = *getChildIndex(branch); auto [_, hashes, children] = hashesAndChildren_.getHashesAndChildren(); - assert(node->getHash() == hashes[childIndex]); + ASSERT( + node->getHash() == hashes[childIndex], + "ripple::SHAMapInnerNode::canonicalizeChild : node and branch inputs " + "hash do match"); packed_spinlock sl(lock_, childIndex); std::lock_guard lock(sl); @@ -395,7 +431,9 @@ SHAMapInnerNode::invariants(bool is_root) const auto const branchCount = getBranchCount(); for (int i = 0; i < branchCount; ++i) { - assert(hashes[i].isNonZero()); + ASSERT( + hashes[i].isNonZero(), + "ripple::SHAMapInnerNode::invariants : nonzero hash in branch"); if (children[i] != nullptr) children[i]->invariants(); ++count; @@ -407,24 +445,35 @@ SHAMapInnerNode::invariants(bool is_root) const { if (hashes[i].isNonZero()) { - assert((isBranch_ & (1 << i)) != 0); + ASSERT( + (isBranch_ & (1 << i)) != 0, + "ripple::SHAMapInnerNode::invariants : valid branch when " + "nonzero hash"); if (children[i] != nullptr) children[i]->invariants(); ++count; } else { - assert((isBranch_ & (1 << i)) == 0); + ASSERT( + (isBranch_ & (1 << i)) == 0, + "ripple::SHAMapInnerNode::invariants : valid branch when " + "zero hash"); } } } if (!is_root) { - assert(hash_.isNonZero()); - assert(count >= 1); + ASSERT( + hash_.isNonZero(), + "ripple::SHAMapInnerNode::invariants : nonzero hash"); + ASSERT( + count >= 1, "ripple::SHAMapInnerNode::invariants : minimum count"); } - assert((count == 0) ? hash_.isZero() : hash_.isNonZero()); + ASSERT( + (count == 0) ? hash_.isZero() : hash_.isNonZero(), + "ripple::SHAMapInnerNode::invariants : hash and count do match"); } } // namespace ripple diff --git a/src/xrpld/shamap/detail/SHAMapLeafNode.cpp b/src/xrpld/shamap/detail/SHAMapLeafNode.cpp index 972919a9bda..f6f13cfdaab 100644 --- a/src/xrpld/shamap/detail/SHAMapLeafNode.cpp +++ b/src/xrpld/shamap/detail/SHAMapLeafNode.cpp @@ -28,7 +28,10 @@ SHAMapLeafNode::SHAMapLeafNode( std::uint32_t cowid) : SHAMapTreeNode(cowid), item_(std::move(item)) { - assert(item_->size() >= 12); + ASSERT( + item_->size() >= 12, + "ripple::SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr<" + "SHAMapItem const>, std::uint32_t) : minimum input size"); } SHAMapLeafNode::SHAMapLeafNode( @@ -37,7 +40,11 @@ SHAMapLeafNode::SHAMapLeafNode( SHAMapHash const& hash) : SHAMapTreeNode(cowid, hash), item_(std::move(item)) { - assert(item_->size() >= 12); + ASSERT( + item_->size() >= 12, + "ripple::SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr<" + "SHAMapItem const>, std::uint32_t, SHAMapHash const&) : minimum input " + "size"); } boost::intrusive_ptr const& @@ -49,7 +56,7 @@ SHAMapLeafNode::peekItem() const bool SHAMapLeafNode::setItem(boost::intrusive_ptr item) { - assert(cowid_ != 0); + ASSERT(cowid_ != 0, "ripple::SHAMapLeafNode::setItem : nonzero cowid"); item_ = std::move(item); auto const oldHash = hash_; @@ -87,8 +94,10 @@ SHAMapLeafNode::getString(const SHAMapNodeID& id) const void SHAMapLeafNode::invariants(bool) const { - assert(hash_.isNonZero()); - assert(item_ != nullptr); + ASSERT( + hash_.isNonZero(), "ripple::SHAMapLeafNode::invariants : nonzero hash"); + ASSERT( + item_ != nullptr, "ripple::SHAMapLeafNode::invariants : non-null item"); } } // namespace ripple diff --git a/src/xrpld/shamap/detail/SHAMapNodeID.cpp b/src/xrpld/shamap/detail/SHAMapNodeID.cpp index 5cbd095e7a9..82cf9436366 100644 --- a/src/xrpld/shamap/detail/SHAMapNodeID.cpp +++ b/src/xrpld/shamap/detail/SHAMapNodeID.cpp @@ -20,9 +20,9 @@ #include #include #include +#include #include #include -#include namespace ripple { @@ -57,8 +57,12 @@ depthMask(unsigned int depth) SHAMapNodeID::SHAMapNodeID(unsigned int depth, uint256 const& hash) : id_(hash), depth_(depth) { - assert(depth <= SHAMap::leafDepth); - assert(id_ == (id_ & depthMask(depth))); + ASSERT( + depth <= SHAMap::leafDepth, + "ripple::SHAMapNodeID::SHAMapNodeID : maximum depth input"); + ASSERT( + id_ == (id_ & depthMask(depth)), + "ripple::SHAMapNodeID::SHAMapNodeID : hash and depth inputs do match"); } std::string @@ -73,7 +77,9 @@ SHAMapNodeID::getRawString() const SHAMapNodeID SHAMapNodeID::getChildNodeID(unsigned int m) const { - assert(m < SHAMap::branchFactor); + ASSERT( + m < SHAMap::branchFactor, + "ripple::SHAMapNodeID::getChildNodeID : valid branch input"); // A SHAMap has exactly 65 levels, so nodes must not exceed that // depth; if they do, this breaks the invariant of never allowing @@ -83,7 +89,9 @@ SHAMapNodeID::getChildNodeID(unsigned int m) const // We throw (but never assert) if the node is at level 64, since // entries at that depth are leaf nodes and have no children and even // constructing a child node from them would break the above invariant. - assert(depth_ <= SHAMap::leafDepth); + ASSERT( + depth_ <= SHAMap::leafDepth, + "ripple::SHAMapNodeID::getChildNodeID : maximum leaf depth"); if (depth_ >= SHAMap::leafDepth) Throw( @@ -128,14 +136,17 @@ selectBranch(SHAMapNodeID const& id, uint256 const& hash) else branch >>= 4; - assert(branch < SHAMap::branchFactor); + ASSERT( + branch < SHAMap::branchFactor, "ripple::selectBranch : maximum result"); return branch; } SHAMapNodeID SHAMapNodeID::createID(int depth, uint256 const& key) { - assert((depth >= 0) && (depth < 65)); + ASSERT( + (depth >= 0) && (depth < 65), + "ripple::SHAMapNodeID::createID : valid branch input"); return SHAMapNodeID(depth, key & depthMask(depth)); } diff --git a/src/xrpld/shamap/detail/SHAMapSync.cpp b/src/xrpld/shamap/detail/SHAMapSync.cpp index 7235e526560..4425662415e 100644 --- a/src/xrpld/shamap/detail/SHAMapSync.cpp +++ b/src/xrpld/shamap/detail/SHAMapSync.cpp @@ -314,8 +314,10 @@ SHAMap::gmn_ProcessDeferredReads(MissingNodes& mn) std::vector> SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) { - assert(root_->getHash().isNonZero()); - assert(max > 0); + ASSERT( + root_->getHash().isNonZero(), + "ripple::SHAMap::getMissingNodes : nonzero root hash"); + ASSERT(max > 0, "ripple::SHAMap::getMissingNodes : valid max input"); MissingNodes mn( max, @@ -374,7 +376,9 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) // This is a node we are continuing to process fullBelow = fullBelow && was; // was and still is } - assert(node); + ASSERT( + node != nullptr, + "ripple::SHAMap::getMissingNodes : first non-null node"); } } @@ -405,7 +409,9 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) // Resume at the top of the stack pos = mn.stack_.top(); mn.stack_.pop(); - assert(node != nullptr); + ASSERT( + node != nullptr, + "ripple::SHAMap::getMissingNodes : second non-null node"); } } @@ -532,11 +538,13 @@ SHAMap::addRootNode( if (root_->getHash().isNonZero()) { JLOG(journal_.trace()) << "got root node, already have one"; - assert(root_->getHash() == hash); + ASSERT( + root_->getHash() == hash, + "ripple::SHAMap::addRootNode : valid hash input"); return SHAMapAddNode::duplicate(); } - assert(cowid_ >= 1); + ASSERT(cowid_ >= 1, "ripple::SHAMap::addRootNode : valid cowid"); auto node = SHAMapTreeNode::makeFromWire(rootNode); if (!node || node->getHash() != hash) return SHAMapAddNode::invalid(); @@ -570,7 +578,7 @@ SHAMap::addKnownNode( Slice const& rawNode, SHAMapSyncFilter* filter) { - assert(!node.isRoot()); + ASSERT(!node.isRoot(), "ripple::SHAMap::addKnownNode : valid node input"); if (!isSynching()) { @@ -587,7 +595,7 @@ SHAMap::addKnownNode( (iNodeID.getDepth() < node.getDepth())) { int branch = selectBranch(iNodeID, node.getNodeID()); - assert(branch >= 0); + ASSERT(branch >= 0, "ripple::SHAMap::addKnownNode : valid branch"); auto inner = static_cast(iNode); if (inner->isEmptyBranch(branch)) { diff --git a/src/xrpld/shamap/detail/TaggedPointer.ipp b/src/xrpld/shamap/detail/TaggedPointer.ipp index 487b88e3461..3833ce58a11 100644 --- a/src/xrpld/shamap/detail/TaggedPointer.ipp +++ b/src/xrpld/shamap/detail/TaggedPointer.ipp @@ -79,14 +79,18 @@ constexpr auto chunksPerBlock = [[nodiscard]] inline std::uint8_t numAllocatedChildren(std::uint8_t n) { - assert(n <= SHAMapInnerNode::branchFactor); + ASSERT( + n <= SHAMapInnerNode::branchFactor, + "ripple::numAllocatedChildren : valid input"); return *std::lower_bound(boundaries.begin(), boundaries.end(), n); } [[nodiscard]] inline std::size_t boundariesIndex(std::uint8_t numChildren) { - assert(numChildren <= SHAMapInnerNode::branchFactor); + ASSERT( + numChildren <= SHAMapInnerNode::branchFactor, + "ripple::boundariesIndex : valid input"); return std::distance( boundaries.begin(), std::lower_bound(boundaries.begin(), boundaries.end(), numChildren)); @@ -156,7 +160,9 @@ allocateArrays(std::uint8_t numChildren) inline void deallocateArrays(std::uint8_t boundaryIndex, void* p) { - assert(isFromArrayFuns[boundaryIndex](p)); + ASSERT( + isFromArrayFuns[boundaryIndex](p), + "ripple::deallocateArrays : valid inputs"); freeArrayFuns[boundaryIndex](p); } @@ -270,10 +276,15 @@ TaggedPointer::getChildIndex(std::uint16_t isBranch, int i) const inline TaggedPointer::TaggedPointer(RawAllocateTag, std::uint8_t numChildren) { auto [tag, p] = allocateArrays(numChildren); - assert(tag < boundaries.size()); - assert( + ASSERT( + tag < boundaries.size(), + "ripple::TaggedPointer::TaggedPointer(RawAllocateTag, std::uint8_t) : " + "maximum tag"); + ASSERT( (reinterpret_cast(p) & ptrMask) == - reinterpret_cast(p)); + reinterpret_cast(p), + "ripple::TaggedPointer::TaggedPointer(RawAllocateTag, std::uint8_t) : " + "valid pointer"); tp_ = reinterpret_cast(p) + tag; } @@ -283,7 +294,10 @@ inline TaggedPointer::TaggedPointer( std::uint16_t dstBranches, std::uint8_t toAllocate) { - assert(toAllocate >= popcnt16(dstBranches)); + ASSERT( + toAllocate >= popcnt16(dstBranches), + "ripple::TaggedPointer::TaggedPointer(TaggedPointer&& ...) : minimum " + "toAllocate input"); if (other.capacity() == numAllocatedChildren(toAllocate)) { @@ -428,7 +442,10 @@ inline TaggedPointer::TaggedPointer( } } // If sparse, may need to run additional constructors - assert(!dstIsDense || dstIndex == dstNumAllocated); + ASSERT( + !dstIsDense || dstIndex == dstNumAllocated, + "ripple::TaggedPointer::TaggedPointer(TaggedPointer&& ...) : " + "non-sparse or valid sparse"); for (int i = dstIndex; i < dstNumAllocated; ++i) { new (&dstHashes[i]) SHAMapHash{}; From 8215c605b456d16ce041f5fc579e0dfdaf415576 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Tue, 3 Dec 2024 15:03:22 -0500 Subject: [PATCH 6/8] test: Check for some unlikely null dereferences in tests (#5004) --- src/test/jtx/impl/flags.cpp | 8 ++++++-- src/test/rpc/AccountSet_test.cpp | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/test/jtx/impl/flags.cpp b/src/test/jtx/impl/flags.cpp index 992e1a88bb2..6658d3eba9b 100644 --- a/src/test/jtx/impl/flags.cpp +++ b/src/test/jtx/impl/flags.cpp @@ -41,7 +41,9 @@ void flags::operator()(Env& env) const { auto const sle = env.le(account_); - if (sle->isFieldPresent(sfFlags)) + if (!sle) + env.test.fail(); + else if (sle->isFieldPresent(sfFlags)) env.test.expect((sle->getFieldU32(sfFlags) & mask_) == mask_); else env.test.expect(mask_ == 0); @@ -51,7 +53,9 @@ void nflags::operator()(Env& env) const { auto const sle = env.le(account_); - if (sle->isFieldPresent(sfFlags)) + if (!sle) + env.test.fail(); + else if (sle->isFieldPresent(sfFlags)) env.test.expect((sle->getFieldU32(sfFlags) & mask_) == 0); else env.test.pass(); diff --git a/src/test/rpc/AccountSet_test.cpp b/src/test/rpc/AccountSet_test.cpp index e5475e3f530..3c6cad00e28 100644 --- a/src/test/rpc/AccountSet_test.cpp +++ b/src/test/rpc/AccountSet_test.cpp @@ -41,7 +41,7 @@ class AccountSet_test : public beast::unit_test::suite env.fund(XRP(10000), noripple(alice)); // ask for the ledger entry - account root, to check its flags auto const jrr = env.le(alice); - BEAST_EXPECT((*env.le(alice))[sfFlags] == 0u); + BEAST_EXPECT(jrr && jrr->at(sfFlags) == 0u); } void From 47b0543461a1200a93893fa052bab870a09808c5 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Tue, 3 Dec 2024 16:13:31 -0500 Subject: [PATCH 7/8] test: Add more test cases for Base58 parser (#5174) --------- Co-authored-by: John Freeman --- include/xrpl/protocol/detail/b58_utils.h | 3 ++- src/test/protocol/types_test.cpp | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/include/xrpl/protocol/detail/b58_utils.h b/include/xrpl/protocol/detail/b58_utils.h index 960b3d8dcb6..76e470f54e7 100644 --- a/include/xrpl/protocol/detail/b58_utils.h +++ b/include/xrpl/protocol/detail/b58_utils.h @@ -177,7 +177,8 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) [[nodiscard]] inline std::array b58_10_to_b58_be(std::uint64_t input) { - constexpr std::uint64_t B_58_10 = 430804206899405824; // 58^10; + [[maybe_unused]] static constexpr std::uint64_t B_58_10 = + 430804206899405824; // 58^10; ASSERT( input < B_58_10, "ripple::b58_fast::detail::b58_10_to_b58_be : valid input"); diff --git a/src/test/protocol/types_test.cpp b/src/test/protocol/types_test.cpp index ac4314df640..8257d9c6495 100644 --- a/src/test/protocol/types_test.cpp +++ b/src/test/protocol/types_test.cpp @@ -28,8 +28,16 @@ struct types_test : public beast::unit_test::suite testAccountID() { auto const s = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - if (BEAST_EXPECT(parseBase58(s))) - BEAST_EXPECT(toBase58(*parseBase58(s)) == s); + if (auto const parsed = parseBase58(s); BEAST_EXPECT(parsed)) + { + BEAST_EXPECT(toBase58(*parsed) == s); + } + + { + auto const s = + "âabcd1rNxp4h8apvRis6mJf9Sh8C6iRxfrDWNâabcdAVâ\xc2\x80\xc2\x8f"; + BEAST_EXPECT(!parseBase58(s)); + } } void From 6d5806590958c3d3d7326b1b17323b341a678100 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Wed, 4 Dec 2024 15:33:50 -0500 Subject: [PATCH 8/8] refactor: clean up `LedgerEntry.cpp` (#5199) Refactors LedgerEntry to make it easier to read and understand. --- API-CHANGELOG.md | 14 +- src/test/rpc/LedgerRPC_test.cpp | 338 +++--- src/xrpld/net/detail/RPCCall.cpp | 18 +- src/xrpld/rpc/detail/RPCHelpers.cpp | 10 +- src/xrpld/rpc/handlers/LedgerEntry.cpp | 1535 +++++++++++++----------- 5 files changed, 1023 insertions(+), 892 deletions(-) diff --git a/API-CHANGELOG.md b/API-CHANGELOG.md index 1c0595b0081..b3691d5ddcc 100644 --- a/API-CHANGELOG.md +++ b/API-CHANGELOG.md @@ -83,11 +83,13 @@ The [commandline](https://xrpl.org/docs/references/http-websocket-apis/api-conve The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). However, use of reporting mode is now discouraged, in favor of using [Clio](https://github.com/XRPLF/clio) instead. -## XRP Ledger server version 2.2.0 +## XRP Ledger server version 2.4.0 -The following is a non-breaking addition to the API. +### Addition in 2.4 -- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781)) +- `ledger_entry`: `state` is added an alias for `ripple_state`. + +## XRP Ledger server version 2.3.0 ### Breaking change in 2.3 @@ -105,6 +107,12 @@ The following additions are non-breaking (because they are purely additive). - In `Payment` transactions, `DeliverMax` has been added. This is a replacement for the `Amount` field, which should not be used. Typically, the `delivered_amount` (in transaction metadata) should be used. To ease the transition, `DeliverMax` is present regardless of API version, since adding a field is non-breaking. - API version 2 has been moved from beta to supported, meaning that it is generally available (regardless of the `beta_rpc_api` setting). +## XRP Ledger server version 2.2.0 + +The following is a non-breaking addition to the API. + +- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781)) + ## XRP Ledger server version 1.12.0 [Version 1.12.0](https://github.com/XRPLF/rippled/releases/tag/1.12.0) was released on Sep 6, 2023. The following additions are non-breaking (because they are purely additive). diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 41657468666..41b0239fb50 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -1877,160 +1877,164 @@ class LedgerRPC_test : public beast::unit_test::suite env(pay(gw, alice, USD(97))); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; - { - // Request the trust line using the accounts and currency. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfBalance.jsonName][jss::value] == "-97"); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.jsonName][jss::value] == "999"); - } - { - // ripple_state is not an object. - Json::Value jvParams; - jvParams[jss::ripple_state] = "ripple_state"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state.currency is missing. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state accounts is not an array. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = 2; - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state one of the accounts is missing. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state more than 2 accounts. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ripple_state][jss::accounts][2u] = alice.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } + // check both aliases + for (auto const& fieldName : {jss::ripple_state, jss::state}) { - // ripple_state account[0] is not a string. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = 44; - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state account[1] is not a string. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = 21; - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state account[0] == account[1]. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = alice.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state malformed account[0]. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = - makeBadAddress(alice.human()); - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedAddress", ""); - } - { - // ripple_state malformed account[1]. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = - makeBadAddress(gw.human()); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedAddress", ""); - } - { - // ripple_state malformed currency. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ripple_state][jss::currency] = "USDollars"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedCurrency", ""); + std::string const ledgerHash{to_string(env.closed()->info().hash)}; + { + // Request the trust line using the accounts and currency. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT( + jrr[jss::node][sfBalance.jsonName][jss::value] == "-97"); + BEAST_EXPECT( + jrr[jss::node][sfHighLimit.jsonName][jss::value] == "999"); + } + { + // ripple_state is not an object. + Json::Value jvParams; + jvParams[fieldName] = "ripple_state"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state.currency is missing. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state accounts is not an array. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = 2; + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state one of the accounts is missing. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state more than 2 accounts. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[fieldName][jss::accounts][2u] = alice.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state account[0] is not a string. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = 44; + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state account[1] is not a string. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = 21; + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state account[0] == account[1]. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = alice.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state malformed account[0]. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = + makeBadAddress(alice.human()); + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedAddress", ""); + } + { + // ripple_state malformed account[1]. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = + makeBadAddress(gw.human()); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedAddress", ""); + } + { + // ripple_state malformed currency. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[fieldName][jss::currency] = "USDollars"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedCurrency", ""); + } } } @@ -3055,6 +3059,33 @@ class LedgerRPC_test : public beast::unit_test::suite } } + void + testLedgerEntryCLI() + { + testcase("ledger_entry command-line"); + using namespace test::jtx; + + Env env{*this}; + Account const alice{"alice"}; + env.fund(XRP(10000), alice); + env.close(); + + auto const checkId = keylet::check(env.master, env.seq(env.master)); + + env(check::create(env.master, alice, XRP(100))); + env.close(); + + std::string const ledgerHash{to_string(env.closed()->info().hash)}; + { + // Request a check. + Json::Value const jrr = + env.rpc("ledger_entry", to_string(checkId.key))[jss::result]; + BEAST_EXPECT( + jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check); + BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] == "100000000"); + } + } + public: void run() override @@ -3085,6 +3116,7 @@ class LedgerRPC_test : public beast::unit_test::suite testInvalidOracleLedgerEntry(); testOracleLedgerEntry(); testLedgerEntryMPT(); + testLedgerEntryCLI(); forAllApiVersions(std::bind_front( &LedgerRPC_test::testLedgerEntryInvalidParams, this)); diff --git a/src/xrpld/net/detail/RPCCall.cpp b/src/xrpld/net/detail/RPCCall.cpp index 06989765108..bbcd4fd52c1 100644 --- a/src/xrpld/net/detail/RPCCall.cpp +++ b/src/xrpld/net/detail/RPCCall.cpp @@ -668,6 +668,21 @@ class RPCParser return jvRequest; } + // ledger_entry [id] [] + Json::Value + parseLedgerEntry(Json::Value const& jvParams) + { + Json::Value jvRequest{Json::objectValue}; + + jvRequest[jss::index] = jvParams[0u].asString(); + + if (jvParams.size() == 2 && + !jvParseLedger(jvRequest, jvParams[1u].asString())) + return rpcError(rpcLGR_IDX_MALFORMED); + + return jvRequest; + } + // log_level: Get log levels // log_level : Set master log level to the // specified severity log_level : Set specified @@ -1183,8 +1198,7 @@ class RPCParser {"ledger_accept", &RPCParser::parseAsIs, 0, 0}, {"ledger_closed", &RPCParser::parseAsIs, 0, 0}, {"ledger_current", &RPCParser::parseAsIs, 0, 0}, - // { "ledger_entry", &RPCParser::parseLedgerEntry, - // -1, -1 }, + {"ledger_entry", &RPCParser::parseLedgerEntry, 1, 2}, {"ledger_header", &RPCParser::parseLedgerId, 1, 1}, {"ledger_request", &RPCParser::parseLedgerId, 1, 1}, {"log_level", &RPCParser::parseLogLevel, 0, 2}, diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index 6ab8cee27e2..60eff492dc9 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -947,20 +947,20 @@ chooseLedgerEntryType(Json::Value const& params) {jss::escrow, ltESCROW}, {jss::fee, ltFEE_SETTINGS}, {jss::hashes, ltLEDGER_HASHES}, - {jss::nunl, ltNEGATIVE_UNL}, - {jss::oracle, ltORACLE}, + {jss::mpt_issuance, ltMPTOKEN_ISSUANCE}, + {jss::mptoken, ltMPTOKEN}, {jss::nft_offer, ltNFTOKEN_OFFER}, {jss::nft_page, ltNFTOKEN_PAGE}, + {jss::nunl, ltNEGATIVE_UNL}, {jss::offer, ltOFFER}, + {jss::oracle, ltORACLE}, {jss::payment_channel, ltPAYCHAN}, {jss::signer_list, ltSIGNER_LIST}, {jss::state, ltRIPPLE_STATE}, {jss::ticket, ltTICKET}, {jss::xchain_owned_claim_id, ltXCHAIN_OWNED_CLAIM_ID}, {jss::xchain_owned_create_account_claim_id, - ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}, - {jss::mpt_issuance, ltMPTOKEN_ISSUANCE}, - {jss::mptoken, ltMPTOKEN}}}; + ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}}}; auto const& p = params[jss::type]; if (!p.isString()) diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index 5d03bbb189d..4401b4dacd0 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace ripple { @@ -66,814 +67,890 @@ parseAuthorizeCredentials(Json::Value const& jv) return arr; } -// { -// ledger_hash : -// ledger_index : -// ... -// } -Json::Value -doLedgerEntry(RPC::JsonContext& context) +std::optional +parseIndex(Json::Value const& params, Json::Value& jvResult) { - std::shared_ptr lpLedger; - auto jvResult = RPC::lookupLedger(lpLedger, context); + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } - if (!lpLedger) - return jvResult; + return uNodeIndex; +} +std::optional +parseAccountRoot(Json::Value const& params, Json::Value& jvResult) +{ + auto const account = parseBase58(params.asString()); + if (!account || account->isZero()) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + return keylet::account(*account).key; +} + +std::optional +parseCheck(Json::Value const& params, Json::Value& jvResult) +{ uint256 uNodeIndex; - bool bNodeBinary = false; - LedgerEntryType expectedType = ltANY; + if (!uNodeIndex.parseHex(params.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } - try + return uNodeIndex; +} + +std::optional +parseDepositPreauth(Json::Value const& dp, Json::Value& jvResult) +{ + if (!dp.isObject()) { - if (context.params.isMember(jss::index)) + uint256 uNodeIndex; + if (!dp.isString() || !uNodeIndex.parseHex(dp.asString())) { - if (!uNodeIndex.parseHex(context.params[jss::index].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::account_root)) + return uNodeIndex; + } + + // clang-format off + if ( + (!dp.isMember(jss::owner) || !dp[jss::owner].isString()) || + (dp.isMember(jss::authorized) == dp.isMember(jss::authorized_credentials)) || + (dp.isMember(jss::authorized) && !dp[jss::authorized].isString()) || + (dp.isMember(jss::authorized_credentials) && !dp[jss::authorized_credentials].isArray()) + ) + // clang-format on + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const owner = parseBase58(dp[jss::owner].asString()); + if (!owner) + { + jvResult[jss::error] = "malformedOwner"; + return std::nullopt; + } + + if (dp.isMember(jss::authorized)) + { + auto const authorized = + parseBase58(dp[jss::authorized].asString()); + if (!authorized) { - expectedType = ltACCOUNT_ROOT; - auto const account = parseBase58( - context.params[jss::account_root].asString()); - if (!account || account->isZero()) - jvResult[jss::error] = "malformedAddress"; - else - uNodeIndex = keylet::account(*account).key; + jvResult[jss::error] = "malformedAuthorized"; + return std::nullopt; } - else if (context.params.isMember(jss::check)) + return keylet::depositPreauth(*owner, *authorized).key; + } + + auto const& ac(dp[jss::authorized_credentials]); + STArray const arr = parseAuthorizeCredentials(ac); + + if (arr.empty() || (arr.size() > maxCredentialsArraySize)) + { + jvResult[jss::error] = "malformedAuthorizedCredentials"; + return std::nullopt; + } + + auto const& sorted = credentials::makeSorted(arr); + if (sorted.empty()) + { + jvResult[jss::error] = "malformedAuthorizedCredentials"; + return std::nullopt; + } + + return keylet::depositPreauth(*owner, sorted).key; +} + +std::optional +parseDirectory(Json::Value const& params, Json::Value& jvResult) +{ + if (params.isNull()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) { - expectedType = ltCHECK; - if (!uNodeIndex.parseHex(context.params[jss::check].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::deposit_preauth)) - { - expectedType = ltDEPOSIT_PREAUTH; - auto const& dp = context.params[jss::deposit_preauth]; + return uNodeIndex; + } - if (!dp.isObject()) - { - if (!dp.isString() || !uNodeIndex.parseHex(dp.asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - // clang-format off - else if ( - (!dp.isMember(jss::owner) || !dp[jss::owner].isString()) || - (dp.isMember(jss::authorized) == dp.isMember(jss::authorized_credentials)) || - (dp.isMember(jss::authorized) && !dp[jss::authorized].isString()) || - (dp.isMember(jss::authorized_credentials) && !dp[jss::authorized_credentials].isArray()) - ) - // clang-format on - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const owner = - parseBase58(dp[jss::owner].asString()); - if (!owner) - { - jvResult[jss::error] = "malformedOwner"; - } - else if (dp.isMember(jss::authorized)) - { - auto const authorized = - parseBase58(dp[jss::authorized].asString()); - if (!authorized) - jvResult[jss::error] = "malformedAuthorized"; - else - uNodeIndex = - keylet::depositPreauth(*owner, *authorized).key; - } - else - { - auto const& ac(dp[jss::authorized_credentials]); - STArray const arr = parseAuthorizeCredentials(ac); - - if (arr.empty() || (arr.size() > maxCredentialsArraySize)) - jvResult[jss::error] = "malformedAuthorizedCredentials"; - else - { - auto sorted = credentials::makeSorted(arr); - if (sorted.empty()) - jvResult[jss::error] = - "malformedAuthorizedCredentials"; - else - uNodeIndex = - keylet::depositPreauth(*owner, sorted).key; - } - } - } - } - else if (context.params.isMember(jss::directory)) + if (params.isMember(jss::sub_index) && !params[jss::sub_index].isIntegral()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + std::uint64_t uSubIndex = + params.isMember(jss::sub_index) ? params[jss::sub_index].asUInt() : 0; + + if (params.isMember(jss::dir_root)) + { + uint256 uDirRoot; + + if (params.isMember(jss::owner)) { - expectedType = ltDIR_NODE; - if (context.params[jss::directory].isNull()) - { - jvResult[jss::error] = "malformedRequest"; - } - else if (!context.params[jss::directory].isObject()) - { - if (!uNodeIndex.parseHex( - context.params[jss::directory].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - context.params[jss::directory].isMember(jss::sub_index) && - !context.params[jss::directory][jss::sub_index].isIntegral()) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - std::uint64_t uSubIndex = - context.params[jss::directory].isMember(jss::sub_index) - ? context.params[jss::directory][jss::sub_index].asUInt() - : 0; + // May not specify both dir_root and owner. + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } - if (context.params[jss::directory].isMember(jss::dir_root)) - { - uint256 uDirRoot; - - if (context.params[jss::directory].isMember(jss::owner)) - { - // May not specify both dir_root and owner. - jvResult[jss::error] = "malformedRequest"; - } - else if (!uDirRoot.parseHex( - context.params[jss::directory][jss::dir_root] - .asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - else - { - uNodeIndex = keylet::page(uDirRoot, uSubIndex).key; - } - } - else if (context.params[jss::directory].isMember(jss::owner)) - { - auto const ownerID = parseBase58( - context.params[jss::directory][jss::owner].asString()); - - if (!ownerID) - { - jvResult[jss::error] = "malformedAddress"; - } - else - { - uNodeIndex = - keylet::page(keylet::ownerDir(*ownerID), uSubIndex) - .key; - } - } - else - { - jvResult[jss::error] = "malformedRequest"; - } - } + if (!uDirRoot.parseHex(params[jss::dir_root].asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::escrow)) + return keylet::page(uDirRoot, uSubIndex).key; + } + + if (params.isMember(jss::owner)) + { + auto const ownerID = + parseBase58(params[jss::owner].asString()); + + if (!ownerID) { - expectedType = ltESCROW; - if (!context.params[jss::escrow].isObject()) - { - if (!uNodeIndex.parseHex( - context.params[jss::escrow].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !context.params[jss::escrow].isMember(jss::owner) || - !context.params[jss::escrow].isMember(jss::seq) || - !context.params[jss::escrow][jss::seq].isIntegral()) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const id = parseBase58( - context.params[jss::escrow][jss::owner].asString()); - if (!id) - jvResult[jss::error] = "malformedOwner"; - else - uNodeIndex = - keylet::escrow( - *id, context.params[jss::escrow][jss::seq].asUInt()) - .key; - } + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; } - else if (context.params.isMember(jss::offer)) + + return keylet::page(keylet::ownerDir(*ownerID), uSubIndex).key; + } + + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; +} + +std::optional +parseEscrow(Json::Value const& params, Json::Value& jvResult) +{ + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) { - expectedType = ltOFFER; - if (!context.params[jss::offer].isObject()) - { - if (!uNodeIndex.parseHex(context.params[jss::offer].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !context.params[jss::offer].isMember(jss::account) || - !context.params[jss::offer].isMember(jss::seq) || - !context.params[jss::offer][jss::seq].isIntegral()) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const id = parseBase58( - context.params[jss::offer][jss::account].asString()); - if (!id) - jvResult[jss::error] = "malformedAddress"; - else - uNodeIndex = - keylet::offer( - *id, context.params[jss::offer][jss::seq].asUInt()) - .key; - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::payment_channel)) + + return uNodeIndex; + } + + if (!params.isMember(jss::owner) || !params.isMember(jss::seq) || + !params[jss::seq].isIntegral()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const id = parseBase58(params[jss::owner].asString()); + + if (!id) + { + jvResult[jss::error] = "malformedOwner"; + return std::nullopt; + } + + return keylet::escrow(*id, params[jss::seq].asUInt()).key; +} + +std::optional +parseOffer(Json::Value const& params, Json::Value& jvResult) +{ + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) { - expectedType = ltPAYCHAN; + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + return uNodeIndex; + } - if (!uNodeIndex.parseHex( - context.params[jss::payment_channel].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } + if (!params.isMember(jss::account) || !params.isMember(jss::seq) || + !params[jss::seq].isIntegral()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const id = parseBase58(params[jss::account].asString()); + if (!id) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + return keylet::offer(*id, params[jss::seq].asUInt()).key; +} + +std::optional +parsePaymentChannel(Json::Value const& params, Json::Value& jvResult) +{ + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + return uNodeIndex; +} + +std::optional +parseRippleState(Json::Value const& jvRippleState, Json::Value& jvResult) +{ + Currency uCurrency; + + if (!jvRippleState.isObject() || !jvRippleState.isMember(jss::currency) || + !jvRippleState.isMember(jss::accounts) || + !jvRippleState[jss::accounts].isArray() || + 2 != jvRippleState[jss::accounts].size() || + !jvRippleState[jss::accounts][0u].isString() || + !jvRippleState[jss::accounts][1u].isString() || + (jvRippleState[jss::accounts][0u].asString() == + jvRippleState[jss::accounts][1u].asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const id1 = + parseBase58(jvRippleState[jss::accounts][0u].asString()); + auto const id2 = + parseBase58(jvRippleState[jss::accounts][1u].asString()); + if (!id1 || !id2) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + if (!to_currency(uCurrency, jvRippleState[jss::currency].asString())) + { + jvResult[jss::error] = "malformedCurrency"; + return std::nullopt; + } + + return keylet::line(*id1, *id2, uCurrency).key; +} + +std::optional +parseTicket(Json::Value const& params, Json::Value& jvResult) +{ + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::ripple_state)) + return uNodeIndex; + } + + if (!params.isMember(jss::account) || !params.isMember(jss::ticket_seq) || + !params[jss::ticket_seq].isIntegral()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const id = parseBase58(params[jss::account].asString()); + if (!id) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + return getTicketIndex(*id, params[jss::ticket_seq].asUInt()); +} + +std::optional +parseNFTokenPage(Json::Value const& params, Json::Value& jvResult) +{ + if (params.isString()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) { - expectedType = ltRIPPLE_STATE; - Currency uCurrency; - Json::Value jvRippleState = context.params[jss::ripple_state]; - - if (!jvRippleState.isObject() || - !jvRippleState.isMember(jss::currency) || - !jvRippleState.isMember(jss::accounts) || - !jvRippleState[jss::accounts].isArray() || - 2 != jvRippleState[jss::accounts].size() || - !jvRippleState[jss::accounts][0u].isString() || - !jvRippleState[jss::accounts][1u].isString() || - (jvRippleState[jss::accounts][0u].asString() == - jvRippleState[jss::accounts][1u].asString())) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const id1 = parseBase58( - jvRippleState[jss::accounts][0u].asString()); - auto const id2 = parseBase58( - jvRippleState[jss::accounts][1u].asString()); - if (!id1 || !id2) - { - jvResult[jss::error] = "malformedAddress"; - } - else if (!to_currency( - uCurrency, - jvRippleState[jss::currency].asString())) - { - jvResult[jss::error] = "malformedCurrency"; - } - else - { - uNodeIndex = keylet::line(*id1, *id2, uCurrency).key; - } - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::ticket)) + return uNodeIndex; + } + + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; +} + +std::optional +parseAMM(Json::Value const& params, Json::Value& jvResult) +{ + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) { - expectedType = ltTICKET; - if (!context.params[jss::ticket].isObject()) - { - if (!uNodeIndex.parseHex( - context.params[jss::ticket].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !context.params[jss::ticket].isMember(jss::account) || - !context.params[jss::ticket].isMember(jss::ticket_seq) || - !context.params[jss::ticket][jss::ticket_seq].isIntegral()) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const id = parseBase58( - context.params[jss::ticket][jss::account].asString()); - if (!id) - jvResult[jss::error] = "malformedAddress"; - else - uNodeIndex = getTicketIndex( - *id, - context.params[jss::ticket][jss::ticket_seq].asUInt()); - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::nft_page)) + return uNodeIndex; + } + + if (!params.isMember(jss::asset) || !params.isMember(jss::asset2)) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + try + { + auto const issue = issueFromJson(params[jss::asset]); + auto const issue2 = issueFromJson(params[jss::asset2]); + return keylet::amm(issue, issue2).key; + } + catch (std::runtime_error const&) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } +} + +std::optional +parseBridge(Json::Value const& params, Json::Value& jvResult) +{ + // return the keylet for the specified bridge or nullopt if the + // request is malformed + auto const maybeKeylet = [&]() -> std::optional { + try { - expectedType = ltNFTOKEN_PAGE; + if (!params.isMember(jss::bridge_account)) + return std::nullopt; - if (context.params[jss::nft_page].isString()) + auto const& jsBridgeAccount = params[jss::bridge_account]; + if (!jsBridgeAccount.isString()) { - if (!uNodeIndex.parseHex( - context.params[jss::nft_page].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } + return std::nullopt; } - else + + auto const account = + parseBase58(jsBridgeAccount.asString()); + if (!account || account->isZero()) { - jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } + + // This may throw and is the reason for the `try` block. The + // try block has a larger scope so the `bridge` variable + // doesn't need to be an optional. + STXChainBridge const bridge(params[jss::bridge]); + STXChainBridge::ChainType const chainType = + STXChainBridge::srcChain(account == bridge.lockingChainDoor()); + + if (account != bridge.door(chainType)) + return std::nullopt; + + return keylet::bridge(bridge, chainType); } - else if (context.params.isMember(jss::amm)) + catch (...) { - expectedType = ltAMM; - if (!context.params[jss::amm].isObject()) - { - if (!uNodeIndex.parseHex(context.params[jss::amm].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !context.params[jss::amm].isMember(jss::asset) || - !context.params[jss::amm].isMember(jss::asset2)) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - try - { - auto const issue = - issueFromJson(context.params[jss::amm][jss::asset]); - auto const issue2 = - issueFromJson(context.params[jss::amm][jss::asset2]); - uNodeIndex = keylet::amm(issue, issue2).key; - } - catch (std::runtime_error const&) - { - jvResult[jss::error] = "malformedRequest"; - } - } + return std::nullopt; } - else if (context.params.isMember(jss::bridge)) + }(); + + if (maybeKeylet) + { + return maybeKeylet->key; + } + + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; +} + +std::optional +parseXChainOwnedClaimID(Json::Value const& claim_id, Json::Value& jvResult) +{ + if (claim_id.isString()) + { + uint256 uNodeIndex; + // we accept a node id as specifier of a xchain claim id + if (!uNodeIndex.parseHex(claim_id.asString())) { - expectedType = ltBRIDGE; + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + return uNodeIndex; + } - // return the keylet for the specified bridge or nullopt if the - // request is malformed - auto const maybeKeylet = [&]() -> std::optional { - try - { - if (!context.params.isMember(jss::bridge_account)) - return std::nullopt; - - auto const& jsBridgeAccount = - context.params[jss::bridge_account]; - if (!jsBridgeAccount.isString()) - { - return std::nullopt; - } - auto const account = - parseBase58(jsBridgeAccount.asString()); - if (!account || account->isZero()) - { - return std::nullopt; - } - - // This may throw and is the reason for the `try` block. The - // try block has a larger scope so the `bridge` variable - // doesn't need to be an optional. - STXChainBridge const bridge(context.params[jss::bridge]); - STXChainBridge::ChainType const chainType = - STXChainBridge::srcChain( - account == bridge.lockingChainDoor()); - if (account != bridge.door(chainType)) - return std::nullopt; - - return keylet::bridge(bridge, chainType); - } - catch (...) - { - return std::nullopt; - } - }(); + if (!claim_id.isObject() || + !(claim_id.isMember(sfIssuingChainDoor.getJsonName()) && + claim_id[sfIssuingChainDoor.getJsonName()].isString()) || + !(claim_id.isMember(sfLockingChainDoor.getJsonName()) && + claim_id[sfLockingChainDoor.getJsonName()].isString()) || + !claim_id.isMember(sfIssuingChainIssue.getJsonName()) || + !claim_id.isMember(sfLockingChainIssue.getJsonName()) || + !claim_id.isMember(jss::xchain_owned_claim_id)) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } - if (maybeKeylet) - { - uNodeIndex = maybeKeylet->key; - } - else - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } + // if not specified with a node id, a claim_id is specified by + // four strings defining the bridge (locking_chain_door, + // locking_chain_issue, issuing_chain_door, issuing_chain_issue) + // and the claim id sequence number. + auto const lockingChainDoor = parseBase58( + claim_id[sfLockingChainDoor.getJsonName()].asString()); + auto const issuingChainDoor = parseBase58( + claim_id[sfIssuingChainDoor.getJsonName()].asString()); + Issue lockingChainIssue, issuingChainIssue; + bool valid = lockingChainDoor && issuingChainDoor; + + if (valid) + { + try + { + lockingChainIssue = + issueFromJson(claim_id[sfLockingChainIssue.getJsonName()]); + issuingChainIssue = + issueFromJson(claim_id[sfIssuingChainIssue.getJsonName()]); } - else if (context.params.isMember(jss::xchain_owned_claim_id)) + catch (std::runtime_error const& ex) { - expectedType = ltXCHAIN_OWNED_CLAIM_ID; - auto& claim_id = context.params[jss::xchain_owned_claim_id]; - if (claim_id.isString()) - { - // we accept a node id as specifier of a xchain claim id - if (!uNodeIndex.parseHex(claim_id.asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !claim_id.isObject() || - !(claim_id.isMember(sfIssuingChainDoor.getJsonName()) && - claim_id[sfIssuingChainDoor.getJsonName()].isString()) || - !(claim_id.isMember(sfLockingChainDoor.getJsonName()) && - claim_id[sfLockingChainDoor.getJsonName()].isString()) || - !claim_id.isMember(sfIssuingChainIssue.getJsonName()) || - !claim_id.isMember(sfLockingChainIssue.getJsonName()) || - !claim_id.isMember(jss::xchain_owned_claim_id)) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - // if not specified with a node id, a claim_id is specified by - // four strings defining the bridge (locking_chain_door, - // locking_chain_issue, issuing_chain_door, issuing_chain_issue) - // and the claim id sequence number. - auto lockingChainDoor = parseBase58( - claim_id[sfLockingChainDoor.getJsonName()].asString()); - auto issuingChainDoor = parseBase58( - claim_id[sfIssuingChainDoor.getJsonName()].asString()); - Issue lockingChainIssue, issuingChainIssue; - bool valid = lockingChainDoor && issuingChainDoor; - if (valid) - { - try - { - lockingChainIssue = issueFromJson( - claim_id[sfLockingChainIssue.getJsonName()]); - issuingChainIssue = issueFromJson( - claim_id[sfIssuingChainIssue.getJsonName()]); - } - catch (std::runtime_error const& ex) - { - valid = false; - jvResult[jss::error] = "malformedRequest"; - } - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + } - if (valid && claim_id[jss::xchain_owned_claim_id].isIntegral()) - { - auto seq = claim_id[jss::xchain_owned_claim_id].asUInt(); - - STXChainBridge bridge_spec( - *lockingChainDoor, - lockingChainIssue, - *issuingChainDoor, - issuingChainIssue); - Keylet keylet = keylet::xChainClaimID(bridge_spec, seq); - uNodeIndex = keylet.key; - } - } + if (valid && claim_id[jss::xchain_owned_claim_id].isIntegral()) + { + auto const seq = claim_id[jss::xchain_owned_claim_id].asUInt(); + + STXChainBridge bridge_spec( + *lockingChainDoor, + lockingChainIssue, + *issuingChainDoor, + issuingChainIssue); + Keylet keylet = keylet::xChainClaimID(bridge_spec, seq); + return keylet.key; + } + + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; +} + +std::optional +parseXChainOwnedCreateAccountClaimID( + Json::Value const& claim_id, + Json::Value& jvResult) +{ + if (claim_id.isString()) + { + uint256 uNodeIndex; + // we accept a node id as specifier of a xchain create account + // claim_id + if (!uNodeIndex.parseHex(claim_id.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember( - jss::xchain_owned_create_account_claim_id)) + return uNodeIndex; + } + + if (!claim_id.isObject() || + !(claim_id.isMember(sfIssuingChainDoor.getJsonName()) && + claim_id[sfIssuingChainDoor.getJsonName()].isString()) || + !(claim_id.isMember(sfLockingChainDoor.getJsonName()) && + claim_id[sfLockingChainDoor.getJsonName()].isString()) || + !claim_id.isMember(sfIssuingChainIssue.getJsonName()) || + !claim_id.isMember(sfLockingChainIssue.getJsonName()) || + !claim_id.isMember(jss::xchain_owned_create_account_claim_id)) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + // if not specified with a node id, a create account claim_id is + // specified by four strings defining the bridge + // (locking_chain_door, locking_chain_issue, issuing_chain_door, + // issuing_chain_issue) and the create account claim id sequence + // number. + auto const lockingChainDoor = parseBase58( + claim_id[sfLockingChainDoor.getJsonName()].asString()); + auto const issuingChainDoor = parseBase58( + claim_id[sfIssuingChainDoor.getJsonName()].asString()); + Issue lockingChainIssue, issuingChainIssue; + bool valid = lockingChainDoor && issuingChainDoor; + if (valid) + { + try { - // see object definition in LedgerFormats.cpp - expectedType = ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID; - auto& claim_id = - context.params[jss::xchain_owned_create_account_claim_id]; - if (claim_id.isString()) - { - // we accept a node id as specifier of a xchain create account - // claim_id - if (!uNodeIndex.parseHex(claim_id.asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !claim_id.isObject() || - !(claim_id.isMember(sfIssuingChainDoor.getJsonName()) && - claim_id[sfIssuingChainDoor.getJsonName()].isString()) || - !(claim_id.isMember(sfLockingChainDoor.getJsonName()) && - claim_id[sfLockingChainDoor.getJsonName()].isString()) || - !claim_id.isMember(sfIssuingChainIssue.getJsonName()) || - !claim_id.isMember(sfLockingChainIssue.getJsonName()) || - !claim_id.isMember(jss::xchain_owned_create_account_claim_id)) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - // if not specified with a node id, a create account claim_id is - // specified by four strings defining the bridge - // (locking_chain_door, locking_chain_issue, issuing_chain_door, - // issuing_chain_issue) and the create account claim id sequence - // number. - auto lockingChainDoor = parseBase58( - claim_id[sfLockingChainDoor.getJsonName()].asString()); - auto issuingChainDoor = parseBase58( - claim_id[sfIssuingChainDoor.getJsonName()].asString()); - Issue lockingChainIssue, issuingChainIssue; - bool valid = lockingChainDoor && issuingChainDoor; - if (valid) - { - try - { - lockingChainIssue = issueFromJson( - claim_id[sfLockingChainIssue.getJsonName()]); - issuingChainIssue = issueFromJson( - claim_id[sfIssuingChainIssue.getJsonName()]); - } - catch (std::runtime_error const& ex) - { - valid = false; - jvResult[jss::error] = "malformedRequest"; - } - } + lockingChainIssue = + issueFromJson(claim_id[sfLockingChainIssue.getJsonName()]); + issuingChainIssue = + issueFromJson(claim_id[sfIssuingChainIssue.getJsonName()]); + } + catch (std::runtime_error const& ex) + { + valid = false; + jvResult[jss::error] = "malformedRequest"; + } + } - if (valid && - claim_id[jss::xchain_owned_create_account_claim_id] - .isIntegral()) - { - auto seq = - claim_id[jss::xchain_owned_create_account_claim_id] - .asUInt(); - - STXChainBridge bridge_spec( - *lockingChainDoor, - lockingChainIssue, - *issuingChainDoor, - issuingChainIssue); - Keylet keylet = - keylet::xChainCreateAccountClaimID(bridge_spec, seq); - uNodeIndex = keylet.key; - } - } + if (valid && + claim_id[jss::xchain_owned_create_account_claim_id].isIntegral()) + { + auto const seq = + claim_id[jss::xchain_owned_create_account_claim_id].asUInt(); + + STXChainBridge bridge_spec( + *lockingChainDoor, + lockingChainIssue, + *issuingChainDoor, + issuingChainIssue); + Keylet keylet = keylet::xChainCreateAccountClaimID(bridge_spec, seq); + return keylet.key; + } + + return std::nullopt; +} + +std::optional +parseDID(Json::Value const& params, Json::Value& jvResult) +{ + auto const account = parseBase58(params.asString()); + if (!account || account->isZero()) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + return keylet::did(*account).key; +} + +std::optional +parseOracle(Json::Value const& params, Json::Value& jvResult) +{ + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::did)) + return uNodeIndex; + } + + if (!params.isMember(jss::oracle_document_id) || + !params.isMember(jss::account)) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const& oracle = params; + auto const documentID = [&]() -> std::optional { + auto const id = oracle[jss::oracle_document_id]; + if (id.isUInt() || (id.isInt() && id.asInt() >= 0)) + return std::make_optional(id.asUInt()); + + if (id.isString()) { - expectedType = ltDID; - auto const account = - parseBase58(context.params[jss::did].asString()); - if (!account || account->isZero()) - jvResult[jss::error] = "malformedAddress"; - else - uNodeIndex = keylet::did(*account).key; + std::uint32_t v; + if (beast::lexicalCastChecked(v, id.asString())) + return std::make_optional(v); } - else if (context.params.isMember(jss::oracle)) + + return std::nullopt; + }(); + + auto const account = + parseBase58(oracle[jss::account].asString()); + if (!account || account->isZero()) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + if (!documentID) + { + jvResult[jss::error] = "malformedDocumentID"; + return std::nullopt; + } + + return keylet::oracle(*account, *documentID).key; +} + +std::optional +parseCredential(Json::Value const& cred, Json::Value& jvResult) +{ + if (cred.isString()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(cred.asString())) { - expectedType = ltORACLE; - if (!context.params[jss::oracle].isObject()) - { - if (!uNodeIndex.parseHex( - context.params[jss::oracle].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !context.params[jss::oracle].isMember( - jss::oracle_document_id) || - !context.params[jss::oracle].isMember(jss::account)) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - uNodeIndex = beast::zero; - auto const& oracle = context.params[jss::oracle]; - auto const documentID = [&]() -> std::optional { - auto const& id = oracle[jss::oracle_document_id]; - if (id.isUInt() || (id.isInt() && id.asInt() >= 0)) - return std::make_optional(id.asUInt()); - else if (id.isString()) - { - std::uint32_t v; - if (beast::lexicalCastChecked(v, id.asString())) - return std::make_optional(v); - } - return std::nullopt; - }(); - auto const account = - parseBase58(oracle[jss::account].asString()); - if (!account || account->isZero()) - jvResult[jss::error] = "malformedAddress"; - else if (!documentID) - jvResult[jss::error] = "malformedDocumentID"; - else - uNodeIndex = keylet::oracle(*account, *documentID).key; - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::credential)) + return uNodeIndex; + } + + if ((!cred.isMember(jss::subject) || !cred[jss::subject].isString()) || + (!cred.isMember(jss::issuer) || !cred[jss::issuer].isString()) || + (!cred.isMember(jss::credential_type) || + !cred[jss::credential_type].isString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const subject = parseBase58(cred[jss::subject].asString()); + auto const issuer = parseBase58(cred[jss::issuer].asString()); + auto const credType = strUnHex(cred[jss::credential_type].asString()); + + if (!subject || subject->isZero() || !issuer || issuer->isZero() || + !credType || credType->empty()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + return keylet::credential( + *subject, *issuer, Slice(credType->data(), credType->size())) + .key; +} + +std::optional +parseMPTokenIssuance( + Json::Value const& unparsedMPTIssuanceID, + Json::Value& jvResult) +{ + if (unparsedMPTIssuanceID.isString()) + { + uint192 mptIssuanceID; + if (!mptIssuanceID.parseHex(unparsedMPTIssuanceID.asString())) { - expectedType = ltCREDENTIAL; - auto const& cred = context.params[jss::credential]; + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } - if (cred.isString()) - { - if (!uNodeIndex.parseHex(cred.asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - (!cred.isMember(jss::subject) || - !cred[jss::subject].isString()) || - (!cred.isMember(jss::issuer) || - !cred[jss::issuer].isString()) || - (!cred.isMember(jss::credential_type) || - !cred[jss::credential_type].isString())) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const subject = - parseBase58(cred[jss::subject].asString()); - auto const issuer = - parseBase58(cred[jss::issuer].asString()); - auto const credType = - strUnHex(cred[jss::credential_type].asString()); - if (!subject || subject->isZero() || !issuer || - issuer->isZero() || !credType || credType->empty()) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - uNodeIndex = keylet::credential( - *subject, - *issuer, - Slice(credType->data(), credType->size())) - .key; - } - } + return keylet::mptIssuance(mptIssuanceID).key; + } + + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; +} + +std::optional +parseMPToken(Json::Value const& mptJson, Json::Value& jvResult) +{ + if (!mptJson.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(mptJson.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::mpt_issuance)) + return uNodeIndex; + } + + if (!mptJson.isMember(jss::mpt_issuance_id) || + !mptJson.isMember(jss::account)) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + try + { + auto const mptIssuanceIdStr = mptJson[jss::mpt_issuance_id].asString(); + + uint192 mptIssuanceID; + if (!mptIssuanceID.parseHex(mptIssuanceIdStr)) + Throw("Cannot parse mpt_issuance_id"); + + auto const account = + parseBase58(mptJson[jss::account].asString()); + + if (!account || account->isZero()) { - expectedType = ltMPTOKEN_ISSUANCE; - auto const unparsedMPTIssuanceID = - context.params[jss::mpt_issuance]; - if (unparsedMPTIssuanceID.isString()) - { - uint192 mptIssuanceID; - if (!mptIssuanceID.parseHex(unparsedMPTIssuanceID.asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - else - uNodeIndex = keylet::mptIssuance(mptIssuanceID).key; - } - else - { - jvResult[jss::error] = "malformedRequest"; - } + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; } - else if (context.params.isMember(jss::mptoken)) + + return keylet::mptoken(mptIssuanceID, *account).key; + } + catch (std::runtime_error const&) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } +} + +using FunctionType = + std::optional (*)(Json::Value const&, Json::Value&); + +struct LedgerEntry +{ + Json::StaticString fieldName; + FunctionType parseFunction; + LedgerEntryType expectedType; +}; + +// { +// ledger_hash : +// ledger_index : +// ... +// } +Json::Value +doLedgerEntry(RPC::JsonContext& context) +{ + std::shared_ptr lpLedger; + auto jvResult = RPC::lookupLedger(lpLedger, context); + + if (!lpLedger) + return jvResult; + + static auto ledgerEntryParsers = std::to_array({ + {jss::index, parseIndex, ltANY}, + {jss::account_root, parseAccountRoot, ltACCOUNT_ROOT}, + // TODO: add amendments + {jss::amm, parseAMM, ltAMM}, + {jss::bridge, parseBridge, ltBRIDGE}, + {jss::check, parseCheck, ltCHECK}, + {jss::credential, parseCredential, ltCREDENTIAL}, + {jss::deposit_preauth, parseDepositPreauth, ltDEPOSIT_PREAUTH}, + {jss::did, parseDID, ltDID}, + {jss::directory, parseDirectory, ltDIR_NODE}, + {jss::escrow, parseEscrow, ltESCROW}, + // TODO: add fee, hashes + {jss::mpt_issuance, parseMPTokenIssuance, ltMPTOKEN_ISSUANCE}, + {jss::mptoken, parseMPToken, ltMPTOKEN}, + // TODO: add NFT Offers + {jss::nft_page, parseNFTokenPage, ltNFTOKEN_PAGE}, + // TODO: add NegativeUNL + {jss::offer, parseOffer, ltOFFER}, + {jss::oracle, parseOracle, ltORACLE}, + {jss::payment_channel, parsePaymentChannel, ltPAYCHAN}, + {jss::ripple_state, parseRippleState, ltRIPPLE_STATE}, + // This is an alias, since the `ledger_data` filter uses jss::state + {jss::state, parseRippleState, ltRIPPLE_STATE}, + {jss::ticket, parseTicket, ltTICKET}, + {jss::xchain_owned_claim_id, + parseXChainOwnedClaimID, + ltXCHAIN_OWNED_CLAIM_ID}, + {jss::xchain_owned_create_account_claim_id, + parseXChainOwnedCreateAccountClaimID, + ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}, + }); + + uint256 uNodeIndex; + LedgerEntryType expectedType = ltANY; + + try + { + bool found = false; + for (const auto& ledgerEntry : ledgerEntryParsers) { - expectedType = ltMPTOKEN; - auto const& mptJson = context.params[jss::mptoken]; - if (!mptJson.isObject()) + if (context.params.isMember(ledgerEntry.fieldName)) { - if (!uNodeIndex.parseHex(mptJson.asString())) + expectedType = ledgerEntry.expectedType; + // `Bridge` is the only type that involves two fields at the + // `ledger_entry` param level. + // So that parser needs to have the whole `params` field. + // All other parsers only need the one field name's info. + Json::Value const& params = ledgerEntry.fieldName == jss::bridge + ? context.params + : context.params[ledgerEntry.fieldName]; + uNodeIndex = ledgerEntry.parseFunction(params, jvResult) + .value_or(beast::zero); + if (jvResult.isMember(jss::error)) { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !mptJson.isMember(jss::mpt_issuance_id) || - !mptJson.isMember(jss::account)) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - try - { - auto const mptIssuanceIdStr = - mptJson[jss::mpt_issuance_id].asString(); - - uint192 mptIssuanceID; - if (!mptIssuanceID.parseHex(mptIssuanceIdStr)) - Throw( - "Cannot parse mpt_issuance_id"); - - auto const account = parseBase58( - mptJson[jss::account].asString()); - - if (!account || account->isZero()) - jvResult[jss::error] = "malformedAddress"; - else - uNodeIndex = - keylet::mptoken(mptIssuanceID, *account).key; - } - catch (std::runtime_error const&) - { - jvResult[jss::error] = "malformedRequest"; + return jvResult; } + found = true; + break; } } - else + if (!found) { - if (context.params.isMember("params") && - context.params["params"].isArray() && - context.params["params"].size() == 1 && - context.params["params"][0u].isString()) - { - if (!uNodeIndex.parseHex( - context.params["params"][0u].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } + if (context.apiVersion < 2u) + jvResult[jss::error] = "unknownOption"; else - { - if (context.apiVersion < 2u) - jvResult[jss::error] = "unknownOption"; - else - jvResult[jss::error] = "invalidParams"; - } + jvResult[jss::error] = "invalidParams"; + return jvResult; } } catch (Json::error& e) { if (context.apiVersion > 1u) { - // For apiVersion 2 onwards, any parsing failures that throw - // this + // For apiVersion 2 onwards, any parsing failures that throw this // exception return an invalidParam error. - uNodeIndex = beast::zero; jvResult[jss::error] = "invalidParams"; + return jvResult; } else throw; } - if (uNodeIndex.isNonZero()) + if (uNodeIndex.isZero()) { - auto const sleNode = lpLedger->read(keylet::unchecked(uNodeIndex)); - if (context.params.isMember(jss::binary)) - bNodeBinary = context.params[jss::binary].asBool(); + jvResult[jss::error] = "entryNotFound"; + return jvResult; + } - if (!sleNode) - { - // Not found. - jvResult[jss::error] = "entryNotFound"; - } - else if ( - (expectedType != ltANY) && (expectedType != sleNode->getType())) - { - jvResult[jss::error] = "unexpectedLedgerType"; - } - else if (bNodeBinary) - { - Serializer s; + auto const sleNode = lpLedger->read(keylet::unchecked(uNodeIndex)); - sleNode->add(s); + bool bNodeBinary = false; + if (context.params.isMember(jss::binary)) + bNodeBinary = context.params[jss::binary].asBool(); - jvResult[jss::node_binary] = strHex(s.peekData()); - jvResult[jss::index] = to_string(uNodeIndex); - } - else - { - jvResult[jss::node] = sleNode->getJson(JsonOptions::none); - jvResult[jss::index] = to_string(uNodeIndex); - } + if (!sleNode) + { + // Not found. + jvResult[jss::error] = "entryNotFound"; + return jvResult; + } + + if ((expectedType != ltANY) && (expectedType != sleNode->getType())) + { + jvResult[jss::error] = "unexpectedLedgerType"; + return jvResult; + } + + if (bNodeBinary) + { + Serializer s; + + sleNode->add(s); + + jvResult[jss::node_binary] = strHex(s.peekData()); + jvResult[jss::index] = to_string(uNodeIndex); + } + else + { + jvResult[jss::node] = sleNode->getJson(JsonOptions::none); + jvResult[jss::index] = to_string(uNodeIndex); } return jvResult; @@ -904,7 +981,7 @@ doLedgerEntryGrpc( return {response, errorStatus}; } - auto key = uint256::fromVoidChecked(request.key()); + auto const key = uint256::fromVoidChecked(request.key()); if (!key) { grpc::Status errorStatus{