mirror of
https://github.com/monero-project/monero.git
synced 2024-11-17 16:27:39 +00:00
DNS checkpoint updating added, and daemon flag to enforce them
The daemon should now check for updated checkpoints from checkpoints.moneropulse.org as well as from the configured json file every ~1hr (and on launch). The daemon now has a flag to enable enforcing these checkpoints (rather than just printing a warning when they fail). TODO: an easily configurable list of DNS servers to check for checkpoints as opposed to the hard-coded "checkpoints.moneropulse.org"
This commit is contained in:
parent
30caebfce3
commit
b261d9207b
7 changed files with 107 additions and 17 deletions
|
@ -442,6 +442,13 @@ difficulty_type blockchain_storage::get_difficulty_for_next_block()
|
||||||
bool blockchain_storage::rollback_blockchain_switching(std::list<block>& original_chain, size_t rollback_height)
|
bool blockchain_storage::rollback_blockchain_switching(std::list<block>& original_chain, size_t rollback_height)
|
||||||
{
|
{
|
||||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||||
|
|
||||||
|
// fail if rollback_height passed is too high
|
||||||
|
if (rollback_height > m_blocks.size())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//remove failed subchain
|
//remove failed subchain
|
||||||
for(size_t i = m_blocks.size()-1; i >=rollback_height; i--)
|
for(size_t i = m_blocks.size()-1; i >=rollback_height; i--)
|
||||||
{
|
{
|
||||||
|
@ -1775,13 +1782,11 @@ bool blockchain_storage::add_new_block(const block& bl_, block_verification_cont
|
||||||
return handle_block_to_main_chain(bl, id, bvc);
|
return handle_block_to_main_chain(bl, id, bvc);
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
void blockchain_storage::update_checkpoints(const std::string& file_path)
|
bool blockchain_storage::update_checkpoints(const std::string& file_path)
|
||||||
{
|
{
|
||||||
// if a path is supplied, updated checkpoints from json.
|
if (!cryptonote::load_new_checkpoints(m_checkpoints, file_path))
|
||||||
// if not, probably fetch from DNS TXT Records.
|
|
||||||
if (file_path.size() > 0)
|
|
||||||
{
|
{
|
||||||
cryptonote::load_checkpoints_from_json(m_checkpoints, file_path);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& points = m_checkpoints.get_points();
|
const auto& points = m_checkpoints.get_points();
|
||||||
|
@ -1790,7 +1795,22 @@ void blockchain_storage::update_checkpoints(const std::string& file_path)
|
||||||
{
|
{
|
||||||
if (!m_checkpoints.check_block(pt.first, get_block_hash(m_blocks[pt.first].bl)))
|
if (!m_checkpoints.check_block(pt.first, get_block_hash(m_blocks[pt.first].bl)))
|
||||||
{
|
{
|
||||||
LOG_ERROR("Checkpoint failed when adding new checkpoints from json file, this could be very bad.");
|
// if we're enforcing dns checkpoints, roll back to a couple of blocks before the checkpoint
|
||||||
|
if (m_enforce_dns_checkpoints)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Checkpoint failed when adding new checkpoints, rolling back!");
|
||||||
|
std::list<block> empty;
|
||||||
|
rollback_blockchain_switching(empty, pt.first - 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR("Checkpoint failed when adding new checkpoints, this could be very bad.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void blockchain_storage::set_enforce_dns_checkpoints(bool enforce_checkpoints)
|
||||||
|
{
|
||||||
|
m_enforce_dns_checkpoints = enforce_checkpoints;
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ namespace cryptonote
|
||||||
uint64_t already_generated_coins;
|
uint64_t already_generated_coins;
|
||||||
};
|
};
|
||||||
|
|
||||||
blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), m_is_blockchain_storing(false)
|
blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), m_is_blockchain_storing(false), m_enforce_dns_checkpoints(false)
|
||||||
{};
|
{};
|
||||||
|
|
||||||
bool init() { return init(tools::get_default_data_dir(), true); }
|
bool init() { return init(tools::get_default_data_dir(), true); }
|
||||||
|
@ -180,7 +180,8 @@ namespace cryptonote
|
||||||
void print_blockchain(uint64_t start_index, uint64_t end_index);
|
void print_blockchain(uint64_t start_index, uint64_t end_index);
|
||||||
void print_blockchain_index();
|
void print_blockchain_index();
|
||||||
void print_blockchain_outs(const std::string& file);
|
void print_blockchain_outs(const std::string& file);
|
||||||
void update_checkpoints(const std::string& file_path);
|
bool update_checkpoints(const std::string& file_path);
|
||||||
|
void set_enforce_dns_checkpoints(bool enforce_checkpoints);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::unordered_map<crypto::hash, size_t> blocks_by_id_index;
|
typedef std::unordered_map<crypto::hash, size_t> blocks_by_id_index;
|
||||||
|
@ -215,6 +216,8 @@ namespace cryptonote
|
||||||
std::atomic<bool> m_is_in_checkpoint_zone;
|
std::atomic<bool> m_is_in_checkpoint_zone;
|
||||||
std::atomic<bool> m_is_blockchain_storing;
|
std::atomic<bool> m_is_blockchain_storing;
|
||||||
|
|
||||||
|
bool m_enforce_dns_checkpoints;
|
||||||
|
|
||||||
bool switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::iterator>& alt_chain, bool discard_disconnected_chain);
|
bool switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::iterator>& alt_chain, bool discard_disconnected_chain);
|
||||||
bool pop_block_from_blockchain();
|
bool pop_block_from_blockchain();
|
||||||
bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count);
|
bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count);
|
||||||
|
|
|
@ -29,6 +29,9 @@
|
||||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||||
|
|
||||||
#include "checkpoints_create.h"
|
#include "checkpoints_create.h"
|
||||||
|
#include "common/dns_utils.h"
|
||||||
|
#include "include_base_utils.h"
|
||||||
|
#include <sstream>
|
||||||
#include "storages/portable_storage_template_helper.h" // epee json include
|
#include "storages/portable_storage_template_helper.h" // epee json include
|
||||||
|
|
||||||
namespace cryptonote
|
namespace cryptonote
|
||||||
|
@ -107,4 +110,51 @@ bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::strin
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool load_checkpoints_from_dns(cryptonote::checkpoints& checkpoints, const std::string& url)
|
||||||
|
{
|
||||||
|
bool avail, valid;
|
||||||
|
auto records = tools::DNSResolver::instance().get_txt_record(url, avail, valid);
|
||||||
|
|
||||||
|
if (avail && !valid)
|
||||||
|
{
|
||||||
|
LOG_ERROR("DNSSEC present and failed validation for query to" << url);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& record : records)
|
||||||
|
{
|
||||||
|
auto pos = record.find(":");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
uint64_t height;
|
||||||
|
crypto::hash hash;
|
||||||
|
|
||||||
|
// parse the first part as uint64_t,
|
||||||
|
// if this fails move on to the next record
|
||||||
|
std::stringstream ss(record.substr(0, pos));
|
||||||
|
if (!(ss >> height))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the second part as crypto::hash,
|
||||||
|
// if this fails move on to the next record
|
||||||
|
std::string hashStr = record.substr(pos + 1);
|
||||||
|
if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADD_CHECKPOINT(height, hashStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load_new_checkpoints(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath)
|
||||||
|
{
|
||||||
|
// TODO: replace hard-coded url with const string or #define
|
||||||
|
return (load_checkpoints_from_json(checkpoints, json_hashfile_fullpath) && load_checkpoints_from_dns(checkpoints, "checkpoints.moneropulse.org"));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace cryptonote
|
} // namespace cryptonote
|
||||||
|
|
|
@ -42,5 +42,7 @@ namespace cryptonote
|
||||||
bool create_checkpoints(cryptonote::checkpoints& checkpoints);
|
bool create_checkpoints(cryptonote::checkpoints& checkpoints);
|
||||||
|
|
||||||
bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath);
|
bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath);
|
||||||
|
bool load_checkpoints_from_dns(cryptonote::checkpoints& checkpoints);
|
||||||
|
bool load_new_checkpoints(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath);
|
||||||
|
|
||||||
} // namespace cryptonote
|
} // namespace cryptonote
|
||||||
|
|
|
@ -54,7 +54,9 @@ namespace cryptonote
|
||||||
m_miner(this),
|
m_miner(this),
|
||||||
m_miner_address(boost::value_initialized<account_public_address>()),
|
m_miner_address(boost::value_initialized<account_public_address>()),
|
||||||
m_starter_message_showed(false),
|
m_starter_message_showed(false),
|
||||||
m_target_blockchain_height(0)
|
m_target_blockchain_height(0),
|
||||||
|
m_checkpoints_path(""),
|
||||||
|
m_last_checkpoints_update(0)
|
||||||
{
|
{
|
||||||
set_cryptonote_protocol(pprotocol);
|
set_cryptonote_protocol(pprotocol);
|
||||||
}
|
}
|
||||||
|
@ -69,21 +71,27 @@ namespace cryptonote
|
||||||
void core::set_checkpoints(checkpoints&& chk_pts)
|
void core::set_checkpoints(checkpoints&& chk_pts)
|
||||||
{
|
{
|
||||||
m_blockchain_storage.set_checkpoints(std::move(chk_pts));
|
m_blockchain_storage.set_checkpoints(std::move(chk_pts));
|
||||||
m_last_checkpoints_update = time(NULL);
|
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
void core::set_checkpoints_file_path(const std::string& path)
|
void core::set_checkpoints_file_path(const std::string& path)
|
||||||
{
|
{
|
||||||
m_checkpoints_path = path;
|
m_checkpoints_path = path;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
void core::update_checkpoints()
|
void core::set_enforce_dns_checkpoints(bool enforce_dns)
|
||||||
{
|
{
|
||||||
|
m_blockchain_storage.set_enforce_dns_checkpoints(enforce_dns);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------------
|
||||||
|
bool core::update_checkpoints()
|
||||||
|
{
|
||||||
|
bool res = true;
|
||||||
if (time(NULL) - m_last_checkpoints_update >= 3600)
|
if (time(NULL) - m_last_checkpoints_update >= 3600)
|
||||||
{
|
{
|
||||||
m_blockchain_storage.update_checkpoints(m_checkpoints_path);
|
res = m_blockchain_storage.update_checkpoints(m_checkpoints_path);
|
||||||
m_last_checkpoints_update = time(NULL);
|
m_last_checkpoints_update = time(NULL);
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
void core::init_options(boost::program_options::options_description& /*desc*/)
|
void core::init_options(boost::program_options::options_description& /*desc*/)
|
||||||
|
|
|
@ -95,6 +95,7 @@ namespace cryptonote
|
||||||
void set_cryptonote_protocol(i_cryptonote_protocol* pprotocol);
|
void set_cryptonote_protocol(i_cryptonote_protocol* pprotocol);
|
||||||
void set_checkpoints(checkpoints&& chk_pts);
|
void set_checkpoints(checkpoints&& chk_pts);
|
||||||
void set_checkpoints_file_path(const std::string& path);
|
void set_checkpoints_file_path(const std::string& path);
|
||||||
|
void set_enforce_dns_checkpoints(bool enforce_dns);
|
||||||
|
|
||||||
bool get_pool_transactions(std::list<transaction>& txs);
|
bool get_pool_transactions(std::list<transaction>& txs);
|
||||||
size_t get_pool_transactions_count();
|
size_t get_pool_transactions_count();
|
||||||
|
@ -122,9 +123,9 @@ namespace cryptonote
|
||||||
void set_target_blockchain_height(uint64_t target_blockchain_height);
|
void set_target_blockchain_height(uint64_t target_blockchain_height);
|
||||||
uint64_t get_target_blockchain_height() const;
|
uint64_t get_target_blockchain_height() const;
|
||||||
|
|
||||||
private:
|
bool update_checkpoints();
|
||||||
void update_checkpoints();
|
|
||||||
|
|
||||||
|
private:
|
||||||
bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block);
|
bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block);
|
||||||
bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block);
|
bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block);
|
||||||
bool add_new_block(const block& b, block_verification_context& bvc);
|
bool add_new_block(const block& b, block_verification_context& bvc);
|
||||||
|
|
|
@ -69,6 +69,7 @@ namespace
|
||||||
, "Run on testnet. The wallet must be launched with --testnet flag."
|
, "Run on testnet. The wallet must be launched with --testnet flag."
|
||||||
, false
|
, false
|
||||||
};
|
};
|
||||||
|
const command_line::arg_descriptor<bool> arg_dns_checkpoints = {"enforce-dns-checkpointing", "checkpoints from DNS server will be enforced", false};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool command_line_preprocessor(const boost::program_options::variables_map& vm)
|
bool command_line_preprocessor(const boost::program_options::variables_map& vm)
|
||||||
|
@ -135,6 +136,7 @@ int main(int argc, char* argv[])
|
||||||
command_line::add_arg(desc_cmd_sett, arg_log_level);
|
command_line::add_arg(desc_cmd_sett, arg_log_level);
|
||||||
command_line::add_arg(desc_cmd_sett, arg_console);
|
command_line::add_arg(desc_cmd_sett, arg_console);
|
||||||
command_line::add_arg(desc_cmd_sett, arg_testnet_on);
|
command_line::add_arg(desc_cmd_sett, arg_testnet_on);
|
||||||
|
command_line::add_arg(desc_cmd_sett, arg_dns_checkpoints);
|
||||||
|
|
||||||
cryptonote::core::init_options(desc_cmd_sett);
|
cryptonote::core::init_options(desc_cmd_sett);
|
||||||
cryptonote::core_rpc_server::init_options(desc_cmd_sett);
|
cryptonote::core_rpc_server::init_options(desc_cmd_sett);
|
||||||
|
@ -206,17 +208,21 @@ int main(int argc, char* argv[])
|
||||||
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints");
|
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints");
|
||||||
boost::filesystem::path json(JSON_HASH_FILE_NAME);
|
boost::filesystem::path json(JSON_HASH_FILE_NAME);
|
||||||
boost::filesystem::path checkpoint_json_hashfile_fullpath = data_dir / json;
|
boost::filesystem::path checkpoint_json_hashfile_fullpath = data_dir / json;
|
||||||
res = cryptonote::load_checkpoints_from_json(checkpoints, checkpoint_json_hashfile_fullpath.string().c_str());
|
|
||||||
CHECK_AND_ASSERT_MES(res, 1, "Failed to load initial checkpoints");
|
|
||||||
|
|
||||||
//create objects and link them
|
//create objects and link them
|
||||||
cryptonote::core ccore(NULL);
|
cryptonote::core ccore(NULL);
|
||||||
|
|
||||||
|
// tell core if we're enforcing dns checkpoints
|
||||||
|
bool enforce_dns = command_line::get_arg(vm, arg_dns_checkpoints);
|
||||||
|
ccore.set_enforce_dns_checkpoints(enforce_dns);
|
||||||
|
|
||||||
if (testnet_mode) {
|
if (testnet_mode) {
|
||||||
LOG_PRINT_L0("Starting in testnet mode!");
|
LOG_PRINT_L0("Starting in testnet mode!");
|
||||||
} else {
|
} else {
|
||||||
ccore.set_checkpoints(std::move(checkpoints));
|
ccore.set_checkpoints(std::move(checkpoints));
|
||||||
ccore.set_checkpoints_file_path(checkpoint_json_hashfile_fullpath.string());
|
ccore.set_checkpoints_file_path(checkpoint_json_hashfile_fullpath.string());
|
||||||
|
res = ccore.update_checkpoints();
|
||||||
|
CHECK_AND_ASSERT_MES(res, 1, "Failed to load initial checkpoints");
|
||||||
}
|
}
|
||||||
|
|
||||||
cryptonote::t_cryptonote_protocol_handler<cryptonote::core> cprotocol(ccore, NULL);
|
cryptonote::t_cryptonote_protocol_handler<cryptonote::core> cprotocol(ccore, NULL);
|
||||||
|
|
Loading…
Reference in a new issue