mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-17 18:25:51 +00:00
@@ -62,6 +62,7 @@ target_sources(clio PRIVATE
|
||||
src/rpc/ngHandlers/Tx.cpp
|
||||
src/rpc/ngHandlers/GatewayBalances.cpp
|
||||
src/rpc/ngHandlers/LedgerEntry.cpp
|
||||
src/rpc/ngHandlers/BookOffers.cpp
|
||||
## RPC Methods
|
||||
# Account
|
||||
src/rpc/handlers/AccountChannels.cpp
|
||||
@@ -126,7 +127,8 @@ if(BUILD_TESTS)
|
||||
unittests/rpc/handlers/AccountChannelsTest.cpp
|
||||
unittests/rpc/handlers/TxTest.cpp
|
||||
unittests/rpc/handlers/GatewayBalancesTest.cpp
|
||||
unittests/rpc/handlers/LedgerEntryTest.cpp)
|
||||
unittests/rpc/handlers/LedgerEntryTest.cpp
|
||||
unittests/rpc/handlers/BookOffersTest.cpp)
|
||||
include(CMake/deps/gtest.cmake)
|
||||
|
||||
# if CODE_COVERAGE enable, add clio_test-ccov
|
||||
|
||||
@@ -173,7 +173,6 @@ BackendInterface::fetchBookOffers(
|
||||
ripple::uint256 const& book,
|
||||
std::uint32_t const ledgerSequence,
|
||||
std::uint32_t const limit,
|
||||
std::optional<ripple::uint256> const& cursor,
|
||||
boost::asio::yield_context& yield) const
|
||||
{
|
||||
// TODO try to speed this up. This can take a few seconds. The goal is
|
||||
|
||||
@@ -479,7 +479,6 @@ public:
|
||||
ripple::uint256 const& book,
|
||||
std::uint32_t const ledgerSequence,
|
||||
std::uint32_t const limit,
|
||||
std::optional<ripple::uint256> const& cursor,
|
||||
boost::asio::yield_context& yield) const;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1269,7 +1269,7 @@ postProcessOrderBook(
|
||||
|
||||
bool globalFreeze =
|
||||
isGlobalFrozen(backend, ledgerSequence, book.out.account, yield) ||
|
||||
isGlobalFrozen(backend, ledgerSequence, book.out.account, yield);
|
||||
isGlobalFrozen(backend, ledgerSequence, book.in.account, yield);
|
||||
|
||||
auto rate = transferRate(backend, ledgerSequence, book.out.account, yield);
|
||||
|
||||
@@ -1312,14 +1312,13 @@ postProcessOrderBook(
|
||||
}
|
||||
else
|
||||
{
|
||||
bool zeroIfFrozen = true;
|
||||
saOwnerFunds = accountHolds(
|
||||
backend,
|
||||
ledgerSequence,
|
||||
uOfferOwnerID,
|
||||
book.out.currency,
|
||||
book.out.account,
|
||||
zeroIfFrozen,
|
||||
true,
|
||||
yield);
|
||||
|
||||
if (saOwnerFunds < beast::zero)
|
||||
@@ -1388,6 +1387,43 @@ postProcessOrderBook(
|
||||
return jsonOffers;
|
||||
}
|
||||
|
||||
// get book via currency type
|
||||
std::variant<Status, ripple::Book>
|
||||
parseBook(
|
||||
ripple::Currency pays,
|
||||
ripple::AccountID payIssuer,
|
||||
ripple::Currency gets,
|
||||
ripple::AccountID getIssuer)
|
||||
{
|
||||
if (isXRP(pays) && !isXRP(payIssuer))
|
||||
return Status{
|
||||
RippledError::rpcSRC_ISR_MALFORMED,
|
||||
"Unneeded field 'taker_pays.issuer' for XRP currency "
|
||||
"specification."};
|
||||
|
||||
if (!isXRP(pays) && isXRP(payIssuer))
|
||||
return Status{
|
||||
RippledError::rpcSRC_ISR_MALFORMED,
|
||||
"Invalid field 'taker_pays.issuer', expected non-XRP "
|
||||
"issuer."};
|
||||
|
||||
if (ripple::isXRP(gets) && !ripple::isXRP(getIssuer))
|
||||
return Status{
|
||||
RippledError::rpcDST_ISR_MALFORMED,
|
||||
"Unneeded field 'taker_gets.issuer' for XRP currency "
|
||||
"specification."};
|
||||
|
||||
if (!ripple::isXRP(gets) && ripple::isXRP(getIssuer))
|
||||
return Status{
|
||||
RippledError::rpcDST_ISR_MALFORMED,
|
||||
"Invalid field 'taker_gets.issuer', expected non-XRP issuer."};
|
||||
|
||||
if (pays == gets && payIssuer == getIssuer)
|
||||
return Status{RippledError::rpcBAD_MARKET, "badMarket"};
|
||||
|
||||
return ripple::Book{{pays, payIssuer}, {gets, getIssuer}};
|
||||
}
|
||||
|
||||
std::variant<Status, ripple::Book>
|
||||
parseBook(boost::json::object const& request)
|
||||
{
|
||||
|
||||
@@ -216,6 +216,13 @@ postProcessOrderBook(
|
||||
std::uint32_t ledgerSequence,
|
||||
boost::asio::yield_context& yield);
|
||||
|
||||
std::variant<Status, ripple::Book>
|
||||
parseBook(
|
||||
ripple::Currency pays,
|
||||
ripple::AccountID payIssuer,
|
||||
ripple::Currency gets,
|
||||
ripple::AccountID getIssuer);
|
||||
|
||||
std::variant<Status, ripple::Book>
|
||||
parseBook(boost::json::object const& request);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <rpc/common/Validators.h>
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <charconv>
|
||||
#include <string_view>
|
||||
@@ -200,4 +201,27 @@ CustomValidator CurrencyValidator = CustomValidator{
|
||||
return MaybeError{};
|
||||
}};
|
||||
|
||||
CustomValidator IssuerValidator = CustomValidator{
|
||||
[](boost::json::value const& value, std::string_view key) -> MaybeError {
|
||||
if (!value.is_string())
|
||||
return Error{RPC::Status{
|
||||
RPC::RippledError::rpcINVALID_PARAMS,
|
||||
std::string(key) + "NotString"}};
|
||||
ripple::AccountID issuer;
|
||||
if (!ripple::to_issuer(issuer, value.as_string().c_str()))
|
||||
return Error{RPC::Status{
|
||||
// TODO: need to align with the error
|
||||
RPC::RippledError::rpcINVALID_PARAMS,
|
||||
fmt::format("Invalid field '{}', bad issuer.", key)}};
|
||||
|
||||
if (issuer == ripple::noAccount())
|
||||
return Error{RPC::Status{
|
||||
RPC::RippledError::rpcINVALID_PARAMS,
|
||||
fmt::format(
|
||||
"Invalid field '{}', bad issuer account "
|
||||
"one.",
|
||||
key)}};
|
||||
return MaybeError{};
|
||||
}};
|
||||
|
||||
} // namespace RPCng::validation
|
||||
|
||||
@@ -485,4 +485,10 @@ extern CustomValidator Uint256HexStringValidator;
|
||||
*/
|
||||
extern CustomValidator CurrencyValidator;
|
||||
|
||||
/**
|
||||
* @brief Provide a common used validator for issuer type
|
||||
* It must be a hex string or base58 string
|
||||
*/
|
||||
extern CustomValidator IssuerValidator;
|
||||
|
||||
} // namespace RPCng::validation
|
||||
|
||||
@@ -83,13 +83,9 @@ doBookOffers(Context const& context)
|
||||
if (auto const status = getTaker(request, takerID); status)
|
||||
return status;
|
||||
|
||||
ripple::uint256 marker = beast::zero;
|
||||
if (auto const status = getHexMarker(request, marker); status)
|
||||
return status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
auto [offers, retMarker] = context.backend->fetchBookOffers(
|
||||
bookBase, lgrInfo.seq, limit, marker, context.yield);
|
||||
auto [offers, _] = context.backend->fetchBookOffers(
|
||||
bookBase, lgrInfo.seq, limit, context.yield);
|
||||
auto end = std::chrono::system_clock::now();
|
||||
|
||||
gLog.warn() << "Time loading books: "
|
||||
@@ -111,10 +107,6 @@ doBookOffers(Context const& context)
|
||||
end2 - end)
|
||||
.count()
|
||||
<< " milliseconds - request = " << request;
|
||||
|
||||
if (retMarker)
|
||||
response["marker"] = ripple::strHex(*retMarker);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@@ -263,8 +263,8 @@ validateAndGetBooks(
|
||||
auto book,
|
||||
boost::asio::yield_context& yield) {
|
||||
auto bookBase = getBookBase(book);
|
||||
auto [offers, retMarker] = backend->fetchBookOffers(
|
||||
bookBase, rng->maxSequence, 200, {}, yield);
|
||||
auto [offers, _] = backend->fetchBookOffers(
|
||||
bookBase, rng->maxSequence, 200, yield);
|
||||
|
||||
auto orderBook = postProcessOrderBook(
|
||||
offers, book, takerID, *backend, rng->maxSequence, yield);
|
||||
|
||||
134
src/rpc/ngHandlers/BookOffers.cpp
Normal file
134
src/rpc/ngHandlers/BookOffers.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <rpc/RPCHelpers.h>
|
||||
#include <rpc/ngHandlers/BookOffers.h>
|
||||
|
||||
namespace RPCng {
|
||||
|
||||
BookOffersHandler::Result
|
||||
BookOffersHandler::process(Input input, boost::asio::yield_context& yield) const
|
||||
{
|
||||
auto bookMaybe = RPC::parseBook(
|
||||
input.paysCurrency, input.paysID, input.getsCurrency, input.getsID);
|
||||
if (auto const status = std::get_if<RPC::Status>(&bookMaybe))
|
||||
return Error{*status};
|
||||
|
||||
// check ledger
|
||||
auto const range = sharedPtrBackend_->fetchLedgerRange();
|
||||
auto const lgrInfoOrStatus = RPC::getLedgerInfoFromHashOrSeq(
|
||||
*sharedPtrBackend_,
|
||||
yield,
|
||||
input.ledgerHash,
|
||||
input.ledgerIndex,
|
||||
range->maxSequence);
|
||||
|
||||
if (auto const status = std::get_if<RPC::Status>(&lgrInfoOrStatus))
|
||||
return Error{*status};
|
||||
|
||||
auto const lgrInfo = std::get<ripple::LedgerInfo>(lgrInfoOrStatus);
|
||||
auto const book = std::get<ripple::Book>(bookMaybe);
|
||||
auto const bookKey = getBookBase(book);
|
||||
|
||||
// TODO: Add perfomance metrics if needed in future
|
||||
auto [offers, _] = sharedPtrBackend_->fetchBookOffers(
|
||||
bookKey, lgrInfo.seq, input.limit, yield);
|
||||
|
||||
BookOffersHandler::Output output;
|
||||
output.ledgerHash = ripple::strHex(lgrInfo.hash);
|
||||
output.ledgerIndex = lgrInfo.seq;
|
||||
output.offers = RPC::postProcessOrderBook(
|
||||
offers,
|
||||
book,
|
||||
input.taker ? *(input.taker) : beast::zero,
|
||||
*sharedPtrBackend_,
|
||||
lgrInfo.seq,
|
||||
yield);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void
|
||||
tag_invoke(
|
||||
boost::json::value_from_tag,
|
||||
boost::json::value& jv,
|
||||
BookOffersHandler::Output const& output)
|
||||
{
|
||||
jv = boost::json::object{
|
||||
{"ledger_hash", output.ledgerHash},
|
||||
{"ledger_index", output.ledgerIndex},
|
||||
{"offers", output.offers},
|
||||
};
|
||||
}
|
||||
|
||||
BookOffersHandler::Input
|
||||
tag_invoke(
|
||||
boost::json::value_to_tag<BookOffersHandler::Input>,
|
||||
boost::json::value const& jv)
|
||||
{
|
||||
BookOffersHandler::Input input;
|
||||
auto const& jsonObject = jv.as_object();
|
||||
ripple::to_currency(
|
||||
input.getsCurrency,
|
||||
jv.at("taker_gets").as_object().at("currency").as_string().c_str());
|
||||
ripple::to_currency(
|
||||
input.paysCurrency,
|
||||
jv.at("taker_pays").as_object().at("currency").as_string().c_str());
|
||||
if (jv.at("taker_gets").as_object().contains("issuer"))
|
||||
{
|
||||
ripple::to_issuer(
|
||||
input.getsID,
|
||||
jv.at("taker_gets").as_object().at("issuer").as_string().c_str());
|
||||
}
|
||||
if (jv.at("taker_pays").as_object().contains("issuer"))
|
||||
{
|
||||
ripple::to_issuer(
|
||||
input.paysID,
|
||||
jv.at("taker_pays").as_object().at("issuer").as_string().c_str());
|
||||
}
|
||||
if (jsonObject.contains("ledger_hash"))
|
||||
{
|
||||
input.ledgerHash = jv.at("ledger_hash").as_string().c_str();
|
||||
}
|
||||
if (jsonObject.contains("ledger_index"))
|
||||
{
|
||||
if (!jsonObject.at("ledger_index").is_string())
|
||||
{
|
||||
input.ledgerIndex = jv.at("ledger_index").as_int64();
|
||||
}
|
||||
else if (jsonObject.at("ledger_index").as_string() != "validated")
|
||||
{
|
||||
input.ledgerIndex =
|
||||
std::stoi(jv.at("ledger_index").as_string().c_str());
|
||||
}
|
||||
}
|
||||
if (jsonObject.contains("taker"))
|
||||
{
|
||||
input.taker =
|
||||
RPC::accountFromStringStrict(jv.at("taker").as_string().c_str());
|
||||
}
|
||||
if (jsonObject.contains("limit"))
|
||||
{
|
||||
input.limit = jv.at("limit").as_int64();
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
} // namespace RPCng
|
||||
118
src/rpc/ngHandlers/BookOffers.h
Normal file
118
src/rpc/ngHandlers/BookOffers.h
Normal file
@@ -0,0 +1,118 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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 <backend/BackendInterface.h>
|
||||
#include <rpc/common/Types.h>
|
||||
#include <rpc/common/Validators.h>
|
||||
|
||||
#include <boost/asio/spawn.hpp>
|
||||
|
||||
namespace RPCng {
|
||||
class BookOffersHandler
|
||||
{
|
||||
std::shared_ptr<BackendInterface> sharedPtrBackend_;
|
||||
|
||||
public:
|
||||
struct Output
|
||||
{
|
||||
std::string ledgerHash;
|
||||
uint32_t ledgerIndex;
|
||||
boost::json::array offers;
|
||||
bool validated = true;
|
||||
};
|
||||
|
||||
// the taker is not really used in both clio and rippled, both of them
|
||||
// return all the offers regardless the funding status
|
||||
struct Input
|
||||
{
|
||||
std::optional<std::string> ledgerHash;
|
||||
std::optional<uint32_t> ledgerIndex;
|
||||
uint32_t limit = 50;
|
||||
std::optional<ripple::AccountID> taker;
|
||||
ripple::Currency paysCurrency;
|
||||
ripple::Currency getsCurrency;
|
||||
// accountID will be filled by input converter, if no issuer is given,
|
||||
// will use XRP issuer
|
||||
ripple::AccountID paysID = ripple::xrpAccount();
|
||||
ripple::AccountID getsID = ripple::xrpAccount();
|
||||
};
|
||||
|
||||
using Result = RPCng::HandlerReturnType<Output>;
|
||||
|
||||
BookOffersHandler(std::shared_ptr<BackendInterface> const& sharedPtrBackend)
|
||||
: sharedPtrBackend_(sharedPtrBackend)
|
||||
{
|
||||
}
|
||||
|
||||
RpcSpecConstRef
|
||||
spec() const
|
||||
{
|
||||
static const RpcSpec rpcSpec = {
|
||||
{"taker_gets",
|
||||
validation::Required{},
|
||||
validation::Type<boost::json::object>{},
|
||||
validation::Section{
|
||||
{"currency",
|
||||
validation::Required{},
|
||||
validation::WithCustomError{
|
||||
validation::CurrencyValidator,
|
||||
RPC::Status(RPC::RippledError::rpcDST_AMT_MALFORMED)}},
|
||||
{"issuer",
|
||||
validation::WithCustomError{
|
||||
validation::IssuerValidator,
|
||||
RPC::Status(RPC::RippledError::rpcDST_ISR_MALFORMED)}}}},
|
||||
{"taker_pays",
|
||||
validation::Required{},
|
||||
validation::Type<boost::json::object>{},
|
||||
validation::Section{
|
||||
{"currency",
|
||||
validation::Required{},
|
||||
validation::WithCustomError{
|
||||
validation::CurrencyValidator,
|
||||
RPC::Status(RPC::RippledError::rpcSRC_CUR_MALFORMED)}},
|
||||
{"issuer",
|
||||
validation::WithCustomError{
|
||||
validation::IssuerValidator,
|
||||
RPC::Status(RPC::RippledError::rpcSRC_ISR_MALFORMED)}}}},
|
||||
{"taker", validation::AccountValidator},
|
||||
{"limit",
|
||||
validation::Type<uint32_t>{},
|
||||
validation::Between{1, 100}},
|
||||
{"ledger_hash", validation::Uint256HexStringValidator},
|
||||
{"ledger_index", validation::LedgerIndexValidator}};
|
||||
return rpcSpec;
|
||||
}
|
||||
|
||||
Result
|
||||
process(Input input, boost::asio::yield_context& yield) const;
|
||||
};
|
||||
|
||||
void
|
||||
tag_invoke(
|
||||
boost::json::value_from_tag,
|
||||
boost::json::value& jv,
|
||||
BookOffersHandler::Output const& output);
|
||||
|
||||
BookOffersHandler::Input
|
||||
tag_invoke(
|
||||
boost::json::value_to_tag<BookOffersHandler::Input>,
|
||||
boost::json::value const& jv);
|
||||
} // namespace RPCng
|
||||
@@ -171,15 +171,15 @@ TEST_F(RPCAccountCurrenciesHandlerTest, DefaultParameter)
|
||||
// ACCOUNT can receive USD 10 from ACCOUNT2 and send USD 20 to ACCOUNT2, now
|
||||
// the balance is 100, ACCOUNT can only send USD to ACCOUNT2
|
||||
auto const line1 = CreateRippleStateLedgerObject(
|
||||
ACCOUNT, "USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123);
|
||||
ACCOUNT, "USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0);
|
||||
// ACCOUNT2 can receive JPY 10 from ACCOUNT and send JPY 20 to ACCOUNT, now
|
||||
// the balance is 100, ACCOUNT2 can only send JPY to ACCOUNT
|
||||
auto const line2 = CreateRippleStateLedgerObject(
|
||||
ACCOUNT, "JPY", ISSUER, 100, ACCOUNT2, 10, ACCOUNT, 20, TXNID, 123);
|
||||
ACCOUNT, "JPY", ISSUER, 100, ACCOUNT2, 10, ACCOUNT, 20, TXNID, 123, 0);
|
||||
// ACCOUNT can receive EUR 10 from ACCOUNT and send EUR 20 to ACCOUNT2, now
|
||||
// the balance is 8, ACCOUNT can receive/send EUR to/from ACCOUNT2
|
||||
auto const line3 = CreateRippleStateLedgerObject(
|
||||
ACCOUNT, "EUR", ISSUER, 8, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123);
|
||||
ACCOUNT, "EUR", ISSUER, 8, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0);
|
||||
std::vector<Blob> bbs;
|
||||
bbs.push_back(line1.getSerializer().peekData());
|
||||
bbs.push_back(line2.getSerializer().peekData());
|
||||
@@ -226,7 +226,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, RequestViaLegderHash)
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
|
||||
std::vector<Blob> bbs;
|
||||
auto const line1 = CreateRippleStateLedgerObject(
|
||||
ACCOUNT, "USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123);
|
||||
ACCOUNT, "USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0);
|
||||
bbs.push_back(line1.getSerializer().peekData());
|
||||
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
@@ -272,7 +272,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, RequestViaLegderSeq)
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
|
||||
std::vector<Blob> bbs;
|
||||
auto const line1 = CreateRippleStateLedgerObject(
|
||||
ACCOUNT, "USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123);
|
||||
ACCOUNT, "USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0);
|
||||
bbs.push_back(line1.getSerializer().peekData());
|
||||
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
|
||||
1389
unittests/rpc/handlers/BookOffersTest.cpp
Normal file
1389
unittests/rpc/handlers/BookOffersTest.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -746,7 +746,15 @@ generateTestValuesForNormalPathTest()
|
||||
}})",
|
||||
INDEX1),
|
||||
ripple::uint256{INDEX1},
|
||||
CreateOfferLedgerObject(ACCOUNT, 100, 200, "USD", ACCOUNT2)},
|
||||
CreateOfferLedgerObject(
|
||||
ACCOUNT,
|
||||
100,
|
||||
200,
|
||||
"USD",
|
||||
"XRP",
|
||||
ACCOUNT2,
|
||||
ripple::toBase58(ripple::xrpAccount()),
|
||||
INDEX1)},
|
||||
NormalPathTestBundle{
|
||||
"EscrowIndex",
|
||||
fmt::format(
|
||||
@@ -879,7 +887,8 @@ generateTestValuesForNormalPathTest()
|
||||
ACCOUNT2,
|
||||
20,
|
||||
INDEX1,
|
||||
123)},
|
||||
123,
|
||||
0)},
|
||||
NormalPathTestBundle{
|
||||
"Ticket",
|
||||
fmt::format(
|
||||
@@ -905,7 +914,15 @@ generateTestValuesForNormalPathTest()
|
||||
}})",
|
||||
ACCOUNT),
|
||||
ripple::keylet::offer(account1, 2).key,
|
||||
CreateOfferLedgerObject(ACCOUNT, 100, 200, "USD", ACCOUNT2)}};
|
||||
CreateOfferLedgerObject(
|
||||
ACCOUNT,
|
||||
100,
|
||||
200,
|
||||
"USD",
|
||||
"XRP",
|
||||
ACCOUNT2,
|
||||
ripple::toBase58(ripple::xrpAccount()),
|
||||
INDEX1)}};
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
|
||||
@@ -152,6 +152,21 @@ struct SyncAsioContextTest : virtual public NoLoggerFixture
|
||||
{
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void
|
||||
runSpawn(F&& f)
|
||||
{
|
||||
auto called = false;
|
||||
auto work = std::optional<boost::asio::io_context::work>{ctx};
|
||||
boost::asio::spawn(ctx, [&](boost::asio::yield_context yield) {
|
||||
f(yield);
|
||||
called = true;
|
||||
work.reset();
|
||||
});
|
||||
ctx.run();
|
||||
ASSERT_TRUE(called);
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_context ctx;
|
||||
};
|
||||
|
||||
@@ -101,7 +101,8 @@ CreateAccountRootObject(
|
||||
int balance,
|
||||
uint32_t ownerCount,
|
||||
std::string_view previousTxnID,
|
||||
uint32_t previousTxnSeq)
|
||||
uint32_t previousTxnSeq,
|
||||
uint32_t transferRate)
|
||||
{
|
||||
ripple::STObject accountRoot(ripple::sfAccount);
|
||||
accountRoot.setFieldU16(ripple::sfLedgerEntryType, ripple::ltACCOUNT_ROOT);
|
||||
@@ -115,6 +116,7 @@ CreateAccountRootObject(
|
||||
accountRoot.setFieldH256(
|
||||
ripple::sfPreviousTxnID, ripple::uint256{previousTxnID});
|
||||
accountRoot.setFieldU32(ripple::sfPreviousTxnLgrSeq, previousTxnSeq);
|
||||
accountRoot.setFieldU32(ripple::sfTransferRate, transferRate);
|
||||
return accountRoot;
|
||||
}
|
||||
|
||||
@@ -303,11 +305,12 @@ CreateRippleStateLedgerObject(
|
||||
std::string_view highNodeAccountId,
|
||||
int highLimit,
|
||||
std::string_view previousTxnId,
|
||||
uint32_t previousTxnSeq)
|
||||
uint32_t previousTxnSeq,
|
||||
uint32_t flag)
|
||||
{
|
||||
auto line = ripple::STObject(ripple::sfLedgerEntry);
|
||||
line.setFieldU16(ripple::sfLedgerEntryType, ripple::ltRIPPLE_STATE);
|
||||
line.setFieldU32(ripple::sfFlags, 0);
|
||||
line.setFieldU32(ripple::sfFlags, flag);
|
||||
line.setFieldAmount(
|
||||
ripple::sfBalance,
|
||||
ripple::STAmount(GetIssue(currency, issuerId), balance));
|
||||
@@ -327,22 +330,27 @@ CreateOfferLedgerObject(
|
||||
std::string_view account,
|
||||
int takerGets,
|
||||
int takerPays,
|
||||
std::string_view currency,
|
||||
std::string_view issueId)
|
||||
std::string_view getsCurrency,
|
||||
std::string_view paysCurrency,
|
||||
std::string_view getsIssueId,
|
||||
std::string_view paysIssueId,
|
||||
std::string_view dirId)
|
||||
{
|
||||
ripple::STObject offer(ripple::sfLedgerEntry);
|
||||
offer.setFieldU16(ripple::sfLedgerEntryType, ripple::ltOFFER);
|
||||
offer.setAccountID(ripple::sfAccount, GetAccountIDWithString(account));
|
||||
offer.setFieldU32(ripple::sfSequence, 0);
|
||||
offer.setFieldU32(ripple::sfFlags, 0);
|
||||
ripple::Issue issue1 = GetIssue(currency, issueId);
|
||||
ripple::Issue issue1 = GetIssue(getsCurrency, getsIssueId);
|
||||
offer.setFieldAmount(
|
||||
ripple::sfTakerGets, ripple::STAmount(issue1, takerGets));
|
||||
ripple::Issue issue2 = GetIssue(paysCurrency, paysIssueId);
|
||||
offer.setFieldAmount(
|
||||
ripple::sfTakerPays, ripple::STAmount(takerPays, false));
|
||||
ripple::sfTakerPays, ripple::STAmount(issue2, takerPays));
|
||||
offer.setFieldH256(ripple::sfBookDirectory, ripple::uint256{});
|
||||
offer.setFieldU64(ripple::sfBookNode, 0);
|
||||
offer.setFieldU64(ripple::sfOwnerNode, 0);
|
||||
offer.setFieldH256(ripple::sfBookDirectory, ripple::uint256{dirId});
|
||||
offer.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{});
|
||||
offer.setFieldU32(ripple::sfPreviousTxnLgrSeq, 0);
|
||||
return offer;
|
||||
|
||||
@@ -79,7 +79,8 @@ CreateAccountRootObject(
|
||||
int balance,
|
||||
uint32_t ownerCount,
|
||||
std::string_view previousTxnID,
|
||||
uint32_t previousTxnSeq);
|
||||
uint32_t previousTxnSeq,
|
||||
uint32_t transferRate = 0);
|
||||
|
||||
/*
|
||||
* Create a createoffer treansaction
|
||||
@@ -168,15 +169,19 @@ CreateRippleStateLedgerObject(
|
||||
std::string_view highNodeAccountId,
|
||||
int highLimit,
|
||||
std::string_view previousTxnId,
|
||||
uint32_t previousTxnSeq);
|
||||
uint32_t previousTxnSeq,
|
||||
uint32_t flag = 0);
|
||||
|
||||
ripple::STObject
|
||||
CreateOfferLedgerObject(
|
||||
std::string_view account,
|
||||
int takerGets,
|
||||
int takerPays,
|
||||
std::string_view currency,
|
||||
std::string_view issueId);
|
||||
std::string_view getsCurrency,
|
||||
std::string_view payssCurrency,
|
||||
std::string_view getsIssueId,
|
||||
std::string_view paysIssueId,
|
||||
std::string_view bookDirId);
|
||||
|
||||
ripple::STObject
|
||||
CreateTicketLedgerObject(std::string_view rootIndex, uint32_t sequence);
|
||||
|
||||
Reference in New Issue
Block a user