Merge pull request #5525
0605406
daemon: sort alt chains by height (moneromooo-monero)4228ee0
daemon: add optional arguments to alt_chain_info (moneromooo-monero)880ebfd
daemon: add more chain specific info in alt_chain_info (moneromooo-monero)
This commit is contained in:
commit
564bb1da3a
|
@ -1068,6 +1068,23 @@ std::string get_nix_version_display_string()
|
||||||
return std::string(buffer);
|
return std::string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string get_human_readable_timespan(uint64_t seconds)
|
||||||
|
{
|
||||||
|
if (seconds < 60)
|
||||||
|
return std::to_string(seconds) + " seconds";
|
||||||
|
if (seconds < 3600)
|
||||||
|
return std::to_string((uint64_t)(seconds / 60)) + " minutes";
|
||||||
|
if (seconds < 3600 * 24)
|
||||||
|
return std::to_string((uint64_t)(seconds / 3600)) + " hours";
|
||||||
|
if (seconds < 3600 * 24 * 30.5)
|
||||||
|
return std::to_string((uint64_t)(seconds / (3600 * 24))) + " days";
|
||||||
|
if (seconds < 3600 * 24 * 365.25)
|
||||||
|
return std::to_string((uint64_t)(seconds / (3600 * 24 * 30.5))) + " months";
|
||||||
|
if (seconds < 3600 * 24 * 365.25 * 100)
|
||||||
|
return std::to_string((uint64_t)(seconds / (3600 * 24 * 30.5 * 365.25))) + " years";
|
||||||
|
return "a long time";
|
||||||
|
}
|
||||||
|
|
||||||
std::string get_human_readable_bytes(uint64_t bytes)
|
std::string get_human_readable_bytes(uint64_t bytes)
|
||||||
{
|
{
|
||||||
// Use 1024 for "kilo", 1024*1024 for "mega" and so on instead of the more modern and standard-conforming
|
// Use 1024 for "kilo", 1024*1024 for "mega" and so on instead of the more modern and standard-conforming
|
||||||
|
|
|
@ -245,5 +245,7 @@ namespace tools
|
||||||
|
|
||||||
std::string get_human_readable_timestamp(uint64_t ts);
|
std::string get_human_readable_timestamp(uint64_t ts);
|
||||||
|
|
||||||
|
std::string get_human_readable_timespan(uint64_t seconds);
|
||||||
|
|
||||||
std::string get_human_readable_bytes(uint64_t bytes);
|
std::string get_human_readable_bytes(uint64_t bytes);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4853,9 +4853,9 @@ std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> Blockchain:: get_ou
|
||||||
return m_db->get_output_histogram(amounts, unlocked, recent_cutoff, min_count);
|
return m_db->get_output_histogram(amounts, unlocked, recent_cutoff, min_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> Blockchain::get_alternative_chains() const
|
std::vector<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> Blockchain::get_alternative_chains() const
|
||||||
{
|
{
|
||||||
std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> chains;
|
std::vector<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> chains;
|
||||||
|
|
||||||
blocks_ext_by_hash alt_blocks;
|
blocks_ext_by_hash alt_blocks;
|
||||||
alt_blocks.reserve(m_db->get_alt_block_count());
|
alt_blocks.reserve(m_db->get_alt_block_count());
|
||||||
|
|
|
@ -950,9 +950,9 @@ namespace cryptonote
|
||||||
/**
|
/**
|
||||||
* @brief returns a set of known alternate chains
|
* @brief returns a set of known alternate chains
|
||||||
*
|
*
|
||||||
* @return a list of chains
|
* @return a vector of chains
|
||||||
*/
|
*/
|
||||||
std::list<std::pair<block_extended_info,std::vector<crypto::hash>>> get_alternative_chains() const;
|
std::vector<std::pair<block_extended_info,std::vector<crypto::hash>>> get_alternative_chains() const;
|
||||||
|
|
||||||
void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t &meta);
|
void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t &meta);
|
||||||
void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta);
|
void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta);
|
||||||
|
|
|
@ -674,11 +674,38 @@ bool t_command_parser_executor::alt_chain_info(const std::vector<std::string>& a
|
||||||
{
|
{
|
||||||
if(args.size() > 1)
|
if(args.size() > 1)
|
||||||
{
|
{
|
||||||
std::cout << "usage: alt_chain_info [block_hash]" << std::endl;
|
std::cout << "usage: alt_chain_info [block_hash|>N|-N]" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_executor.alt_chain_info(args.size() == 1 ? args[0] : "");
|
std::string tip;
|
||||||
|
size_t above = 0;
|
||||||
|
uint64_t last_blocks = 0;
|
||||||
|
if (args.size() == 1)
|
||||||
|
{
|
||||||
|
if (args[0].size() > 0 && args[0][0] == '>')
|
||||||
|
{
|
||||||
|
if (!epee::string_tools::get_xtype_from_string(above, args[0].c_str() + 1))
|
||||||
|
{
|
||||||
|
std::cout << "invalid above parameter" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[0].size() > 0 && args[0][0] == '-')
|
||||||
|
{
|
||||||
|
if (!epee::string_tools::get_xtype_from_string(last_blocks, args[0].c_str() + 1))
|
||||||
|
{
|
||||||
|
std::cout << "invalid last_blocks parameter" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tip = args[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_executor.alt_chain_info(tip, above, last_blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector<std::string>& args)
|
bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector<std::string>& args)
|
||||||
|
|
|
@ -1818,7 +1818,7 @@ bool t_rpc_command_executor::print_coinbase_tx_sum(uint64_t height, uint64_t cou
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool t_rpc_command_executor::alt_chain_info(const std::string &tip)
|
bool t_rpc_command_executor::alt_chain_info(const std::string &tip, size_t above, uint64_t last_blocks)
|
||||||
{
|
{
|
||||||
cryptonote::COMMAND_RPC_GET_INFO::request ireq;
|
cryptonote::COMMAND_RPC_GET_INFO::request ireq;
|
||||||
cryptonote::COMMAND_RPC_GET_INFO::response ires;
|
cryptonote::COMMAND_RPC_GET_INFO::response ires;
|
||||||
|
@ -1855,16 +1855,31 @@ bool t_rpc_command_executor::alt_chain_info(const std::string &tip)
|
||||||
|
|
||||||
if (tip.empty())
|
if (tip.empty())
|
||||||
{
|
{
|
||||||
tools::msg_writer() << boost::lexical_cast<std::string>(res.chains.size()) << " alternate chains found:";
|
auto chains = res.chains;
|
||||||
for (const auto &chain: res.chains)
|
std::sort(chains.begin(), chains.end(), [](const cryptonote::COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info &info0, cryptonote::COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info &info1){ return info0.height < info1.height; });
|
||||||
|
std::vector<size_t> display;
|
||||||
|
for (size_t i = 0; i < chains.size(); ++i)
|
||||||
{
|
{
|
||||||
uint64_t start_height = (chain.height - chain.length + 1);
|
const auto &chain = chains[i];
|
||||||
|
if (chain.length <= above)
|
||||||
|
continue;
|
||||||
|
const uint64_t start_height = (chain.height - chain.length + 1);
|
||||||
|
if (last_blocks > 0 && ires.height - 1 - start_height >= last_blocks)
|
||||||
|
continue;
|
||||||
|
display.push_back(i);
|
||||||
|
}
|
||||||
|
tools::msg_writer() << boost::lexical_cast<std::string>(display.size()) << " alternate chains found:";
|
||||||
|
for (const size_t idx: display)
|
||||||
|
{
|
||||||
|
const auto &chain = chains[idx];
|
||||||
|
const uint64_t start_height = (chain.height - chain.length + 1);
|
||||||
tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1)
|
tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1)
|
||||||
<< " deep), diff " << chain.difficulty << ": " << chain.block_hash;
|
<< " deep), diff " << chain.difficulty << ": " << chain.block_hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
const uint64_t now = time(NULL);
|
||||||
const auto i = std::find_if(res.chains.begin(), res.chains.end(), [&tip](cryptonote::COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info &info){ return info.block_hash == tip; });
|
const auto i = std::find_if(res.chains.begin(), res.chains.end(), [&tip](cryptonote::COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info &info){ return info.block_hash == tip; });
|
||||||
if (i != res.chains.end())
|
if (i != res.chains.end())
|
||||||
{
|
{
|
||||||
|
@ -1876,6 +1891,49 @@ bool t_rpc_command_executor::alt_chain_info(const std::string &tip)
|
||||||
for (const std::string &block_id: chain.block_hashes)
|
for (const std::string &block_id: chain.block_hashes)
|
||||||
tools::msg_writer() << " " << block_id;
|
tools::msg_writer() << " " << block_id;
|
||||||
tools::msg_writer() << "Chain parent on main chain: " << chain.main_chain_parent_block;
|
tools::msg_writer() << "Chain parent on main chain: " << chain.main_chain_parent_block;
|
||||||
|
cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request bhreq;
|
||||||
|
cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response bhres;
|
||||||
|
bhreq.hashes = chain.block_hashes;
|
||||||
|
bhreq.hashes.push_back(chain.main_chain_parent_block);
|
||||||
|
bhreq.fill_pow_hash = false;
|
||||||
|
if (m_is_rpc)
|
||||||
|
{
|
||||||
|
if (!m_rpc_client->json_rpc_request(bhreq, bhres, "getblockheaderbyhash", fail_message.c_str()))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!m_rpc_server->on_get_block_header_by_hash(bhreq, bhres, error_resp))
|
||||||
|
{
|
||||||
|
tools::fail_msg_writer() << make_error(fail_message, res.status);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bhres.block_headers.size() != chain.length + 1)
|
||||||
|
{
|
||||||
|
tools::fail_msg_writer() << "Failed to get block header info for alt chain";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
uint64_t t0 = bhres.block_headers.front().timestamp, t1 = t0;
|
||||||
|
for (const cryptonote::block_header_response &block_header: bhres.block_headers)
|
||||||
|
{
|
||||||
|
t0 = std::min<uint64_t>(t0, block_header.timestamp);
|
||||||
|
t1 = std::max<uint64_t>(t1, block_header.timestamp);
|
||||||
|
}
|
||||||
|
const uint64_t dt = t1 - t0;
|
||||||
|
const uint64_t age = std::max(dt, t0 < now ? now - t0 : 0);
|
||||||
|
tools::msg_writer() << "Age: " << tools::get_human_readable_timespan(age);
|
||||||
|
if (chain.length > 1)
|
||||||
|
{
|
||||||
|
tools::msg_writer() << "Time span: " << tools::get_human_readable_timespan(dt);
|
||||||
|
cryptonote::difficulty_type start_difficulty = bhres.block_headers.back().difficulty;
|
||||||
|
if (start_difficulty > 0)
|
||||||
|
tools::msg_writer() << "Approximated " << 100.f * DIFFICULTY_TARGET_V2 * chain.length / dt << "% of network hash rate";
|
||||||
|
else
|
||||||
|
tools::fail_msg_writer() << "Bad cmumulative difficulty reported by dameon";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tools::fail_msg_writer() << "Block hash " << tip << " is not the tip of any known alternate chain";
|
tools::fail_msg_writer() << "Block hash " << tip << " is not the tip of any known alternate chain";
|
||||||
|
|
|
@ -145,7 +145,7 @@ public:
|
||||||
|
|
||||||
bool print_coinbase_tx_sum(uint64_t height, uint64_t count);
|
bool print_coinbase_tx_sum(uint64_t height, uint64_t count);
|
||||||
|
|
||||||
bool alt_chain_info(const std::string &tip);
|
bool alt_chain_info(const std::string &tip, size_t above, uint64_t last_blocks);
|
||||||
|
|
||||||
bool print_blockchain_dynamic_stats(uint64_t nblocks);
|
bool print_blockchain_dynamic_stats(uint64_t nblocks);
|
||||||
|
|
||||||
|
|
|
@ -1612,12 +1612,13 @@ namespace cryptonote
|
||||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH>(invoke_http_mode::JON_RPC, "getblockheaderbyhash", req, res, r))
|
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH>(invoke_http_mode::JON_RPC, "getblockheaderbyhash", req, res, r))
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
auto get = [this](const std::string &hash, bool fill_pow_hash, block_header_response &block_header, bool restricted, epee::json_rpc::error& error_resp) -> bool {
|
||||||
crypto::hash block_hash;
|
crypto::hash block_hash;
|
||||||
bool hash_parsed = parse_hash256(req.hash, block_hash);
|
bool hash_parsed = parse_hash256(hash, block_hash);
|
||||||
if(!hash_parsed)
|
if(!hash_parsed)
|
||||||
{
|
{
|
||||||
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
|
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
|
||||||
error_resp.message = "Failed to parse hex representation of block hash. Hex = " + req.hash + '.';
|
error_resp.message = "Failed to parse hex representation of block hash. Hex = " + hash + '.';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
block blk;
|
block blk;
|
||||||
|
@ -1626,7 +1627,7 @@ namespace cryptonote
|
||||||
if (!have_block)
|
if (!have_block)
|
||||||
{
|
{
|
||||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||||
error_resp.message = "Internal error: can't get block by hash. Hash = " + req.hash + '.';
|
error_resp.message = "Internal error: can't get block by hash. Hash = " + hash + '.';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (blk.miner_tx.vin.size() != 1 || blk.miner_tx.vin.front().type() != typeid(txin_gen))
|
if (blk.miner_tx.vin.size() != 1 || blk.miner_tx.vin.front().type() != typeid(txin_gen))
|
||||||
|
@ -1636,14 +1637,30 @@ namespace cryptonote
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint64_t block_height = boost::get<txin_gen>(blk.miner_tx.vin.front()).height;
|
uint64_t block_height = boost::get<txin_gen>(blk.miner_tx.vin.front()).height;
|
||||||
const bool restricted = m_restricted && ctx;
|
bool response_filled = fill_block_header_response(blk, orphan, block_height, block_hash, block_header, fill_pow_hash && !restricted);
|
||||||
bool response_filled = fill_block_header_response(blk, orphan, block_height, block_hash, res.block_header, req.fill_pow_hash && !restricted);
|
|
||||||
if (!response_filled)
|
if (!response_filled)
|
||||||
{
|
{
|
||||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||||
error_resp.message = "Internal error: can't produce valid response.";
|
error_resp.message = "Internal error: can't produce valid response.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const bool restricted = m_restricted && ctx;
|
||||||
|
if (!req.hash.empty())
|
||||||
|
{
|
||||||
|
if (!get(req.hash, req.fill_pow_hash, res.block_header, restricted, error_resp))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
res.block_headers.reserve(req.hashes.size());
|
||||||
|
for (const std::string &hash: req.hashes)
|
||||||
|
{
|
||||||
|
res.block_headers.push_back({});
|
||||||
|
if (!get(hash, req.fill_pow_hash, res.block_headers.back(), restricted, error_resp))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
res.status = CORE_RPC_STATUS_OK;
|
res.status = CORE_RPC_STATUS_OK;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2073,7 +2090,7 @@ namespace cryptonote
|
||||||
PERF_TIMER(on_get_alternate_chains);
|
PERF_TIMER(on_get_alternate_chains);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::list<std::pair<Blockchain::block_extended_info, std::vector<crypto::hash>>> chains = m_core.get_blockchain_storage().get_alternative_chains();
|
std::vector<std::pair<Blockchain::block_extended_info, std::vector<crypto::hash>>> chains = m_core.get_blockchain_storage().get_alternative_chains();
|
||||||
for (const auto &i: chains)
|
for (const auto &i: chains)
|
||||||
{
|
{
|
||||||
difficulty_type wdiff = i.first.cumulative_difficulty;
|
difficulty_type wdiff = i.first.cumulative_difficulty;
|
||||||
|
|
|
@ -1096,10 +1096,12 @@ namespace cryptonote
|
||||||
struct request_t
|
struct request_t
|
||||||
{
|
{
|
||||||
std::string hash;
|
std::string hash;
|
||||||
|
std::vector<std::string> hashes;
|
||||||
bool fill_pow_hash;
|
bool fill_pow_hash;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(hash)
|
KV_SERIALIZE(hash)
|
||||||
|
KV_SERIALIZE(hashes)
|
||||||
KV_SERIALIZE_OPT(fill_pow_hash, false);
|
KV_SERIALIZE_OPT(fill_pow_hash, false);
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
|
@ -1109,10 +1111,12 @@ namespace cryptonote
|
||||||
{
|
{
|
||||||
std::string status;
|
std::string status;
|
||||||
block_header_response block_header;
|
block_header_response block_header;
|
||||||
|
std::vector<block_header_response> block_headers;
|
||||||
bool untrusted;
|
bool untrusted;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(block_header)
|
KV_SERIALIZE(block_header)
|
||||||
|
KV_SERIALIZE(block_headers)
|
||||||
KV_SERIALIZE(status)
|
KV_SERIALIZE(status)
|
||||||
KV_SERIALIZE(untrusted)
|
KV_SERIALIZE(untrusted)
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
|
@ -2100,7 +2104,7 @@ namespace cryptonote
|
||||||
struct response_t
|
struct response_t
|
||||||
{
|
{
|
||||||
std::string status;
|
std::string status;
|
||||||
std::list<chain_info> chains;
|
std::vector<chain_info> chains;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(status)
|
KV_SERIALIZE(status)
|
||||||
|
|
|
@ -90,11 +90,12 @@ class Daemon(object):
|
||||||
}
|
}
|
||||||
return self.rpc.send_json_rpc_request(getlastblockheader)
|
return self.rpc.send_json_rpc_request(getlastblockheader)
|
||||||
|
|
||||||
def getblockheaderbyhash(self, hash):
|
def getblockheaderbyhash(self, hash = "", hashes = []):
|
||||||
getblockheaderbyhash = {
|
getblockheaderbyhash = {
|
||||||
'method': 'getblockheaderbyhash',
|
'method': 'getblockheaderbyhash',
|
||||||
'params': {
|
'params': {
|
||||||
'hash': hash,
|
'hash': hash,
|
||||||
|
'hashes': hashes,
|
||||||
},
|
},
|
||||||
'jsonrpc': '2.0',
|
'jsonrpc': '2.0',
|
||||||
'id': '0'
|
'id': '0'
|
||||||
|
|
Loading…
Reference in New Issue