mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-28 07:35:52 +00:00
Add date to transactions table.
* Add date to account_tx response * Add support for signer_lists to account_info * Add support for converting seeds to accounts * Add urlgravatar to account_info
This commit is contained in:
@@ -810,6 +810,7 @@ CREATE INDEX IF NOT EXISTS ledgers_ledger_hash_idx ON ledgers
|
||||
CREATE TABLE IF NOT EXISTS transactions (
|
||||
hash bytea NOT NULL,
|
||||
ledger_seq bigint NOT NULL REFERENCES ledgers ON DELETE CASCADE,
|
||||
date bigint,
|
||||
transaction bytea NOT NULL,
|
||||
metadata bytea NOT NULL
|
||||
) PARTITION BY RANGE(ledger_seq);
|
||||
|
||||
@@ -280,7 +280,7 @@ PostgresBackend::fetchTransaction(ripple::uint256 const& hash) const
|
||||
"WHERE hash = "
|
||||
<< "\'\\x" << ripple::strHex(hash) << "\'";
|
||||
auto res = pgQuery(sql.str().data());
|
||||
if (checkResult(res, 3))
|
||||
if (checkResult(res, 4))
|
||||
{
|
||||
return {
|
||||
{res.asUnHexedBlob(0, 0),
|
||||
@@ -301,7 +301,7 @@ PostgresBackend::fetchAllTransactionsInLedger(uint32_t ledgerSequence) const
|
||||
"WHERE "
|
||||
<< "ledger_seq = " << std::to_string(ledgerSequence);
|
||||
auto res = pgQuery(sql.str().data());
|
||||
if (size_t numRows = checkResult(res, 3))
|
||||
if (size_t numRows = checkResult(res, 4))
|
||||
{
|
||||
std::vector<TransactionAndMetadata> txns;
|
||||
for (size_t i = 0; i < numRows; ++i)
|
||||
@@ -420,7 +420,7 @@ PostgresBackend::fetchTransactions(
|
||||
<< ripple::strHex(hash) << "\'";
|
||||
|
||||
auto res = pgQuery(sql.str().data());
|
||||
if (size_t numRows = checkResult(res, 3))
|
||||
if (size_t numRows = checkResult(res, 4))
|
||||
{
|
||||
results[i] = {
|
||||
res.asUnHexedBlob(0, 0),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <backend/BackendInterface.h>
|
||||
#include <rpc/RPCHelpers.h>
|
||||
namespace RPC {
|
||||
@@ -51,6 +52,20 @@ canHaveDeliveredAmount(
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<ripple::AccountID>
|
||||
accountFromSeed(std::string const& account)
|
||||
{
|
||||
auto const seed = ripple::parseGenericSeed(account);
|
||||
|
||||
if (!seed)
|
||||
return {};
|
||||
|
||||
auto const keypair =
|
||||
ripple::generateKeyPair(ripple::KeyType::secp256k1, *seed);
|
||||
|
||||
return ripple::calcAccountID(keypair.first);
|
||||
}
|
||||
|
||||
std::optional<ripple::AccountID>
|
||||
accountFromStringStrict(std::string const& account)
|
||||
{
|
||||
@@ -198,7 +213,17 @@ toJson(ripple::SLE const& sle)
|
||||
{
|
||||
boost::json::value value = boost::json::parse(
|
||||
sle.getJson(ripple::JsonOptions::none).toStyledString());
|
||||
|
||||
if (sle.getType() == ripple::ltACCOUNT_ROOT)
|
||||
{
|
||||
if (sle.isFieldPresent(ripple::sfEmailHash))
|
||||
{
|
||||
auto const& hash = sle.getFieldH128(ripple::sfEmailHash);
|
||||
std::string md5 = strHex(hash);
|
||||
boost::algorithm::to_lower(md5);
|
||||
value.as_object()["urlgravatar"] =
|
||||
str(boost::format("http://www.gravatar.com/avatar/%s") % md5);
|
||||
}
|
||||
}
|
||||
return value.as_object();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
namespace RPC {
|
||||
std::optional<ripple::AccountID>
|
||||
accountFromStringStrict(std::string const& account);
|
||||
std::optional<ripple::AccountID>
|
||||
accountFromSeed(std::string const& account);
|
||||
|
||||
// TODO this function should probably be in a different file and namespace
|
||||
std::pair<
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#include <ripple/protocol/STLedgerEntry.h>
|
||||
#include <boost/json.hpp>
|
||||
|
||||
#include <rpc/RPCHelpers.h>
|
||||
#include <backend/BackendInterface.h>
|
||||
#include <rpc/RPCHelpers.h>
|
||||
|
||||
// {
|
||||
// account: <ident>,
|
||||
@@ -39,8 +39,7 @@
|
||||
// // error.
|
||||
// }
|
||||
|
||||
namespace RPC
|
||||
{
|
||||
namespace RPC {
|
||||
|
||||
Result
|
||||
doAccountInfo(Context const& context)
|
||||
@@ -64,6 +63,18 @@ doAccountInfo(Context const& context)
|
||||
|
||||
// Get info on account.
|
||||
auto accountID = accountFromStringStrict(strIdent);
|
||||
if (!accountID)
|
||||
{
|
||||
if (!request.contains("strict") || !request.at("strict").as_bool())
|
||||
{
|
||||
accountID = accountFromSeed(strIdent);
|
||||
if (!accountID)
|
||||
return Status{Error::rpcBAD_SEED};
|
||||
}
|
||||
else
|
||||
return Status{Error::rpcACT_MALFORMED};
|
||||
}
|
||||
assert(accountID.has_value());
|
||||
|
||||
auto key = ripple::keylet::account(accountID.value());
|
||||
|
||||
@@ -98,26 +109,34 @@ doAccountInfo(Context const& context)
|
||||
response["ledger_index"] = lgrInfo.seq;
|
||||
|
||||
// Return SignerList(s) if that is requested.
|
||||
/*
|
||||
if (params.isMember(jss::signer_lists) &&
|
||||
params[jss::signer_lists].asBool())
|
||||
if (request.contains("signer_lists") &&
|
||||
request.at("signer_lists").as_bool())
|
||||
{
|
||||
// We put the SignerList in an array because of an anticipated
|
||||
// future when we support multiple signer lists on one account.
|
||||
Json::Value jvSignerList = Json::arrayValue;
|
||||
boost::json::array signerList;
|
||||
auto signersKey = ripple::keylet::signers(*accountID);
|
||||
|
||||
// This code will need to be revisited if in the future we
|
||||
// support multiple SignerLists on one account.
|
||||
auto const sleSigners = ledger->read(keylet::signers(accountID));
|
||||
if (sleSigners)
|
||||
jvSignerList.append(sleSigners->getJson(JsonOptions::none));
|
||||
auto const signers =
|
||||
context.backend->fetchLedgerObject(signersKey.key, lgrInfo.seq);
|
||||
if (signers)
|
||||
{
|
||||
ripple::STLedgerEntry sleSigners{
|
||||
ripple::SerialIter{signers->data(), signers->size()},
|
||||
signersKey.key};
|
||||
if (!signersKey.check(sleSigners))
|
||||
return Status{Error::rpcDB_DESERIALIZATION};
|
||||
|
||||
result[jss::account_data][jss::signer_lists] =
|
||||
std::move(jvSignerList);
|
||||
signerList.push_back(toJson(sleSigners));
|
||||
}
|
||||
|
||||
response["account_data"].as_object()["signer_lists"] =
|
||||
std::move(signerList);
|
||||
}
|
||||
*/
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
} //namespace RPC
|
||||
} // namespace RPC
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <backend/Pg.h>
|
||||
#include <rpc/RPCHelpers.h>
|
||||
|
||||
|
||||
namespace RPC {
|
||||
|
||||
Result
|
||||
@@ -198,12 +197,14 @@ doAccountTx(Context const& context)
|
||||
obj["meta"] = meta;
|
||||
obj["tx"] = txn;
|
||||
obj["tx"].as_object()["ledger_index"] = txnPlusMeta.ledgerSequence;
|
||||
obj["tx"].as_object()["date"] = txnPlusMeta.date;
|
||||
}
|
||||
else
|
||||
{
|
||||
obj["meta"] = ripple::strHex(txnPlusMeta.metadata);
|
||||
obj["tx_blob"] = ripple::strHex(txnPlusMeta.transaction);
|
||||
obj["ledger_index"] = txnPlusMeta.ledgerSequence;
|
||||
obj["date"] = txnPlusMeta.date;
|
||||
}
|
||||
|
||||
obj["validated"] = true;
|
||||
|
||||
@@ -60,8 +60,6 @@ doTx(Context const& context)
|
||||
if (!dbResponse)
|
||||
return Status{Error::rpcTXN_NOT_FOUND};
|
||||
|
||||
auto lgrInfo =
|
||||
context.backend->fetchLedgerBySequence(dbResponse->ledgerSequence);
|
||||
if (!binary)
|
||||
{
|
||||
auto [txn, meta] = toExpandedJson(*dbResponse);
|
||||
@@ -72,9 +70,9 @@ doTx(Context const& context)
|
||||
{
|
||||
response["tx"] = ripple::strHex(dbResponse->transaction);
|
||||
response["meta"] = ripple::strHex(dbResponse->metadata);
|
||||
response["hash"] = request.at("transaction").as_string();
|
||||
response["hash"] = std::move(request.at("transaction").as_string());
|
||||
}
|
||||
response["date"] = lgrInfo->closeTime.time_since_epoch().count();
|
||||
response["date"] = dbResponse->date;
|
||||
response["ledger_index"] = dbResponse->ledgerSequence;
|
||||
|
||||
return response;
|
||||
|
||||
@@ -179,6 +179,8 @@ handle_request(
|
||||
result = error;
|
||||
|
||||
responseStr = boost::json::serialize(response);
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< __func__ << " Encountered error: " << responseStr;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -197,6 +199,8 @@ handle_request(
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error)
|
||||
<< __func__ << " Caught exception : " << e.what();
|
||||
return send(httpResponse(
|
||||
http::status::internal_server_error,
|
||||
"application/json",
|
||||
|
||||
Reference in New Issue
Block a user