Ledger handler

This commit is contained in:
CJ Cobb
2021-03-04 14:34:55 -05:00
parent 694ec7bfe5
commit 6bbb5579ca
9 changed files with 135 additions and 7 deletions

View File

@@ -66,7 +66,8 @@ target_sources(reporting PRIVATE
handlers/RPCHelpers.cpp
handlers/AccountTx.cpp
handlers/LedgerData.cpp
handlers/BookOffers.cpp)
handlers/BookOffers.cpp
handlers/Ledger.cpp)
message(${Boost_LIBRARIES})

53
handlers/Ledger.cpp Normal file
View File

@@ -0,0 +1,53 @@
#include <handlers/RPCHelpers.h>
#include <reporting/BackendInterface.h>
boost::json::object
doLedger(boost::json::object const& request, BackendInterface const& backend)
{
boost::json::object response;
if (!request.contains("ledger_index"))
{
response["error"] = "Please specify a ledger index";
return response;
}
uint32_t ledgerSequence = request.at("ledger_index").as_int64();
auto lgrInfo = backend.fetchLedgerBySequence(ledgerSequence);
if (!lgrInfo)
{
response["error"] = "ledger not found";
return response;
}
boost::json::object header;
header["ledger_sequence"] = lgrInfo->seq;
header["ledger_hash"] = ripple::strHex(lgrInfo->hash);
header["txns_hash"] = ripple::strHex(lgrInfo->txHash);
header["state_hash"] = ripple::strHex(lgrInfo->accountHash);
header["parent_hash"] = ripple::strHex(lgrInfo->parentHash);
header["total_coins"] = ripple::to_string(lgrInfo->drops);
header["close_flags"] = lgrInfo->closeFlags;
// Always show fields that contribute to the ledger hash
header["parent_close_time"] =
lgrInfo->parentCloseTime.time_since_epoch().count();
header["close_time"] = lgrInfo->closeTime.time_since_epoch().count();
header["close_time_resolution"] = lgrInfo->closeTimeResolution.count();
auto txns = backend.fetchAllTransactionsInLedger(ledgerSequence);
response["transactions"] = boost::json::value(boost::json::array_kind);
boost::json::array& jsonTransactions =
response.at("transactions").as_array();
std::transform(
std::move_iterator(txns.begin()),
std::move_iterator(txns.end()),
std::back_inserter(jsonTransactions),
[](auto obj) {
boost::json::object entry;
auto [sttx, meta] = deserializeTxPlusMeta(obj);
entry["transaction"] = getJson(*sttx);
entry["meta"] = getJson(*meta);
return entry;
});
return response;
}

View File

@@ -54,6 +54,9 @@ public:
virtual std::optional<TransactionAndMetadata>
fetchTransaction(ripple::uint256 const& hash) const = 0;
virtual std::vector<TransactionAndMetadata>
fetchAllTransactionsInLedger(uint32_t ledgerSequence) const = 0;
virtual LedgerPage
fetchLedgerPage(
std::optional<ripple::uint256> const& cursor,

View File

@@ -225,6 +225,23 @@ CassandraBackend::fetchLedgerRange() const
}
return range;
}
std::vector<TransactionAndMetadata>
CassandraBackend::fetchAllTransactionsInLedger(uint32_t ledgerSequence) const
{
CassandraStatement statement{selectAllTransactionsInLedger_};
CassandraResult result = executeSyncRead(statement);
if (!result)
{
BOOST_LOG_TRIVIAL(error) << __func__ << " - no rows";
return {};
}
std::vector<TransactionAndMetadata> txns;
do
{
txns.push_back({result.getBytes(), result.getBytes()});
} while (result.nextRow());
return txns;
}
void
CassandraBackend::open()
@@ -455,12 +472,19 @@ CassandraBackend::open()
if (!executeSimpleStatement(query.str()))
continue;
query = {};
query << "CREATE TABLE IF NOT EXISTS " << tablePrefix << "transactions"
<< " ( hash blob PRIMARY KEY, sequence bigint, transaction "
query
<< "CREATE TABLE IF NOT EXISTS " << tablePrefix << "transactions"
<< " ( hash blob PRIMARY KEY, ledger_sequence bigint, transaction "
"blob, metadata blob)";
if (!executeSimpleStatement(query.str()))
continue;
query = {};
query << "CREATE INDEX ON " << tablePrefix
<< "transactions(ledger_sequence)";
if (!executeSimpleStatement(query.str()))
continue;
query = {};
query << "SELECT * FROM " << tablePrefix << "transactions"
<< " LIMIT 1";
@@ -558,8 +582,9 @@ CassandraBackend::open()
continue;
query = {};
query << "INSERT INTO " << tablePrefix << "transactions"
<< " (hash, sequence, transaction, metadata) VALUES (?, ?, "
query
<< "INSERT INTO " << tablePrefix << "transactions"
<< " (hash, ledger_sequence, transaction, metadata) VALUES (?, ?, "
"?, ?)";
if (!insertTransaction_.prepareStatement(query, session_.get()))
continue;
@@ -602,6 +627,14 @@ CassandraBackend::open()
if (!selectTransaction_.prepareStatement(query, session_.get()))
continue;
query = {};
query << "SELECT transaction,metadata FROM " << tablePrefix
<< "transactions"
<< " WHERE ledger_sequence = ?";
if (!selectAllTransactionsInLedger_.prepareStatement(
query, session_.get()))
continue;
query = {};
query << "SELECT key FROM " << tablePrefix << "keys "
<< " WHERE TOKEN(key) >= ? and created <= ?"

View File

@@ -503,6 +503,7 @@ private:
CassandraPreparedStatement insertObject_;
CassandraPreparedStatement insertTransaction_;
CassandraPreparedStatement selectTransaction_;
CassandraPreparedStatement selectAllTransactionsInLedger_;
CassandraPreparedStatement selectObject_;
CassandraPreparedStatement selectLedgerPageKeys_;
CassandraPreparedStatement selectLedgerPage_;
@@ -760,6 +761,9 @@ public:
std::optional<LedgerRange>
fetchLedgerRange() const override;
std::vector<TransactionAndMetadata>
fetchAllTransactionsInLedger(uint32_t ledgerSequence) const override;
// Synchronously fetch the object with key key and store the result in
// pno
// @param key the key of the object

View File

@@ -761,6 +761,9 @@ CREATE TABLE IF NOT EXISTS transactions (
transaction bytea NOT NULL,
metadata bytea NOT NULL
);
-- Index for lookups by ledger hash.
CREATE INDEX IF NOT EXISTS ledgers_ledger_seq_idx ON transactions
USING hash (ledger_seq);
-- Table that maps accounts to transactions affecting them. Deletes from the
-- ledger table cascade here based on ledger_seq.

View File

@@ -285,6 +285,31 @@ PostgresBackend::fetchTransaction(ripple::uint256 const& hash) const
return {};
}
std::vector<TransactionAndMetadata>
PostgresBackend::fetchAllTransactionsInLedger(uint32_t ledgerSequence) const
{
PgQuery pgQuery(pgPool_);
std::stringstream sql;
sql << "SELECT transaction, metadata, ledger_seq FROM transactions WHERE "
<< "ledger_seq = " << std::to_string(ledgerSequence);
auto res = pgQuery(sql.str().data());
if (size_t numRows = checkResult(res, 3))
{
std::vector<TransactionAndMetadata> txns;
for (size_t i = 0; i < numRows; ++i)
{
char const* txn = res.c_str(0, 0);
char const* metadata = res.c_str(0, 1);
std::string_view txnView{txn};
std::string_view metadataView{metadata};
txns.push_back(
{{txnView.front(), txnView.back()},
{metadataView.front(), metadataView.back()}});
}
return txns;
}
return {};
}
LedgerPage
PostgresBackend::fetchLedgerPage(

View File

@@ -34,6 +34,9 @@ public:
std::optional<TransactionAndMetadata>
fetchTransaction(ripple::uint256 const& hash) const override;
std::vector<TransactionAndMetadata>
fetchAllTransactionsInLedger(uint32_t ledgerSequence) const override;
LedgerPage
fetchLedgerPage(
std::optional<ripple::uint256> const& cursor,

View File

@@ -69,6 +69,8 @@ boost::json::object
doBookOffers(
boost::json::object const& request,
BackendInterface const& backend);
boost::json::object
doLedger(boost::json::object const& request, BackendInterface const& backend);
boost::json::object
buildResponse(
@@ -87,6 +89,7 @@ buildResponse(
return doAccountTx(request, backend);
break;
case ledger:
return doLedgerData(request, backend);
break;
case ledger_data:
return doLedgerData(request, backend);