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
This commit is contained in:
Bronek Kozicki
2024-12-03 14:52:21 -05:00
committed by Ed Hennis
parent f64cf9187a
commit d7e949193f
261 changed files with 3827 additions and 1034 deletions

View File

@@ -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<IOUAmount>(STAmount const& amt)
{
assert(amt.mantissa() < std::numeric_limits<std::int64_t>::max());
ASSERT(
amt.mantissa() < std::numeric_limits<std::int64_t>::max(),
"ripple::toAmount<IOUAmount> : 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<IOUAmount> : is not XRP");
return IOUAmount(sMant, amt.exponent());
}
@@ -85,12 +89,14 @@ template <>
inline XRPAmount
toAmount<XRPAmount>(STAmount const& amt)
{
assert(amt.mantissa() < std::numeric_limits<std::int64_t>::max());
ASSERT(
amt.mantissa() < std::numeric_limits<std::int64_t>::max(),
"ripple::toAmount<XRPAmount> : 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<XRPAmount> : is XRP");
return XRPAmount(sMant);
}

View File

@@ -151,14 +151,19 @@ public:
explicit FeatureBitset(base const& b) : base(b)
{
assert(b.count() == count());
ASSERT(
b.count() == count(),
"ripple::FeatureBitset::FeatureBitset(base) : count match");
}
template <class... Fs>
explicit FeatureBitset(uint256 const& f, Fs&&... fs)
{
initFromFeatures(f, std::forward<Fs>(fs)...);
assert(count() == (sizeof...(fs) + 1));
ASSERT(
count() == (sizeof...(fs) + 1),
"ripple::FeatureBitset::FeatureBitset(uint256) : count and "
"sizeof... do match");
}
template <class Col>
@@ -166,7 +171,10 @@ public:
{
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

View File

@@ -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);
}
/** @} */

View File

@@ -20,10 +20,10 @@
#ifndef RIPPLE_PROTOCOL_ISSUE_H_INCLUDED
#define RIPPLE_PROTOCOL_ISSUE_H_INCLUDED
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/UintTypes.h>
#include <cassert>
#include <functional>
#include <type_traits>

View File

@@ -23,8 +23,8 @@
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/ApiVersion.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <array>
#include <cassert>
#include <concepts>
#include <cstdlib>
#include <functional>
@@ -159,8 +159,10 @@ struct MultiApiJson
-> std::
invoke_result_t<Fn, decltype(json.val[0]), Version, Args&&...>
{
assert(
valid(version) && index(version) >= 0 && index(version) < size);
ASSERT(
valid(version) && index(version) >= 0 && index(version) < size,
"ripple::detail::MultiApiJson::operator<Args...>() : 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<Fn, decltype(json.val[0])>
{
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 = {};

View File

@@ -298,7 +298,9 @@ public:
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;

View File

@@ -20,9 +20,9 @@
#ifndef RIPPLE_PROTOCOL_RATE_H_INCLUDED
#define RIPPLE_PROTOCOL_RATE_H_INCLUDED
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/STAmount.h>
#include <boost/operators.hpp>
#include <cassert>
#include <cstdint>
#include <ostream>

View File

@@ -26,6 +26,7 @@
#include <xrpl/basics/MPTAmount.h>
#include <xrpl/basics/Number.h>
#include <xrpl/basics/XRPAmount.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STBase.h>
@@ -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<std::int64_t>::max());
ASSERT(
mValue <= std::numeric_limits<std::int64_t>::max(),
"ripple::STAmount::STAmount(SField, A, std::uint64_t, int, bool) : "
"maximum mantissa input");
canonicalize();
}

View File

@@ -170,8 +170,10 @@ template <int Bits>
void
STBitString<Bits>::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<Bits>(value_);
}

View File

@@ -23,9 +23,9 @@
#include <xrpl/basics/Buffer.h>
#include <xrpl/basics/CountedObject.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/STBase.h>
#include <cassert>
#include <cstring>
#include <memory>

View File

@@ -110,8 +110,10 @@ template <typename Integer>
inline void
STInteger<Integer>::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_);
}

View File

@@ -25,6 +25,7 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/basics/contract.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/SOTemplate.h>
#include <xrpl/protocol/STAmount.h>
@@ -35,7 +36,6 @@
#include <xrpl/protocol/STVector256.h>
#include <xrpl/protocol/detail/STVar.h>
#include <boost/iterator/transform_iterator.hpp>
#include <cassert>
#include <optional>
#include <stdexcept>
#include <type_traits>
@@ -737,7 +737,8 @@ STObject::Proxy<T>::assign(U&& u)
t = dynamic_cast<T*>(st_->getPField(*f_, true));
else
t = dynamic_cast<T*>(st_->makeFieldPresent(*f_));
assert(t);
ASSERT(
t != nullptr, "ripple::STObject::Proxy::assign : type cast succeeded");
*t = std::forward<U>(u);
}
@@ -1033,13 +1034,19 @@ STObject::at(TypedField<T> const& f) const
if (auto const u = dynamic_cast<T const*>(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<STObject::FieldErr>("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<T> const& of) const
auto const u = dynamic_cast<T const*>(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();

View File

@@ -21,11 +21,11 @@
#define RIPPLE_PROTOCOL_STPATHSET_H_INCLUDED
#include <xrpl/basics/CountedObject.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STBase.h>
#include <xrpl/protocol/UintTypes.h>
#include <cassert>
#include <cstddef>
#include <optional>
@@ -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);

View File

@@ -22,10 +22,10 @@
#include <xrpl/basics/FeeUnits.h>
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/PublicKey.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/protocol/SecretKey.h>
#include <cassert>
#include <cstdint>
#include <functional>
#include <memory>
@@ -176,7 +176,9 @@ STValidation::STValidation(
Throw<std::runtime_error>("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)

View File

@@ -27,9 +27,9 @@
#include <xrpl/basics/contract.h>
#include <xrpl/basics/safe_cast.h>
#include <xrpl/basics/strHex.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/SField.h>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iomanip>
@@ -55,7 +55,9 @@ public:
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;
}

View File

@@ -116,7 +116,9 @@ public:
STAmount
getDeliveredAmount() const
{
assert(hasDeliveredAmount());
ASSERT(
hasDeliveredAmount(),
"ripple::TxMeta::getDeliveredAmount : non-null delivered amount");
return *mDelivered;
}

View File

@@ -21,12 +21,12 @@
#define RIPPLE_PROTOCOL_B58_UTILS_H_INCLUDED
#include <xrpl/basics/contract.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/detail/token_errors.h>
#include <boost/outcome.hpp>
#include <boost/outcome/result.hpp>
#include <cassert>
#include <cinttypes>
#include <span>
#include <system_error>
@@ -130,7 +130,9 @@ inplace_bigint_div_rem(std::span<uint64_t> 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<uint64_t> 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<std::uint64_t>(d), static_cast<std::uint64_t>(r)};
};
@@ -170,7 +178,9 @@ inplace_bigint_div_rem(std::span<uint64_t> 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<std::uint8_t, resultSize> result{};
int i = 0;