daemon: guard against rare 'difficulty drift' bug with checkpoints and recalculation
On startup, it checks against the difficulty checkpoints, and if any mismatch is found, recalculates all the blocks with wrong difficulties. Additionally, once a week it recalculates difficulties of blocks after the last difficulty checkpoint.
This commit is contained in:
parent
ff4d470629
commit
7bd66b01bf
|
@ -1038,6 +1038,16 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual difficulty_type get_block_difficulty(const uint64_t& height) const = 0;
|
virtual difficulty_type get_block_difficulty(const uint64_t& height) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief correct blocks cumulative difficulties that were incorrectly calculated due to the 'difficulty drift' bug
|
||||||
|
*
|
||||||
|
* If the block does not exist, the subclass should throw BLOCK_DNE
|
||||||
|
*
|
||||||
|
* @param start_height the height where the drift starts
|
||||||
|
* @param new_cumulative_difficulties new cumulative difficulties to be stored
|
||||||
|
*/
|
||||||
|
virtual void correct_block_cumulative_difficulties(const uint64_t& start_height, const std::vector<difficulty_type>& new_cumulative_difficulties) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief fetch a block's already generated coins
|
* @brief fetch a block's already generated coins
|
||||||
*
|
*
|
||||||
|
|
|
@ -2750,6 +2750,44 @@ difficulty_type BlockchainLMDB::get_block_difficulty(const uint64_t& height) con
|
||||||
return diff1 - diff2;
|
return diff1 - diff2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlockchainLMDB::correct_block_cumulative_difficulties(const uint64_t& start_height, const std::vector<difficulty_type>& new_cumulative_difficulties)
|
||||||
|
{
|
||||||
|
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||||
|
check_open();
|
||||||
|
mdb_txn_cursors *m_cursors = &m_wcursors;
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
block_wtxn_start();
|
||||||
|
CURSOR(block_info)
|
||||||
|
|
||||||
|
const uint64_t bc_height = height();
|
||||||
|
if (start_height + new_cumulative_difficulties.size() != bc_height)
|
||||||
|
{
|
||||||
|
block_wtxn_abort();
|
||||||
|
throw0(DB_ERROR("Incorrect new_cumulative_difficulties size"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint64_t height = start_height; height < bc_height; ++height)
|
||||||
|
{
|
||||||
|
MDB_val_set(key, height);
|
||||||
|
result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &key, MDB_GET_BOTH);
|
||||||
|
if (result)
|
||||||
|
throw1(BLOCK_DNE(lmdb_error("Failed to get block info: ", result).c_str()));
|
||||||
|
|
||||||
|
mdb_block_info bi = *(mdb_block_info*)key.mv_data;
|
||||||
|
const difficulty_type d = new_cumulative_difficulties[height - start_height];
|
||||||
|
bi.bi_diff_hi = ((d >> 64) & 0xffffffffffffffff).convert_to<uint64_t>();
|
||||||
|
bi.bi_diff_lo = (d & 0xffffffffffffffff).convert_to<uint64_t>();
|
||||||
|
|
||||||
|
MDB_val_set(key2, height);
|
||||||
|
MDB_val_set(val, bi);
|
||||||
|
result = mdb_cursor_put(m_cur_block_info, &key2, &val, MDB_CURRENT);
|
||||||
|
if (result)
|
||||||
|
throw0(DB_ERROR(lmdb_error("Failed to overwrite block info to db transaction: ", result).c_str()));
|
||||||
|
}
|
||||||
|
block_wtxn_stop();
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t BlockchainLMDB::get_block_already_generated_coins(const uint64_t& height) const
|
uint64_t BlockchainLMDB::get_block_already_generated_coins(const uint64_t& height) const
|
||||||
{
|
{
|
||||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||||
|
|
|
@ -229,6 +229,8 @@ public:
|
||||||
|
|
||||||
virtual difficulty_type get_block_difficulty(const uint64_t& height) const;
|
virtual difficulty_type get_block_difficulty(const uint64_t& height) const;
|
||||||
|
|
||||||
|
virtual void correct_block_cumulative_difficulties(const uint64_t& start_height, const std::vector<difficulty_type>& new_cumulative_difficulties);
|
||||||
|
|
||||||
virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const;
|
virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const;
|
||||||
|
|
||||||
virtual uint64_t get_block_long_term_weight(const uint64_t& height) const;
|
virtual uint64_t get_block_long_term_weight(const uint64_t& height) const;
|
||||||
|
|
|
@ -82,6 +82,7 @@ public:
|
||||||
virtual std::vector<uint64_t> get_block_weights(uint64_t start_height, size_t count) const override { return {}; }
|
virtual std::vector<uint64_t> get_block_weights(uint64_t start_height, size_t count) const override { return {}; }
|
||||||
virtual cryptonote::difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const override { return 10; }
|
virtual cryptonote::difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const override { return 10; }
|
||||||
virtual cryptonote::difficulty_type get_block_difficulty(const uint64_t& height) const override { return 0; }
|
virtual cryptonote::difficulty_type get_block_difficulty(const uint64_t& height) const override { return 0; }
|
||||||
|
virtual void correct_block_cumulative_difficulties(const uint64_t& start_height, const std::vector<difficulty_type>& new_cumulative_difficulties) override {}
|
||||||
virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const override { return 10000000000; }
|
virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const override { return 10000000000; }
|
||||||
virtual uint64_t get_block_long_term_weight(const uint64_t& height) const override { return 128; }
|
virtual uint64_t get_block_long_term_weight(const uint64_t& height) const override { return 128; }
|
||||||
virtual std::vector<uint64_t> get_long_term_block_weights(uint64_t start_height, size_t count) const override { return {}; }
|
virtual std::vector<uint64_t> get_long_term_block_weights(uint64_t start_height, size_t count) const override { return {}; }
|
||||||
|
|
|
@ -72,7 +72,7 @@ namespace cryptonote
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str)
|
bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str, const std::string& difficulty_str)
|
||||||
{
|
{
|
||||||
crypto::hash h = crypto::null_hash;
|
crypto::hash h = crypto::null_hash;
|
||||||
bool r = epee::string_tools::hex_to_pod(hash_str, h);
|
bool r = epee::string_tools::hex_to_pod(hash_str, h);
|
||||||
|
@ -84,6 +84,23 @@ namespace cryptonote
|
||||||
CHECK_AND_ASSERT_MES(h == m_points[height], false, "Checkpoint at given height already exists, and hash for new checkpoint was different!");
|
CHECK_AND_ASSERT_MES(h == m_points[height], false, "Checkpoint at given height already exists, and hash for new checkpoint was different!");
|
||||||
}
|
}
|
||||||
m_points[height] = h;
|
m_points[height] = h;
|
||||||
|
if (!difficulty_str.empty())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
difficulty_type difficulty(difficulty_str);
|
||||||
|
if (m_difficulty_points.count(height))
|
||||||
|
{
|
||||||
|
CHECK_AND_ASSERT_MES(difficulty == m_difficulty_points[height], false, "Difficulty checkpoint at given height already exists, and difficulty for new checkpoint was different!");
|
||||||
|
}
|
||||||
|
m_difficulty_points[height] = difficulty;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Failed to parse difficulty checkpoint: " << difficulty_str);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -143,6 +160,11 @@ namespace cryptonote
|
||||||
{
|
{
|
||||||
return m_points;
|
return m_points;
|
||||||
}
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
const std::map<uint64_t, difficulty_type>& checkpoints::get_difficulty_points() const
|
||||||
|
{
|
||||||
|
return m_difficulty_points;
|
||||||
|
}
|
||||||
|
|
||||||
bool checkpoints::check_for_conflicts(const checkpoints& other) const
|
bool checkpoints::check_for_conflicts(const checkpoints& other) const
|
||||||
{
|
{
|
||||||
|
@ -160,58 +182,60 @@ namespace cryptonote
|
||||||
{
|
{
|
||||||
if (nettype == TESTNET)
|
if (nettype == TESTNET)
|
||||||
{
|
{
|
||||||
ADD_CHECKPOINT(0, "48ca7cd3c8de5b6a4d53d2861fbdaedca141553559f9be9520068053cda8430b");
|
ADD_CHECKPOINT2(0, "48ca7cd3c8de5b6a4d53d2861fbdaedca141553559f9be9520068053cda8430b", "0x1");
|
||||||
ADD_CHECKPOINT(1000000, "46b690b710a07ea051bc4a6b6842ac37be691089c0f7758cfeec4d5fc0b4a258");
|
ADD_CHECKPOINT2(1000000, "46b690b710a07ea051bc4a6b6842ac37be691089c0f7758cfeec4d5fc0b4a258", "0x7aaad7153");
|
||||||
ADD_CHECKPOINT(1058600, "12904f6b4d9e60fd875674e07147d2c83d6716253f046af7b894c3e81da7e1bd");
|
ADD_CHECKPOINT2(1058600, "12904f6b4d9e60fd875674e07147d2c83d6716253f046af7b894c3e81da7e1bd", "0x971efd119");
|
||||||
|
ADD_CHECKPOINT2(1450000, "87562ca6786f41556b8d5b48067303a57dc5ca77155b35199aedaeca1550f5a0", "0xa639e2930e");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (nettype == STAGENET)
|
if (nettype == STAGENET)
|
||||||
{
|
{
|
||||||
ADD_CHECKPOINT(0, "76ee3cc98646292206cd3e86f74d88b4dcc1d937088645e9b0cbca84b7ce74eb");
|
ADD_CHECKPOINT2(0, "76ee3cc98646292206cd3e86f74d88b4dcc1d937088645e9b0cbca84b7ce74eb", "0x1");
|
||||||
ADD_CHECKPOINT(10000, "1f8b0ce313f8b9ba9a46108bfd285c45ad7c2176871fd41c3a690d4830ce2fd5");
|
ADD_CHECKPOINT2(10000, "1f8b0ce313f8b9ba9a46108bfd285c45ad7c2176871fd41c3a690d4830ce2fd5", "0x1d73ba");
|
||||||
|
ADD_CHECKPOINT2(550000, "409f68cddd8e74b37469b41c1e61250d81c5776b42264f416d5d27c4626383ed", "0x5f3d4d03e");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148");
|
ADD_CHECKPOINT2(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148", "0x2");
|
||||||
ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381");
|
ADD_CHECKPOINT2(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381", "0x2a974");
|
||||||
ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d");
|
ADD_CHECKPOINT2(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d", "0x35d14b");
|
||||||
ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876");
|
ADD_CHECKPOINT2(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876", "0x36a0373");
|
||||||
ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2");
|
ADD_CHECKPOINT2(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2", "0x60a91390");
|
||||||
ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25");
|
ADD_CHECKPOINT2(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25", "0x1e288793d");
|
||||||
ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6");
|
ADD_CHECKPOINT2(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6", "0x71f64cce8");
|
||||||
ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c");
|
ADD_CHECKPOINT2(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c", "0x893044b400");
|
||||||
ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3");
|
ADD_CHECKPOINT2(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3", "0x5cc113f1076");
|
||||||
ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698");
|
ADD_CHECKPOINT2(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698", "0x73310a259eb2");
|
||||||
ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2");
|
ADD_CHECKPOINT2(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2", "0x733154039b97");
|
||||||
ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb");
|
ADD_CHECKPOINT2(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb", "0x73319dc90cb6");
|
||||||
ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063");
|
ADD_CHECKPOINT2(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063", "0x75fcc3d85123");
|
||||||
ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553");
|
ADD_CHECKPOINT2(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553", "0x89cfed0cae3c");
|
||||||
ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61");
|
ADD_CHECKPOINT2(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61", "0x967d13e5baa9");
|
||||||
ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf");
|
ADD_CHECKPOINT2(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf", "0x96fb9663ebe7");
|
||||||
ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131");
|
ADD_CHECKPOINT2(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131", "0x97b9919177bf");
|
||||||
ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8");
|
ADD_CHECKPOINT2(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8", "0x98a038b612e8");
|
||||||
ADD_CHECKPOINT(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d");
|
ADD_CHECKPOINT2(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d", "0xac9739634e6d");
|
||||||
ADD_CHECKPOINT(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831");
|
ADD_CHECKPOINT2(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831", "0x167799549bdda");
|
||||||
ADD_CHECKPOINT(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02");
|
ADD_CHECKPOINT2(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02", "0x188ce145e4ba9");
|
||||||
ADD_CHECKPOINT(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5");
|
ADD_CHECKPOINT2(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5", "0x1d9f3759e1554");
|
||||||
ADD_CHECKPOINT(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd");
|
ADD_CHECKPOINT2(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd", "0x2201e4ee39c2c");
|
||||||
ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60");
|
ADD_CHECKPOINT2(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60", "0x27565a442d5df");
|
||||||
ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337");
|
ADD_CHECKPOINT2(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337", "0x2a6334031546e");
|
||||||
ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f");
|
ADD_CHECKPOINT2(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f", "0x2aefe7f40f5ea");
|
||||||
ADD_CHECKPOINT(1000000, "a886ef5149902d8342475fee9bb296341b891ac67c4842f47a833f23c00ed721");
|
ADD_CHECKPOINT2(1000000, "a886ef5149902d8342475fee9bb296341b891ac67c4842f47a833f23c00ed721", "0x2edd71370f0e5");
|
||||||
ADD_CHECKPOINT(1100000, "3fd720c5c8b3072fc1ccda922dec1ef25f9ed88a1e6ad4103d0fe00b180a5903");
|
ADD_CHECKPOINT2(1100000, "3fd720c5c8b3072fc1ccda922dec1ef25f9ed88a1e6ad4103d0fe00b180a5903", "0x390eb0035c53a");
|
||||||
ADD_CHECKPOINT(1150000, "1dd16f626d18e1e988490dfd06de5920e22629c972c58b4d8daddea0038627b2");
|
ADD_CHECKPOINT2(1150000, "1dd16f626d18e1e988490dfd06de5920e22629c972c58b4d8daddea0038627b2", "0x422d5662e9e37");
|
||||||
ADD_CHECKPOINT(1200000, "fa7d13a90850882060479d100141ff84286599ae39c3277c8ea784393f882d1f");
|
ADD_CHECKPOINT2(1200000, "fa7d13a90850882060479d100141ff84286599ae39c3277c8ea784393f882d1f", "0x4c73503fc4aa3");
|
||||||
ADD_CHECKPOINT(1300000, "31b34272343a44a9f4ac7de7a8fcf3b7d8a3124d7d6870affd510d2f37e74cd0");
|
ADD_CHECKPOINT2(1300000, "31b34272343a44a9f4ac7de7a8fcf3b7d8a3124d7d6870affd510d2f37e74cd0", "0x723f49bc249d5");
|
||||||
ADD_CHECKPOINT(1390000, "a8f5649dd4ded60eedab475f2bec8c934681c07e3cf640e9be0617554f13ff6c");
|
ADD_CHECKPOINT2(1390000, "a8f5649dd4ded60eedab475f2bec8c934681c07e3cf640e9be0617554f13ff6c", "0xb4bba65e2841b");
|
||||||
ADD_CHECKPOINT(1450000, "ac94e8860093bc7c83e4e91215cba1d663421ecf4067a0ae609c3a8b52bcfac2");
|
ADD_CHECKPOINT2(1450000, "ac94e8860093bc7c83e4e91215cba1d663421ecf4067a0ae609c3a8b52bcfac2", "0x11a4aabdca9511");
|
||||||
ADD_CHECKPOINT(1530000, "01759bce497ec38e63c78b1038892169203bb78f87e488172f6b854fcd63ba7e");
|
ADD_CHECKPOINT2(1530000, "01759bce497ec38e63c78b1038892169203bb78f87e488172f6b854fcd63ba7e", "0x2819ce9f9e91e5");
|
||||||
ADD_CHECKPOINT(1579000, "7d0d7a2346373afd41ed1e744a939fc5d474a7dbaa257be5c6fff4009e789241");
|
ADD_CHECKPOINT2(1579000, "7d0d7a2346373afd41ed1e744a939fc5d474a7dbaa257be5c6fff4009e789241", "0x357a590e7dda83");
|
||||||
ADD_CHECKPOINT(1668900, "ac2dcaf3d2f58ffcf8391639f0f1ebafcb8eac43c49479c7c37f611868d07568");
|
ADD_CHECKPOINT2(1668900, "ac2dcaf3d2f58ffcf8391639f0f1ebafcb8eac43c49479c7c37f611868d07568", "0x474226e475cc3b");
|
||||||
ADD_CHECKPOINT(1775600, "1c6e01c661dc22cab939e79ec6a5272190624ce8356d2f7b958e4f9a57fdb05e");
|
ADD_CHECKPOINT2(1775600, "1c6e01c661dc22cab939e79ec6a5272190624ce8356d2f7b958e4f9a57fdb05e", "0x5e3b9d206a27c6");
|
||||||
ADD_CHECKPOINT(1856000, "9b57f17f29c71a3acd8a7904b93c41fa6eb8d2b7c73936ce4f1702d14880ba29");
|
ADD_CHECKPOINT2(1856000, "9b57f17f29c71a3acd8a7904b93c41fa6eb8d2b7c73936ce4f1702d14880ba29", "0x6bde5e1caccee1");
|
||||||
ADD_CHECKPOINT(1958000, "98a5d6e51afdf3146e0eefb10a66e8648d8d4d5c2742be8835e976ba217c9bb2");
|
ADD_CHECKPOINT2(1958000, "98a5d6e51afdf3146e0eefb10a66e8648d8d4d5c2742be8835e976ba217c9bb2", "0x79dd46d2a0971a");
|
||||||
ADD_CHECKPOINT(2046000, "5e867f0b8baefed9244a681df97fc885d8ab36c3dfcd24c7a3abf3b8ac8b8314");
|
ADD_CHECKPOINT2(2046000, "5e867f0b8baefed9244a681df97fc885d8ab36c3dfcd24c7a3abf3b8ac8b8314", "0x9cb8b6ff2978c6");
|
||||||
ADD_CHECKPOINT(2092500, "c4e00820c9c7989b49153d5e90ae095a18a11d990e82fcc3be54e6ed785472b5");
|
ADD_CHECKPOINT2(2092500, "c4e00820c9c7989b49153d5e90ae095a18a11d990e82fcc3be54e6ed785472b5", "0xb4e585a31369cb");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,10 @@
|
||||||
#include "misc_log_ex.h"
|
#include "misc_log_ex.h"
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
#include "cryptonote_config.h"
|
#include "cryptonote_config.h"
|
||||||
|
#include "cryptonote_basic/difficulty.h"
|
||||||
|
|
||||||
#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false);
|
#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false);
|
||||||
|
#define ADD_CHECKPOINT2(h, hash, difficulty) CHECK_AND_ASSERT(add_checkpoint(h, hash, difficulty), false);
|
||||||
#define JSON_HASH_FILE_NAME "checkpoints.json"
|
#define JSON_HASH_FILE_NAME "checkpoints.json"
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,12 +63,13 @@ namespace cryptonote
|
||||||
*
|
*
|
||||||
* @param height the height of the block the checkpoint is for
|
* @param height the height of the block the checkpoint is for
|
||||||
* @param hash_str the hash of the block, as a string
|
* @param hash_str the hash of the block, as a string
|
||||||
|
* @param difficulty_str the cumulative difficulty of the block, as a string (optional)
|
||||||
*
|
*
|
||||||
* @return false if parsing the hash fails, or if the height is a duplicate
|
* @return false if parsing the hash fails, or if the height is a duplicate
|
||||||
* AND the existing checkpoint hash does not match the new one,
|
* AND the existing checkpoint hash does not match the new one,
|
||||||
* otherwise returns true
|
* otherwise returns true
|
||||||
*/
|
*/
|
||||||
bool add_checkpoint(uint64_t height, const std::string& hash_str);
|
bool add_checkpoint(uint64_t height, const std::string& hash_str, const std::string& difficulty_str = "");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief checks if there is a checkpoint in the future
|
* @brief checks if there is a checkpoint in the future
|
||||||
|
@ -133,6 +136,13 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
const std::map<uint64_t, crypto::hash>& get_points() const;
|
const std::map<uint64_t, crypto::hash>& get_points() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief gets the difficulty checkpoints container
|
||||||
|
*
|
||||||
|
* @return a const reference to the difficulty checkpoints container
|
||||||
|
*/
|
||||||
|
const std::map<uint64_t, difficulty_type>& get_difficulty_points() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief checks if our checkpoints container conflicts with another
|
* @brief checks if our checkpoints container conflicts with another
|
||||||
*
|
*
|
||||||
|
@ -187,6 +197,7 @@ namespace cryptonote
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<uint64_t, crypto::hash> m_points; //!< the checkpoints container
|
std::map<uint64_t, crypto::hash> m_points; //!< the checkpoints container
|
||||||
|
std::map<uint64_t, difficulty_type> m_difficulty_points; //!< the difficulty checkpoints container
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/range/adaptor/reversed.hpp>
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
#include "include_base_utils.h"
|
#include "include_base_utils.h"
|
||||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||||
|
@ -439,6 +440,15 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
|
||||||
m_long_term_block_weights_cache_rolling_median = epee::misc_utils::rolling_median_t<uint64_t>(m_long_term_block_weights_window);
|
m_long_term_block_weights_cache_rolling_median = epee::misc_utils::rolling_median_t<uint64_t>(m_long_term_block_weights_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool difficulty_ok;
|
||||||
|
uint64_t difficulty_recalc_height;
|
||||||
|
std::tie(difficulty_ok, difficulty_recalc_height) = check_difficulty_checkpoints();
|
||||||
|
if (!difficulty_ok)
|
||||||
|
{
|
||||||
|
MERROR("Difficulty drift detected!");
|
||||||
|
recalculate_difficulties(difficulty_recalc_height);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
db_txn_guard txn_guard(m_db, m_db->is_read_only());
|
db_txn_guard txn_guard(m_db, m_db->is_read_only());
|
||||||
if (!update_next_cumulative_weight_limit())
|
if (!update_next_cumulative_weight_limit())
|
||||||
|
@ -888,6 +898,111 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
std::pair<bool, uint64_t> Blockchain::check_difficulty_checkpoints() const
|
||||||
|
{
|
||||||
|
uint64_t res = 0;
|
||||||
|
for (const std::pair<uint64_t, difficulty_type>& i : m_checkpoints.get_difficulty_points())
|
||||||
|
{
|
||||||
|
if (i.first >= m_db->height())
|
||||||
|
break;
|
||||||
|
if (m_db->get_block_cumulative_difficulty(i.first) != i.second)
|
||||||
|
return {false, res};
|
||||||
|
res = i.first;
|
||||||
|
}
|
||||||
|
return {true, res};
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
size_t Blockchain::recalculate_difficulties(boost::optional<uint64_t> start_height_opt)
|
||||||
|
{
|
||||||
|
if (m_fixed_difficulty)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||||
|
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||||
|
|
||||||
|
const uint64_t start_height = start_height_opt ? *start_height_opt : check_difficulty_checkpoints().second;
|
||||||
|
const uint64_t top_height = m_db->height() - 1;
|
||||||
|
MGINFO("Recalculating difficulties from height " << start_height << " to height " << top_height);
|
||||||
|
|
||||||
|
std::vector<uint64_t> timestamps;
|
||||||
|
std::vector<difficulty_type> difficulties;
|
||||||
|
timestamps.reserve(DIFFICULTY_BLOCKS_COUNT + 1);
|
||||||
|
difficulties.reserve(DIFFICULTY_BLOCKS_COUNT + 1);
|
||||||
|
if (start_height > 1)
|
||||||
|
{
|
||||||
|
for (uint64_t i = 0; i < DIFFICULTY_BLOCKS_COUNT; ++i)
|
||||||
|
{
|
||||||
|
uint64_t height = start_height - 1 - i;
|
||||||
|
if (height == 0)
|
||||||
|
break;
|
||||||
|
timestamps.insert(timestamps.begin(), m_db->get_block_timestamp(height));
|
||||||
|
difficulties.insert(difficulties.begin(), m_db->get_block_cumulative_difficulty(height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
difficulty_type last_cum_diff = start_height <= 1 ? start_height : difficulties.back();
|
||||||
|
uint64_t drift_start_height = 0;
|
||||||
|
std::vector<difficulty_type> new_cumulative_difficulties;
|
||||||
|
for (uint64_t height = start_height; height <= top_height; ++height)
|
||||||
|
{
|
||||||
|
size_t target = get_ideal_hard_fork_version(height) < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
|
||||||
|
difficulty_type recalculated_diff = next_difficulty(timestamps, difficulties, target);
|
||||||
|
|
||||||
|
boost::multiprecision::uint256_t recalculated_cum_diff_256 = boost::multiprecision::uint256_t(recalculated_diff) + last_cum_diff;
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(recalculated_cum_diff_256 <= std::numeric_limits<difficulty_type>::max(), "Difficulty overflow!");
|
||||||
|
difficulty_type recalculated_cum_diff = recalculated_cum_diff_256.convert_to<difficulty_type>();
|
||||||
|
|
||||||
|
if (drift_start_height == 0)
|
||||||
|
{
|
||||||
|
difficulty_type existing_cum_diff = m_db->get_block_cumulative_difficulty(height);
|
||||||
|
if (recalculated_cum_diff != existing_cum_diff)
|
||||||
|
{
|
||||||
|
drift_start_height = height;
|
||||||
|
new_cumulative_difficulties.reserve(top_height + 1 - height);
|
||||||
|
LOG_ERROR("Difficulty drift found at height:" << height << ", hash:" << m_db->get_block_hash_from_height(height) << ", existing:" << existing_cum_diff << ", recalculated:" << recalculated_cum_diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (drift_start_height > 0)
|
||||||
|
{
|
||||||
|
new_cumulative_difficulties.push_back(recalculated_cum_diff);
|
||||||
|
if (height % 100000 == 0)
|
||||||
|
LOG_ERROR(boost::format("%llu / %llu (%.1f%%)") % height % top_height % (100 * (height - drift_start_height) / float(top_height - drift_start_height)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height > 0)
|
||||||
|
{
|
||||||
|
timestamps.push_back(m_db->get_block_timestamp(height));
|
||||||
|
difficulties.push_back(recalculated_cum_diff);
|
||||||
|
}
|
||||||
|
if (timestamps.size() > DIFFICULTY_BLOCKS_COUNT)
|
||||||
|
{
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(timestamps.size() == DIFFICULTY_BLOCKS_COUNT + 1, "Wrong timestamps size: " << timestamps.size());
|
||||||
|
timestamps.erase(timestamps.begin());
|
||||||
|
difficulties.erase(difficulties.begin());
|
||||||
|
}
|
||||||
|
last_cum_diff = recalculated_cum_diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drift_start_height > 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Writing to the DB...");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_db->correct_block_cumulative_difficulties(drift_start_height, new_cumulative_difficulties);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Error correcting cumulative difficulties from height " << drift_start_height << ", what = " << e.what());
|
||||||
|
}
|
||||||
|
LOG_ERROR("Corrected difficulties for " << new_cumulative_difficulties.size() << " blocks");
|
||||||
|
// clear cache
|
||||||
|
m_difficulty_for_next_block_top_hash = crypto::null_hash;
|
||||||
|
m_timestamps_and_difficulties_height = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_cumulative_difficulties.size();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------
|
||||||
std::vector<time_t> Blockchain::get_last_block_timestamps(unsigned int blocks) const
|
std::vector<time_t> Blockchain::get_last_block_timestamps(unsigned int blocks) const
|
||||||
{
|
{
|
||||||
uint64_t height = m_db->height();
|
uint64_t height = m_db->height();
|
||||||
|
|
|
@ -309,6 +309,22 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
difficulty_type get_difficulty_for_next_block();
|
difficulty_type get_difficulty_for_next_block();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief check currently stored difficulties against difficulty checkpoints
|
||||||
|
*
|
||||||
|
* @return {flag, height} flag: true if all difficulty checkpoints pass, height: the last checkpoint height before the difficulty drift bug starts
|
||||||
|
*/
|
||||||
|
std::pair<bool, uint64_t> check_difficulty_checkpoints() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief recalculate difficulties for blocks after the last difficulty checkpoints to circumvent the annoying 'difficulty drift' bug
|
||||||
|
*
|
||||||
|
* @param start_height: if omitted, starts recalculation from the last difficulty checkpoint
|
||||||
|
*
|
||||||
|
* @return number of blocks whose difficulties got corrected
|
||||||
|
*/
|
||||||
|
size_t recalculate_difficulties(boost::optional<uint64_t> start_height = boost::none);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief adds a block to the blockchain
|
* @brief adds a block to the blockchain
|
||||||
*
|
*
|
||||||
|
|
|
@ -1662,6 +1662,7 @@ namespace cryptonote
|
||||||
m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this));
|
m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this));
|
||||||
m_block_rate_interval.do_call(boost::bind(&core::check_block_rate, this));
|
m_block_rate_interval.do_call(boost::bind(&core::check_block_rate, this));
|
||||||
m_blockchain_pruning_interval.do_call(boost::bind(&core::update_blockchain_pruning, this));
|
m_blockchain_pruning_interval.do_call(boost::bind(&core::update_blockchain_pruning, this));
|
||||||
|
m_diff_recalc_interval.do_call(boost::bind(&core::recalculate_difficulties, this));
|
||||||
m_miner.on_idle();
|
m_miner.on_idle();
|
||||||
m_mempool.on_idle();
|
m_mempool.on_idle();
|
||||||
return true;
|
return true;
|
||||||
|
@ -1923,6 +1924,12 @@ namespace cryptonote
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------------
|
||||||
|
bool core::recalculate_difficulties()
|
||||||
|
{
|
||||||
|
m_blockchain_storage.recalculate_difficulties();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------------
|
||||||
void core::flush_bad_txs_cache()
|
void core::flush_bad_txs_cache()
|
||||||
{
|
{
|
||||||
bad_semantics_txes_lock.lock();
|
bad_semantics_txes_lock.lock();
|
||||||
|
|
|
@ -1040,6 +1040,13 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
bool check_block_rate();
|
bool check_block_rate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief recalculate difficulties after the last difficulty checklpoint to circumvent the annoying 'difficulty drift' bug
|
||||||
|
*
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
bool recalculate_difficulties();
|
||||||
|
|
||||||
bool m_test_drop_download = true; //!< whether or not to drop incoming blocks (for testing)
|
bool m_test_drop_download = true; //!< whether or not to drop incoming blocks (for testing)
|
||||||
|
|
||||||
uint64_t m_test_drop_download_height = 0; //!< height under which to drop incoming blocks, if doing so
|
uint64_t m_test_drop_download_height = 0; //!< height under which to drop incoming blocks, if doing so
|
||||||
|
@ -1065,6 +1072,7 @@ namespace cryptonote
|
||||||
epee::math_helper::once_a_time_seconds<60*10, true> m_check_disk_space_interval; //!< interval for checking for disk space
|
epee::math_helper::once_a_time_seconds<60*10, true> m_check_disk_space_interval; //!< interval for checking for disk space
|
||||||
epee::math_helper::once_a_time_seconds<90, false> m_block_rate_interval; //!< interval for checking block rate
|
epee::math_helper::once_a_time_seconds<90, false> m_block_rate_interval; //!< interval for checking block rate
|
||||||
epee::math_helper::once_a_time_seconds<60*60*5, true> m_blockchain_pruning_interval; //!< interval for incremental blockchain pruning
|
epee::math_helper::once_a_time_seconds<60*60*5, true> m_blockchain_pruning_interval; //!< interval for incremental blockchain pruning
|
||||||
|
epee::math_helper::once_a_time_seconds<60*60*24*7, false> m_diff_recalc_interval; //!< interval for recalculating difficulties
|
||||||
|
|
||||||
std::atomic<bool> m_starter_message_showed; //!< has the "daemon will sync now" message been shown?
|
std::atomic<bool> m_starter_message_showed; //!< has the "daemon will sync now" message been shown?
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue