feat: AmendmentCenter (#1418)

Fixes #1416
This commit is contained in:
Alex Kremer
2024-06-27 18:21:30 +01:00
committed by GitHub
parent 2ff51ff416
commit 7bd21345a1
21 changed files with 865 additions and 151 deletions

View File

@@ -0,0 +1,172 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and 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 "data/AmendmentCenter.hpp"
#include "data/BackendInterface.hpp"
#include "data/Types.hpp"
#include "util/Assert.hpp"
#include <boost/asio/spawn.hpp>
#include <fmt/compile.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/protocol/digest.h>
#include <algorithm>
#include <cstdint>
#include <iterator>
#include <map>
#include <memory>
#include <ranges>
#include <string>
#include <string_view>
#include <unordered_set>
#include <utility>
#include <vector>
namespace {
std::unordered_set<std::string>&
SUPPORTED_AMENDMENTS()
{
static std::unordered_set<std::string> amendments = {};
return amendments;
}
} // namespace
namespace data {
namespace impl {
WritingAmendmentKey::WritingAmendmentKey(std::string amendmentName) : AmendmentKey{std::move(amendmentName)}
{
ASSERT(not SUPPORTED_AMENDMENTS().contains(name), "Attempt to register the same amendment twice");
SUPPORTED_AMENDMENTS().insert(name);
}
} // namespace impl
AmendmentKey::operator std::string const&() const
{
return name;
}
AmendmentKey::operator ripple::uint256() const
{
return Amendment::GetAmendmentId(name);
}
AmendmentCenter::AmendmentCenter(std::shared_ptr<data::BackendInterface> const& backend) : backend_{backend}
{
namespace rg = std::ranges;
namespace vs = std::views;
rg::copy(
ripple::allAmendments() | vs::transform([&](auto const& p) {
auto const& [name, support] = p;
return Amendment{
.name = name,
.feature = Amendment::GetAmendmentId(name),
.isSupportedByXRPL = support != ripple::AmendmentSupport::Unsupported,
.isSupportedByClio = rg::find(SUPPORTED_AMENDMENTS(), name) != rg::end(SUPPORTED_AMENDMENTS()),
.isRetired = support == ripple::AmendmentSupport::Retired
};
}),
std::back_inserter(all_)
);
for (auto const& am : all_ | vs::filter([](auto const& am) { return am.isSupportedByClio; }))
supported_.insert_or_assign(am.name, am);
}
bool
AmendmentCenter::isSupported(AmendmentKey const& key) const
{
return supported_.contains(key);
}
std::map<std::string, Amendment> const&
AmendmentCenter::getSupported() const
{
return supported_;
}
std::vector<Amendment> const&
AmendmentCenter::getAll() const
{
return all_;
}
bool
AmendmentCenter::isEnabled(AmendmentKey const& key, uint32_t seq) const
{
return data::synchronous([this, &key, seq](auto yield) { return isEnabled(yield, key, seq); });
}
bool
AmendmentCenter::isEnabled(boost::asio::yield_context yield, AmendmentKey const& key, uint32_t seq) const
{
namespace rg = std::ranges;
// the amendments should always be present on the ledger
auto const& amendments = backend_->fetchLedgerObject(ripple::keylet::amendments().key, seq, yield);
ASSERT(amendments.has_value(), "Amendments ledger object must be present in the database");
ripple::SLE const amendmentsSLE{
ripple::SerialIter{amendments->data(), amendments->size()}, ripple::keylet::amendments().key
};
if (not amendmentsSLE.isFieldPresent(ripple::sfAmendments))
return false;
auto const listAmendments = amendmentsSLE.getFieldV256(ripple::sfAmendments);
if (auto am = rg::find(all_, key.name, [](auto const& am) { return am.name; }); am != rg::end(all_)) {
return rg::find(listAmendments, am->feature) != rg::end(listAmendments);
}
return false;
}
Amendment const&
AmendmentCenter::getAmendment(AmendmentKey const& key) const
{
ASSERT(supported_.contains(key), "The amendment '{}' must be present in supported amendments list", key.name);
return supported_.at(key);
}
Amendment const&
AmendmentCenter::operator[](AmendmentKey const& key) const
{
return getAmendment(key);
}
ripple::uint256
Amendment::GetAmendmentId(std::string_view name)
{
return ripple::sha512Half(ripple::Slice(name.data(), name.size()));
}
} // namespace data

View File

@@ -0,0 +1,234 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and 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.
*/
//==============================================================================
#pragma once
#include "data/AmendmentCenterInterface.hpp"
#include "data/BackendInterface.hpp"
#include "data/Types.hpp"
#include <boost/asio/spawn.hpp>
#include <boost/preprocessor.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/protocol/digest.h>
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <vector>
#define REGISTER(name) inline static impl::WritingAmendmentKey const name = std::string(BOOST_PP_STRINGIZE(name))
namespace data {
namespace impl {
struct WritingAmendmentKey : AmendmentKey {
WritingAmendmentKey(std::string amendmentName);
};
} // namespace impl
/**
* @brief List of supported amendments
*/
struct Amendments {
// NOTE: if Clio wants to report it supports an Amendment it should be listed here.
// Whether an amendment is obsolete and/or supported by libxrpl is extracted directly from libxrpl.
// If an amendment is in the list below it just means Clio did whatever changes needed to support it.
// Most of the time it's going to be no changes at all.
/** @cond */
REGISTER(OwnerPaysFee);
REGISTER(Flow);
REGISTER(FlowCross);
REGISTER(fix1513);
REGISTER(DepositAuth);
REGISTER(Checks);
REGISTER(fix1571);
REGISTER(fix1543);
REGISTER(fix1623);
REGISTER(DepositPreauth);
REGISTER(fix1515);
REGISTER(fix1578);
REGISTER(MultiSignReserve);
REGISTER(fixTakerDryOfferRemoval);
REGISTER(fixMasterKeyAsRegularKey);
REGISTER(fixCheckThreading);
REGISTER(fixPayChanRecipientOwnerDir);
REGISTER(DeletableAccounts);
REGISTER(fixQualityUpperBound);
REGISTER(RequireFullyCanonicalSig);
REGISTER(fix1781);
REGISTER(HardenedValidations);
REGISTER(fixAmendmentMajorityCalc);
REGISTER(NegativeUNL);
REGISTER(TicketBatch);
REGISTER(FlowSortStrands);
REGISTER(fixSTAmountCanonicalize);
REGISTER(fixRmSmallIncreasedQOffers);
REGISTER(CheckCashMakesTrustLine);
REGISTER(ExpandedSignerList);
REGISTER(NonFungibleTokensV1_1);
REGISTER(fixTrustLinesToSelf);
REGISTER(fixRemoveNFTokenAutoTrustLine);
REGISTER(ImmediateOfferKilled);
REGISTER(DisallowIncoming);
REGISTER(XRPFees);
REGISTER(fixUniversalNumber);
REGISTER(fixNonFungibleTokensV1_2);
REGISTER(fixNFTokenRemint);
REGISTER(fixReducedOffersV1);
REGISTER(Clawback);
REGISTER(AMM);
REGISTER(XChainBridge);
REGISTER(fixDisallowIncomingV1);
REGISTER(DID);
REGISTER(fixFillOrKill);
REGISTER(fixNFTokenReserve);
REGISTER(fixInnerObjTemplate);
REGISTER(fixAMMOverflowOffer);
REGISTER(PriceOracle);
REGISTER(fixEmptyDID);
REGISTER(fixXChainRewardRounding);
REGISTER(fixPreviousTxnID);
REGISTER(fixAMMv1_1);
REGISTER(NFTokenMintOffer);
REGISTER(fixReducedOffersV2);
REGISTER(fixEnforceNFTokenTrustline);
// Obsolete but supported by libxrpl
REGISTER(CryptoConditionsSuite);
REGISTER(NonFungibleTokensV1);
REGISTER(fixNFTokenDirV1);
REGISTER(fixNFTokenNegOffer);
// Retired amendments
REGISTER(MultiSign);
REGISTER(TrustSetAuth);
REGISTER(FeeEscalation);
REGISTER(PayChan);
REGISTER(fix1368);
REGISTER(CryptoConditions);
REGISTER(Escrow);
REGISTER(TickSize);
REGISTER(fix1373);
REGISTER(EnforceInvariants);
REGISTER(SortedDirectories);
REGISTER(fix1201);
REGISTER(fix1512);
REGISTER(fix1523);
REGISTER(fix1528);
/** @endcond */
};
#undef REGISTER
/**
* @brief Knowledge center for amendments within XRPL
*/
class AmendmentCenter : public AmendmentCenterInterface {
std::shared_ptr<data::BackendInterface> backend_;
std::map<std::string, Amendment> supported_;
std::vector<Amendment> all_;
public:
/**
* @brief Construct a new AmendmentCenter instance
*
* @param backend The backend
*/
explicit AmendmentCenter(std::shared_ptr<data::BackendInterface> const& backend);
/**
* @brief Check whether an amendment is supported by Clio
*
* @param key The key of the amendment to check
* @return true if supported; false otherwise
*/
bool
isSupported(AmendmentKey const& key) const final;
/**
* @brief Get all supported amendments as a map
*
* @return The amendments supported by Clio
*/
std::map<std::string, Amendment> const&
getSupported() const final;
/**
* @brief Get all known amendments
*
* @return All known amendments as a vector
*/
std::vector<Amendment> const&
getAll() const final;
/**
* @brief Check whether an amendment was/is enabled for a given sequence
*
* @param key The key of the amendment to check
* @param seq The sequence to check for
* @return true if enabled; false otherwise
*/
bool
isEnabled(AmendmentKey const& key, uint32_t seq) const final;
/**
* @brief Check whether an amendment was/is enabled for a given sequence
*
* @param yield The coroutine context to use
* @param key The key of the amendment to check
* @param seq The sequence to check for
* @return true if enabled; false otherwise
*/
bool
isEnabled(boost::asio::yield_context yield, AmendmentKey const& key, uint32_t seq) const final;
/**
* @brief Get an amendment
*
* @param key The key of the amendment to get
* @return The amendment as a const ref; asserts if the amendment is unknown
*/
Amendment const&
getAmendment(AmendmentKey const& key) const final;
/**
* @brief Get an amendment by its key
* @param key The amendment key from @see Amendments
* @return The amendment as a const ref; asserts if the amendment is unknown
*/
Amendment const&
operator[](AmendmentKey const& key) const final;
};
} // namespace data

View File

@@ -0,0 +1,105 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and 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.
*/
//==============================================================================
#pragma once
#include "data/Types.hpp"
#include <boost/asio/spawn.hpp>
#include <cstdint>
#include <map>
#include <string>
#include <vector>
namespace data {
/**
* @brief The interface of an amendment center
*/
class AmendmentCenterInterface {
public:
virtual ~AmendmentCenterInterface() = default;
/**
* @brief Check whether an amendment is supported by Clio
*
* @param key The key of the amendment to check
* @return true if supported; false otherwise
*/
virtual bool
isSupported(AmendmentKey const& key) const = 0;
/**
* @brief Get all supported amendments as a map
*
* @return The amendments supported by Clio
*/
virtual std::map<std::string, Amendment> const&
getSupported() const = 0;
/**
* @brief Get all known amendments
*
* @return All known amendments as a vector
*/
virtual std::vector<Amendment> const&
getAll() const = 0;
/**
* @brief Check whether an amendment was/is enabled for a given sequence
*
* @param key The key of the amendment to check
* @param seq The sequence to check for
* @return true if enabled; false otherwise
*/
virtual bool
isEnabled(AmendmentKey const& key, uint32_t seq) const = 0;
/**
* @brief Check whether an amendment was/is enabled for a given sequence
*
* @param yield The coroutine context to use
* @param key The key of the amendment to check
* @param seq The sequence to check for
* @return true if enabled; false otherwise
*/
virtual bool
isEnabled(boost::asio::yield_context yield, AmendmentKey const& key, uint32_t seq) const = 0;
/**
* @brief Get an amendment
*
* @param key The key of the amendment to get
* @return The amendment as a const ref; asserts if the amendment is unknown
*/
virtual Amendment const&
getAmendment(AmendmentKey const& key) const = 0;
/**
* @brief Get an amendment by its key
*
* @param key The amendment key from @see Amendments
* @return The amendment as a const ref; asserts if the amendment is unknown
*/
virtual Amendment const&
operator[](AmendmentKey const& key) const = 0;
};
} // namespace data

View File

@@ -1,7 +1,8 @@
add_library(clio_data)
target_sources(
clio_data
PRIVATE BackendCounters.cpp
PRIVATE AmendmentCenter.cpp
BackendCounters.cpp
BackendInterface.cpp
LedgerCache.cpp
cassandra/impl/Future.cpp

View File

@@ -22,8 +22,10 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/AccountID.h>
#include <concepts>
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
@@ -239,6 +241,66 @@ struct LedgerRange {
std::uint32_t maxSequence = 0;
};
/**
* @brief Represents an amendment in the XRPL
*/
struct Amendment {
std::string name;
ripple::uint256 feature;
bool isSupportedByXRPL;
bool isSupportedByClio;
bool isRetired;
/**
* @brief Get the amendment Id from its name
*
* @param name The name of the amendment
* @return The amendment Id as uint256
*/
static ripple::uint256
GetAmendmentId(std::string_view const name);
/**
* @brief Equality comparison operator
* @param other The object to compare to
* @return Whether the objects are equal
*/
bool
operator==(Amendment const& other) const
{
return name == other.name;
}
};
/**
* @brief A helper for amendment name to feature conversions
*/
struct AmendmentKey {
std::string name;
/**
* @brief Construct a new AmendmentKey
* @param val Anything convertible to a string
*/
AmendmentKey(std::convertible_to<std::string> auto&& val) : name{std::forward<decltype(val)>(val)}
{
}
/** @brief Conversion to string */
operator std::string const&() const;
/** @brief Conversion to uint256 */
operator ripple::uint256() const;
/**
* @brief Comparison operators
* @param other The object to compare to
* @return Whether the objects are equal, greater or less
*/
auto
operator<=>(AmendmentKey const& other) const = default;
};
constexpr ripple::uint256 firstKey{"0000000000000000000000000000000000000000000000000000000000000000"};
constexpr ripple::uint256 lastKey{"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"};
constexpr ripple::uint256 hi192{"0000000000000000000000000000000000000000000000001111111111111111"};

View File

@@ -19,7 +19,7 @@
#pragma once
#include "etl/ETLHelpers.hpp"
#include "etl/NetworkValidatedLedgersInterface.hpp"
#include "etl/Source.hpp"
#include "feed/SubscriptionManagerInterface.hpp"
#include "util/Mutex.hpp"
@@ -99,8 +99,8 @@ public:
* @param wsPort The port of the source
* @param validatedLedgers The network validated ledgers object
* @param subscriptions The subscription manager object
* @param onConnect The onConnect hook. Called when the connection is established
* @param onDisconnect The onDisconnect hook. Called when the connection is lost
* @param onNewLedger The onNewLedger hook. Called when a new ledger is received
* @param onLedgerClosed The onLedgerClosed hook. Called when the ledger is closed but only if the source is
* forwarding
* @param connectionTimeout The connection timeout. Defaults to 30 seconds

View File

@@ -109,6 +109,7 @@ public:
* @brief Subscribe to the ledger feed.
* @param yield The coroutine context
* @param subscriber The subscriber to the ledger feed
*
* @return The ledger feed
*/
virtual boost::json::object

View File

@@ -17,6 +17,7 @@
*/
//==============================================================================
#include "data/AmendmentCenter.hpp"
#include "data/BackendFactory.hpp"
#include "etl/ETLService.hpp"
#include "etl/NetworkValidatedLedgers.hpp"
@@ -217,8 +218,9 @@ try {
auto workQueue = rpc::WorkQueue::make_WorkQueue(config);
auto counters = rpc::Counters::make_Counters(workQueue);
auto const amendmentCenter = std::make_shared<data::AmendmentCenter const>(backend);
auto const handlerProvider = std::make_shared<rpc::impl::ProductionHandlerProvider const>(
config, backend, subscriptions, balancer, etl, counters
config, backend, subscriptions, balancer, etl, amendmentCenter, counters
);
auto const rpcEngine =
rpc::RPCEngine::make_RPCEngine(backend, balancer, dosGuard, workQueue, counters, handlerProvider);

View File

@@ -1,49 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2023, the clio developers.
Permission to use, copy, modify, and 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.
*/
//==============================================================================
#pragma once
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/digest.h>
#include <string_view>
namespace rpc {
#define REGISTER_AMENDMENT(name) inline static const ripple::uint256 name = GetAmendmentId(#name);
/**
* @brief Represents a list of amendments in the XRPL.
*/
struct Amendments {
/**
* @param name The name of the amendment
* @return The corresponding amendment Id
*/
static ripple::uint256
GetAmendmentId(std::string_view const name)
{
return ripple::sha512Half(ripple::Slice(name.data(), name.size()));
}
REGISTER_AMENDMENT(DisallowIncoming)
REGISTER_AMENDMENT(Clawback)
};
} // namespace rpc

View File

@@ -1288,25 +1288,6 @@ getNFTID(boost::json::object const& request)
return tokenid;
}
bool
isAmendmentEnabled(
std::shared_ptr<data::BackendInterface const> const& backend,
boost::asio::yield_context yield,
uint32_t seq,
ripple::uint256 amendmentId
)
{
// the amendments should always be present in ledger
auto const& amendments = backend->fetchLedgerObject(ripple::keylet::amendments().key, seq, yield);
ripple::SLE const amendmentsSLE{
ripple::SerialIter{amendments->data(), amendments->size()}, ripple::keylet::amendments().key
};
auto const listAmendments = amendmentsSLE.getFieldV256(ripple::sfAmendments);
return std::find(listAmendments.begin(), listAmendments.end(), amendmentId) != listAmendments.end();
}
boost::json::object
toJsonWithBinaryTx(data::TransactionAndMetadata const& txnPlusMeta, std::uint32_t const apiVersion)
{

View File

@@ -566,23 +566,6 @@ specifiesCurrentOrClosedLedger(boost::json::object const& request);
std::variant<ripple::uint256, Status>
getNFTID(boost::json::object const& request);
/**
* @brief Check if the amendment is enabled
*
* @param backend The backend to use
* @param yield The yield context
* @param seq The ledger sequence
* @param amendmentId The amendment ID
* @return true if the amendment is enabled
*/
bool
isAmendmentEnabled(
std::shared_ptr<data::BackendInterface const> const& backend,
boost::asio::yield_context yield,
uint32_t seq,
ripple::uint256 amendmentId
);
/**
* @brief Encode CTID as string
*

View File

@@ -19,6 +19,8 @@
#include "rpc/common/impl/HandlerProvider.hpp"
#include "data/AmendmentCenter.hpp"
#include "data/AmendmentCenterInterface.hpp"
#include "data/BackendInterface.hpp"
#include "etl/ETLService.hpp"
#include "feed/SubscriptionManager.hpp"
@@ -71,12 +73,13 @@ ProductionHandlerProvider::ProductionHandlerProvider(
std::shared_ptr<feed::SubscriptionManager> const& subscriptionManager,
std::shared_ptr<etl::LoadBalancer> const& balancer,
std::shared_ptr<etl::ETLService const> const& etl,
std::shared_ptr<data::AmendmentCenterInterface const> const& amendmentCenter,
Counters const& counters
)
: handlerMap_{
{"account_channels", {AccountChannelsHandler{backend}}},
{"account_currencies", {AccountCurrenciesHandler{backend}}},
{"account_info", {AccountInfoHandler{backend}}},
{"account_info", {AccountInfoHandler{backend, amendmentCenter}}},
{"account_lines", {AccountLinesHandler{backend}}},
{"account_nfts", {AccountNFTsHandler{backend}}},
{"account_objects", {AccountObjectsHandler{backend}}},

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/AmendmentCenterInterface.hpp"
#include "data/BackendInterface.hpp"
#include "feed/SubscriptionManager.hpp"
#include "rpc/common/AnyHandler.hpp"
@@ -59,6 +60,7 @@ public:
std::shared_ptr<feed::SubscriptionManager> const& subscriptionManager,
std::shared_ptr<etl::LoadBalancer> const& balancer,
std::shared_ptr<etl::ETLService const> const& etl,
std::shared_ptr<data::AmendmentCenterInterface const> const& amendmentCenter,
Counters const& counters
);

View File

@@ -19,7 +19,7 @@
#include "rpc/handlers/AccountInfo.hpp"
#include "rpc/Amendments.hpp"
#include "data/AmendmentCenter.hpp"
#include "rpc/Errors.hpp"
#include "rpc/JS.hpp"
#include "rpc/RPCHelpers.hpp"
@@ -52,6 +52,8 @@ namespace rpc {
AccountInfoHandler::Result
AccountInfoHandler::process(AccountInfoHandler::Input input, Context const& ctx) const
{
using namespace data;
if (!input.account && !input.ident)
return Error{Status{RippledError::rpcINVALID_PARAMS, ripple::RPC::missing_field_message(JS(account))}};
@@ -79,11 +81,12 @@ AccountInfoHandler::process(AccountInfoHandler::Input input, Context const& ctx)
if (!accountKeylet.check(sle))
return Error{Status{RippledError::rpcDB_DESERIALIZATION}};
auto const isDisallowIncomingEnabled =
rpc::isAmendmentEnabled(sharedPtrBackend_, ctx.yield, lgrInfo.seq, rpc::Amendments::DisallowIncoming);
auto isEnabled = [this, &ctx, seq = lgrInfo.seq](auto key) {
return amendmentCenter_->isEnabled(ctx.yield, key, seq);
};
auto const isClawbackEnabled =
rpc::isAmendmentEnabled(sharedPtrBackend_, ctx.yield, lgrInfo.seq, rpc::Amendments::Clawback);
auto const isDisallowIncomingEnabled = isEnabled(Amendments::DisallowIncoming);
auto const isClawbackEnabled = isEnabled(Amendments::Clawback);
// Return SignerList(s) if that is requested.
if (input.signerLists) {

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/AmendmentCenterInterface.hpp"
#include "data/BackendInterface.hpp"
#include "rpc/JS.hpp"
#include "rpc/common/Checkers.hpp"
@@ -48,6 +49,7 @@ namespace rpc {
*/
class AccountInfoHandler {
std::shared_ptr<BackendInterface> sharedPtrBackend_;
std::shared_ptr<data::AmendmentCenterInterface const> amendmentCenter_;
public:
/**
@@ -115,8 +117,13 @@ public:
* @brief Construct a new AccountInfoHandler object
*
* @param sharedPtrBackend The backend to use
* @param amendmentCenter The amendment center to use
*/
AccountInfoHandler(std::shared_ptr<BackendInterface> const& sharedPtrBackend) : sharedPtrBackend_(sharedPtrBackend)
AccountInfoHandler(
std::shared_ptr<BackendInterface> const& sharedPtrBackend,
std::shared_ptr<data::AmendmentCenterInterface const> const& amendmentCenter
)
: sharedPtrBackend_(sharedPtrBackend), amendmentCenter_{amendmentCenter}
{
}

View File

@@ -307,22 +307,7 @@ template <template <typename> typename MockType = ::testing::NiceMock>
struct HandlerBaseTestBase : util::prometheus::WithPrometheus,
MockBackendTestBase<MockType>,
SyncAsioContextTest,
MockETLServiceTestBase<MockType> {
protected:
void
SetUp() override
{
SyncAsioContextTest::SetUp();
MockETLServiceTestBase<MockType>::SetUp();
}
void
TearDown() override
{
MockETLServiceTestBase<MockType>::TearDown();
SyncAsioContextTest::TearDown();
}
};
MockETLServiceTestBase<MockType> {};
/**
* @brief Fixture with a "nice" backend mock and an embedded boost::asio context.

View File

@@ -0,0 +1,83 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and 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.
*/
//==============================================================================
#pragma once
#include "data/AmendmentCenterInterface.hpp"
#include "data/Types.hpp"
#include <boost/asio/spawn.hpp>
#include <boost/json/object.hpp>
#include <gmock/gmock.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/LedgerHeader.h>
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <vector>
struct MockAmendmentCenter : public data::AmendmentCenterInterface {
MOCK_METHOD(bool, isSupported, (data::AmendmentKey const&), (const, override));
MOCK_METHOD((std::map<std::string, data::Amendment> const&), getSupported, (), (const, override));
MOCK_METHOD(std::vector<data::Amendment> const&, getAll, (), (const, override));
MOCK_METHOD(bool, isEnabled, (data::AmendmentKey const&, uint32_t), (const, override));
MOCK_METHOD(bool, isEnabled, (boost::asio::yield_context, data::AmendmentKey const&, uint32_t), (const, override));
MOCK_METHOD(data::Amendment const&, getAmendment, (data::AmendmentKey const&), (const, override));
MOCK_METHOD(data::Amendment const&, IndexOperator, (data::AmendmentKey const&), (const));
data::Amendment const&
operator[](data::AmendmentKey const& key) const override
{
return IndexOperator(key);
}
};
template <template <typename> typename MockType = ::testing::NiceMock>
struct MockAmendmentCenterSharedPtrImpl {
std::shared_ptr<MockType<MockAmendmentCenter>> amendmentCenterMock =
std::make_shared<MockType<MockAmendmentCenter>>();
operator std::shared_ptr<data::AmendmentCenterInterface>()
{
return amendmentCenterMock;
}
operator std::shared_ptr<data::AmendmentCenterInterface const>()
{
return amendmentCenterMock;
}
MockType<MockAmendmentCenter>&
operator*()
{
return *amendmentCenterMock;
}
};
using MockAmendmentCenterSharedPtr = MockAmendmentCenterSharedPtrImpl<>;
using StrictMockAmendmentCenterSharedPtr = MockAmendmentCenterSharedPtrImpl<testing::StrictMock>;

View File

@@ -4,6 +4,7 @@ target_sources(
clio_tests
PRIVATE # Common
ConfigTests.cpp
data/AmendmentCenterTests.cpp
data/BackendCountersTests.cpp
data/BackendInterfaceTests.cpp
data/cassandra/AsyncExecutorTests.cpp
@@ -45,7 +46,6 @@ target_sources(
Playground.cpp
ProfilerTests.cpp
# RPC
rpc/AmendmentsTests.cpp
rpc/APIVersionTests.cpp
rpc/BaseTests.cpp
rpc/CountersTests.cpp

View File

@@ -22,6 +22,11 @@
* Note: Please don't push your temporary work to the repo.
*/
// TEST(PlaygroundTest, MyTest)
// #include <gmock/gmock.h>
// #include <gtest/gtest.h>
// using namespace testing;
// TEST(PlaygroundTest, Test)
// {
// }

View File

@@ -0,0 +1,129 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and 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 "data/AmendmentCenter.hpp"
#include "data/Types.hpp"
#include "util/Fixtures.hpp"
#include "util/MockPrometheus.hpp"
#include "util/TestObject.hpp"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <string>
using namespace data;
constexpr auto SEQ = 30;
struct AmendmentCenterTest : util::prometheus::WithPrometheus, MockBackendTest {
AmendmentCenter amendmentCenter{backend};
};
// This is a safety net test that will fail anytime we built Clio against a new libXRPL that added some Amendment that
// we forgot to register in data::Amendments.
TEST_F(AmendmentCenterTest, AllAmendmentsFromLibXRPLAreSupported)
{
for (auto const& [name, _] : ripple::allAmendments()) {
ASSERT_TRUE(amendmentCenter.isSupported(name)) << "XRPL amendment not supported by Clio: " << name;
}
ASSERT_EQ(amendmentCenter.getSupported().size(), ripple::allAmendments().size());
ASSERT_EQ(amendmentCenter.getAll().size(), ripple::allAmendments().size());
}
TEST_F(AmendmentCenterTest, Accessors)
{
{
auto const am = amendmentCenter.getAmendment("DisallowIncoming");
EXPECT_EQ(am.feature, ripple::uint256("47C3002ABA31628447E8E9A8B315FAA935CE30183F9A9B86845E469CA2CDC3DF"));
}
{
auto const am = amendmentCenter["DisallowIncoming"];
EXPECT_EQ(am.feature, ripple::uint256("47C3002ABA31628447E8E9A8B315FAA935CE30183F9A9B86845E469CA2CDC3DF"));
}
auto const a = amendmentCenter[Amendments::OwnerPaysFee];
auto const b = amendmentCenter["OwnerPaysFee"];
EXPECT_EQ(a, b);
}
TEST_F(AmendmentCenterTest, IsEnabled)
{
EXPECT_TRUE(amendmentCenter.isSupported("fixUniversalNumber"));
EXPECT_FALSE(amendmentCenter.isSupported("unknown"));
auto const amendments = CreateAmendmentsObject({Amendments::fixUniversalNumber});
EXPECT_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, SEQ, testing::_))
.WillRepeatedly(testing::Return(amendments.getSerializer().peekData()));
EXPECT_TRUE(amendmentCenter.isEnabled("fixUniversalNumber", SEQ));
EXPECT_FALSE(amendmentCenter.isEnabled("unknown", SEQ));
EXPECT_FALSE(amendmentCenter.isEnabled("ImmediateOfferKilled", SEQ));
}
TEST(AmendmentTest, GenerateAmendmentId)
{
// https://xrpl.org/known-amendments.html#disallowincoming refer to the published id
EXPECT_EQ(
ripple::uint256("47C3002ABA31628447E8E9A8B315FAA935CE30183F9A9B86845E469CA2CDC3DF"),
Amendment::GetAmendmentId("DisallowIncoming")
);
}
struct AmendmentCenterDeathTest : AmendmentCenterTest {};
TEST_F(AmendmentCenterDeathTest, GetInvalidAmendmentAsserts)
{
EXPECT_DEATH({ amendmentCenter.getAmendment("invalidAmendmentKey"); }, ".*");
EXPECT_DEATH({ amendmentCenter["invalidAmendmentKey"]; }, ".*");
}
struct AmendmentKeyTest : testing::Test {};
TEST_F(AmendmentKeyTest, Convertible)
{
std::string key1 = "key1";
auto key2 = "key2";
EXPECT_NO_THROW({
auto const first = AmendmentKey(key1);
auto const second = AmendmentKey(key2);
auto const third = AmendmentKey("test");
std::string s1 = first;
EXPECT_EQ(s1, key1);
ripple::uint256 k1 = first;
ripple::uint256 k2 = second;
EXPECT_EQ(k1, ripple::uint256{"7E365F775657DC0EB960E6295A1F44B3F67479F54D5D12C5D87E6DB234F072E3"});
EXPECT_EQ(k2, ripple::uint256{"B4F33541E0E2FC2F7AA17D2D2E6A9B424809123485251D3413E91CC462309772"});
});
}
TEST_F(AmendmentKeyTest, Comparison)
{
auto const first = AmendmentKey("1");
auto const second = AmendmentKey("2");
EXPECT_GT(second, first);
}

View File

@@ -17,13 +17,15 @@
*/
//==============================================================================
#include "data/AmendmentCenter.hpp"
#include "data/AmendmentCenterInterface.hpp"
#include "data/Types.hpp"
#include "rpc/Amendments.hpp"
#include "rpc/Errors.hpp"
#include "rpc/common/AnyHandler.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/handlers/AccountInfo.hpp"
#include "util/Fixtures.hpp"
#include "util/MockAmendmentCenter.hpp"
#include "util/NameGenerator.hpp"
#include "util/TestObject.hpp"
@@ -52,7 +54,10 @@ constexpr static auto ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun";
constexpr static auto LEDGERHASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652";
constexpr static auto INDEX1 = "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC";
class RPCAccountInfoHandlerTest : public HandlerBaseTest {};
struct RPCAccountInfoHandlerTest : HandlerBaseTest {
protected:
StrictMockAmendmentCenterSharedPtr mockAmendmentCenterPtr;
};
struct AccountInfoParamTestCaseBundle {
std::string testName;
@@ -112,7 +117,7 @@ TEST_P(AccountInfoParameterTest, InvalidParams)
{
auto const testBundle = GetParam();
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
auto const req = json::parse(testBundle.testJson);
auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2});
ASSERT_FALSE(output);
@@ -132,7 +137,7 @@ TEST_F(AccountInfoParameterTest, ApiV1SignerListIsNotBool)
EXPECT_CALL(*backend, fetchLedgerBySequence);
runSpawn([&, this](auto yield) {
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
auto const req = json::parse(reqJson);
auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 1});
ASSERT_FALSE(output);
@@ -158,7 +163,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaIntSequence)
}})",
ACCOUNT
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
ASSERT_FALSE(output);
@@ -182,7 +187,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaStringSequence)
}})",
ACCOUNT
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
ASSERT_FALSE(output);
@@ -208,7 +213,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaHash)
ACCOUNT,
LEDGERHASH
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
ASSERT_FALSE(output);
@@ -234,7 +239,7 @@ TEST_F(RPCAccountInfoHandlerTest, AccountNotExist)
}})",
ACCOUNT
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
ASSERT_FALSE(output);
@@ -261,7 +266,7 @@ TEST_F(RPCAccountInfoHandlerTest, AccountInvalid)
}})",
ACCOUNT
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
ASSERT_FALSE(output);
@@ -286,9 +291,9 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsInvalid)
auto signersKey = ripple::keylet::signers(account).key;
ON_CALL(*backend, doFetchLedgerObject(signersKey, 30, _))
.WillByDefault(Return(CreateLegacyFeeSettingBlob(1, 2, 3, 4, 0)));
ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _))
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
EXPECT_CALL(*backend, doFetchLedgerObject).Times(4);
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::DisallowIncoming, _)).WillOnce(Return(false));
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::Clawback, _)).WillOnce(Return(false));
EXPECT_CALL(*backend, doFetchLedgerObject).Times(2);
auto static const input = json::parse(fmt::format(
R"({{
@@ -297,7 +302,7 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsInvalid)
}})",
ACCOUNT
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
ASSERT_FALSE(output);
@@ -390,9 +395,9 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsTrueV2)
auto signersKey = ripple::keylet::signers(account).key;
ON_CALL(*backend, doFetchLedgerObject(signersKey, 30, _))
.WillByDefault(Return(CreateSignerLists({{ACCOUNT1, 1}, {ACCOUNT2, 1}}).getSerializer().peekData()));
ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _))
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
EXPECT_CALL(*backend, doFetchLedgerObject).Times(4);
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::DisallowIncoming, _)).WillOnce(Return(false));
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::Clawback, _)).WillOnce(Return(false));
EXPECT_CALL(*backend, doFetchLedgerObject).Times(2);
auto static const input = json::parse(fmt::format(
R"({{
@@ -401,7 +406,7 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsTrueV2)
}})",
ACCOUNT
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{.yield = yield, .apiVersion = 2});
ASSERT_TRUE(output);
@@ -492,9 +497,9 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsTrueV1)
auto signersKey = ripple::keylet::signers(account).key;
ON_CALL(*backend, doFetchLedgerObject(signersKey, 30, _))
.WillByDefault(Return(CreateSignerLists({{ACCOUNT1, 1}, {ACCOUNT2, 1}}).getSerializer().peekData()));
ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _))
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
EXPECT_CALL(*backend, doFetchLedgerObject).Times(4);
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::DisallowIncoming, _)).WillOnce(Return(false));
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::Clawback, _)).WillOnce(Return(false));
EXPECT_CALL(*backend, doFetchLedgerObject).Times(2);
auto static const input = json::parse(fmt::format(
R"({{
@@ -503,7 +508,7 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsTrueV1)
}})",
ACCOUNT
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{.yield = yield, .apiVersion = 1});
ASSERT_TRUE(output);
@@ -567,9 +572,9 @@ TEST_F(RPCAccountInfoHandlerTest, Flags)
);
ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _))
.WillByDefault(Return(accountRoot.getSerializer().peekData()));
ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _))
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
EXPECT_CALL(*backend, doFetchLedgerObject).Times(3);
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::DisallowIncoming, _)).WillOnce(Return(false));
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::Clawback, _)).WillOnce(Return(false));
EXPECT_CALL(*backend, doFetchLedgerObject);
auto static const input = json::parse(fmt::format(
R"({{
@@ -577,7 +582,7 @@ TEST_F(RPCAccountInfoHandlerTest, Flags)
}})",
ACCOUNT
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
ASSERT_TRUE(output);
@@ -597,9 +602,9 @@ TEST_F(RPCAccountInfoHandlerTest, IdentAndSignerListsFalse)
auto const accountRoot = CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2);
ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _))
.WillByDefault(Return(accountRoot.getSerializer().peekData()));
ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _))
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
EXPECT_CALL(*backend, doFetchLedgerObject).Times(3);
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::DisallowIncoming, _)).WillOnce(Return(false));
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::Clawback, _)).WillOnce(Return(false));
EXPECT_CALL(*backend, doFetchLedgerObject);
auto static const input = json::parse(fmt::format(
R"({{
@@ -607,7 +612,7 @@ TEST_F(RPCAccountInfoHandlerTest, IdentAndSignerListsFalse)
}})",
ACCOUNT
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
ASSERT_TRUE(output);
@@ -676,9 +681,9 @@ TEST_F(RPCAccountInfoHandlerTest, DisallowIncoming)
);
ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _))
.WillByDefault(Return(accountRoot.getSerializer().peekData()));
ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _))
.WillByDefault(Return(CreateAmendmentsObject({rpc::Amendments::DisallowIncoming}).getSerializer().peekData()));
EXPECT_CALL(*backend, doFetchLedgerObject).Times(3);
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::DisallowIncoming, _)).WillOnce(Return(true));
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::Clawback, _)).WillOnce(Return(false));
EXPECT_CALL(*backend, doFetchLedgerObject);
auto static const input = json::parse(fmt::format(
R"({{
@@ -686,7 +691,7 @@ TEST_F(RPCAccountInfoHandlerTest, DisallowIncoming)
}})",
ACCOUNT
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
ASSERT_TRUE(output);
@@ -751,9 +756,9 @@ TEST_F(RPCAccountInfoHandlerTest, Clawback)
);
ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _))
.WillByDefault(Return(accountRoot.getSerializer().peekData()));
ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _))
.WillByDefault(Return(CreateAmendmentsObject({rpc::Amendments::Clawback}).getSerializer().peekData()));
EXPECT_CALL(*backend, doFetchLedgerObject).Times(3);
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::DisallowIncoming, _)).WillOnce(Return(false));
EXPECT_CALL(*mockAmendmentCenterPtr, isEnabled(_, Amendments::Clawback, _)).WillOnce(Return(true));
EXPECT_CALL(*backend, doFetchLedgerObject);
auto static const input = json::parse(fmt::format(
R"({{
@@ -761,7 +766,7 @@ TEST_F(RPCAccountInfoHandlerTest, Clawback)
}})",
ACCOUNT
));
auto const handler = AnyHandler{AccountInfoHandler{backend}};
auto const handler = AnyHandler{AccountInfoHandler{backend, mockAmendmentCenterPtr}};
runSpawn([&](auto yield) {
auto const output = handler.process(input, Context{yield});
ASSERT_TRUE(output);