mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-04-29 15:37:59 +00:00
Ledger query infrastructure. (#275)
* Added json ledger query param parser. * Added initial query response creation. * Updated client lib. * Implemented get ledger by seq no. * Added ledger query execution wrappers. * Included log record info. * Fixed empty output hash issue. * Added bson support. * Added db file existance check. * Added requesy/reply tracking for queries in client lib. * Improved multi connection usage in client lib. * Added genesis ledger query support. * Updated naming convention of query result fields. * Comments. * Used sqlite bind() for query param. * Used binary hashes in ledger sqlite db. * Missing const.
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
#include "sqlite.hpp"
|
||||
#include "../util/h32.hpp"
|
||||
#include "ledger_common.hpp"
|
||||
|
||||
namespace ledger::sqlite
|
||||
{
|
||||
constexpr const char *LEDGER_TABLE = "ledger";
|
||||
constexpr const char *LEDGER_COLUMNS = "seq_no, time, ledger_hash, prev_ledger_hash, data_hash, state_hash, patch_hash, user_hash, input_hash, output_hash";
|
||||
constexpr const char *HP_VERSION_TABLE = "hp";
|
||||
constexpr const char *HP_VERSION_COLUMN = "hp_version";
|
||||
constexpr const char *COLUMN_DATA_TYPES[]{"INT", "TEXT"};
|
||||
constexpr const char *COLUMN_DATA_TYPES[]{"INT", "TEXT", "BLOB"};
|
||||
constexpr const char *CREATE_TABLE = "CREATE TABLE IF NOT EXISTS ";
|
||||
constexpr const char *INSERT_INTO = "INSERT INTO ";
|
||||
constexpr const char *PRIMARY_KEY = "PRIMARY KEY";
|
||||
@@ -15,8 +16,16 @@ namespace ledger::sqlite
|
||||
constexpr const char *SELECT_ALL = "SELECT * FROM ";
|
||||
constexpr const char *SQLITE_MASTER = "sqlite_master";
|
||||
constexpr const char *WHERE = " WHERE ";
|
||||
constexpr const char *ORDER_BY = " ORDER BY ";
|
||||
constexpr const char *AND = " AND ";
|
||||
constexpr const char *SELECT_LAST_LEDGER = "SELECT * FROM ledger ORDER BY seq_no DESC LIMIT 1";
|
||||
constexpr const char *SELECT_LEDGER_BY_SEQ_NO = "SELECT * FROM ledger WHERE seq_no=? LIMIT 1";
|
||||
constexpr const char *INSERT_INTO_LEDGER = "INSERT INTO ledger("
|
||||
"seq_no, time, ledger_hash, prev_ledger_hash, data_hash,"
|
||||
"state_hash, patch_hash, user_hash, input_hash, output_hash"
|
||||
") VALUES(?,?,?,?,?,?,?,?,?,?)";
|
||||
|
||||
#define BIND_H32_BLOB(idx, field) (sqlite3_bind_blob(stmt, idx, field.data(), sizeof(util::h32), SQLITE_STATIC) == SQLITE_OK)
|
||||
#define GET_H32_BLOB(idx) std::string((char *)sqlite3_column_blob(stmt, idx), sizeof(util::h32))
|
||||
|
||||
/**
|
||||
* Opens a connection to a given databse and give the db pointer.
|
||||
@@ -26,10 +35,11 @@ namespace ledger::sqlite
|
||||
*/
|
||||
int open_db(std::string_view db_name, sqlite3 **db)
|
||||
{
|
||||
if (sqlite3_open(db_name.data(), db) != SQLITE_OK)
|
||||
int ret;
|
||||
if ((ret = sqlite3_open(db_name.data(), db)) != SQLITE_OK)
|
||||
{
|
||||
*db = NULL;
|
||||
LOG_ERROR << "Can't open database: " << sqlite3_errmsg(*db);
|
||||
LOG_ERROR << "Can't open database: " << ret << ", " << sqlite3_errmsg(*db);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -97,14 +107,14 @@ namespace ledger::sqlite
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert values to a table.
|
||||
* Inserts mulitple rows to a table.
|
||||
* @param db Pointer to the db.
|
||||
* @param table_name Table name to be populated.
|
||||
* @param column_names_string Comma seperated string of colums (eg: "col_1,col_2,...").
|
||||
* @param value_strings Vector of comma seperated values (wrap in single quotes for TEXT type) (eg: ["r1val1,'r1val2',...", "r2val1,'r2val2',..."]).
|
||||
* @returns returns 0 on success, or -1 on error.
|
||||
*/
|
||||
int insert_values(sqlite3 *db, std::string_view table_name, std::string_view column_names_string, const std::vector<std::string> &value_strings)
|
||||
int insert_rows(sqlite3 *db, std::string_view table_name, std::string_view column_names_string, const std::vector<std::string> &value_strings)
|
||||
{
|
||||
std::string sql;
|
||||
|
||||
@@ -130,14 +140,14 @@ namespace ledger::sqlite
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a value row to a table.
|
||||
* Inserts a row to a table.
|
||||
* @param db Pointer to the db.
|
||||
* @param table_name Table name to be populated.
|
||||
* @param column_names_string Comma seperated string of colums (eg: "col_1,col_2,...").
|
||||
* @param value_string comma seperated values as per column order (wrap in single quotes for TEXT type) (eg: "r1val1,'r1val2',...").
|
||||
* @returns returns 0 on success, or -1 on error.
|
||||
*/
|
||||
int insert_value(sqlite3 *db, std::string_view table_name, std::string_view column_names_string, std::string_view value_string)
|
||||
int insert_row(sqlite3 *db, std::string_view table_name, std::string_view column_names_string, std::string_view value_string)
|
||||
{
|
||||
std::string sql;
|
||||
// Reserving the space for the query before construction.
|
||||
@@ -217,17 +227,17 @@ namespace ledger::sqlite
|
||||
*/
|
||||
int create_ledger_table(sqlite3 *db)
|
||||
{
|
||||
std::vector<table_column_info> column_info{
|
||||
const std::vector<table_column_info> column_info{
|
||||
table_column_info("seq_no", COLUMN_DATA_TYPE::INT, true),
|
||||
table_column_info("time", COLUMN_DATA_TYPE::INT),
|
||||
table_column_info("ledger_hash", COLUMN_DATA_TYPE::TEXT),
|
||||
table_column_info("prev_ledger_hash", COLUMN_DATA_TYPE::TEXT),
|
||||
table_column_info("data_hash", COLUMN_DATA_TYPE::TEXT),
|
||||
table_column_info("state_hash", COLUMN_DATA_TYPE::TEXT),
|
||||
table_column_info("patch_hash", COLUMN_DATA_TYPE::TEXT),
|
||||
table_column_info("user_hash", COLUMN_DATA_TYPE::TEXT),
|
||||
table_column_info("input_hash", COLUMN_DATA_TYPE::TEXT),
|
||||
table_column_info("output_hash", COLUMN_DATA_TYPE::TEXT)};
|
||||
table_column_info("ledger_hash", COLUMN_DATA_TYPE::BLOB),
|
||||
table_column_info("prev_ledger_hash", COLUMN_DATA_TYPE::BLOB),
|
||||
table_column_info("data_hash", COLUMN_DATA_TYPE::BLOB),
|
||||
table_column_info("state_hash", COLUMN_DATA_TYPE::BLOB),
|
||||
table_column_info("patch_hash", COLUMN_DATA_TYPE::BLOB),
|
||||
table_column_info("user_hash", COLUMN_DATA_TYPE::BLOB),
|
||||
table_column_info("input_hash", COLUMN_DATA_TYPE::BLOB),
|
||||
table_column_info("output_hash", COLUMN_DATA_TYPE::BLOB)};
|
||||
|
||||
if (create_table(db, LEDGER_TABLE, column_info) == -1)
|
||||
return -1;
|
||||
@@ -244,7 +254,6 @@ namespace ledger::sqlite
|
||||
*/
|
||||
int create_hp_version_table_and_update(sqlite3 *db, std::string_view version)
|
||||
{
|
||||
|
||||
const std::vector<table_column_info> column_info{
|
||||
table_column_info(HP_VERSION_COLUMN, COLUMN_DATA_TYPE::TEXT)};
|
||||
|
||||
@@ -252,7 +261,7 @@ namespace ledger::sqlite
|
||||
return -1;
|
||||
|
||||
const std::string value_string = "\"" + std::string(version) + "\"";
|
||||
if (insert_value(db, HP_VERSION_TABLE, HP_VERSION_COLUMN, value_string) == -1)
|
||||
if (insert_row(db, HP_VERSION_TABLE, HP_VERSION_COLUMN, value_string) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
@@ -264,23 +273,28 @@ namespace ledger::sqlite
|
||||
* @param ledger Ledger struct to be inserted.
|
||||
* @returns returns 0 on success, or -1 on error.
|
||||
*/
|
||||
int insert_ledger_row(sqlite3 *db, const ledger &ledger)
|
||||
int insert_ledger_row(sqlite3 *db, const ledger::ledger_record &ledger)
|
||||
{
|
||||
std::string value_string = std::to_string(ledger.seq_no) + "," +
|
||||
std::to_string(ledger.time) + "," +
|
||||
"'" + ledger.ledger_hash_hex + "'," +
|
||||
"'" + ledger.prev_ledger_hash_hex + "'," +
|
||||
"'" + ledger.data_hash_hex + "'," +
|
||||
"'" + ledger.state_hash_hex + "'," +
|
||||
"'" + ledger.patch_hash_hex + "'," +
|
||||
"'" + ledger.user_hash_hex + "'," +
|
||||
"'" + ledger.input_hash_hex + "'," +
|
||||
"'" + ledger.output_hash_hex + "'";
|
||||
sqlite3_stmt *stmt;
|
||||
if (sqlite3_prepare_v2(db, INSERT_INTO_LEDGER, -1, &stmt, 0) == SQLITE_OK && stmt != NULL &&
|
||||
sqlite3_bind_int64(stmt, 1, ledger.seq_no) == SQLITE_OK &&
|
||||
sqlite3_bind_int64(stmt, 2, ledger.timestamp) == SQLITE_OK &&
|
||||
BIND_H32_BLOB(3, ledger.ledger_hash) &&
|
||||
BIND_H32_BLOB(4, ledger.prev_ledger_hash) &&
|
||||
BIND_H32_BLOB(5, ledger.data_hash) &&
|
||||
BIND_H32_BLOB(6, ledger.state_hash) &&
|
||||
BIND_H32_BLOB(7, ledger.config_hash) &&
|
||||
BIND_H32_BLOB(8, ledger.user_hash) &&
|
||||
BIND_H32_BLOB(9, ledger.input_hash) &&
|
||||
BIND_H32_BLOB(10, ledger.output_hash) &&
|
||||
sqlite3_step(stmt) == SQLITE_DONE)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (insert_value(db, LEDGER_TABLE, LEDGER_COLUMNS, value_string) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
sqlite3_finalize(stmt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,36 +310,71 @@ namespace ledger::sqlite
|
||||
/**
|
||||
* Get the last ledger record of the given db.
|
||||
* @param db Pointer to the db.
|
||||
* @returns returns the last ledger as a struct.
|
||||
* @param ledger Ledger structure to populate.
|
||||
* @returns 0 on success. -1 on failure.
|
||||
*/
|
||||
ledger get_last_ledger(sqlite3 *db)
|
||||
int get_last_ledger(sqlite3 *db, ledger::ledger_record &ledger)
|
||||
{
|
||||
std::string sql;
|
||||
sql.append(SELECT_ALL);
|
||||
sql.append(LEDGER_TABLE);
|
||||
sql.append(ORDER_BY);
|
||||
sql.append("seq_no DESC LIMIT 1");
|
||||
|
||||
sqlite3_stmt *stmt;
|
||||
sqlite::ledger ledger;
|
||||
|
||||
if (sqlite3_prepare_v2(db, sql.data(), -1, &stmt, 0) == SQLITE_OK &&
|
||||
stmt != NULL && sqlite3_step(stmt) == SQLITE_ROW)
|
||||
if (sqlite3_prepare_v2(db, SELECT_LAST_LEDGER, -1, &stmt, 0) == SQLITE_OK && stmt != NULL &&
|
||||
sqlite3_step(stmt) == SQLITE_ROW)
|
||||
{
|
||||
ledger.seq_no = sqlite3_column_int64(stmt, 0);
|
||||
ledger.time = sqlite3_column_int64(stmt, 1);
|
||||
ledger.ledger_hash_hex = std::string((char *)sqlite3_column_text(stmt, 2));
|
||||
ledger.prev_ledger_hash_hex = std::string((char *)sqlite3_column_text(stmt, 3));
|
||||
ledger.data_hash_hex = std::string((char *)sqlite3_column_text(stmt, 4));
|
||||
ledger.state_hash_hex = std::string((char *)sqlite3_column_text(stmt, 5));
|
||||
ledger.patch_hash_hex = std::string((char *)sqlite3_column_text(stmt, 6));
|
||||
ledger.user_hash_hex = std::string((char *)sqlite3_column_text(stmt, 7));
|
||||
ledger.input_hash_hex = std::string((char *)sqlite3_column_text(stmt, 8));
|
||||
ledger.output_hash_hex = std::string((char *)sqlite3_column_text(stmt, 9));
|
||||
populate_ledger_from_sql_record(ledger, stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Finalize and distroys the statement.
|
||||
LOG_ERROR << "Error when querying last ledger from db.";
|
||||
sqlite3_finalize(stmt);
|
||||
return ledger;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ledger record by seq no.
|
||||
* @param db Pointer to the db.
|
||||
* @param seq_no Ledger sequence no. to search for.
|
||||
* @param ledger Ledger structure to populate.
|
||||
* @returns 1 if ledger found. 0 if ledger not found. -1 on failure.
|
||||
*/
|
||||
int get_ledger_by_seq_no(sqlite3 *db, const uint64_t seq_no, ledger::ledger_record &ledger)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
if (sqlite3_prepare_v2(db, SELECT_LEDGER_BY_SEQ_NO, -1, &stmt, 0) == SQLITE_OK && stmt != NULL &&
|
||||
sqlite3_bind_int64(stmt, 1, seq_no) == SQLITE_OK)
|
||||
{
|
||||
const int result = sqlite3_step(stmt);
|
||||
if (result == SQLITE_ROW)
|
||||
{
|
||||
populate_ledger_from_sql_record(ledger, stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
return 1; // Ledger found.
|
||||
}
|
||||
else if (result == SQLITE_DONE)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return 0; // Not found.
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR << "Error when querying ledger by seq no. from db.";
|
||||
sqlite3_finalize(stmt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void populate_ledger_from_sql_record(ledger::ledger_record &ledger, sqlite3_stmt *stmt)
|
||||
{
|
||||
ledger.seq_no = sqlite3_column_int64(stmt, 0);
|
||||
ledger.timestamp = sqlite3_column_int64(stmt, 1);
|
||||
ledger.ledger_hash = GET_H32_BLOB(2);
|
||||
ledger.prev_ledger_hash = GET_H32_BLOB(3);
|
||||
ledger.data_hash = GET_H32_BLOB(4);
|
||||
ledger.state_hash = GET_H32_BLOB(5);
|
||||
ledger.config_hash = GET_H32_BLOB(6);
|
||||
ledger.user_hash = GET_H32_BLOB(7);
|
||||
ledger.input_hash = GET_H32_BLOB(8);
|
||||
ledger.output_hash = GET_H32_BLOB(9);
|
||||
}
|
||||
|
||||
} // namespace ledger::sqlite
|
||||
Reference in New Issue
Block a user