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:
CJ Cobb
2021-09-09 15:20:23 -04:00
parent cc76ece6f2
commit 01aed9f6e8
8 changed files with 73 additions and 23 deletions

View File

@@ -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);

View File

@@ -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),

View File

@@ -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();
}

View File

@@ -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<

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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",