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
|
@ -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)
|
||||
{
|
||||
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
|
||||
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);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
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 not, probably fetch from DNS TXT Records.
|
||||
if (file_path.size() > 0)
|
||||
if (!cryptonote::load_new_checkpoints(m_checkpoints, file_path))
|
||||
{
|
||||
cryptonote::load_checkpoints_from_json(m_checkpoints, file_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
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)))
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
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); }
|
||||
|
@ -180,7 +180,8 @@ namespace cryptonote
|
|||
void print_blockchain(uint64_t start_index, uint64_t end_index);
|
||||
void print_blockchain_index();
|
||||
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:
|
||||
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_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 pop_block_from_blockchain();
|
||||
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
|
||||
|
||||
#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
|
||||
|
||||
namespace cryptonote
|
||||
|
@ -107,4 +110,51 @@ bool load_checkpoints_from_json(cryptonote::checkpoints& checkpoints, std::strin
|
|||
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
|
||||
|
|
|
@ -42,5 +42,7 @@ namespace cryptonote
|
|||
bool create_checkpoints(cryptonote::checkpoints& checkpoints);
|
||||
|
||||
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
|
||||
|
|
|
@ -54,7 +54,9 @@ namespace cryptonote
|
|||
m_miner(this),
|
||||
m_miner_address(boost::value_initialized<account_public_address>()),
|
||||
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);
|
||||
}
|
||||
|
@ -69,21 +71,27 @@ namespace cryptonote
|
|||
void core::set_checkpoints(checkpoints&& 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
m_blockchain_storage.update_checkpoints(m_checkpoints_path);
|
||||
res = m_blockchain_storage.update_checkpoints(m_checkpoints_path);
|
||||
m_last_checkpoints_update = time(NULL);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
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_checkpoints(checkpoints&& chk_pts);
|
||||
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);
|
||||
size_t get_pool_transactions_count();
|
||||
|
@ -122,9 +123,9 @@ namespace cryptonote
|
|||
void set_target_blockchain_height(uint64_t target_blockchain_height);
|
||||
uint64_t get_target_blockchain_height() const;
|
||||
|
||||
private:
|
||||
void update_checkpoints();
|
||||
bool 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, tx_verification_context& tvc, bool keeped_by_block);
|
||||
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."
|
||||
, 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)
|
||||
|
@ -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_console);
|
||||
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_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");
|
||||
boost::filesystem::path json(JSON_HASH_FILE_NAME);
|
||||
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
|
||||
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) {
|
||||
LOG_PRINT_L0("Starting in testnet mode!");
|
||||
} else {
|
||||
ccore.set_checkpoints(std::move(checkpoints));
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue