mirror of
				https://github.com/XRPLF/clio.git
				synced 2025-11-04 11:55:51 +00:00 
			
		
		
		
	
							
								
								
									
										172
									
								
								src/data/AmendmentCenter.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								src/data/AmendmentCenter.cpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										234
									
								
								src/data/AmendmentCenter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								src/data/AmendmentCenter.hpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										105
									
								
								src/data/AmendmentCenterInterface.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/data/AmendmentCenterInterface.hpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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"};
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -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)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
@@ -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}}},
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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}
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										83
									
								
								tests/common/util/MockAmendmentCenter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								tests/common/util/MockAmendmentCenter.hpp
									
									
									
									
									
										Normal 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>;
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
// {
 | 
			
		||||
// }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										129
									
								
								tests/unit/data/AmendmentCenterTests.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								tests/unit/data/AmendmentCenterTests.cpp
									
									
									
									
									
										Normal 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);
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user