Make database reads async

* yield on db read using asio
* PostgresBackend fetches multiple transactions or objects in parallel
This commit is contained in:
natenichols
2022-02-07 07:00:15 -06:00
committed by CJ Cobb
parent 7c2bef70bc
commit d016253264
50 changed files with 3612 additions and 2593 deletions

View File

@@ -1,10 +1,13 @@
#include <boost/asio/spawn.hpp>
#include <etl/ETLSource.h>
#include <rpc/Handlers.h>
#include <unordered_map>
namespace RPC {
std::optional<Context>
make_WsContext(
boost::asio::yield_context& yc,
boost::json::object const& request,
std::shared_ptr<BackendInterface const> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
@@ -20,6 +23,7 @@ make_WsContext(
std::string command = request.at("command").as_string().c_str();
return Context{
yc,
command,
1,
request,
@@ -34,6 +38,7 @@ make_WsContext(
std::optional<Context>
make_HttpContext(
boost::asio::yield_context& yc,
boost::json::object const& request,
std::shared_ptr<BackendInterface const> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
@@ -62,6 +67,7 @@ make_HttpContext(
return {};
return Context{
yc,
command,
1,
array.at(0).as_object(),
@@ -169,7 +175,8 @@ buildResponse(Context const& ctx)
boost::json::object toForward = ctx.params;
toForward["command"] = ctx.method;
auto res = ctx.balancer->forwardToRippled(toForward, ctx.clientIp);
auto res =
ctx.balancer->forwardToRippled(toForward, ctx.clientIp, ctx.yield);
ctx.counters.rpcForwarded(ctx.method);

View File

@@ -2,6 +2,7 @@
#define REPORTING_RPC_H_INCLUDED
#include <ripple/protocol/ErrorCodes.h>
#include <boost/asio/spawn.hpp>
#include <boost/json.hpp>
#include <backend/BackendInterface.h>
#include <optional>
@@ -27,6 +28,7 @@ namespace RPC {
struct Context
{
boost::asio::yield_context& yield;
std::string method;
std::uint32_t version;
boost::json::object const& params;
@@ -42,6 +44,7 @@ struct Context
std::string clientIp;
Context(
boost::asio::yield_context& yield_,
std::string const& command_,
std::uint32_t version_,
boost::json::object const& params_,
@@ -52,7 +55,8 @@ struct Context
Backend::LedgerRange const& range_,
Counters& counters_,
std::string const& clientIp_)
: method(command_)
: yield(yield_)
, method(command_)
, version(version_)
, params(params_)
, backend(backend_)
@@ -135,6 +139,7 @@ make_error(Error err);
std::optional<Context>
make_WsContext(
boost::asio::yield_context& yc,
boost::json::object const& request,
std::shared_ptr<BackendInterface const> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
@@ -146,6 +151,7 @@ make_WsContext(
std::optional<Context>
make_HttpContext(
boost::asio::yield_context& yc,
boost::json::object const& request,
std::shared_ptr<BackendInterface const> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,

View File

@@ -32,7 +32,8 @@ getRequiredBool(boost::json::object const& request, std::string const& field)
else
throw InvalidParamsError("Missing field " + field);
}
std::optional<uint32_t>
std::optional<std::uint32_t>
getUInt(boost::json::object const& request, std::string const& field)
{
if (!request.contains(field))
@@ -44,18 +45,20 @@ getUInt(boost::json::object const& request, std::string const& field)
else
throw InvalidParamsError("Invalid field " + field + ", not uint.");
}
uint32_t
std::uint32_t
getUInt(
boost::json::object const& request,
std::string const& field,
uint32_t dfault)
std::uint32_t const dfault)
{
if (auto res = getUInt(request, field))
return *res;
else
return dfault;
}
uint32_t
std::uint32_t
getRequiredUInt(boost::json::object const& request, std::string const& field)
{
if (auto res = getUInt(request, field))
@@ -63,6 +66,7 @@ getRequiredUInt(boost::json::object const& request, std::string const& field)
else
throw InvalidParamsError("Missing field " + field);
}
std::optional<std::string>
getString(boost::json::object const& request, std::string const& field)
{
@@ -97,7 +101,7 @@ std::optional<ripple::STAmount>
getDeliveredAmount(
std::shared_ptr<ripple::STTx const> const& txn,
std::shared_ptr<ripple::TxMeta const> const& meta,
uint32_t ledgerSequence)
std::uint32_t const ledgerSequence)
{
if (meta->hasDeliveredAmount())
return meta->getDeliveredAmount();
@@ -358,7 +362,7 @@ ledgerInfoFromRequest(Context const& ctx)
if (!ledgerHash.parseHex(hashValue.as_string().c_str()))
return Status{Error::rpcINVALID_PARAMS, "ledgerHashMalformed"};
lgrInfo = ctx.backend->fetchLedgerByHash(ledgerHash);
lgrInfo = ctx.backend->fetchLedgerByHash(ledgerHash, ctx.yield);
}
else if (!indexValue.is_null())
{
@@ -370,11 +374,12 @@ ledgerInfoFromRequest(Context const& ctx)
else
return Status{Error::rpcINVALID_PARAMS, "ledgerIndexMalformed"};
lgrInfo = ctx.backend->fetchLedgerBySequence(ledgerSequence);
lgrInfo = ctx.backend->fetchLedgerBySequence(ledgerSequence, ctx.yield);
}
else
{
lgrInfo = ctx.backend->fetchLedgerBySequence(ctx.range.maxSequence);
lgrInfo = ctx.backend->fetchLedgerBySequence(
ctx.range.maxSequence, ctx.yield);
}
if (!lgrInfo)
@@ -407,10 +412,11 @@ traverseOwnedNodes(
ripple::AccountID const& accountID,
std::uint32_t sequence,
ripple::uint256 const& cursor,
boost::asio::yield_context& yield,
std::function<bool(ripple::SLE)> atOwnedNode)
{
if (!backend.fetchLedgerObject(
ripple::keylet::account(accountID).key, sequence))
ripple::keylet::account(accountID).key, sequence, yield))
throw AccountNotFoundError(ripple::toBase58(accountID));
auto const rootIndex = ripple::keylet::ownerDir(accountID);
auto currentIndex = rootIndex;
@@ -421,7 +427,8 @@ traverseOwnedNodes(
auto start = std::chrono::system_clock::now();
for (;;)
{
auto ownedNode = backend.fetchLedgerObject(currentIndex.key, sequence);
auto ownedNode =
backend.fetchLedgerObject(currentIndex.key, sequence, yield);
if (!ownedNode)
{
@@ -449,7 +456,7 @@ traverseOwnedNodes(
<< ((end - start).count() / 1000000000.0);
start = std::chrono::system_clock::now();
auto objects = backend.fetchLedgerObjects(keys, sequence);
auto objects = backend.fetchLedgerObjects(keys, sequence, yield);
end = std::chrono::system_clock::now();
BOOST_LOG_TRIVIAL(debug) << "Time loading owned entries: "
@@ -639,13 +646,14 @@ bool
isGlobalFrozen(
BackendInterface const& backend,
std::uint32_t sequence,
ripple::AccountID const& issuer)
ripple::AccountID const& issuer,
boost::asio::yield_context& yield)
{
if (ripple::isXRP(issuer))
return false;
auto key = ripple::keylet::account(issuer).key;
auto blob = backend.fetchLedgerObject(key, sequence);
auto blob = backend.fetchLedgerObject(key, sequence, yield);
if (!blob)
return false;
@@ -662,13 +670,14 @@ isFrozen(
std::uint32_t sequence,
ripple::AccountID const& account,
ripple::Currency const& currency,
ripple::AccountID const& issuer)
ripple::AccountID const& issuer,
boost::asio::yield_context& yield)
{
if (ripple::isXRP(currency))
return false;
auto key = ripple::keylet::account(issuer).key;
auto blob = backend.fetchLedgerObject(key, sequence);
auto blob = backend.fetchLedgerObject(key, sequence, yield);
if (!blob)
return false;
@@ -682,7 +691,7 @@ isFrozen(
if (issuer != account)
{
key = ripple::keylet::line(account, issuer, currency).key;
blob = backend.fetchLedgerObject(key, sequence);
blob = backend.fetchLedgerObject(key, sequence, yield);
if (!blob)
return false;
@@ -704,10 +713,11 @@ ripple::XRPAmount
xrpLiquid(
BackendInterface const& backend,
std::uint32_t sequence,
ripple::AccountID const& id)
ripple::AccountID const& id,
boost::asio::yield_context& yield)
{
auto key = ripple::keylet::account(id).key;
auto blob = backend.fetchLedgerObject(key, sequence);
auto blob = backend.fetchLedgerObject(key, sequence, yield);
if (!blob)
return beast::zero;
@@ -718,7 +728,7 @@ xrpLiquid(
std::uint32_t const ownerCount = sle.getFieldU32(ripple::sfOwnerCount);
auto const reserve =
backend.fetchFees(sequence)->accountReserve(ownerCount);
backend.fetchFees(sequence, yield)->accountReserve(ownerCount);
auto const balance = sle.getFieldAmount(ripple::sfBalance);
@@ -732,9 +742,10 @@ xrpLiquid(
ripple::STAmount
accountFunds(
BackendInterface const& backend,
uint32_t sequence,
std::uint32_t const sequence,
ripple::STAmount const& amount,
ripple::AccountID const& id)
ripple::AccountID const& id,
boost::asio::yield_context& yield)
{
if (!amount.native() && amount.getIssuer() == id)
{
@@ -743,7 +754,13 @@ accountFunds(
else
{
return accountHolds(
backend, sequence, id, amount.getCurrency(), amount.getIssuer());
backend,
sequence,
id,
amount.getCurrency(),
amount.getIssuer(),
true,
yield);
}
}
@@ -754,16 +771,17 @@ accountHolds(
ripple::AccountID const& account,
ripple::Currency const& currency,
ripple::AccountID const& issuer,
bool zeroIfFrozen)
bool const zeroIfFrozen,
boost::asio::yield_context& yield)
{
ripple::STAmount amount;
if (ripple::isXRP(currency))
{
return {xrpLiquid(backend, sequence, account)};
return {xrpLiquid(backend, sequence, account, yield)};
}
auto key = ripple::keylet::line(account, issuer, currency).key;
auto const blob = backend.fetchLedgerObject(key, sequence);
auto const blob = backend.fetchLedgerObject(key, sequence, yield);
if (!blob)
{
@@ -774,7 +792,8 @@ accountHolds(
ripple::SerialIter it{blob->data(), blob->size()};
ripple::SLE sle{it, key};
if (zeroIfFrozen && isFrozen(backend, sequence, account, currency, issuer))
if (zeroIfFrozen &&
isFrozen(backend, sequence, account, currency, issuer, yield))
{
amount.clear(ripple::Issue(currency, issuer));
}
@@ -796,10 +815,11 @@ ripple::Rate
transferRate(
BackendInterface const& backend,
std::uint32_t sequence,
ripple::AccountID const& issuer)
ripple::AccountID const& issuer,
boost::asio::yield_context& yield)
{
auto key = ripple::keylet::account(issuer).key;
auto blob = backend.fetchLedgerObject(key, sequence);
auto blob = backend.fetchLedgerObject(key, sequence, yield);
if (blob)
{
@@ -819,17 +839,18 @@ postProcessOrderBook(
ripple::Book const& book,
ripple::AccountID const& takerID,
Backend::BackendInterface const& backend,
uint32_t ledgerSequence)
std::uint32_t const ledgerSequence,
boost::asio::yield_context& yield)
{
boost::json::array jsonOffers;
std::map<ripple::AccountID, ripple::STAmount> umBalance;
bool globalFreeze =
isGlobalFrozen(backend, ledgerSequence, book.out.account) ||
isGlobalFrozen(backend, ledgerSequence, book.out.account);
isGlobalFrozen(backend, ledgerSequence, book.out.account, yield) ||
isGlobalFrozen(backend, ledgerSequence, book.out.account, yield);
auto rate = transferRate(backend, ledgerSequence, book.out.account);
auto rate = transferRate(backend, ledgerSequence, book.out.account, yield);
for (auto const& obj : offers)
{
@@ -877,7 +898,8 @@ postProcessOrderBook(
uOfferOwnerID,
book.out.currency,
book.out.account,
zeroIfFrozen);
zeroIfFrozen,
yield);
if (saOwnerFunds < beast::zero)
saOwnerFunds.clear();

View File

@@ -64,7 +64,7 @@ generatePubLedgerMessage(
ripple::LedgerInfo const& lgrInfo,
ripple::Fees const& fees,
std::string const& ledgerRange,
uint32_t txnCount);
std::uint32_t txnCount);
std::variant<Status, ripple::LedgerInfo>
ledgerInfoFromRequest(Context const& ctx);
@@ -75,6 +75,7 @@ traverseOwnedNodes(
ripple::AccountID const& accountID,
std::uint32_t sequence,
ripple::uint256 const& cursor,
boost::asio::yield_context& yield,
std::function<bool(ripple::SLE)> atOwnedNode);
std::variant<Status, std::pair<ripple::PublicKey, ripple::SecretKey>>
@@ -90,7 +91,8 @@ bool
isGlobalFrozen(
BackendInterface const& backend,
std::uint32_t seq,
ripple::AccountID const& issuer);
ripple::AccountID const& issuer,
boost::asio::yield_context& yield);
bool
isFrozen(
@@ -98,14 +100,16 @@ isFrozen(
std::uint32_t sequence,
ripple::AccountID const& account,
ripple::Currency const& currency,
ripple::AccountID const& issuer);
ripple::AccountID const& issuer,
boost::asio::yield_context& yield);
ripple::STAmount
accountFunds(
BackendInterface const& backend,
uint32_t sequence,
std::uint32_t sequence,
ripple::STAmount const& amount,
ripple::AccountID const& id);
ripple::AccountID const& id,
boost::asio::yield_context& yield);
ripple::STAmount
accountHolds(
@@ -114,26 +118,31 @@ accountHolds(
ripple::AccountID const& account,
ripple::Currency const& currency,
ripple::AccountID const& issuer,
bool zeroIfFrozen = false);
bool zeroIfFrozen,
boost::asio::yield_context& yield);
ripple::Rate
transferRate(
BackendInterface const& backend,
std::uint32_t sequence,
ripple::AccountID const& issuer);
ripple::AccountID const& issuer,
boost::asio::yield_context& yield);
ripple::XRPAmount
xrpLiquid(
BackendInterface const& backend,
std::uint32_t sequence,
ripple::AccountID const& id);
ripple::AccountID const& id,
boost::asio::yield_context& yield);
boost::json::array
postProcessOrderBook(
std::vector<Backend::LedgerObject> const& offers,
ripple::Book const& book,
ripple::AccountID const& takerID,
Backend::BackendInterface const& backend,
uint32_t ledgerSequence);
std::uint32_t ledgerSequence,
boost::asio::yield_context& yield);
std::variant<Status, ripple::Book>
parseBook(boost::json::object const& request);
@@ -141,16 +150,16 @@ parseBook(boost::json::object const& request);
std::variant<Status, ripple::AccountID>
parseTaker(boost::json::value const& request);
std::optional<uint32_t>
std::optional<std::uint32_t>
getUInt(boost::json::object const& request, std::string const& field);
uint32_t
std::uint32_t
getUInt(
boost::json::object const& request,
std::string const& field,
uint32_t dfault);
std::uint32_t dfault);
uint32_t
std::uint32_t
getRequiredUInt(boost::json::object const& request, std::string const& field);
std::optional<bool>

View File

@@ -122,7 +122,12 @@ doAccountChannels(Context const& context)
};
auto nextCursor = traverseOwnedNodes(
*context.backend, *accountID, lgrInfo.seq, marker, addToResponse);
*context.backend,
*accountID,
lgrInfo.seq,
marker,
context.yield,
addToResponse);
response["ledger_hash"] = ripple::strHex(lgrInfo.hash);
response["ledger_index"] = lgrInfo.seq;

View File

@@ -60,7 +60,12 @@ doAccountCurrencies(Context const& context)
};
traverseOwnedNodes(
*context.backend, *accountID, lgrInfo.seq, beast::zero, addToResponse);
*context.backend,
*accountID,
lgrInfo.seq,
beast::zero,
context.yield,
addToResponse);
response["ledger_hash"] = ripple::strHex(lgrInfo.hash);
response["ledger_index"] = lgrInfo.seq;

View File

@@ -64,7 +64,7 @@ doAccountInfo(Context const& context)
auto start = std::chrono::system_clock::now();
std::optional<std::vector<unsigned char>> dbResponse =
context.backend->fetchLedgerObject(key.key, lgrInfo.seq);
context.backend->fetchLedgerObject(key.key, lgrInfo.seq, context.yield);
auto end = std::chrono::system_clock::now();
auto time =
@@ -103,8 +103,8 @@ doAccountInfo(Context const& context)
// This code will need to be revisited if in the future we
// support multiple SignerLists on one account.
auto const signers =
context.backend->fetchLedgerObject(signersKey.key, lgrInfo.seq);
auto const signers = context.backend->fetchLedgerObject(
signersKey.key, lgrInfo.seq, context.yield);
if (signers)
{
ripple::STLedgerEntry sleSigners{

View File

@@ -166,7 +166,12 @@ doAccountLines(Context const& context)
};
auto nextCursor = traverseOwnedNodes(
*context.backend, *accountID, lgrInfo.seq, cursor, addToResponse);
*context.backend,
*accountID,
lgrInfo.seq,
cursor,
context.yield,
addToResponse);
if (nextCursor)
response["marker"] = ripple::strHex(*nextCursor);

View File

@@ -102,7 +102,12 @@ doAccountObjects(Context const& context)
};
auto nextCursor = traverseOwnedNodes(
*context.backend, *accountID, lgrInfo.seq, cursor, addToResponse);
*context.backend,
*accountID,
lgrInfo.seq,
cursor,
context.yield,
addToResponse);
response["ledger_hash"] = ripple::strHex(lgrInfo.hash);
response["ledger_index"] = lgrInfo.seq;

View File

@@ -128,7 +128,12 @@ doAccountOffers(Context const& context)
};
auto nextCursor = traverseOwnedNodes(
*context.backend, *accountID, lgrInfo.seq, cursor, addToResponse);
*context.backend,
*accountID,
lgrInfo.seq,
cursor,
context.yield,
addToResponse);
if (nextCursor)
response["marker"] = ripple::strHex(*nextCursor);

View File

@@ -54,7 +54,8 @@ doAccountTx(Context const& context)
return Status{
Error::rpcINVALID_PARAMS, "transactionIndexNotInt"};
transactionIndex = value_to<std::uint32_t>(obj.at("seq"));
transactionIndex =
boost::json::value_to<std::uint32_t>(obj.at("seq"));
}
std::optional<std::uint32_t> ledgerIndex = {};
@@ -63,7 +64,8 @@ doAccountTx(Context const& context)
if (!obj.at("ledger").is_int64())
return Status{Error::rpcINVALID_PARAMS, "ledgerIndexNotInt"};
ledgerIndex = value_to<std::uint32_t>(obj.at("ledger"));
ledgerIndex =
boost::json::value_to<std::uint32_t>(obj.at("ledger"));
}
if (!transactionIndex || !ledgerIndex)
@@ -124,7 +126,8 @@ doAccountTx(Context const& context)
if (!request.at("ledger_index").is_int64())
return Status{Error::rpcINVALID_PARAMS, "ledgerIndexNotNumber"};
auto ledgerIndex = value_to<uint32_t>(request.at("ledger_index"));
auto ledgerIndex =
boost::json::value_to<std::uint32_t>(request.at("ledger_index"));
maxIndex = minIndex = ledgerIndex;
}
@@ -139,7 +142,8 @@ doAccountTx(Context const& context)
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS, "ledgerHashMalformed"};
auto lgrInfo = context.backend->fetchLedgerByHash(ledgerHash);
auto lgrInfo =
context.backend->fetchLedgerByHash(ledgerHash, context.yield);
maxIndex = minIndex = lgrInfo->seq;
}
@@ -167,7 +171,7 @@ doAccountTx(Context const& context)
boost::json::array txns;
auto start = std::chrono::system_clock::now();
auto [blobs, retCursor] = context.backend->fetchAccountTransactions(
*accountID, limit, forward, cursor);
*accountID, limit, forward, cursor, context.yield);
auto end = std::chrono::system_clock::now();
BOOST_LOG_TRIVIAL(info) << __func__ << " db fetch took "

View File

@@ -82,8 +82,8 @@ doBookOffers(Context const& context)
}
auto start = std::chrono::system_clock::now();
auto [offers, retCursor, warning] =
context.backend->fetchBookOffers(bookBase, lgrInfo.seq, limit, cursor);
auto [offers, retCursor, warning] = context.backend->fetchBookOffers(
bookBase, lgrInfo.seq, limit, cursor, context.yield);
auto end = std::chrono::system_clock::now();
BOOST_LOG_TRIVIAL(warning)
@@ -93,7 +93,7 @@ doBookOffers(Context const& context)
response["ledger_index"] = lgrInfo.seq;
response["offers"] = postProcessOrderBook(
offers, book, takerID, *context.backend, lgrInfo.seq);
offers, book, takerID, *context.backend, lgrInfo.seq, context.yield);
end = std::chrono::system_clock::now();

View File

@@ -145,8 +145,14 @@ doGatewayBalances(Context const& context)
}
return true;
};
traverseOwnedNodes(
*context.backend, *accountID, lgrInfo.seq, beast::zero, addToResponse);
*context.backend,
*accountID,
lgrInfo.seq,
beast::zero,
context.yield,
addToResponse);
if (!sums.empty())
{

View File

@@ -85,8 +85,8 @@ doLedger(Context const& context)
boost::json::array& jsonTxs = header.at("transactions").as_array();
if (expand)
{
auto txns =
context.backend->fetchAllTransactionsInLedger(lgrInfo.seq);
auto txns = context.backend->fetchAllTransactionsInLedger(
lgrInfo.seq, context.yield);
std::transform(
std::move_iterator(txns.begin()),
@@ -111,8 +111,8 @@ doLedger(Context const& context)
}
else
{
auto hashes =
context.backend->fetchAllTransactionHashesInLedger(lgrInfo.seq);
auto hashes = context.backend->fetchAllTransactionHashesInLedger(
lgrInfo.seq, context.yield);
std::transform(
std::move_iterator(hashes.begin()),
std::move_iterator(hashes.end()),
@@ -128,7 +128,8 @@ doLedger(Context const& context)
{
header["diff"] = boost::json::value(boost::json::array_kind);
boost::json::array& jsonDiff = header.at("diff").as_array();
auto diff = context.backend->fetchLedgerDiff(lgrInfo.seq);
auto diff =
context.backend->fetchLedgerDiff(lgrInfo.seq, context.yield);
for (auto const& obj : diff)
{
boost::json::object entry;

View File

@@ -43,7 +43,7 @@ doLedgerData(Context const& context)
if (!request.at("limit").is_int64())
return Status{Error::rpcINVALID_PARAMS, "limitNotInteger"};
limit = value_to<int>(request.at("limit"));
limit = boost::json::value_to<int>(request.at("limit"));
}
std::optional<ripple::uint256> cursor;
@@ -67,7 +67,8 @@ doLedgerData(Context const& context)
Backend::LedgerPage page;
auto start = std::chrono::system_clock::now();
page = context.backend->fetchLedgerPage(cursor, lgrInfo.seq, limit);
page = context.backend->fetchLedgerPage(
cursor, lgrInfo.seq, limit, 0, context.yield);
auto end = std::chrono::system_clock::now();

View File

@@ -128,7 +128,8 @@ doLedgerEntry(Context const& context)
{
auto directory = request.at("directory").as_object();
std::uint64_t subIndex = directory.contains("sub_index")
? value_to<std::uint64_t>(directory.at("sub_index"))
? boost::json::value_to<std::uint64_t>(
directory.at("sub_index"))
: 0;
if (directory.contains("dir_root"))
@@ -242,7 +243,8 @@ doLedgerEntry(Context const& context)
return Status{Error::rpcINVALID_PARAMS, "malformedAccount"};
else
{
std::uint32_t seq = value_to<std::uint32_t>(offer.at("seq"));
std::uint32_t seq =
boost::json::value_to<std::uint32_t>(offer.at("seq"));
key = ripple::keylet::offer(*id, seq).key;
}
}
@@ -342,7 +344,8 @@ doLedgerEntry(Context const& context)
}
auto start = std::chrono::system_clock::now();
auto dbResponse = context.backend->fetchLedgerObject(key, lgrInfo.seq);
auto dbResponse =
context.backend->fetchLedgerObject(key, lgrInfo.seq, context.yield);
auto end = std::chrono::system_clock::now();
auto time =
std::chrono::duration_cast<std::chrono::microseconds>(end - start)

View File

@@ -45,14 +45,15 @@ doNoRippleCheck(Context const& context)
return *status;
auto lgrInfo = std::get<ripple::LedgerInfo>(v);
std::optional<ripple::Fees> fees =
includeTxs ? context.backend->fetchFees(lgrInfo.seq) : std::nullopt;
std::optional<ripple::Fees> fees = includeTxs
? context.backend->fetchFees(lgrInfo.seq, context.yield)
: std::nullopt;
boost::json::array transactions;
auto keylet = ripple::keylet::account(*accountID);
auto accountObj =
context.backend->fetchLedgerObject(keylet.key, lgrInfo.seq);
auto accountObj = context.backend->fetchLedgerObject(
keylet.key, lgrInfo.seq, context.yield);
if (!accountObj)
throw AccountNotFoundError(ripple::toBase58(*accountID));
@@ -90,6 +91,7 @@ doNoRippleCheck(Context const& context)
*accountID,
lgrInfo.seq,
{},
context.yield,
[roleGateway,
includeTxs,
&fees,

View File

@@ -30,12 +30,15 @@ doServerInfo(Context const& context)
info["counters"].as_object()["rpc"] = context.counters.report();
}
auto serverInfoRippled =
context.balancer->forwardToRippled(context.params, context.clientIp);
auto serverInfoRippled = context.balancer->forwardToRippled(
context.params, context.clientIp, context.yield);
if (serverInfoRippled && !serverInfoRippled->contains("error"))
response["info"].as_object()["load_factor"] = 1;
auto lgrInfo = context.backend->fetchLedgerBySequence(range->maxSequence);
auto lgrInfo = context.backend->fetchLedgerBySequence(
range->maxSequence, context.yield);
assert(lgrInfo.has_value());
auto age = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch())
@@ -46,7 +49,7 @@ doServerInfo(Context const& context)
validatedLgr["age"] = age;
validatedLgr["hash"] = ripple::strHex(lgrInfo->hash);
validatedLgr["seq"] = lgrInfo->seq;
auto fees = context.backend->fetchFees(lgrInfo->seq);
auto fees = context.backend->fetchFees(lgrInfo->seq, context.yield);
assert(fees.has_value());
validatedLgr["base_fee_xrp"] = fees->base.decimalXRP();
validatedLgr["reserve_base_xrp"] = fees->reserve.decimalXRP();

View File

@@ -35,6 +35,7 @@ validateStreams(boost::json::object const& request)
boost::json::object
subscribeToStreams(
boost::asio::yield_context& yield,
boost::json::object const& request,
std::shared_ptr<WsBase> session,
SubscriptionManager& manager)
@@ -47,7 +48,7 @@ subscribeToStreams(
std::string s = stream.as_string().c_str();
if (s == "ledger")
response = manager.subLedger(session);
response = manager.subLedger(yield, session);
else if (s == "transactions")
manager.subTransactions(session);
else if (s == "transactions_proposed")
@@ -207,6 +208,7 @@ unsubscribeToAccountsProposed(
std::variant<Status, std::pair<std::vector<ripple::Book>, boost::json::array>>
validateAndGetBooks(
boost::asio::yield_context& yield,
boost::json::object const& request,
std::shared_ptr<Backend::BackendInterface const> const& backend)
{
@@ -245,23 +247,29 @@ validateAndGetBooks(
takerID = std::get<ripple::AccountID>(parsed);
}
}
auto getOrderBook =
[&snapshot, &backend, &rng, &takerID](auto book) {
auto bookBase = getBookBase(book);
auto [offers, retCursor, warning] =
backend->fetchBookOffers(
bookBase, rng->maxSequence, 200, {});
auto getOrderBook = [&snapshot, &backend, &rng, &takerID](
auto book,
boost::asio::yield_context& yield) {
auto bookBase = getBookBase(book);
auto [offers, retCursor, warning] =
backend->fetchBookOffers(
bookBase, rng->maxSequence, 200, {}, yield);
auto orderBook = postProcessOrderBook(
offers, book, takerID, *backend, rng->maxSequence);
std::copy(
orderBook.begin(),
orderBook.end(),
std::back_inserter(snapshot));
};
getOrderBook(b);
auto orderBook = postProcessOrderBook(
offers,
book,
takerID,
*backend,
rng->maxSequence,
yield);
std::copy(
orderBook.begin(),
orderBook.end(),
std::back_inserter(snapshot));
};
getOrderBook(b, yield);
if (both)
getOrderBook(ripple::reversed(b));
getOrderBook(ripple::reversed(b), yield);
}
}
}
@@ -322,7 +330,8 @@ doSubscribe(Context const& context)
boost::json::array snapshot;
if (request.contains("books"))
{
auto parsed = validateAndGetBooks(request, context.backend);
auto parsed =
validateAndGetBooks(context.yield, request, context.backend);
if (auto status = std::get_if<Status>(&parsed))
return *status;
auto [bks, snap] =
@@ -335,7 +344,7 @@ doSubscribe(Context const& context)
boost::json::object response;
if (request.contains("streams"))
response = subscribeToStreams(
request, context.session, *context.subscriptions);
context.yield, request, context.session, *context.subscriptions);
if (request.contains("accounts"))
subscribeToAccounts(request, context.session, *context.subscriptions);

View File

@@ -16,7 +16,7 @@ doTransactionEntry(Context const& context)
if (!hash.parseHex(getRequiredString(context.params, "tx_hash")))
return Status{Error::rpcINVALID_PARAMS, "malformedTransaction"};
auto dbResponse = context.backend->fetchTransaction(hash);
auto dbResponse = context.backend->fetchTransaction(hash, context.yield);
// Note: transaction_entry is meant to only search a specified ledger for
// the specified transaction. tx searches the entire range of history. For
// rippled, having two separate commands made sense, as tx would use SQLite

View File

@@ -37,7 +37,7 @@ doTx(Context const& context)
if (!range)
return Status{Error::rpcNOT_READY};
auto dbResponse = context.backend->fetchTransaction(hash);
auto dbResponse = context.backend->fetchTransaction(hash, context.yield);
if (!dbResponse)
return Status{Error::rpcTXN_NOT_FOUND};