From d9157034a6783fd333c5be7f3abf2d77299d406e Mon Sep 17 00:00:00 2001
From: Aiwe
Date: Mon, 4 Jul 2022 17:26:51 +0300
Subject: [PATCH] Implement simple block info by hash
---
src/Rpc/CoreRpcServerCommandsDefinitions.h | 12 ++
src/Rpc/RpcServer.cpp | 127 +++++++++++++++++++++
src/Rpc/RpcServer.h | 1 +
3 files changed, 140 insertions(+)
diff --git a/src/Rpc/CoreRpcServerCommandsDefinitions.h b/src/Rpc/CoreRpcServerCommandsDefinitions.h
index fbfe487c24..2c95c6481b 100755
--- a/src/Rpc/CoreRpcServerCommandsDefinitions.h
+++ b/src/Rpc/CoreRpcServerCommandsDefinitions.h
@@ -321,6 +321,18 @@ struct COMMAND_EXPLORER {
typedef std::string response;
};
+struct COMMAND_EXPLORER_GET_BLOCK_DETAILS_BY_HASH {
+ struct request {
+ std::string hash;
+
+ void serialize(ISerializer& s) {
+ KV_MEMBER(hash)
+ }
+ };
+
+ typedef std::string response;
+};
+
//-----------------------------------------------
struct COMMAND_RPC_GET_INFO {
typedef EMPTY_STRUCT request;
diff --git a/src/Rpc/RpcServer.cpp b/src/Rpc/RpcServer.cpp
index 18d95c7dad..9b1ba59521 100755
--- a/src/Rpc/RpcServer.cpp
+++ b/src/Rpc/RpcServer.cpp
@@ -468,6 +468,26 @@ void RpcServer::processRequest(const httplib::Request& request, httplib::Respons
std::string tx_method = "/explorer/tx/";
if (Common::starts_with(url, block_method)) {
+ std::string hash_str = url.substr(block_method.size());
+ if (hash_str.size() < 64) { // assume it's height
+ //on_get_explorer_block_by_height
+
+ }
+ else {
+ COMMAND_EXPLORER_GET_BLOCK_DETAILS_BY_HASH::request req;
+ req.hash = hash_str;
+ COMMAND_EXPLORER_GET_BLOCK_DETAILS_BY_HASH::response rsp;
+ bool r = on_get_explorer_block_by_hash(req, rsp);
+ if (r) {
+ response.status = 200;
+ response.set_content(rsp, "text/html");
+ }
+ else {
+ response.status = 500;
+ response.set_content("Internal error", "text/html");
+ }
+ return;
+ }
return;
}
@@ -1552,11 +1572,118 @@ bool RpcServer::on_get_explorer(const COMMAND_EXPLORER::request& req, COMMAND_EX
body += std::to_string(next_page);
body += "\">next page
";
+ body += index_finish;
+
res = body;
return true;
}
+bool RpcServer::on_get_explorer_block_by_hash(const COMMAND_EXPLORER_GET_BLOCK_DETAILS_BY_HASH::request& req, COMMAND_EXPLORER_GET_BLOCK_DETAILS_BY_HASH::response& res) {
+ try {
+ Crypto::Hash block_hash;
+ if (!parse_hash256(req.hash, block_hash)) {
+ throw JsonRpc::JsonRpcError{
+ CORE_RPC_ERROR_CODE_WRONG_PARAM,
+ "Failed to parse hex representation of block hash. Hex = " + req.hash + '.' };
+ }
+ Block blk;
+ if (!m_core.getBlockByHash(block_hash, blk)) {
+ throw JsonRpc::JsonRpcError{
+ CORE_RPC_ERROR_CODE_INTERNAL_ERROR,
+ "Internal error: can't get block by hash. Hash = " + req.hash + '.' };
+ }
+
+ Crypto::Hash blockHash = get_block_hash(blk);
+ uint32_t blockIndex = boost::get(blk.baseTransaction.inputs.front()).blockIndex;
+
+ std::string body = index_start + (m_core.currency().isTestnet() ? "testnet" : "mainnet") + "\n";
+
+ body += "
Block " + Common::podToHex(blockHash) + "
\n";
+
+ body += "\n";
+ body += " - \n";
+ body += " Index: " + std::to_string(blockIndex) + "\n";
+ body += "
\n";
+ body += " - \n";
+ time_t rawtime = (const time_t)blk.timestamp;
+ struct tm* timeinfo;
+ timeinfo = localtime(&rawtime);
+ body += " Time: " + std::to_string(blk.timestamp) + " • ";
+ body += asctime(timeinfo);
+ body += "
\n";
+ body += " - \n";
+ body += " Version: " + std::to_string(blk.majorVersion) + "." + std::to_string(blk.minorVersion) + "\n";
+ body += "
\n";
+ body += " - \n";
+ Crypto::Hash tmpHash = m_core.getBlockIdByHeight(blockIndex);
+ bool isOrphaned = blockHash != tmpHash;
+ body += " Orphan: ";
+ if (isOrphaned)
+ body += "YES\n";
+ else
+ body += "NO\n";
+ body += "
\n";
+ body += " - \n";
+ size_t blockSize = 0;
+ if (!m_core.getBlockSize(blockHash, blockSize)) {
+ throw JsonRpc::JsonRpcError{
+ CORE_RPC_ERROR_CODE_INTERNAL_ERROR,
+ "Internal error: can't get size of block " + req.hash + '.' };
+ }
+ body += " Size: " + std::to_string(blockSize) + "\n";
+ body += "
\n";
+ body += " - \n";
+ uint64_t blockDifficulty = 0;
+ if (!m_core.getBlockDifficulty(blockIndex, blockDifficulty)) {
+ throw JsonRpc::JsonRpcError{
+ CORE_RPC_ERROR_CODE_INTERNAL_ERROR,
+ "Internal error: can't calcualate difficulty for block " + req.hash + '.' };
+ }
+ body += " Difficulty: " + std::to_string(blockDifficulty) + "\n";
+ body += "
\n";
+ body += " - \n";
+ body += " Previous block hash: " + Common::podToHex(blk.previousBlockHash);
+ body += "
\n";
+ body += "
";
+
+ body += "Transactions
\n";
+
+ // simple list of tx hashes without details
+ body += "\n";
+ body += " - \n";
+ Crypto::Hash coinbaseHash = getObjectHash(blk.baseTransaction);
+ std::string txHashStr = Common::podToHex(coinbaseHash);
+ body += " ";
+ body += txHashStr;
+ body += "";
+ body += "
\n";
+
+ for (const auto& t : blk.transactionHashes) {
+ body += " - \n";
+ body += " ";
+ body += Common::podToHex(t);
+ body += "
\n";
+ }
+
+ body += "
\n";
+
+ body += index_finish;
+
+ res = body;
+ }
+ catch (std::system_error& e) {
+ throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_INTERNAL_ERROR, e.what() };
+ return false;
+ }
+ catch (std::exception& e) {
+ throw JsonRpc::JsonRpcError{ CORE_RPC_ERROR_CODE_INTERNAL_ERROR, "Error: " + std::string(e.what()) };
+ return false;
+ }
+
+ return true;
+}
+
//
// JSON handlers
diff --git a/src/Rpc/RpcServer.h b/src/Rpc/RpcServer.h
index 896f89468a..36a05c32e5 100755
--- a/src/Rpc/RpcServer.h
+++ b/src/Rpc/RpcServer.h
@@ -91,6 +91,7 @@ class RpcServer {
// explorer
bool on_get_explorer(const COMMAND_EXPLORER::request& req, COMMAND_EXPLORER::response& res);
+ bool on_get_explorer_block_by_hash(const COMMAND_EXPLORER_GET_BLOCK_DETAILS_BY_HASH::request& req, COMMAND_EXPLORER_GET_BLOCK_DETAILS_BY_HASH::response& res);
// json handlers
bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res);