mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
Achieve parity with rippled API
This commit is contained in:
182
src/handlers/methods/impl/AccountTx.cpp
Normal file
182
src/handlers/methods/impl/AccountTx.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012-2014 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or 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 <handlers/RPCHelpers.h>
|
||||
#include <handlers/methods/Transaction.h>
|
||||
#include <backend/BackendInterface.h>
|
||||
#include <backend/Pg.h>
|
||||
|
||||
namespace RPC
|
||||
{
|
||||
|
||||
Result
|
||||
doAccountTx(Context const& context)
|
||||
{
|
||||
auto request = context.params;
|
||||
boost::json::object response = {};
|
||||
|
||||
if(!request.contains("account"))
|
||||
return Status{Error::rpcINVALID_PARAMS, "missingAccount"};
|
||||
|
||||
if(!request.at("account").is_string())
|
||||
return Status{Error::rpcINVALID_PARAMS, "accountNotString"};
|
||||
|
||||
auto accountID =
|
||||
accountFromStringStrict(request.at("account").as_string().c_str());
|
||||
|
||||
if (!accountID)
|
||||
return Status{Error::rpcINVALID_PARAMS, "malformedAccount"};
|
||||
|
||||
bool binary = false;
|
||||
if(request.contains("binary"))
|
||||
{
|
||||
if(!request.at("binary").is_bool())
|
||||
return Status{Error::rpcINVALID_PARAMS, "binaryFlagNotBool"};
|
||||
|
||||
binary = request.at("binary").as_bool();
|
||||
}
|
||||
|
||||
auto minIndex = context.range.minSequence;
|
||||
if (request.contains("ledger_index_min"))
|
||||
{
|
||||
if (!request.at("ledger_index_min").is_int64())
|
||||
return Status{Error::rpcINVALID_PARAMS, "ledgerSeqMinNotNumber"};
|
||||
|
||||
minIndex = value_to<std::uint32_t>(request.at("ledger_index_min"));
|
||||
}
|
||||
|
||||
std::optional<Backend::AccountTransactionsCursor> cursor;
|
||||
cursor = {context.range.maxSequence, 0};
|
||||
|
||||
if (request.contains("cursor"))
|
||||
{
|
||||
auto const& obj = request.at("cursor").as_object();
|
||||
|
||||
std::optional<std::uint32_t> transactionIndex = {};
|
||||
if (obj.contains("seq"))
|
||||
{
|
||||
if (!obj.at("seq").is_int64())
|
||||
return Status{Error::rpcINVALID_PARAMS, "transactionIndexNotInt"};
|
||||
|
||||
transactionIndex = value_to<std::uint32_t>(obj.at("seq"));
|
||||
}
|
||||
|
||||
std::optional<std::uint32_t> ledgerIndex = {};
|
||||
if (obj.contains("ledger"))
|
||||
{
|
||||
if (!obj.at("ledger").is_int64())
|
||||
return Status{Error::rpcINVALID_PARAMS, "transactionIndexNotInt"};
|
||||
|
||||
transactionIndex = value_to<std::uint32_t>(obj.at("ledger"));
|
||||
}
|
||||
|
||||
if (!transactionIndex || !ledgerIndex)
|
||||
return Status{Error::rpcINVALID_PARAMS, "missingLedgerOrSeq"};
|
||||
|
||||
cursor = {*ledgerIndex, *transactionIndex};
|
||||
}
|
||||
else if (request.contains("ledger_index_max"))
|
||||
{
|
||||
if (!request.at("ledger_index_max").is_int64())
|
||||
return Status{Error::rpcINVALID_PARAMS, "ledgerSeqMaxNotNumber"};
|
||||
|
||||
auto maxIndex = value_to<std::uint32_t>(request.at("ledger_index_max"));
|
||||
|
||||
if (minIndex > maxIndex)
|
||||
return Status{Error::rpcINVALID_PARAMS, "invalidIndex"};
|
||||
|
||||
cursor = {maxIndex, 0};
|
||||
}
|
||||
|
||||
std::uint32_t limit = 200;
|
||||
if (request.contains("limit"))
|
||||
{
|
||||
if(!request.at("limit").is_int64())
|
||||
return Status{Error::rpcINVALID_PARAMS, "limitNotInt"};
|
||||
|
||||
limit = request.at("limit").as_int64();
|
||||
if (limit <= 0)
|
||||
return Status{Error::rpcINVALID_PARAMS, "limitNotPositive"};
|
||||
|
||||
response["limit"] = limit;
|
||||
}
|
||||
|
||||
|
||||
boost::json::array txns;
|
||||
auto start = std::chrono::system_clock::now();
|
||||
auto [blobs, retCursor] =
|
||||
context.backend->fetchAccountTransactions(*accountID, limit, cursor);
|
||||
|
||||
auto end = std::chrono::system_clock::now();
|
||||
BOOST_LOG_TRIVIAL(info) << __func__ << " db fetch took " << ((end - start).count() / 1000000000.0) << " num blobs = " << blobs.size();
|
||||
|
||||
response["account"] = ripple::to_string(*accountID);
|
||||
response["ledger_index_min"] = minIndex;
|
||||
response["ledger_index_max"] = cursor->ledgerSequence;
|
||||
|
||||
if (retCursor)
|
||||
{
|
||||
boost::json::object cursorJson;
|
||||
cursorJson["ledger"] = retCursor->ledgerSequence;
|
||||
cursorJson["seq"] = retCursor->transactionIndex;
|
||||
response["marker"] = cursorJson;
|
||||
}
|
||||
|
||||
for (auto const& txnPlusMeta : blobs)
|
||||
{
|
||||
if (txnPlusMeta.ledgerSequence < minIndex)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< __func__
|
||||
<< " skipping over transactions from incomplete ledger";
|
||||
continue;
|
||||
}
|
||||
|
||||
boost::json::object obj;
|
||||
|
||||
if (!binary)
|
||||
{
|
||||
auto [txn, meta] = deserializeTxPlusMeta(txnPlusMeta);
|
||||
obj["meta"] = toJson(*meta);
|
||||
obj["tx"] = toJson(*txn);
|
||||
obj["tx"].as_object()["ledger_index"] = txnPlusMeta.ledgerSequence;
|
||||
obj["tx"].as_object()["inLedger"] = txnPlusMeta.ledgerSequence;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
obj["meta"] = ripple::strHex(txnPlusMeta.metadata);
|
||||
obj["tx_blob"] = ripple::strHex(txnPlusMeta.transaction);
|
||||
obj["ledger_index"] = txnPlusMeta.ledgerSequence;
|
||||
}
|
||||
|
||||
obj["validated"] = true;
|
||||
|
||||
txns.push_back(obj);
|
||||
}
|
||||
|
||||
response["transactions"] = txns;
|
||||
|
||||
auto end2 = std::chrono::system_clock::now();
|
||||
BOOST_LOG_TRIVIAL(info) << __func__ << " serialization took " << ((end2 - end).count() / 1000000000.0);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
} // namespace RPC
|
||||
Reference in New Issue
Block a user