aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Winget <tewinget@gmail.com>2014-09-26 01:01:58 -0400
committerThomas Winget <tewinget@gmail.com>2014-09-30 16:21:37 -0400
commitb261d9207ba5cdc0334fab403204971f79b6ca03 (patch)
treeb113fc0deb913b3e27be1d33f60daa62a52462b4
parentreload checkpoints file every ~hr and print if any fail (diff)
downloadmonero-b261d9207ba5cdc0334fab403204971f79b6ca03.tar.xz
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"
-rw-r--r--src/cryptonote_core/blockchain_storage.cpp32
-rw-r--r--src/cryptonote_core/blockchain_storage.h7
-rw-r--r--src/cryptonote_core/checkpoints_create.cpp50
-rw-r--r--src/cryptonote_core/checkpoints_create.h2
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp16
-rw-r--r--src/cryptonote_core/cryptonote_core.h5
-rw-r--r--src/daemon/daemon.cpp10
7 files changed, 106 insertions, 16 deletions
diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp
index 90820232c..5dfda08ba 100644
--- a/src/cryptonote_core/blockchain_storage.cpp
+++ b/src/cryptonote_core/blockchain_storage.cpp
@@ -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;
}
diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h
index b89db1825..1ab49a7bc 100644
--- a/src/cryptonote_core/blockchain_storage.h
+++ b/src/cryptonote_core/blockchain_storage.h
@@ -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);
diff --git a/src/cryptonote_core/checkpoints_create.cpp b/src/cryptonote_core/checkpoints_create.cpp
index ff927396e..b81353539 100644
--- a/src/cryptonote_core/checkpoints_create.cpp
+++ b/src/cryptonote_core/checkpoints_create.cpp
@@ -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
diff --git a/src/cryptonote_core/checkpoints_create.h b/src/cryptonote_core/checkpoints_create.h
index 8e7a58228..92a970e9f 100644
--- a/src/cryptonote_core/checkpoints_create.h
+++ b/src/cryptonote_core/checkpoints_create.h
@@ -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
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 7586421b3..1dbc7bf52 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -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::set_enforce_dns_checkpoints(bool enforce_dns)
+ {
+ m_blockchain_storage.set_enforce_dns_checkpoints(enforce_dns);
+ }
//-----------------------------------------------------------------------------------------------
- void core::update_checkpoints()
+ 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*/)
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 81eddc657..b3bfddff3 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -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);
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index 5e4e9c266..8e915fb1d 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -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);