diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index d3c66d091..5d5121504 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -4464,9 +4464,9 @@ std::map> Blockchain:: get_ou return m_db->get_output_histogram(amounts, unlocked, recent_cutoff, min_count); } -std::list> Blockchain::get_alternative_chains() const +std::list>> Blockchain::get_alternative_chains() const { - std::list> chains; + std::list>> chains; for (const auto &i: m_alternative_chains) { @@ -4482,15 +4482,16 @@ std::list> Blockchain::get_a } if (!found) { - uint64_t length = 1; + std::vector chain; auto h = i.second.bl.prev_id; + chain.push_back(top); blocks_ext_by_hash::const_iterator prev; while ((prev = m_alternative_chains.find(h)) != m_alternative_chains.end()) { + chain.push_back(h); h = prev->second.bl.prev_id; - ++length; } - chains.push_back(std::make_pair(i.second, length)); + chains.push_back(std::make_pair(i.second, chain)); } } return chains; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index d52a964c3..d95c8ed15 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -947,7 +947,7 @@ namespace cryptonote * * @return a list of chains */ - std::list> get_alternative_chains() const; + std::list>> get_alternative_chains() const; void add_txpool_tx(transaction &tx, const txpool_tx_meta_t &meta); void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta); diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index aa688294d..1638cf505 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -614,13 +614,13 @@ bool t_command_parser_executor::print_coinbase_tx_sum(const std::vector& args) { - if(args.size()) + if(args.size() > 1) { - std::cout << "No parameters allowed" << std::endl; + std::cout << "usage: alt_chain_info [block_hash]" << std::endl; return false; } - return m_executor.alt_chain_info(); + return m_executor.alt_chain_info(args.size() == 1 ? args[0] : ""); } bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector& args) diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 144603597..35504f2c9 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -255,6 +255,7 @@ t_command_server::t_command_server( m_command_lookup.set_handler( "alt_chain_info" , std::bind(&t_command_parser_executor::alt_chain_info, &m_parser, p::_1) + , "alt_chain_info [blockhash]" , "Print the information about alternative chains." ); m_command_lookup.set_handler( diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 956c84a01..5d1a9a556 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -1628,7 +1628,7 @@ bool t_rpc_command_executor::print_coinbase_tx_sum(uint64_t height, uint64_t cou return true; } -bool t_rpc_command_executor::alt_chain_info() +bool t_rpc_command_executor::alt_chain_info(const std::string &tip) { cryptonote::COMMAND_RPC_GET_INFO::request ireq; cryptonote::COMMAND_RPC_GET_INFO::response ires; @@ -1663,12 +1663,32 @@ bool t_rpc_command_executor::alt_chain_info() } } - tools::msg_writer() << boost::lexical_cast(res.chains.size()) << " alternate chains found:"; - for (const auto &chain: res.chains) + if (tip.empty()) { - 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) - << " deep), diff " << chain.difficulty << ": " << chain.block_hash; + tools::msg_writer() << boost::lexical_cast(res.chains.size()) << " alternate chains found:"; + for (const auto &chain: res.chains) + { + 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) + << " deep), diff " << chain.difficulty << ": " << chain.block_hash; + } + } + else + { + 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()) + { + const auto &chain = *i; + tools::success_msg_writer() << "Found alternate chain with tip " << tip; + 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) + << " deep), diff " << chain.difficulty << ":"; + for (const std::string &block_id: chain.block_hashes) + tools::msg_writer() << " " << block_id; + tools::msg_writer() << "Chain parent on main chain: " << chain.main_chain_parent_block; + } + else + tools::fail_msg_writer() << "Block hash " << tip << " is not the tip of any known alternate chain"; } return true; } diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index 46168c93b..9e6010c5b 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -143,7 +143,7 @@ public: bool print_coinbase_tx_sum(uint64_t height, uint64_t count); - bool alt_chain_info(); + bool alt_chain_info(const std::string &tip); bool print_blockchain_dynamic_stats(uint64_t nblocks); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 52f4c0880..029c4ac09 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1839,10 +1839,22 @@ namespace cryptonote PERF_TIMER(on_get_alternate_chains); try { - std::list> chains = m_core.get_blockchain_storage().get_alternative_chains(); + std::list>> chains = m_core.get_blockchain_storage().get_alternative_chains(); for (const auto &i: chains) { - res.chains.push_back(COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info{epee::string_tools::pod_to_hex(get_block_hash(i.first.bl)), i.first.height, i.second, i.first.cumulative_difficulty}); + res.chains.push_back(COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info{epee::string_tools::pod_to_hex(get_block_hash(i.first.bl)), i.first.height, i.second.size(), i.first.cumulative_difficulty, {}, std::string()}); + res.chains.back().block_hashes.reserve(i.second.size()); + for (const crypto::hash &block_id: i.second) + res.chains.back().block_hashes.push_back(epee::string_tools::pod_to_hex(block_id)); + if (i.first.height < i.second.size()) + { + res.status = "Error finding alternate chain attachment point"; + return true; + } + cryptonote::block main_chain_parent_block; + try { main_chain_parent_block = m_core.get_blockchain_storage().get_db().get_block_from_height(i.first.height - i.second.size()); } + catch (const std::exception &e) { res.status = "Error finding alternate chain attachment point"; return true; } + res.chains.back().main_chain_parent_block = epee::string_tools::pod_to_hex(get_block_hash(main_chain_parent_block)); } res.status = CORE_RPC_STATUS_OK; } diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index bcab58025..b05dcdfc0 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -2117,12 +2117,16 @@ namespace cryptonote uint64_t height; uint64_t length; uint64_t difficulty; + std::vector block_hashes; + std::string main_chain_parent_block; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(block_hash) KV_SERIALIZE(height) KV_SERIALIZE(length) KV_SERIALIZE(difficulty) + KV_SERIALIZE(block_hashes) + KV_SERIALIZE(main_chain_parent_block) END_KV_SERIALIZE_MAP() };