refactor: Use std::expected instead of std::variant for errors (#2160)

This commit is contained in:
Ayaz Salikhov
2025-06-03 13:34:25 +01:00
committed by GitHub
parent 19257f8aa9
commit 550f0fae85
40 changed files with 295 additions and 310 deletions

View File

@@ -163,19 +163,17 @@ public:
[this, &ctx](boost::asio::yield_context
) -> std::expected<util::ResponseExpirationCache::EntryData, util::ResponseExpirationCache::Error> {
auto result = buildResponseImpl(ctx);
auto extracted = std::visit(
util::OverloadSet{
[&result](Status status
) -> std::expected<boost::json::object, util::ResponseExpirationCache::Error> {
auto const extracted =
[&result]() -> std::expected<boost::json::object, util::ResponseExpirationCache::Error> {
if (result.response.has_value())
return std::move(result.response).value();
else
return std::unexpected{util::ResponseExpirationCache::Error{
.status = std::move(status), .warnings = std::move(result.warnings)
.status = std::move(result.response).error(), .warnings = std::move(result.warnings)
}};
},
[](boost::json::object obj
) -> std::expected<boost::json::object, util::ResponseExpirationCache::Error> { return obj; }
},
std::move(result.response)
);
}();
if (extracted.has_value()) {
return util::ResponseExpirationCache::EntryData{
.lastUpdated = std::chrono::steady_clock::now(), .response = std::move(extracted).value()

View File

@@ -467,23 +467,23 @@ parseStringAsUInt(std::string const& value)
return index;
}
std::variant<Status, ripple::LedgerHeader>
std::expected<ripple::LedgerHeader, Status>
ledgerHeaderFromRequest(std::shared_ptr<data::BackendInterface const> const& backend, web::Context const& ctx)
{
auto hashValue = ctx.params.contains("ledger_hash") ? ctx.params.at("ledger_hash") : nullptr;
if (!hashValue.is_null()) {
if (!hashValue.is_string())
return Status{RippledError::rpcINVALID_PARAMS, "ledgerHashNotString"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "ledgerHashNotString"}};
ripple::uint256 ledgerHash;
if (!ledgerHash.parseHex(boost::json::value_to<std::string>(hashValue)))
return Status{RippledError::rpcINVALID_PARAMS, "ledgerHashMalformed"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "ledgerHashMalformed"}};
auto lgrInfo = backend->fetchLedgerByHash(ledgerHash, ctx.yield);
if (!lgrInfo || lgrInfo->seq > ctx.range.maxSequence)
return Status{RippledError::rpcLGR_NOT_FOUND, "ledgerNotFound"};
return std::unexpected{Status{RippledError::rpcLGR_NOT_FOUND, "ledgerNotFound"}};
return *lgrInfo;
}
@@ -507,18 +507,18 @@ ledgerHeaderFromRequest(std::shared_ptr<data::BackendInterface const> const& bac
}
if (!ledgerSequence)
return Status{RippledError::rpcINVALID_PARAMS, "ledgerIndexMalformed"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "ledgerIndexMalformed"}};
auto lgrInfo = backend->fetchLedgerBySequence(*ledgerSequence, ctx.yield);
if (!lgrInfo || lgrInfo->seq > ctx.range.maxSequence)
return Status{RippledError::rpcLGR_NOT_FOUND, "ledgerNotFound"};
return std::unexpected{Status{RippledError::rpcLGR_NOT_FOUND, "ledgerNotFound"}};
return *lgrInfo;
}
// extract ledgerHeaderFromRequest's parameter from context
std::variant<Status, ripple::LedgerHeader>
std::expected<ripple::LedgerHeader, Status>
getLedgerHeaderFromHashOrSeq(
BackendInterface const& backend,
boost::asio::yield_context yield,
@@ -528,7 +528,7 @@ getLedgerHeaderFromHashOrSeq(
)
{
std::optional<ripple::LedgerHeader> lgrInfo;
auto err = Status{RippledError::rpcLGR_NOT_FOUND, "ledgerNotFound"};
auto const err = std::unexpected{Status{RippledError::rpcLGR_NOT_FOUND, "ledgerNotFound"}};
if (ledgerHash) {
// invoke uint256's constructor to parse the hex string , instead of
// copying buffer
@@ -589,7 +589,7 @@ getStartHint(ripple::SLE const& sle, ripple::AccountID const& accountID)
// traverse account's nfts
// return Status if error occurs
// return [nextpage, count of nft already found] if success
std::variant<Status, AccountCursor>
std::expected<AccountCursor, Status>
traverseNFTObjects(
BackendInterface const& backend,
std::uint32_t sequence,
@@ -605,7 +605,7 @@ traverseNFTObjects(
// check if nextPage is valid
if (nextPage != beast::zero and firstNFTPage.key != (nextPage & ~ripple::nft::pageMask))
return Status{RippledError::rpcINVALID_PARAMS, "Invalid marker."};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "Invalid marker."}};
// no marker, start from the last page
ripple::uint256 const currentPage = nextPage == beast::zero ? lastNFTPage.key : nextPage;
@@ -618,7 +618,7 @@ traverseNFTObjects(
return AccountCursor{.index = beast::zero, .hint = 0};
}
// marker is in the right range, but still invalid
return Status{RippledError::rpcINVALID_PARAMS, "Invalid marker."};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "Invalid marker."}};
}
// the object exists and the key is in right range, must be nft page
@@ -641,7 +641,7 @@ traverseNFTObjects(
return AccountCursor{.index = beast::zero, .hint = 0};
}
std::variant<Status, AccountCursor>
std::expected<AccountCursor, Status>
traverseOwnedNodes(
BackendInterface const& backend,
ripple::AccountID const& accountID,
@@ -656,7 +656,7 @@ traverseOwnedNodes(
auto const maybeCursor = parseAccountCursor(jsonCursor);
if (!maybeCursor)
return Status{RippledError::rpcINVALID_PARAMS, "Malformed cursor."};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "Malformed cursor."}};
// the format is checked in RPC framework level
auto [hexCursor, startHint] = *maybeCursor;
@@ -670,10 +670,10 @@ traverseOwnedNodes(
if (nftIncluded and (!jsonCursor or isNftMarkerNonZero)) {
auto const cursorMaybe = traverseNFTObjects(backend, sequence, accountID, hexCursor, limit, yield, atOwnedNode);
if (auto const status = std::get_if<Status>(&cursorMaybe))
return *status;
if (!cursorMaybe.has_value())
return cursorMaybe;
auto const [nextNFTPage, nftsCount] = std::get<AccountCursor>(cursorMaybe);
auto const [nextNFTPage, nftsCount] = cursorMaybe.value();
// if limit reach , we return the next page and max as marker
if (nftsCount >= limit)
@@ -694,7 +694,7 @@ traverseOwnedNodes(
);
}
std::variant<Status, AccountCursor>
std::expected<AccountCursor, Status>
traverseOwnedNodes(
BackendInterface const& backend,
ripple::Keylet const& owner,
@@ -728,7 +728,7 @@ traverseOwnedNodes(
auto hintDir = backend.fetchLedgerObject(hintIndex.key, sequence, yield);
if (!hintDir)
return Status(ripple::rpcINVALID_PARAMS, "Invalid marker.");
return std::unexpected{Status(ripple::rpcINVALID_PARAMS, "Invalid marker.")};
ripple::SerialIter hintDirIt{hintDir->data(), hintDir->size()};
ripple::SLE const hintDirSle{hintDirIt, hintIndex.key};
@@ -736,7 +736,7 @@ traverseOwnedNodes(
if (auto const& indexes = hintDirSle.getFieldV256(ripple::sfIndexes);
std::ranges::find(indexes, hexMarker) == std::end(indexes)) {
// the index specified by marker is not in the page specified by marker
return Status(ripple::rpcINVALID_PARAMS, "Invalid marker.");
return std::unexpected{Status(ripple::rpcINVALID_PARAMS, "Invalid marker.")};
}
currentIndex = hintIndex;
@@ -745,7 +745,7 @@ traverseOwnedNodes(
auto const ownerDir = backend.fetchLedgerObject(currentIndex.key, sequence, yield);
if (!ownerDir)
return Status(ripple::rpcINVALID_PARAMS, "Owner directory not found.");
return std::unexpected{Status(ripple::rpcINVALID_PARAMS, "Owner directory not found.")};
ripple::SerialIter ownedDirIt{ownerDir->data(), ownerDir->size()};
ripple::SLE const ownedDirSle{ownedDirIt, currentIndex.key};
@@ -1309,120 +1309,122 @@ postProcessOrderBook(
}
// get book via currency type
std::variant<Status, ripple::Book>
std::expected<ripple::Book, Status>
parseBook(ripple::Currency pays, ripple::AccountID payIssuer, ripple::Currency gets, ripple::AccountID getIssuer)
{
if (isXRP(pays) && !isXRP(payIssuer)) {
return Status{
return std::unexpected{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."
return std::unexpected{
Status{RippledError::rpcSRC_ISR_MALFORMED, "Invalid field 'taker_pays.issuer', expected non-XRP issuer."}
};
}
if (ripple::isXRP(gets) && !ripple::isXRP(getIssuer)) {
return Status{
return std::unexpected{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."
return std::unexpected{
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 std::unexpected{Status{RippledError::rpcBAD_MARKET, "badMarket"}};
return ripple::Book{{pays, payIssuer}, {gets, getIssuer}};
}
std::variant<Status, ripple::Book>
std::expected<ripple::Book, Status>
parseBook(boost::json::object const& request)
{
if (!request.contains("taker_pays"))
return Status{RippledError::rpcINVALID_PARAMS, "Missing field 'taker_pays'"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "Missing field 'taker_pays'"}};
if (!request.contains("taker_gets"))
return Status{RippledError::rpcINVALID_PARAMS, "Missing field 'taker_gets'"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "Missing field 'taker_gets'"}};
if (!request.at("taker_pays").is_object())
return Status{RippledError::rpcINVALID_PARAMS, "Field 'taker_pays' is not an object"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "Field 'taker_pays' is not an object"}};
if (!request.at("taker_gets").is_object())
return Status{RippledError::rpcINVALID_PARAMS, "Field 'taker_gets' is not an object"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "Field 'taker_gets' is not an object"}};
auto takerPays = request.at("taker_pays").as_object();
if (!takerPays.contains("currency"))
return Status{RippledError::rpcSRC_CUR_MALFORMED};
return std::unexpected{Status{RippledError::rpcSRC_CUR_MALFORMED}};
if (!takerPays.at("currency").is_string())
return Status{RippledError::rpcSRC_CUR_MALFORMED};
return std::unexpected{Status{RippledError::rpcSRC_CUR_MALFORMED}};
auto takerGets = request.at("taker_gets").as_object();
if (!takerGets.contains("currency"))
return Status{RippledError::rpcDST_AMT_MALFORMED};
return std::unexpected{Status{RippledError::rpcDST_AMT_MALFORMED}};
if (!takerGets.at("currency").is_string()) {
return Status{
return std::unexpected{Status{
RippledError::rpcDST_AMT_MALFORMED,
};
}};
}
ripple::Currency payCurrency;
if (!ripple::to_currency(payCurrency, boost::json::value_to<std::string>(takerPays.at("currency"))))
return Status{RippledError::rpcSRC_CUR_MALFORMED};
return std::unexpected{Status{RippledError::rpcSRC_CUR_MALFORMED}};
ripple::Currency getCurrency;
if (!ripple::to_currency(getCurrency, boost::json::value_to<std::string>(takerGets["currency"])))
return Status{RippledError::rpcDST_AMT_MALFORMED};
return std::unexpected{Status{RippledError::rpcDST_AMT_MALFORMED}};
ripple::AccountID payIssuer;
if (takerPays.contains("issuer")) {
if (!takerPays.at("issuer").is_string())
return Status{RippledError::rpcINVALID_PARAMS, "takerPaysIssuerNotString"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "takerPaysIssuerNotString"}};
if (!ripple::to_issuer(payIssuer, boost::json::value_to<std::string>(takerPays.at("issuer"))))
return Status{RippledError::rpcSRC_ISR_MALFORMED};
return std::unexpected{Status{RippledError::rpcSRC_ISR_MALFORMED}};
if (payIssuer == ripple::noAccount())
return Status{RippledError::rpcSRC_ISR_MALFORMED};
return std::unexpected{Status{RippledError::rpcSRC_ISR_MALFORMED}};
} else {
payIssuer = ripple::xrpAccount();
}
if (isXRP(payCurrency) && !isXRP(payIssuer)) {
return Status{
return std::unexpected{Status{
RippledError::rpcSRC_ISR_MALFORMED, "Unneeded field 'taker_pays.issuer' for XRP currency specification."
};
}};
}
if (!isXRP(payCurrency) && isXRP(payIssuer)) {
return Status{
RippledError::rpcSRC_ISR_MALFORMED, "Invalid field 'taker_pays.issuer', expected non-XRP issuer."
return std::unexpected{
Status{RippledError::rpcSRC_ISR_MALFORMED, "Invalid field 'taker_pays.issuer', expected non-XRP issuer."}
};
}
if ((!isXRP(payCurrency)) && (!takerPays.contains("issuer")))
return Status{RippledError::rpcSRC_ISR_MALFORMED, "Missing non-XRP issuer."};
return std::unexpected{Status{RippledError::rpcSRC_ISR_MALFORMED, "Missing non-XRP issuer."}};
ripple::AccountID getIssuer;
if (takerGets.contains("issuer")) {
if (!takerGets["issuer"].is_string())
return Status{RippledError::rpcINVALID_PARAMS, "taker_gets.issuer should be string"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "taker_gets.issuer should be string"}};
if (!ripple::to_issuer(getIssuer, boost::json::value_to<std::string>(takerGets.at("issuer"))))
return Status{RippledError::rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', bad issuer."};
return std::unexpected{
Status{RippledError::rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', bad issuer."}
};
if (getIssuer == ripple::noAccount()) {
return Status{
RippledError::rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', bad issuer account one."
return std::unexpected{
Status{RippledError::rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', bad issuer account one."}
};
}
} else {
@@ -1430,34 +1432,34 @@ parseBook(boost::json::object const& request)
}
if (ripple::isXRP(getCurrency) && !ripple::isXRP(getIssuer)) {
return Status{
return std::unexpected{Status{
RippledError::rpcDST_ISR_MALFORMED, "Unneeded field 'taker_gets.issuer' for XRP currency specification."
};
}};
}
if (!ripple::isXRP(getCurrency) && ripple::isXRP(getIssuer)) {
return Status{
RippledError::rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', expected non-XRP issuer."
return std::unexpected{
Status{RippledError::rpcDST_ISR_MALFORMED, "Invalid field 'taker_gets.issuer', expected non-XRP issuer."}
};
}
if (payCurrency == getCurrency && payIssuer == getIssuer)
return Status{RippledError::rpcBAD_MARKET, "badMarket"};
return std::unexpected{Status{RippledError::rpcBAD_MARKET, "badMarket"}};
return ripple::Book{{payCurrency, payIssuer}, {getCurrency, getIssuer}};
}
std::variant<Status, ripple::AccountID>
std::expected<ripple::AccountID, Status>
parseTaker(boost::json::value const& taker)
{
std::optional<ripple::AccountID> takerID = {};
if (!taker.is_string())
return {Status{RippledError::rpcINVALID_PARAMS, "takerNotString"}};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "takerNotString"}};
takerID = accountFromStringStrict(boost::json::value_to<std::string>(taker));
if (!takerID)
return Status{RippledError::rpcBAD_ISSUER, "invalidTakerAccount"};
return std::unexpected{Status{RippledError::rpcBAD_ISSUER, "invalidTakerAccount"}};
return *takerID;
}
@@ -1511,18 +1513,18 @@ isAdminCmd(std::string const& method, boost::json::object const& request)
return false;
}
std::variant<ripple::uint256, Status>
std::expected<ripple::uint256, Status>
getNFTID(boost::json::object const& request)
{
if (!request.contains(JS(nft_id)))
return Status{RippledError::rpcINVALID_PARAMS, "missingTokenID"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "missingTokenID"}};
if (!request.at(JS(nft_id)).is_string())
return Status{RippledError::rpcINVALID_PARAMS, "tokenIDNotString"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "tokenIDNotString"}};
ripple::uint256 tokenid;
if (!tokenid.parseHex(boost::json::value_to<std::string>(request.at(JS(nft_id)))))
return Status{RippledError::rpcINVALID_PARAMS, "malformedTokenID"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "malformedTokenID"}};
return tokenid;
}

View File

@@ -73,7 +73,6 @@
#include <string>
#include <tuple>
#include <utility>
#include <variant>
#include <vector>
namespace rpc {
@@ -281,7 +280,7 @@ generatePubLedgerMessage(
* @param ctx The context of the request
* @return The ledger info or an error status
*/
std::variant<Status, ripple::LedgerHeader>
std::expected<ripple::LedgerHeader, Status>
ledgerHeaderFromRequest(std::shared_ptr<data::BackendInterface const> const& backend, web::Context const& ctx);
/**
@@ -294,7 +293,7 @@ ledgerHeaderFromRequest(std::shared_ptr<data::BackendInterface const> const& bac
* @param maxSeq The maximum sequence to search
* @return The ledger info or an error status
*/
std::variant<Status, ripple::LedgerHeader>
std::expected<ripple::LedgerHeader, Status>
getLedgerHeaderFromHashOrSeq(
BackendInterface const& backend,
boost::asio::yield_context yield,
@@ -316,7 +315,7 @@ getLedgerHeaderFromHashOrSeq(
* @param atOwnedNode The function to call for each owned node
* @return The status or the account cursor
*/
std::variant<Status, AccountCursor>
std::expected<AccountCursor, Status>
traverseOwnedNodes(
BackendInterface const& backend,
ripple::Keylet const& owner,
@@ -343,7 +342,7 @@ traverseOwnedNodes(
* @param nftIncluded Whether to include NFTs
* @return The status or the account cursor
*/
std::variant<Status, AccountCursor>
std::expected<AccountCursor, Status>
traverseOwnedNodes(
BackendInterface const& backend,
ripple::AccountID const& accountID,
@@ -628,7 +627,7 @@ postProcessOrderBook(
* @param getIssuer The issuer of the currency to get
* @return The book or an error status
*/
std::variant<Status, ripple::Book>
std::expected<ripple::Book, Status>
parseBook(ripple::Currency pays, ripple::AccountID payIssuer, ripple::Currency gets, ripple::AccountID getIssuer);
/**
@@ -637,7 +636,7 @@ parseBook(ripple::Currency pays, ripple::AccountID payIssuer, ripple::Currency g
* @param request The request
* @return The book or an error status
*/
std::variant<Status, ripple::Book>
std::expected<ripple::Book, Status>
parseBook(boost::json::object const& request);
/**
@@ -646,7 +645,7 @@ parseBook(boost::json::object const& request);
* @param taker The taker as json
* @return The taker account or an error status
*/
std::variant<Status, ripple::AccountID>
std::expected<ripple::AccountID, Status>
parseTaker(boost::json::value const& taker);
/**
@@ -683,7 +682,7 @@ isAdminCmd(std::string const& method, boost::json::object const& request);
* @param request The request
* @return The NFTID or an error status
*/
std::variant<ripple::uint256, Status>
std::expected<ripple::uint256, Status>
getNFTID(boost::json::object const& request);
/**
@@ -793,7 +792,7 @@ parseRippleLibSeed(boost::json::value const& value);
* @param atOwnedNode The function to call for each owned node
* @return The account cursor or an error status
*/
std::variant<Status, AccountCursor>
std::expected<AccountCursor, Status>
traverseNFTObjects(
BackendInterface const& backend,
std::uint32_t sequence,

View File

@@ -100,7 +100,7 @@ struct ReturnType {
*/
operator bool() const
{
return result.operator bool();
return result.has_value();
}
std::expected<boost::json::value, Status> result;
@@ -137,7 +137,7 @@ struct Result {
if (returnType) {
response = std::move(returnType.result).value().as_object();
} else {
response = std::move(returnType.result).error();
response = std::unexpected{std::move(returnType.result).error()};
}
warnings = std::move(returnType.warnings);
}
@@ -147,7 +147,7 @@ struct Result {
*
* @param status The status to construct the result from
*/
explicit Result(Status status) : response{std::move(status)}
explicit Result(Status status) : response{std::unexpected{std::move(status)}}
{
}
@@ -160,7 +160,7 @@ struct Result {
{
}
std::variant<Status, boost::json::object> response;
std::expected<boost::json::object, Status> response;
boost::json::array warnings;
};

View File

@@ -97,14 +97,14 @@ AMMInfoHandler::process(AMMInfoHandler::Input input, Context const& ctx) const
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "AMMInfo's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
if (input.accountID) {
auto keylet = keylet::account(*input.accountID);

View File

@@ -86,14 +86,14 @@ AccountChannelsHandler::process(AccountChannelsHandler::Input input, Context con
{
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "AccountChannel's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const accountID = accountFromStringStrict(input.account);
auto const accountLedgerObject =
sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield);
@@ -114,19 +114,19 @@ AccountChannelsHandler::process(AccountChannelsHandler::Input input, Context con
return true;
};
auto const next = traverseOwnedNodes(
auto const expectedNext = traverseOwnedNodes(
*sharedPtrBackend_, *accountID, lgrInfo.seq, input.limit, input.marker, ctx.yield, addToResponse
);
if (auto status = std::get_if<Status>(&next))
return Error{*status};
if (!expectedNext.has_value())
return Error{expectedNext.error()};
response.account = input.account;
response.limit = input.limit;
response.ledgerHash = ripple::strHex(lgrInfo.hash);
response.ledgerIndex = lgrInfo.seq;
auto const nextMarker = std::get<AccountCursor>(next);
auto const nextMarker = expectedNext.value();
if (nextMarker.isNonZero())
response.marker = nextMarker.toString();

View File

@@ -48,14 +48,14 @@ AccountCurrenciesHandler::process(AccountCurrenciesHandler::Input input, Context
{
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "AccountCurrencies' ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const accountID = accountFromStringStrict(input.account);
auto const accountLedgerObject =

View File

@@ -60,14 +60,14 @@ AccountInfoHandler::process(AccountInfoHandler::Input input, Context const& ctx)
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "AccountInfo's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const accountStr = input.account.value_or(input.ident.value_or(""));
auto const accountID = accountFromStringStrict(accountStr);
auto const accountKeylet = ripple::keylet::account(*accountID);

View File

@@ -135,14 +135,14 @@ AccountLinesHandler::process(AccountLinesHandler::Input input, Context const& ct
{
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "AccountLines' ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const accountID = accountFromStringStrict(input.account);
auto const accountLedgerObject =
sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield);
@@ -171,14 +171,14 @@ AccountLinesHandler::process(AccountLinesHandler::Input input, Context const& ct
}
};
auto const next = traverseOwnedNodes(
auto const expectedNext = traverseOwnedNodes(
*sharedPtrBackend_, *accountID, lgrInfo.seq, input.limit, input.marker, ctx.yield, addToResponse
);
if (auto status = std::get_if<Status>(&next))
return Error{*status};
if (!expectedNext.has_value())
return Error{expectedNext.error()};
auto const nextMarker = std::get<AccountCursor>(next);
auto const nextMarker = expectedNext.value();
response.account = input.account;
response.limit = input.limit; // not documented,

View File

@@ -54,14 +54,14 @@ AccountNFTsHandler::process(AccountNFTsHandler::Input input, Context const& ctx)
{
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "AccountNFT's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const accountID = accountFromStringStrict(input.account);
auto const accountLedgerObject =
sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield);

View File

@@ -54,14 +54,14 @@ AccountObjectsHandler::process(AccountObjectsHandler::Input input, Context const
{
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "AccountObject's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const accountID = accountFromStringStrict(input.account);
auto const accountLedgerObject =
sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield);
@@ -97,19 +97,19 @@ AccountObjectsHandler::process(AccountObjectsHandler::Input input, Context const
return true;
};
auto const next = traverseOwnedNodes(
auto const expectedNext = traverseOwnedNodes(
*sharedPtrBackend_, *accountID, lgrInfo.seq, input.limit, input.marker, ctx.yield, addToResponse, true
);
if (auto status = std::get_if<Status>(&next))
return Error{*status};
if (!expectedNext.has_value())
return Error{expectedNext.error()};
response.ledgerHash = ripple::strHex(lgrInfo.hash);
response.ledgerIndex = lgrInfo.seq;
response.limit = input.limit;
response.account = input.account;
auto const& nextMarker = std::get<AccountCursor>(next);
auto const& nextMarker = expectedNext.value();
if (nextMarker.isNonZero())
response.marker = nextMarker.toString();

View File

@@ -70,14 +70,14 @@ AccountOffersHandler::process(AccountOffersHandler::Input input, Context const&
{
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "AccountOffer's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const accountID = accountFromStringStrict(input.account);
auto const accountLedgerObject =
sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield);
@@ -97,14 +97,14 @@ AccountOffersHandler::process(AccountOffersHandler::Input input, Context const&
return true;
};
auto const next = traverseOwnedNodes(
auto const expectedNext = traverseOwnedNodes(
*sharedPtrBackend_, *accountID, lgrInfo.seq, input.limit, input.marker, ctx.yield, addToResponse
);
if (auto const status = std::get_if<Status>(&next))
return Error{*status};
if (!expectedNext.has_value())
return Error{expectedNext.error()};
auto const nextMarker = std::get<AccountCursor>(next);
auto const nextMarker = expectedNext.value();
if (nextMarker.isNonZero())
response.marker = nextMarker.toString();

View File

@@ -94,14 +94,14 @@ AccountTxHandler::process(AccountTxHandler::Input input, Context const& ctx) con
if (!input.ledgerIndexMax && !input.ledgerIndexMin) {
// mimic rippled, when both range and index specified, respect the range.
// take ledger from ledgerHash or ledgerIndex only when range is not specified
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
maxIndex = minIndex = std::get<ripple::LedgerHeader>(lgrInfoOrStatus).seq;
maxIndex = minIndex = expectedLgrInfo.value().seq;
}
}

View File

@@ -48,14 +48,14 @@ BookChangesHandler::process(BookChangesHandler::Input input, Context const& ctx)
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "BookChanges' ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const transactions = sharedPtrBackend_->fetchAllTransactionsInLedger(lgrInfo.seq, ctx.yield);
Output response;

View File

@@ -47,22 +47,22 @@ BookOffersHandler::Result
BookOffersHandler::process(Input input, Context const& ctx) const
{
auto bookMaybe = parseBook(input.paysCurrency, input.paysID, input.getsCurrency, input.getsID);
if (auto const status = std::get_if<Status>(&bookMaybe))
return Error{*status};
if (!bookMaybe.has_value())
return Error{bookMaybe.error()};
// check ledger
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "BookOffer's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const book = std::get<ripple::Book>(bookMaybe);
auto const& lgrInfo = expectedLgrInfo.value();
auto const book = bookMaybe.value();
auto const bookKey = getBookBase(book);
// TODO: Add performance metrics if needed in future

View File

@@ -55,14 +55,14 @@ DepositAuthorizedHandler::process(DepositAuthorizedHandler::Input input, Context
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "DepositAuthorized ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const sourceAccountID = accountFromStringStrict(input.sourceAccount);
auto const destinationAccountID = accountFromStringStrict(input.destinationAccount);

View File

@@ -59,14 +59,14 @@ FeatureHandler::process(FeatureHandler::Input input, Context const& ctx) const
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "Feature's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const& all = amendmentCenter_->getAll();
auto searchPredicate = [search = input.feature](auto const& feature) {

View File

@@ -62,15 +62,15 @@ GatewayBalancesHandler::process(GatewayBalancesHandler::Input input, Context con
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "GatewayBalances' ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
// check account
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const accountID = accountFromStringStrict(input.account);
auto const accountLedgerObject =
sharedPtrBackend_->fetchLedgerObject(ripple::keylet::account(*accountID).key, lgrInfo.seq, ctx.yield);
@@ -142,8 +142,8 @@ GatewayBalancesHandler::process(GatewayBalancesHandler::Input input, Context con
addToResponse
);
if (auto status = std::get_if<Status>(&ret))
return Error{*status};
if (!ret.has_value())
return Error{ret.error()};
output.accountID = input.account;
output.ledgerHash = ripple::strHex(lgrInfo.hash);

View File

@@ -64,14 +64,14 @@ GetAggregatePriceHandler::process(GetAggregatePriceHandler::Input input, Context
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "GetAggregatePrice's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
// sorted descending by lastUpdateTime, ascending by AssetPrice
using TimestampPricesBiMap = boost::bimaps::bimap<

View File

@@ -55,14 +55,14 @@ LedgerHandler::process(LedgerHandler::Input input, Context const& ctx) const
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "LedgerHandler's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
Output output;
output.header = toJson(lgrInfo, input.binary, ctx.apiVersion);

View File

@@ -64,14 +64,14 @@ LedgerDataHandler::process(Input input, Context const& ctx) const
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "LedgerData's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
Output output;

View File

@@ -70,11 +70,11 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
} else if (input.did) {
key = ripple::keylet::did(*util::parseBase58Wrapper<ripple::AccountID>(*(input.did))).key;
} else if (input.directory) {
auto const keyOrStatus = composeKeyFromDirectory(*input.directory);
if (auto const status = std::get_if<Status>(&keyOrStatus))
return Error{*status};
auto const expectedkey = composeKeyFromDirectory(*input.directory);
if (!expectedkey.has_value())
return Error{expectedkey.error()};
key = std::get<ripple::uint256>(keyOrStatus);
key = expectedkey.value();
} else if (input.offer) {
auto const id =
util::parseBase58Wrapper<ripple::AccountID>(boost::json::value_to<std::string>(input.offer->at(JS(account)))
@@ -202,14 +202,14 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
// check ledger exists
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "LedgerEntry's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto output = LedgerEntryHandler::Output{};
auto ledgerObject = sharedPtrBackend_->fetchLedgerObject(key, lgrInfo.seq, ctx.yield);
@@ -243,16 +243,16 @@ LedgerEntryHandler::process(LedgerEntryHandler::Input input, Context const& ctx)
return output;
}
std::variant<ripple::uint256, Status>
std::expected<ripple::uint256, Status>
LedgerEntryHandler::composeKeyFromDirectory(boost::json::object const& directory) noexcept
{
// can not specify both dir_root and owner.
if (directory.contains(JS(dir_root)) && directory.contains(JS(owner)))
return Status{RippledError::rpcINVALID_PARAMS, "mayNotSpecifyBothDirRootAndOwner"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "mayNotSpecifyBothDirRootAndOwner"}};
// at least one should available
if (!(directory.contains(JS(dir_root)) || directory.contains(JS(owner))))
return Status{RippledError::rpcINVALID_PARAMS, "missingOwnerOrDirRoot"};
return std::unexpected{Status{RippledError::rpcINVALID_PARAMS, "missingOwnerOrDirRoot"}};
uint64_t const subIndex =
directory.contains(JS(sub_index)) ? boost::json::value_to<uint64_t>(directory.at(JS(sub_index))) : 0;

View File

@@ -430,7 +430,7 @@ public:
private:
// dir_root and owner can not be both empty or filled at the same time
// This function will return an error if this is the case
static std::variant<ripple::uint256, Status>
static std::expected<ripple::uint256, Status>
composeKeyFromDirectory(boost::json::object const& directory) noexcept;
/**

View File

@@ -52,13 +52,13 @@ MPTHoldersHandler::process(MPTHoldersHandler::Input input, Context const& ctx) c
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "MPTHolder's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<LedgerInfo>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const limit = input.limit.value_or(MPTHoldersHandler::kLIMIT_DEFAULT);
auto const mptID = ripple::uint192{input.mptID.c_str()};

View File

@@ -80,14 +80,14 @@ NFTHistoryHandler::process(NFTHistoryHandler::Input input, Context const& ctx) c
if (input.ledgerIndexMax || input.ledgerIndexMin)
return Error{Status{RippledError::rpcINVALID_PARAMS, "containsLedgerSpecifierAndRange"}};
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
maxIndex = minIndex = std::get<ripple::LedgerHeader>(lgrInfoOrStatus).seq;
maxIndex = minIndex = expectedLgrInfo.value().seq;
}
std::optional<data::TransactionsCursor> cursor;

View File

@@ -50,14 +50,14 @@ NFTInfoHandler::process(NFTInfoHandler::Input input, Context const& ctx) const
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "NFTInfo's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const maybeNft = sharedPtrBackend_->fetchNFT(tokenID, lgrInfo.seq, ctx.yield);
if (not maybeNft.has_value())

View File

@@ -93,14 +93,14 @@ NFTOffersHandlerBase::iterateOfferDirectory(
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "NFTOffersCommon's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
// TODO: just check for existence without pulling
if (not sharedPtrBackend_->fetchLedgerObject(directory.key, lgrInfo.seq, yield))
@@ -156,8 +156,8 @@ NFTOffersHandlerBase::iterateOfferDirectory(
}
);
if (auto status = std::get_if<Status>(&result))
return Error{*status};
if (!result.has_value())
return Error{result.error()};
if (offers.size() == reserve) {
output.limit = input.limit;

View File

@@ -51,13 +51,13 @@ NFTsByIssuerHandler::process(NFTsByIssuerHandler::Input input, Context const& ct
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "NFTsByIssuer's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto const status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const limit = input.limit.value_or(NFTsByIssuerHandler::kLIMIT_DEFAULT);

View File

@@ -61,14 +61,14 @@ NoRippleCheckHandler::process(NoRippleCheckHandler::Input input, Context const&
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "NoRippleCheck's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const& lgrInfo = expectedLgrInfo.value();
auto const accountID = accountFromStringStrict(input.account);
auto const keylet = ripple::keylet::account(*accountID).key;
auto const accountObj = sharedPtrBackend_->fetchLedgerObject(keylet, lgrInfo.seq, ctx.yield);

View File

@@ -92,8 +92,8 @@ SubscribeHandler::spec([[maybe_unused]] uint32_t apiVersion)
}
auto const parsedBook = parseBook(book.as_object());
if (auto const status = std::get_if<Status>(&parsedBook))
return Error(*status);
if (!parsedBook)
return Error(parsedBook.error());
}
return MaybeError{};
@@ -298,7 +298,8 @@ tag_invoke(boost::json::value_to_tag<SubscribeHandler::Input>, boost::json::valu
internalBook.snapshot = snapshot->value().as_bool();
auto const parsedBookMaybe = parseBook(book.as_object());
internalBook.book = std::get<ripple::Book>(parsedBookMaybe);
ASSERT(parsedBookMaybe.has_value(), "Book parsing failed");
internalBook.book = parsedBookMaybe.value();
input.books->push_back(internalBook);
}
}

View File

@@ -46,17 +46,17 @@ TransactionEntryHandler::process(TransactionEntryHandler::Input input, Context c
auto const range = sharedPtrBackend_->fetchLedgerRange();
ASSERT(range.has_value(), "TransactionEntry's ledger range must be available");
auto const lgrInfoOrStatus = getLedgerHeaderFromHashOrSeq(
auto const expectedLgrInfo = getLedgerHeaderFromHashOrSeq(
*sharedPtrBackend_, ctx.yield, input.ledgerHash, input.ledgerIndex, range->maxSequence
);
if (auto status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};
if (!expectedLgrInfo.has_value())
return Error{expectedLgrInfo.error()};
auto output = TransactionEntryHandler::Output{};
output.apiVersion = ctx.apiVersion;
output.ledgerHeader = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
output.ledgerHeader = expectedLgrInfo.value();
auto const dbRet = sharedPtrBackend_->fetchTransaction(ripple::uint256{input.txHash.c_str()}, ctx.yield);
// Note: transaction_entry is meant to only search a specified ledger for
// the specified transaction. tx searches the entire range of history. For

View File

@@ -66,8 +66,8 @@ UnsubscribeHandler::spec([[maybe_unused]] uint32_t apiVersion)
return Error{Status{RippledError::rpcINVALID_PARAMS, "bothNotBool"}};
auto const parsedBook = parseBook(book.as_object());
if (auto const status = std::get_if<Status>(&parsedBook))
return Error(*status);
if (!parsedBook.has_value())
return Error(parsedBook.error());
}
return MaybeError{};
@@ -193,7 +193,8 @@ tag_invoke(boost::json::value_to_tag<UnsubscribeHandler::Input>, boost::json::va
internalBook.both = both->value().as_bool();
auto const parsedBookMaybe = parseBook(book.as_object());
internalBook.book = std::get<ripple::Book>(parsedBookMaybe);
ASSERT(parsedBookMaybe.has_value(), "Invalid book format");
internalBook.book = parsedBookMaybe.value();
input.books->push_back(internalBook);
}
}

View File

@@ -216,9 +216,9 @@ private:
boost::json::object response;
if (auto const status = std::get_if<rpc::Status>(&result.response)) {
if (!result.response.has_value()) {
// note: error statuses are counted/notified in buildResponse itself
response = web::impl::ErrorHelper(connection, request).composeError(*status);
response = web::impl::ErrorHelper(connection, request).composeError(result.response.error());
auto const responseStr = boost::json::serialize(response);
LOG(perfLog_.debug()) << context->tag() << "Encountered error: " << responseStr;
@@ -227,7 +227,7 @@ private:
// This can still technically be an error. Clio counts forwarded requests as successful.
rpcEngine_->notifyComplete(context->method, us);
auto& json = std::get<boost::json::object>(result.response);
auto& json = result.response.value();
auto const isForwarded =
json.contains("forwarded") && json.at("forwarded").is_bool() && json.at("forwarded").as_bool();

View File

@@ -264,9 +264,9 @@ private:
boost::json::object response;
if (auto const status = std::get_if<rpc::Status>(&result.response)) {
if (!result.response.has_value()) {
// note: error statuses are counted/notified in buildResponse itself
response = impl::ErrorHelper(rawRequest, request).composeError(*status);
response = impl::ErrorHelper(rawRequest, request).composeError(result.response.error());
auto const responseStr = boost::json::serialize(response);
LOG(perfLog_.debug()) << context->tag() << "Encountered error: " << responseStr;
@@ -275,7 +275,7 @@ private:
// This can still technically be an error. Clio counts forwarded requests as successful.
rpcEngine_->notifyComplete(context->method, us);
auto& json = std::get<boost::json::object>(result.response);
auto& json = result.response.value();
auto const isForwarded =
json.contains("forwarded") && json.at("forwarded").is_bool() && json.at("forwarded").as_bool();

View File

@@ -318,8 +318,7 @@ TEST_F(RPCForwardingProxyTest, ForwardCallsBalancerWithCorrectParams)
auto const res = proxy_.forward(ctx);
auto const data = std::get_if<json::object>(&res.response);
EXPECT_TRUE(data != nullptr);
EXPECT_TRUE(res.response.has_value());
});
}
@@ -348,8 +347,7 @@ TEST_F(RPCForwardingProxyTest, ForwardingFailYieldsErrorStatus)
auto const res = proxy_.forward(ctx);
auto const status = std::get_if<Status>(&res.response);
EXPECT_TRUE(status != nullptr);
EXPECT_EQ(*status, rpc::ClioError::EtlInvalidResponse);
EXPECT_FALSE(res.response.has_value());
EXPECT_EQ(res.response.error(), rpc::ClioError::EtlInvalidResponse);
});
}

View File

@@ -258,13 +258,11 @@ TEST_P(RPCEngineFlowParameterTest, Test)
);
auto const res = engine->buildResponse(ctx);
auto const status = std::get_if<rpc::Status>(&res.response);
auto const response = std::get_if<boost::json::object>(&res.response);
ASSERT_EQ(status == nullptr, testBundle.response.has_value());
ASSERT_EQ(res.response.has_value(), testBundle.response.has_value());
if (testBundle.response.has_value()) {
EXPECT_EQ(*response, testBundle.response.value());
EXPECT_EQ(res.response.value(), testBundle.response.value());
} else {
EXPECT_EQ(*status, testBundle.status.value());
EXPECT_EQ(res.response.error(), testBundle.status.value());
}
});
}
@@ -295,9 +293,8 @@ TEST_F(RPCEngineTest, ThrowDatabaseError)
);
auto const res = engine->buildResponse(ctx);
auto const status = std::get_if<rpc::Status>(&res.response);
ASSERT_TRUE(status != nullptr);
EXPECT_EQ(*status, Status{RippledError::rpcTOO_BUSY});
ASSERT_FALSE(res.response.has_value());
EXPECT_EQ(res.response.error(), Status{RippledError::rpcTOO_BUSY});
});
}
@@ -327,9 +324,8 @@ TEST_F(RPCEngineTest, ThrowException)
);
auto const res = engine->buildResponse(ctx);
auto const status = std::get_if<rpc::Status>(&res.response);
ASSERT_TRUE(status != nullptr);
EXPECT_EQ(*status, Status{RippledError::rpcINTERNAL});
ASSERT_FALSE(res.response.has_value());
EXPECT_EQ(res.response.error(), Status{RippledError::rpcINTERNAL});
});
}
@@ -454,8 +450,8 @@ TEST_P(RPCEngineCacheParameterTest, Test)
);
auto const res = engine->buildResponse(ctx);
auto const response = std::get_if<boost::json::object>(&res.response);
EXPECT_EQ(*response, boost::json::parse(R"JSON({ "computed": "world_50"})JSON").as_object());
ASSERT_TRUE(res.response.has_value());
EXPECT_EQ(res.response.value(), boost::json::parse(R"JSON({ "computed": "world_50"})JSON").as_object());
});
}
}
@@ -499,9 +495,8 @@ TEST_F(RPCEngineTest, NotCacheIfErrorHappen)
);
auto const res = engine->buildResponse(ctx);
auto const error = std::get_if<rpc::Status>(&res.response);
ASSERT_NE(error, nullptr);
EXPECT_EQ(*error, rpc::Status{"Very custom error"});
ASSERT_FALSE(res.response.has_value());
EXPECT_EQ(res.response.error(), rpc::Status{"Very custom error"});
});
}
}

View File

@@ -103,10 +103,9 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesMarkerInvalidIndexNotHex)
auto ret = traverseOwnedNodes(*backend_, account, 9, 10, "nothex,10", yield, [](auto) {
});
auto status = std::get_if<Status>(&ret);
EXPECT_TRUE(status != nullptr);
EXPECT_EQ(*status, ripple::rpcINVALID_PARAMS);
EXPECT_EQ(status->message, "Malformed cursor.");
EXPECT_FALSE(ret.has_value());
EXPECT_EQ(ret.error(), ripple::rpcINVALID_PARAMS);
EXPECT_EQ(ret.error().message, "Malformed cursor.");
});
ctx_.run();
}
@@ -118,10 +117,9 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesMarkerInvalidPageNotInt)
auto ret = traverseOwnedNodes(*backend_, account, 9, 10, "nothex,abc", yield, [](auto) {
});
auto status = std::get_if<Status>(&ret);
EXPECT_TRUE(status != nullptr);
EXPECT_EQ(*status, ripple::rpcINVALID_PARAMS);
EXPECT_EQ(status->message, "Malformed cursor.");
EXPECT_FALSE(ret.has_value());
EXPECT_EQ(ret.error(), ripple::rpcINVALID_PARAMS);
EXPECT_EQ(ret.error().message, "Malformed cursor.");
});
ctx_.run();
}
@@ -148,13 +146,10 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarker)
EXPECT_CALL(*backend_, doFetchLedgerObjects).Times(1);
boost::asio::spawn(ctx_, [this, &account](boost::asio::yield_context yield) {
auto ret = traverseOwnedNodes(*backend_, account, 9, 10, {}, yield, [](auto) {
});
auto cursor = std::get_if<AccountCursor>(&ret);
EXPECT_TRUE(cursor != nullptr);
auto ret = traverseOwnedNodes(*backend_, account, 9, 10, {}, yield, [](auto) {});
EXPECT_TRUE(ret.has_value());
EXPECT_EQ(
cursor->toString(),
ret.value().toString(),
"0000000000000000000000000000000000000000000000000000000000000000,"
"0"
);
@@ -192,10 +187,9 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarkerReturnSamePageMarker)
boost::asio::spawn(ctx_, [this, &account](boost::asio::yield_context yield) {
auto count = 0;
auto ret = traverseOwnedNodes(*backend_, account, 9, 10, {}, yield, [&](auto) { count++; });
auto cursor = std::get_if<AccountCursor>(&ret);
EXPECT_TRUE(cursor != nullptr);
EXPECT_TRUE(ret.has_value());
EXPECT_EQ(count, 10);
EXPECT_EQ(cursor->toString(), fmt::format("{},0", kINDEX1));
EXPECT_EQ(ret.value().toString(), fmt::format("{},0", kINDEX1));
});
ctx_.run();
}
@@ -244,10 +238,9 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarkerReturnOtherPageMarker)
boost::asio::spawn(ctx_, [&, this](boost::asio::yield_context yield) {
auto count = 0;
auto ret = traverseOwnedNodes(*backend_, account, 9, kLIMIT, {}, yield, [&](auto) { count++; });
auto cursor = std::get_if<AccountCursor>(&ret);
EXPECT_TRUE(cursor != nullptr);
EXPECT_TRUE(ret.has_value());
EXPECT_EQ(count, kLIMIT);
EXPECT_EQ(cursor->toString(), fmt::format("{},{}", kINDEX1, kNEXT_PAGE));
EXPECT_EQ(ret.value().toString(), fmt::format("{},{}", kINDEX1, kNEXT_PAGE));
});
ctx_.run();
}
@@ -291,10 +284,9 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesWithMarkerReturnSamePageMarker)
auto ret = traverseOwnedNodes(
*backend_, account, 9, kLIMIT, fmt::format("{},{}", kINDEX1, kPAGE_NUM), yield, [&](auto) { count++; }
);
auto cursor = std::get_if<AccountCursor>(&ret);
EXPECT_TRUE(cursor != nullptr);
EXPECT_TRUE(ret.has_value());
EXPECT_EQ(count, kLIMIT);
EXPECT_EQ(cursor->toString(), fmt::format("{},{}", kINDEX1, kPAGE_NUM));
EXPECT_EQ(ret.value().toString(), fmt::format("{},{}", kINDEX1, kPAGE_NUM));
});
ctx_.run();
}
@@ -328,10 +320,9 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesWithUnexistingIndexMarker)
auto ret = traverseOwnedNodes(
*backend_, account, 9, kLIMIT, fmt::format("{},{}", kINDEX2, kPAGE_NUM), yield, [&](auto) { count++; }
);
auto status = std::get_if<Status>(&ret);
EXPECT_TRUE(status != nullptr);
EXPECT_EQ(*status, ripple::rpcINVALID_PARAMS);
EXPECT_EQ(status->message, "Invalid marker.");
EXPECT_FALSE(ret.has_value());
EXPECT_EQ(ret.error(), ripple::rpcINVALID_PARAMS);
EXPECT_EQ(ret.error().message, "Invalid marker.");
});
ctx_.run();
}

View File

@@ -611,12 +611,12 @@ generateNormalPathBookOffersTestBundles()
kPAYS20_USD_GETS10_XRP_BOOK_DIR
);
auto const getsXRPPaysUSDBook = getBookBase(std::get<ripple::Book>(
rpc::parseBook(ripple::to_currency("USD"), account, ripple::xrpCurrency(), ripple::xrpAccount())
));
auto const getsUSDPaysXRPBook = getBookBase(std::get<ripple::Book>(
rpc::parseBook(ripple::xrpCurrency(), ripple::xrpAccount(), ripple::to_currency("USD"), account)
));
auto const getsXRPPaysUSDBook = getBookBase(
rpc::parseBook(ripple::to_currency("USD"), account, ripple::xrpCurrency(), ripple::xrpAccount()).value()
);
auto const getsUSDPaysXRPBook = getBookBase(
rpc::parseBook(ripple::xrpCurrency(), ripple::xrpAccount(), ripple::to_currency("USD"), account).value()
);
auto const getsXRPPaysUSDInputJson = fmt::format(
R"JSON({{
@@ -1450,9 +1450,9 @@ TEST_F(RPCBookOffersHandlerTest, Limit)
// return valid book dir
EXPECT_CALL(*backend_, doFetchSuccessorKey).Times(1);
auto const getsXRPPaysUSDBook = getBookBase(std::get<ripple::Book>(
rpc::parseBook(ripple::to_currency("USD"), issuer, ripple::xrpCurrency(), ripple::xrpAccount())
));
auto const getsXRPPaysUSDBook = getBookBase(
rpc::parseBook(ripple::to_currency("USD"), issuer, ripple::xrpCurrency(), ripple::xrpAccount()).value()
);
ON_CALL(*backend_, doFetchSuccessorKey(getsXRPPaysUSDBook, seq, _))
.WillByDefault(Return(ripple::uint256{kPAYS20_USD_GETS10_XRP_BOOK_DIR}));
@@ -1523,9 +1523,9 @@ TEST_F(RPCBookOffersHandlerTest, LimitMoreThanMax)
// return valid book dir
EXPECT_CALL(*backend_, doFetchSuccessorKey).Times(1);
auto const getsXRPPaysUSDBook = getBookBase(std::get<ripple::Book>(
rpc::parseBook(ripple::to_currency("USD"), issuer, ripple::xrpCurrency(), ripple::xrpAccount())
));
auto const getsXRPPaysUSDBook = getBookBase(
rpc::parseBook(ripple::to_currency("USD"), issuer, ripple::xrpCurrency(), ripple::xrpAccount()).value()
);
ON_CALL(*backend_, doFetchSuccessorKey(getsXRPPaysUSDBook, seq, _))
.WillByDefault(Return(ripple::uint256{kPAYS20_USD_GETS10_XRP_BOOK_DIR}));

View File

@@ -822,13 +822,13 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothSnapshotSet)
auto const issuer = getAccountIdWithString(kACCOUNT);
auto const getsXRPPaysUSDBook = getBookBase(std::get<ripple::Book>(
rpc::parseBook(ripple::to_currency("USD"), issuer, ripple::xrpCurrency(), ripple::xrpAccount())
));
auto const getsXRPPaysUSDBook = getBookBase(
rpc::parseBook(ripple::to_currency("USD"), issuer, ripple::xrpCurrency(), ripple::xrpAccount()).value()
);
auto const reversedBook = getBookBase(std::get<ripple::Book>(
rpc::parseBook(ripple::xrpCurrency(), ripple::xrpAccount(), ripple::to_currency("USD"), issuer)
));
auto const reversedBook = getBookBase(
rpc::parseBook(ripple::xrpCurrency(), ripple::xrpAccount(), ripple::to_currency("USD"), issuer).value()
);
ON_CALL(*backend_, doFetchSuccessorKey(getsXRPPaysUSDBook, kMAX_SEQ, _))
.WillByDefault(Return(ripple::uint256{kPAYS20_USD_GETS10_XRP_BOOK_DIR}));
@@ -992,13 +992,13 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothUnsetSnapshotSet)
auto const issuer = getAccountIdWithString(kACCOUNT);
auto const getsXRPPaysUSDBook = getBookBase(std::get<ripple::Book>(
rpc::parseBook(ripple::to_currency("USD"), issuer, ripple::xrpCurrency(), ripple::xrpAccount())
));
auto const getsXRPPaysUSDBook = getBookBase(
rpc::parseBook(ripple::to_currency("USD"), issuer, ripple::xrpCurrency(), ripple::xrpAccount()).value()
);
auto const reversedBook = getBookBase(std::get<ripple::Book>(
rpc::parseBook(ripple::xrpCurrency(), ripple::xrpAccount(), ripple::to_currency("USD"), issuer)
));
auto const reversedBook = getBookBase(
rpc::parseBook(ripple::xrpCurrency(), ripple::xrpAccount(), ripple::to_currency("USD"), issuer).value()
);
ON_CALL(*backend_, doFetchSuccessorKey(getsXRPPaysUSDBook, kMAX_SEQ, _))
.WillByDefault(Return(ripple::uint256{kPAYS20_USD_GETS10_XRP_BOOK_DIR}));

View File

@@ -653,7 +653,7 @@ TEST_F(RPCUnsubscribeTest, Books)
));
auto const parsedBookMaybe = rpc::parseBook(input.as_object().at("books").as_array()[0].as_object());
auto const book = std::get<ripple::Book>(parsedBookMaybe);
auto const book = parsedBookMaybe.value();
EXPECT_CALL(*mockSubscriptionManagerPtr_, unsubBook(book, _)).Times(1);
EXPECT_CALL(*mockSubscriptionManagerPtr_, unsubBook(ripple::reversed(book), _)).Times(1);
@@ -686,7 +686,7 @@ TEST_F(RPCUnsubscribeTest, SingleBooks)
));
auto const parsedBookMaybe = rpc::parseBook(input.as_object().at("books").as_array()[0].as_object());
auto const book = std::get<ripple::Book>(parsedBookMaybe);
auto const book = parsedBookMaybe.value();
EXPECT_CALL(*mockSubscriptionManagerPtr_, unsubBook(book, _)).Times(1);