From c058b8e9f5a3781b61d0965e737f58c79d2250f5 Mon Sep 17 00:00:00 2001 From: fireice-uk Date: Sat, 16 Mar 2024 13:55:30 +0000 Subject: [PATCH 1/3] Basic hash-of-hashes mechanism --- src/CryptoNoteCore/BlockIndex.cpp | 6 ++++++ src/CryptoNoteCore/BlockIndex.h | 1 + src/CryptoNoteCore/Blockchain.cpp | 7 ++++++- src/CryptoNoteCore/Blockchain.h | 3 ++- src/CryptoNoteCore/Core.cpp | 4 ++++ src/CryptoNoteCore/Core.h | 1 + src/Daemon/DaemonCommandsHandler.cpp | 20 ++++++++++++++++++++ src/Daemon/DaemonCommandsHandler.h | 3 ++- 8 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/CryptoNoteCore/BlockIndex.cpp b/src/CryptoNoteCore/BlockIndex.cpp index 243170f2..48a86933 100644 --- a/src/CryptoNoteCore/BlockIndex.cpp +++ b/src/CryptoNoteCore/BlockIndex.cpp @@ -34,6 +34,12 @@ namespace cn { return result; } + crypto::Hash BlockIndex::getHashOfIds(uint32_t startBlockIndex, uint32_t maxCount) const { + /* This can be made more efficient by hashing in-place instead of copying all hashes, but it needs three function hash code */ + std::vector block_ids = getBlockIds(startBlockIndex, maxCount); + return crypto::cn_fast_hash(block_ids.data(), block_ids.size() * sizeof(crypto::Hash)); + } + bool BlockIndex::findSupplement(const std::vector& ids, uint32_t& offset) const { for (const auto& id : ids) { if (getBlockHeight(id, offset)) { diff --git a/src/CryptoNoteCore/BlockIndex.h b/src/CryptoNoteCore/BlockIndex.h index c122c315..d64b1a9e 100644 --- a/src/CryptoNoteCore/BlockIndex.h +++ b/src/CryptoNoteCore/BlockIndex.h @@ -58,6 +58,7 @@ namespace cn crypto::Hash getBlockId(uint32_t height) const; std::vector getBlockIds(uint32_t startBlockIndex, uint32_t maxCount) const; + crypto::Hash getHashOfIds(uint32_t startBlockIndex, uint32_t maxCount) const; bool findSupplement(const std::vector& ids, uint32_t& offset) const; std::vector buildSparseChain(const crypto::Hash& startBlockId) const; crypto::Hash getTailId() const; diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index e97e5a1b..c208715f 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -3287,4 +3287,9 @@ namespace cn return m_checkpoints.is_in_checkpoint_zone(height); } -} // namespace cn \ No newline at end of file + crypto::Hash Blockchain::getCheckpointHash(uint32_t height) const + { + std::lock_guard lk(m_blockchain_lock); + return m_blockIndex.getHashOfIds(0, height); + } +} // namespace cn diff --git a/src/CryptoNoteCore/Blockchain.h b/src/CryptoNoteCore/Blockchain.h index e909bf14..7235aeae 100644 --- a/src/CryptoNoteCore/Blockchain.h +++ b/src/CryptoNoteCore/Blockchain.h @@ -125,6 +125,7 @@ namespace cn uint64_t coinsEmittedAtHeight(uint64_t height); uint64_t difficultyAtHeight(uint64_t height); bool isInCheckpointZone(const uint32_t height) const; + crypto::Hash getCheckpointHash(uint32_t height) const; template bool scanOutputKeysForIndexes(const KeyInput &tx_in_to_key, visitor_t &vis, uint32_t *pmax_related_block_height = nullptr); @@ -482,4 +483,4 @@ namespace cn return true; } }; -} // namespace cn \ No newline at end of file +} // namespace cn diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index 99c3eb6a..49ea45a8 100644 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -106,6 +106,10 @@ void core::get_blockchain_top(uint32_t& height, crypto::Hash& top_id) { top_id = m_blockchain.getTailId(height); } +crypto::Hash core::checkpoint_hash(uint32_t height) { + return m_blockchain.getCheckpointHash(height); +} + bool core::rollback_chain_to(uint32_t height) { return m_blockchain.rollbackBlockchainTo(height); } diff --git a/src/CryptoNoteCore/Core.h b/src/CryptoNoteCore/Core.h index 0be9257f..4935f23f 100644 --- a/src/CryptoNoteCore/Core.h +++ b/src/CryptoNoteCore/Core.h @@ -94,6 +94,7 @@ namespace cn { bool get_blocks(uint32_t start_offset, uint32_t count, std::list& blocks, std::list& txs); bool get_blocks(uint32_t start_offset, uint32_t count, std::list& blocks); bool rollback_chain_to(uint32_t height); + crypto::Hash checkpoint_hash(uint32_t height); template bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) { diff --git a/src/Daemon/DaemonCommandsHandler.cpp b/src/Daemon/DaemonCommandsHandler.cpp index ccb13ac8..61b966f7 100644 --- a/src/Daemon/DaemonCommandsHandler.cpp +++ b/src/Daemon/DaemonCommandsHandler.cpp @@ -34,6 +34,7 @@ DaemonCommandsHandler::DaemonCommandsHandler(cn::core &core, cn::NodeServer &srv m_consoleHandler.setHandler("save", boost::bind(&DaemonCommandsHandler::save, this, boost::arg<1>()), "Save the Blockchain data safely"); m_consoleHandler.setHandler("print_pl", boost::bind(&DaemonCommandsHandler::print_pl, this, boost::arg<1>()), "Print peer list"); m_consoleHandler.setHandler("rollback_chain", boost::bind(&DaemonCommandsHandler::rollback_chain, this, boost::arg<1>()), "Rollback chain to specific height, rollback_chain "); + m_consoleHandler.setHandler("checkpoint_hash", boost::bind(&DaemonCommandsHandler::checkpoint_hash, this, boost::arg<1>()), "Calculate checkpoint hash up to "); m_consoleHandler.setHandler("print_cn", boost::bind(&DaemonCommandsHandler::print_cn, this, boost::arg<1>()), "Print connections"); m_consoleHandler.setHandler("print_bci", boost::bind(&DaemonCommandsHandler::print_bci, this, boost::arg<1>()), "Print blockchain current height"); m_consoleHandler.setHandler("print_bc", boost::bind(&DaemonCommandsHandler::print_bc, this, boost::arg<1>()), "Print blockchain info in a given blocks range, print_bc []"); @@ -309,6 +310,25 @@ bool DaemonCommandsHandler::rollback_chain(const std::vector &args) return true; } +bool DaemonCommandsHandler::checkpoint_hash(const std::vector &args) +{ + if (args.empty()) + { + logger(logging::ERROR) << "Usage: \"checkpoint_hash \""; + return true; + } + logger(logging::DEBUGGING) << "Attempting: checkpoint_hash"; + + const std::string &arg = args.front(); + uint32_t height = boost::lexical_cast(arg); + crypto::Hash hash = m_core.checkpoint_hash(height); + + logger(logging::INFO) << "Checkpoint hash: " << hash << " for " << height; + + logger(logging::DEBUGGING) << "Finished: checkpoint_hash"; + return true; +} + bool DaemonCommandsHandler::rollbackchainto(uint32_t height) { logger(logging::DEBUGGING) << "Attempting: rollbackchainto"; diff --git a/src/Daemon/DaemonCommandsHandler.h b/src/Daemon/DaemonCommandsHandler.h index f7bbc708..7ad8c7dc 100644 --- a/src/Daemon/DaemonCommandsHandler.h +++ b/src/Daemon/DaemonCommandsHandler.h @@ -52,7 +52,8 @@ class DaemonCommandsHandler bool show_hr(const std::vector& args); bool hide_hr(const std::vector& args); bool rollbackchainto(uint32_t height); - bool rollback_chain(const std::vector& args); + bool rollback_chain(const std::vector& args); + bool checkpoint_hash(const std::vector &args); bool print_cn(const std::vector& args); bool print_bc(const std::vector& args); bool print_bci(const std::vector& args); From 53b65b050f94a7c2181c173e968560913937883a Mon Sep 17 00:00:00 2001 From: fireice-uk Date: Fri, 22 Mar 2024 11:34:48 +0000 Subject: [PATCH 2/3] minor lint changes --- src/CryptoNoteCore/Core.cpp | 18 ++++++++++-------- src/CryptoNoteCore/Core.h | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index 49ea45a8..b9b83c3c 100644 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -60,20 +60,22 @@ class BlockWithTransactions : public IBlock { friend class core; }; -core::core(const Currency ¤cy, i_cryptonote_protocol *pprotocol, logging::ILogger &logger, bool blockchainIndexesEnabled, bool blockchainAutosaveEnabled) : m_currency(currency), - logger(logger, "core"), - m_mempool(currency, m_blockchain, m_timeProvider, logger), - m_blockchain(currency, m_mempool, logger, blockchainIndexesEnabled, blockchainAutosaveEnabled), - m_miner(new Miner(currency, *this, logger)), - m_starter_message_showed(false) +core::core(const Currency ¤cy, i_cryptonote_protocol *pprotocol, logging::ILogger &logger, bool blockchainIndexesEnabled, bool blockchainAutosaveEnabled) : + m_currency(currency), + logger(logger, "core"), + m_mempool(currency, m_blockchain, m_timeProvider, logger), + m_blockchain(currency, m_mempool, logger, blockchainIndexesEnabled, blockchainAutosaveEnabled), + m_miner(new Miner(currency, *this, logger)), + m_starter_message_showed(false) { set_cryptonote_protocol(pprotocol); m_blockchain.addObserver(this); m_mempool.addObserver(this); } - //----------------------------------------------------------------------------------------------- - core::~core() { + +//----------------------------------------------------------------------------------------------- +core::~core() { m_blockchain.removeObserver(this); } diff --git a/src/CryptoNoteCore/Core.h b/src/CryptoNoteCore/Core.h index 4935f23f..11164284 100644 --- a/src/CryptoNoteCore/Core.h +++ b/src/CryptoNoteCore/Core.h @@ -161,7 +161,7 @@ namespace cn { bool add_new_tx(const Transaction &tx, const crypto::Hash &tx_hash, size_t blob_size, tx_verification_context &tvc, bool keeped_by_block, uint32_t height); bool load_state_data(); bool parse_tx_from_blob(Transaction &tx, crypto::Hash &tx_hash, crypto::Hash &tx_prefix_hash, const BinaryArray &blob); - bool handle_incoming_block(const Block &b, block_verification_context &bvc, bool control_miner, bool relay_block); + bool handle_incoming_block(const Block &b, block_verification_context &bvc, bool control_miner, bool relay_block) override; bool check_tx_syntax(const Transaction &tx); //check correct values, amounts and all lightweight checks not related with database From 4b96cd6776603269e84ab4b04abcc09f4f85b9da Mon Sep 17 00:00:00 2001 From: fireice-uk Date: Thu, 28 Mar 2024 12:03:11 +0000 Subject: [PATCH 3/3] wip --- src/CryptoNoteConfig.h | 175 ++------------- src/CryptoNoteCore/Blockchain.cpp | 93 +++++--- src/CryptoNoteCore/Blockchain.h | 10 +- src/CryptoNoteCore/CheckpointList.h | 130 +++++++++++ src/CryptoNoteCore/Checkpoints.cpp | 203 ----------------- src/CryptoNoteCore/Checkpoints.h | 36 --- src/CryptoNoteCore/CheckpointsList.cpp | 209 ++++++++++++++++++ src/CryptoNoteCore/Core.cpp | 4 - src/CryptoNoteCore/Core.h | 9 +- src/CryptoNoteCore/Currency.cpp | 1 + src/CryptoNoteCore/Currency.h | 9 +- src/CryptoNoteCore/ICore.h | 3 + .../CryptoNoteProtocolDefinitions.h | 44 ++++ .../CryptoNoteProtocolHandler.cpp | 77 ++++++- .../CryptoNoteProtocolHandler.h | 6 +- src/Daemon/Daemon.cpp | 8 +- src/P2p/ConnectionContext.h | 2 + 17 files changed, 580 insertions(+), 439 deletions(-) create mode 100644 src/CryptoNoteCore/CheckpointList.h delete mode 100644 src/CryptoNoteCore/Checkpoints.cpp delete mode 100644 src/CryptoNoteCore/Checkpoints.h create mode 100644 src/CryptoNoteCore/CheckpointsList.cpp diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index 94ee5c69..f596f03c 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -141,6 +141,7 @@ namespace cn const char P2P_NET_DATA_FILENAME[] = "p2pstate.bin"; const char CRYPTONOTE_BLOCKCHAIN_INDICES_FILENAME[] = "blockchainindices.dat"; const char MINER_CONFIG_FILE_NAME[] = "miner_conf.json"; + const char CRYPTONOTE_CHECKPOINT_FILENAME[] = "checkpoint.dat"; } // namespace parameters @@ -185,12 +186,13 @@ namespace cn and the minimum version for communication between nodes */ const uint8_t P2P_VERSION_1 = 1; const uint8_t P2P_VERSION_2 = 2; - const uint8_t P2P_CURRENT_VERSION = 1; + const uint8_t P2P_CURRENT_VERSION = 2; const uint8_t P2P_MINIMUM_VERSION = 1; const uint8_t P2P_UPGRADE_WINDOW = 2; // This defines the minimum P2P version required for lite blocks propogation - const uint8_t P2P_LITE_BLOCKS_PROPOGATION_VERSION = 3; + const uint8_t P2P_LITE_BLOCKS_PROPOGATION_VERSION = 2; + const uint8_t P2P_CHECKPOINT_LIST_VERSION = 2; const size_t P2P_LOCAL_WHITE_PEERLIST_LIMIT = 1000; const size_t P2P_LOCAL_GRAY_PEERLIST_LIMIT = 5000; @@ -206,6 +208,7 @@ namespace cn const uint32_t P2P_DEFAULT_PING_CONNECTION_TIMEOUT = 2000; // 2 seconds const uint64_t P2P_DEFAULT_INVOKE_TIMEOUT = 60 * 2 * 1000; // 2 minutes const size_t P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT = 5000; // 5 seconds + const size_t P2P_CHECKPOINT_LIST_RE_REQUEST = 300; // 5 minutes const char P2P_STAT_TRUSTED_PUB_KEY[] = "f7061e9a5f0d30549afde49c9bfbaa52ac60afdc46304642b460a9ea34bf7a4e"; // Seed Nodes @@ -230,160 +233,28 @@ namespace cn __attribute__((unused)) #endif + const char DNS_CHECKPOINT_DOMAIN[] = "checkpoints.conceal.id"; + const char TESTNET_DNS_CHECKPOINT_DOMAIN[] = "testpoints.conceal.gq"; + // Blockchain Checkpoints: // {, ""}, const std::initializer_list CHECKPOINTS = { - {0, "b9dc432e56e37b52771970ce014dd23fda517cfd4fc5a9b296f1954b7d4505de"}, - {10000, "55cf271a5c97785fb35fea7ed177cb75f47c18688bd86fc01ae66508878029d6"}, - {20000, "52533de7f1596154c6954530ae8331fe4f92e92d476f097c6d7d20ebab1c2748"}, - {30000, "50b5d84ac0b8abfe25669aac8514505c4c5f7ffd8e2bba0b52ab64f600d90796"}, - {40000, "ae2ed29163a57396f11c743400e55fba3f6b8e6bb6473f421c48ff8c87447ad0"}, - {50000, "8ad7969ca5d3cf48f784d33b60d1ea00bfb35b632447584e5181b194f3bb9cd6"}, - {60000, "22b1a161de2318b1a83ae0e3d1d04a2c420accccadd861aa8ad6365ec630ce04"}, - {70000, "4ef8a3c59b04ad8ae335fee0b5df0c1b114dda57d13232741d82c4984bf22bed"}, - {80000, "a60bd6b446c5b09997b5b70f31c56f35358657a673dcf56213a163fb6516750d"}, - {90000, "9985f631d4b2c15388e8c3797a1384b4610b13ff3852bc6d8f125ea4e13fdd22"}, - {100000, "1ccef60fb31646fc1745ccb42167f2e2efcf953a83b99ff4b6a39c99eb37d0e5"}, - {110000, "1b80bf8355ea023de7ed3367881ef111dfdb3aaeb25db3a0d6cad4c3cc0bb4bd"}, - {120000, "f621bd615716b75716eb89714d60481077a16b1df4046bf829f6d09b1c8e58a6"}, - {130000, "deb2514d03e2faf1c63b55f707b1524665ca4bd71cace3f4e8f0de58f32ecc41"}, - {140000, "c439524c13187bb6008acb1e9999317aa44e8d1cd75c96faae78831f6b961bac"}, - {150000, "90cc70379ea81d47df998e8b9928ba9191968035ae79ec1cb429c64a55497e03"}, - {160000, "4176bdff06416934d7766a6c2f6279d048cfdc516019a0580ea19c1d003038cc"}, - {170000, "50e3af756e96115011c8e4d138852e1f4835da805ca5ccd826f81593a53f4bd3"}, - {180000, "e1672173a2794245830a742d1df38b5fe5006fe6f00707e1b776bf29316ab18b"}, - {190000, "763eaa3c049ef46479144924b41cc9cb37346da88b0a3ae32a10e026c6f7984c"}, - {200000, "2ef304bec067c3a94f04440a593a13903a1487890493d15f74ec79c0ae585109"}, - {210000, "90dd7aca026ec5f9fdfd2fa9cd0c114c1c6c6bfc0536fb6490c804ac7ef72425"}, - {220000, "8de5278fc6703933e32e062b14496b0e1562c941e7e3c5b93147a3b39491fac5"}, - {230000, "f8ed2680d912a7f3aeb452d4eb8023f93f6387ff4c6927615691f66701d05d32"}, - {240000, "4445874d16b3dd8d5b0f9dee287e47219022c2b214c459e03be2bb71e4a12e3d"}, - {250000, "c579d2ad4f95a6c34180a89b32aa9fbe6ab2ecba9f3714ddde90fd5d9f85f6e9"}, - {260000, "ce63d00de7546f1dee417b2391692b367dc5c2cfe19ea43c98cf932d3838c5ec"}, - {270000, "f16000fefb54ad1f0f927f634c5b6f44fcfa201adc5ee093850301bd773c18fa"}, - {280000, "aba16466e085b2c7a792ba449f025bd1e37d6a1d44fa957a1ad4df78f41f6478"}, - {290000, "9fd5f13ac51df7ce2b8d78c45fbb864b231d6275bf7495118b4cc415301e6fe1"}, - {290665, "4e0082f3e66b0fe4176a850ff9560f1d8d2f2e11dc3a2045904209d11478f779"}, - {290674, "ac89a1f4c20674a8d735681b1ded3a1242252bb23341bc9b79bc06b310b490f4"}, - {290675, "6782c5e7436f77f4466253d6a70466cc6bfc66c6c51b675864c4543250c09e8b"}, - {290676, "0b25026f8c7fb194776c081f2bb32874b82f4298bd0d71c2d0a986117b97fa1e"}, - {290720, "36572a88fbed4654f4291f6d7a35a732b81f61e87ec27ce58f38047981b84e09"}, - {300000, "2a984212cc42ef62cd2229b624e05aa72926f0e89006e976c88b52d99ea14225"}, - {305000, "46104ab66387ab6ca6a3889e81c7b9810e27f547a8684659aeb62c438a3b6cf0"}, - {310000, "4a896f5de4f782c59f1f4691505aba0df87a20f2e06499b59496b8d7ffb025fe"}, - {320000, "c68d15c181bdfc6c5b7fe5c46c6432a03b95d640caa425a5cb3aa675c1d8f8fd"}, - {330000, "af9e972f98bed57579a6691c3d21443d3cbff35005e984044bc99cee82d93922"}, - {340000, "6fce13dd473f3673cd08b28171902e281d7fdbbd8b8ba34e0019ae18f597d22f"}, - {350000, "f08aad1562ceee3a6c8147846bb3e5dd15b3168007f588ab68bd8ee816eb386d"}, - {360000, "cd910715be7dccc155ad3e8a6311f1bbcfaffe3ee25186c454ed27ee61faa977"}, - {370000, "6c4a86be9a1f697cadc38d21718803c43f49bf60c71ae253293e29ebac6efe31"}, - {380000, "620709892437c28deb72a56e6a91960f481aa682d8dd8652f792fb33e6683ef5"}, - {390000, "d2ff4c39b4aed7ef08a99a00b9823bed44581e866180ae3daa8b8e990b57ec63"}, - {400000, "9b7302daf5e5933b9a3e75a12651eaad83bea7d0058191cf65eb20985fe281c5"}, - {410000, "4f343219e57f78c1063f4b4c5be6cb5a10599d64d36e9f686f7046469a6c7e73"}, - {420000, "56b2fec8f7a55c9e2960d7224999c2e8c83a77f051931ba1673e071e7bcd6851"}, - {430000, "6d6e24f6c518c9cc24a05967fd1bbb3aeffb670fd7329d0a24053662a2305d9e"}, - {440000, "6a0138801d48150985045bc671c752f8209d084adad3624a57edd22f9edbef78"}, - {460000, "dec1da5df01c3cdf5d25a577816c93de58dfb6dd6b073619c5cbd50aedefceb7"}, - {470000, "1d07fd8995e17429143202da00138f0bfcbdd20aa5ddbba18ac762bc473ffd77"}, - {480000, "c896df9146e8f09f6205496dfa1e28037c8223f531546d2d64119068a6d1db1d"}, - {490000, "faa86e0b546f7655e829dcd8e967a52d9fa933c832863a648df30cc0e8771fa8"}, - {500000, "df5b2b47960ecd7809f037de44c6817640283e13323a36fe3dd894f3b2b3c5e1"}, - {510000, "db784d782ac463fbfbf221b417166a80ca1451f8895a1e3027bd19de2952c9bc"}, - {520000, "70b9c6945d8156d97d5f337b22ec8a4f77fa8af3b89d63e3fe6b834a03f7a613"}, - {530000, "f1b6f4018201e9c498e2b441f8e20f6e562e5d45c69008fe74caa7baa0a16611"}, - {550000, "1b922d13de891cd9f7224bd1a3c879a1d7634505f5f562623d7a487d44211327"}, - {570000, "9efe8868099afd1f6b17de773da0f5baebf2ace666bf5e599188c64d27cd429f"}, - {580000, "39ecee8d292c4e0440467b28ead6ed96c480ac85bec4fdba1e4c14b49b08077e"}, - {590000, "d6201b072cfed013b0e1091517624ca72bdd1ef147143356a1f951dd3241dd88"}, - {600000, "9f87dd161e37e9dbbcd86a3fafe8e1dec8c54194251ca0c36c646173db12c115"}, - {610000, "9c95678a27c5bde2b53efdae5c20a5528f134c4ff75737dee3e3d63b4d79c7ba"}, - {620000, "e5de278b0ea676855873663a32a2d21bc6d98cffcb133e249c8219fb0fcdc3eb"}, - {630000, "762c8269af35d53408d806d453b8ca6f19fc9e83048bb8d985502344f1d5e08a"}, - {640000, "24e1ac8aff3e1e7850c06a377c68b2ea3afe53477b710b988b6b456383a50081"}, - {650000, "4587f3196487cdf12e701bebe30340669374e39b6e0ca7a3c32d6b522be44570"}, - {660000, "8d8338dab606e4010f1fa53bc0ef268c98f63bf727150184bfedbea37c40026d"}, - {670000, "26350d735576a40e4d4e628b57186f4c7f85b3bea6c15f28554706f4c78c3837"}, - {680000, "6774c21beb0f4e2383069da967654ce4d26743f313aa7c705f222c055fcf0e05"}, - {690000, "33e1ddd732edfb8e850cdca304ae398a2eb495fd2a6876ff759725788f5b1135"}, - {700000, "a6b8e9707cd5ac93931b3fcc6bb516d11e7cb840bf49c8d3712bdeba605557be"}, - {710000, "922f1ca029163e58a24d6573e7de6bf9bcecc16ae164ebfd0285c0eda57d4eec"}, - {750000, "0e22dabd4379040815f078525ed02ae95e26ae92bc9eb35628a5d588e176b900"}, - {760000, "ecc64815b44b4c0c67340ff7e0d9fefee2cfbfbed10d61260c49bbe98aeb6ea2"}, - {770000, "7c97512a8ffdefa3e97809779841e48ffa6b68bd8a5bf90fcb59c1547f5ad90f"}, - {780000, "7acd1d5c843245bf1cc12a966f388111e2258c029595d31539b9257bb1217e61"}, - {790000, "580580b3b628b68532d9b141cc5e3299ebdc6e421c58ed155916c418144704ff"}, - {800000, "bb0dc113b1bfde3f06bfa341ba7d6de6ea82cebc86b98fc3d122b695e0bfdebe"}, - {810000, "c8a8e81032d66b137a99087ddd6ca6289040cb336012d4248ff616e1e7abb5b3"}, - {820000, "98a8373323adca6f09048177c774783150bcf25b62e26c804fd33461fc1af09b"}, - {830000, "7007d4331703233f48a3f1a2e824734d02ec81e7da46b7e00a2c354edb8de357"}, - {840000, "eae669f44a964ce5501b971139ee04657b62dc2535e9305857a1c9e2e839790a"}, - {850000, "e354bf503e8273a90d5d338ce78966ee820b69490b3a3183f0765281429d2f77"}, - {860000, "11b35a3f0c78686d75991d5bf65e868e565ea4ba15e96c9b0f643a4d9983eedf"}, - {870000, "21fef5a9cbb6ebe8ba271bdb55ed4d3ccd0468ab31a77f634cabc893e2a9661e"}, - {880000, "a861367503fec46c12f8ae957438a389c4de7b3c267cfdb21a7be29337885e10"}, - {890000, "092b29ab3369d0227239f0604d57ab91a3e1794ca3abe0c75fd5e69acb611a66"}, - {900000, "4cb49bba6abe10464db1075ed7125172e639ec9ee03f08ddb4dbed318d9dbfb9"}, - {910000, "2b3064cc74a3780e55c6eba250ec1e6ad6deb7ea6188430c07ba6fb3b60b63f0"}, - {920000, "961be71463b51c41fa5fbd43213b43b4b66173c26c1cd29d55881aae29a8ce07"}, - {930000, "511d2784b65e9ff0da55358834b88319b653aa1b5bf5a0f76c25c0467c16c536"}, - {940000, "781dba46e6a2d8a7ba4129e32e7764c519e011d8967672f7873599eb5449f760"}, - {950000, "5404a8e358ddf55c018bff01f4c112fc5ea291ac4429524d8b5c496ede697246"}, - {960000, "5133cf16ece3cba43a199c11dc80ecd81a8dbda4ce0c517f78a3e400efa6a730"}, - {970000, "e9ae491f24acd824dbcd43178c3070878e0ec32b494fe293b153fd19b2e8428a"}, - {980000, "c99c74ae4e3ff43ba2c93cd8a6d3ed52598c7bda6b42fac18d9569e29c5753aa"}, - {990000, "0412793a1650aeba2cf9ab7c32bee26668e8e997a55e97d65c609e903f9e04ec"}, - {1000000, "6ad9d4ccc9666b31481079374e573c20ebdf2d63862da8fcc2c45d13093b93ba"}, - {1010000, "f341d678cfbd5d488bbc179bc54fc92587dad7fb29823facc95f3e26158a722d"}, - {1020000, "e3dae82d451358ac300e3960695784efb7d76833e620d75196cd0af9db0568bb"}, - {1030000, "4d1d4f3174e684c93cb3dc0e261776224b02f6c0bd2c7ea91b6f923b42e7b321"}, - {1040000, "c894d5f5a6637d7ec50c9a09722059aa5e878bf1eda7210a1f6c4e61eca770ef"}, - {1050000, "8a0f5df47ce13a082423743651f22209cef78f46b933ced7642d1f6b8d8d80be"}, - {1060000, "59d6ee913234a03eefa023a3a12487c5244973e17a9c9dcc61bd7cb3c5dcc426"}, - {1070000, "0895514f95977bdbb220550f00ec38962a6e672a125dad115f2408600fd9b593"}, - {1080000, "58a71c6f06c16e3337f5dd43a018d2768b2f6ca2d97a7bee9e81b2b2bae866c3"}, - {1090000, "2c268f5a834ac104b04991b8b131205468ed06cd6a5acdadffa05db82394f113"}, - {1100000, "8b87b5d9941cf9b46ceaff134cff5bd8a9d0326bb045e8abcaa1eb63fda739bd"}, - {1110000, "2215193bc9e56654777e40c4d62c7b89f48e8d14b62335a800034bd5bed12835"}, - {1120000, "35a3baaaf080bd2e8321a0344fc939fbeca147f6078bc3c807cc3eec23325f96"}, - {1130000, "ea86d90d85c8b56edd03365d8558acb84dc3f33764a32df426eaf20b7d5b9d71"}, - {1140000, "611dd25b2ec9cc5a630e5aee561921efc13c939f179507f7a08afceb13f5035f"}, - {1150000, "122a7bf817cddd406a016304b35991f6f2a5cdd122cdc1b5a54fdd4e012066ae"}, - {1160000, "85b4997808f2c21ba7f94baa97de19bf1dc809fcd40936bf1fcaaca191ae1466"}, - {1170000, "7675f0144db2ae5f6e0c378a25778850c9fd6facd285e89cdfc4169f19bb79d2"}, - {1180000, "4f9c52d49f270df62ddf2b45f7e616321b686d6204e3c67f8807129ff180cdfb"}, - {1190000, "8b6fd535bec46f3b28772e82e210fd1988b1b4704801b75712c6af17b9a09a2b"}, - {1200000, "9434fdddd2e7521fa92aea42f11a30d364ccc413074993b2aacb31987cca02da"}, - {1210000, "d424b084320d8c138dca36de8bb2dba40e142f9fe6785f50b39c80543a653c4e"}, - {1220000, "9dad391d2c819b482d9a9408db63e480726597f21d180f9a590f3c20f2c9fbc8"}, - {1230000, "3c0fda332a0a1d0d9329087430960fd6506f7d01cf14cd027567074c3c9b79ef"}, - {1240000, "00a5a0b11c0f20fd30e98881dcf7c2246a67aea8529c71400f3bae4658214ce2"}, - {1250000, "786f2af5d5ff526cfb0330baed655d2a7bafbe5bcafa10759b17d6cd9cf9ee1c"}, - {1260000, "0aded508302e4987d6a585990e2b1f27b81582dd0ccff3fc40ca0779daaa7da1"}, - {1270000, "0b8a495699b85eae4e115b84259b056d9084025a0e9b11b67cca1c47552f0998"}, - {1280000, "544b164dfc4e19221e23e427fe821c812dda2a41fe5eee1915065f99a3c707d2"}, - {1290000, "7844314fdd7e70ed38def90377339e249108e328bb94820f070c6aa2a787abf9"}, - {1300000, "68e1ce32210bc1cd41ea26e64382f39c5302bf251273cc6fd35d80a3c19df815"}, - {1310000, "64aab7bbc148131f11479e74bbbd74c67e6ee45312bd6e72f5b68d5d1d383e46"}, - {1320000, "1e3d88026216db2a09b7771f5c36b6a9cf49086d259160b2ad4530155265c394"}, - {1330000, "2c05b06c4412738a06961406cea1d3b605afd0380a29ff306db6f1b820ce802f"}, - {1340000, "271352a6b9d8cdef191aaf3395d5b38d7e7bd1b270766aceec915d0e5d6eb9c4"}, - {1350000, "2911699e718b064a4820a860bff5b421ee122707cd4cc7bacebfcb70ed4ea8a5"}, - {1360000, "2635c819e25ea4d25be05adf7b515c09b14ff0bffd600921ab488d8597e1e35e"}, - {1370000, "a8e01900ca2289971a6f926c9bbd420a86c9213c287b8c207c4ee5accff27f10"}, - {1380000, "d6014404b60a7fd16372aacefb78132d417d8e08b5a6876851ab4862b167c84a"}, - {1390000, "30c3eb1c67b1ff52e84c7637131f6e0a950464c633e6e69bb27be7488a690462"}, - {1400000, "9668035887ed9f819382db025f852e57aa02fa8980b4c9043f0dd535ea4a1085"}, - {1410000, "a01f353bfe5b907f9b0ffa7e4226caca5d8a67e2bf4b39c13c93b63a4a7d4379"}, - {1420000, "930ad5850a8aeeb8ee38b08006bfea2e93474d97bf666b97df9ab9fbe84a79be"}, - {1430000, "8d1b006f9fa277196f62a98a501ecf91a81731d199463c23931181b4a28b694a"}, - {1440000, "b54921b7c396e66e1a15492289e33993a166f49675739f437257fbb760ee1035"}, - {1450000, "f8a2b95f394f6cd188363a20f585dadbfa0db707dd5fa2699604eb7ccab313a6"}, - {1460000, "6bd96b76bd2d3bc7ca320c089ffe21e64565432401cb94736d60d8f70cfb42f3"}, - {1470000, "7e2d26dd0b258ff826d6ff1e36fe6606206fca535ba0ed40e944ddb165da9dc0"}, - {1480000, "f4463eed0890245dca0ccf9fb3a9f101e110f1dc53ce1286ef47d56938faf007"}, - {1490000, "bc76acf39ea16ce02588798b93034208881bab6c6dd9dfc545a6fab51dfce886"} + { 100000, "9b58762e759cd02cef493b310f95d73c36a907ea5c6ab3953b6b304651d3f291"}, + { 200000, "07a7d796f64309b84558b7fc44902dd65dbf1bfd4b727b9f48b9f358b9c7e4f5"}, + { 300000, "d723e8964fd416d1fbb5c8d616b0f7aa2f61cd7dbf1c7f6654daf751915f7967"}, + { 400000, "1b4fbfd19b8502af420b8a38a6ac610a6b9e30a164af4da742092bdf9887d086"}, + { 500000, "47cce8323f661b07048be52a2c6cca29f9f49aa5cc3282253f6e0a54dd3f1d56"}, + { 600000, "086035e107dd22b8be63a86c28f750124306914cd47f46d0c69208580a4d5f9e"}, + { 700000, "b499559416d7198a01bfe6c02d94f0e0c4ff785158ffa6f690e736317372acc3"}, + { 800000, "3c5207312c528b80df4392f5f6a99cb23457d018c08747b072e7ab86a83025b4"}, + { 900000, "4bb3c7c5b7bd24dac9440f3f5797348716b1b1a6335a0de0769f0ea0f409e447"}, + {1000000, "3148b677584d71f5e75b5c7431d525aa6b8d8a7d5e4d01ea4adadc75adcc64d5"}, + {1100000, "480f890918c2c550696109391b55ca465fdc04a4302b403a90ccf00c37a282d9"}, + {1200000, "f730a854601d55c774755a6d8f561ab2454dfb763340f23b7218c24ae14163f4"}, + {1300000, "d130491c88398a2812849d27fa09b884085d7f2feffe5d5da0f56cd8039469f5"}, + {1400000, "570682ba6a7614081071a9f111b7e737789e1c7d445635bcd1f830211a311a19"}, + {1500000, "43f173aba14a6b2d023c07796683789470395d7f15ebd24991617b4cc81c4f8c"} }; const std::initializer_list TESTNET_CHECKPOINTS = { diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index c208715f..2095410d 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -355,7 +355,6 @@ namespace cn m_blockchainIndexesEnabled(blockchainIndexesEnabled), m_blockchainAutosaveEnabled(blockchainAutosaveEnabled), logger(logger, "Blockchain") - { } @@ -461,7 +460,6 @@ namespace cn bool Blockchain::init(const std::string &config_folder, bool load_existing, bool testnet) { m_testnet = testnet; - m_checkpoints.set_testnet(testnet); std::lock_guard lk(m_blockchain_lock); if (!config_folder.empty() && !tools::create_directories_if_necessary(config_folder)) { @@ -471,6 +469,9 @@ namespace cn m_config_folder = config_folder; + m_checkpoints.init_targets(testnet, appendPath(config_folder, m_currency.checkpointFileName())); + m_checkpoints.load_checkpoints_from_file(); + if (!m_blocks.open(appendPath(config_folder, m_currency.blocksFileName()), appendPath(config_folder, m_currency.blockIndexesFileName()), 1024)) { return false; @@ -593,25 +594,44 @@ namespace cn bool Blockchain::checkCheckpoints(uint32_t &lastValidCheckpointHeight) { - std::vector checkpointHeights = m_checkpoints.getCheckpointHeights(); - for (const auto &checkpointHeight : checkpointHeights) + bool rv = true; + std::vector> checkpointHeights = m_checkpoints.get_checkpoint_targets(); + lastValidCheckpointHeight = 0; + + /* Hashes are in reverse order so if everything is ok we will only do one iteration */ + for (const auto &check : checkpointHeights) { - if (m_blocks.size() <= checkpointHeight) - { - return true; - } + uint32_t height = check.first; + if (m_blocks.size() <= height) + continue; - if (m_checkpoints.check_block(checkpointHeight, getBlockIdByHeight(checkpointHeight))) + crypto::Hash hv = m_blockIndex.getHashOfIds(0, height+1); + if (hv == check.second) { - lastValidCheckpointHeight = checkpointHeight; + lastValidCheckpointHeight = height; + break; } else { - return false; + logger(ERROR, BRIGHT_RED) << "Checkpoint failed for " << height << " got " << + hv << " expected " << check.second; + rv = false; } } - logger(INFO, BRIGHT_WHITE) << "Checkpoints passed"; - return true; + + if(rv) + { + logger(INFO, BRIGHT_WHITE) << "Checkpoints passed " << m_checkpoints.get_points_size() << " " << lastValidCheckpointHeight; + uint32_t n_valid_blocks = lastValidCheckpointHeight+1; + if(m_checkpoints.get_points_size() < n_valid_blocks) + m_checkpoints.set_checkpoint_list(m_blockIndex.getBlockIds(0, n_valid_blocks)); + } + else + { + logger(ERROR, BRIGHT_RED) << "Checkpoints failed, last valid height " << lastValidCheckpointHeight; + } + + return rv; } void Blockchain::rebuildCache() @@ -1403,6 +1423,29 @@ namespace cn return true; } + bool Blockchain::is_alternative_block_allowed(uint32_t blockchain_height, uint32_t block_height) const { + if (0 == block_height) + return false; + + uint32_t lowest_height = blockchain_height - cn::parameters::CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; + + if (blockchain_height < cn::parameters::CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW) + { + lowest_height = 0; + } + + if (block_height < lowest_height && !m_checkpoints.is_in_checkpoint_zone(block_height)) + { + logger(logging::DEBUGGING, logging::WHITE) + << "<< Checkpoints.cpp << " + << "Reorganization depth too deep : " << (blockchain_height - block_height) << ". Block Rejected"; + return false; + } + + uint32_t checkpoint_height = m_checkpoints.get_greatest_target_height(); + return checkpoint_height < block_height; + } + bool Blockchain::handle_alternative_block(const Block &b, const crypto::Hash &id, block_verification_context &bvc, bool sendNewAlternativeBlockMessage) { std::lock_guard lk(m_blockchain_lock); @@ -1416,10 +1459,8 @@ namespace cn return false; } - /* in the absence of a better solution, we fetch checkpoints from dns records */ - m_checkpoints.load_checkpoints_from_dns(); - if (!m_checkpoints.is_alternative_block_allowed(getCurrentBlockchainHeight(), block_height)) + if (!is_alternative_block_allowed(getCurrentBlockchainHeight(), block_height)) { logger(DEBUGGING) << "Block with id: " << id << std::endl << " can't be accepted for alternative chain, block height: " << block_height << std::endl @@ -1514,8 +1555,8 @@ namespace cn bei.bl = b; bei.height = alt_chain.size() ? it_prev->second.height + 1 : mainPrevHeight + 1; - bool is_a_checkpoint; - if (!m_checkpoints.check_block(bei.height, id, is_a_checkpoint)) + auto checkpoint_status = m_checkpoints.check_checkpoint(bei.height, id); + if ( checkpoint_status == CheckpointList::is_in_zone_failed ) { logger(ERROR, BRIGHT_RED) << "Checkpoint validaton failure"; @@ -1581,7 +1622,7 @@ namespace cn alt_chain.push_back(i_res.first->first); - if (is_a_checkpoint) + if ( checkpoint_status == CheckpointList::is_checkpointed ) { //do reorganize! logger(INFO, BRIGHT_GREEN) << "###### REORGANIZE on height: " << m_alternative_chains[alt_chain.front()].height << " of " << m_blocks.size() - 1 << ", checkpoint is found in alternative chain on height " << bei.height; @@ -2481,15 +2522,13 @@ namespace cn auto longhashTimeStart = std::chrono::steady_clock::now(); crypto::Hash proof_of_work = NULL_HASH; - if (m_checkpoints.is_in_checkpoint_zone(getCurrentBlockchainHeight())) + auto checkpoint_status = m_checkpoints.check_checkpoint(getCurrentBlockchainHeight(), blockHash); + if (checkpoint_status == CheckpointList::is_in_zone_failed ) { - if (!m_checkpoints.check_block(getCurrentBlockchainHeight(), blockHash)) - { - bvc.m_verification_failed = true; - return false; - } + bvc.m_verification_failed = true; + return false; } - else + else if(checkpoint_status == CheckpointList::is_out_of_zone ) { if (!m_currency.checkProofOfWork(m_cn_context, blockData, currentDifficulty, proof_of_work)) { @@ -3290,6 +3329,6 @@ namespace cn crypto::Hash Blockchain::getCheckpointHash(uint32_t height) const { std::lock_guard lk(m_blockchain_lock); - return m_blockIndex.getHashOfIds(0, height); + return m_blockIndex.getHashOfIds(0, height+1); } } // namespace cn diff --git a/src/CryptoNoteCore/Blockchain.h b/src/CryptoNoteCore/Blockchain.h index 7235aeae..b87b6735 100644 --- a/src/CryptoNoteCore/Blockchain.h +++ b/src/CryptoNoteCore/Blockchain.h @@ -15,7 +15,7 @@ #include "Common/ObserverManager.h" #include "Common/Util.h" #include "CryptoNoteCore/BlockIndex.h" -#include "CryptoNoteCore/Checkpoints.h" +#include "CryptoNoteCore/CheckpointList.h" #include "CryptoNoteCore/Currency.h" #include "CryptoNoteCore/DepositIndex.h" #include "CryptoNoteCore/IBlockchainStorageObserver.h" @@ -68,7 +68,6 @@ namespace cn bool getLowerBound(uint64_t timestamp, uint64_t startOffset, uint32_t &height); std::vector getBlockIds(uint32_t startHeight, uint32_t maxCount); - void setCheckpoints(Checkpoints &&chk_pts) { m_checkpoints = std::move(chk_pts); } bool getBlocks(uint32_t start_offset, uint32_t count, std::list &blocks, std::list &txs); bool getBlocks(uint32_t start_offset, uint32_t count, std::list &blocks); bool getAlternativeBlocks(std::list &blocks); @@ -84,6 +83,10 @@ namespace cn bool haveTransaction(const crypto::Hash &id); bool haveTransactionKeyImagesAsSpent(const Transaction &tx); + CheckpointList& getCheckpointList() { + return m_checkpoints; + } + uint32_t getCurrentBlockchainHeight(); // TODO rename to getCurrentBlockchainSize crypto::Hash getTailId(); crypto::Hash getTailId(uint32_t &height); @@ -285,7 +288,7 @@ namespace cn outputs_container m_outputs; std::string m_config_folder; - Checkpoints m_checkpoints; + CheckpointList m_checkpoints; std::atomic m_is_in_checkpoint_zone; using Blocks = SwappedVector; @@ -320,6 +323,7 @@ namespace cn bool switch_to_alternative_blockchain(const std::list &alt_chain, bool discard_disconnected_chain); + bool is_alternative_block_allowed(uint32_t blockchain_height, uint32_t block_height) const; bool handle_alternative_block(const Block &b, const crypto::Hash &id, block_verification_context &bvc, bool sendNewAlternativeBlockMessage = true); difficulty_type get_next_difficulty_for_alternative_chain(const std::list &alt_chain, const BlockEntry &bei); void pushToDepositIndex(const BlockEntry &block, uint64_t interest); diff --git a/src/CryptoNoteCore/CheckpointList.h b/src/CryptoNoteCore/CheckpointList.h new file mode 100644 index 00000000..efa0d02d --- /dev/null +++ b/src/CryptoNoteCore/CheckpointList.h @@ -0,0 +1,130 @@ +// Copyright (c) 2011-2017 The Cryptonote developers +// Copyright (c) 2017-2018 The Circle Foundation & Conceal Devs +// Copyright (c) 2018-2023 Conceal Network & Conceal Devs +// +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +#include + +#include "CryptoNoteBasicImpl.h" +#include + +namespace cn +{ + class CheckpointList + { + public: + explicit CheckpointList(logging::ILogger& log) : logger(log, "checkpoint_list") {} + + void init_targets(bool is_testnet, const std::string& save_file); + + bool add_checkpoint_list(uint32_t start_height, std::vector& points); + bool set_checkpoint_list(std::vector&& points); + bool load_checkpoints_from_file(); + + uint32_t get_points_size() const + { + const std::lock_guard lock(m_points_lock); + return m_points.size(); + } + + uint32_t get_greatest_target_height() const + { + return m_targets.rbegin()->first - 1; + } + + bool is_ready() const + { + const std::lock_guard lock(m_points_lock); + return m_points.size()-1 >= get_greatest_target_height(); + } + + bool is_in_checkpoint_zone(uint32_t height) const + { + const std::lock_guard lock(m_points_lock); + return m_points.size() < height; + } + + enum check_rt + { + is_out_of_zone, + is_in_zone_failed, + is_checkpointed + }; + + check_rt check_checkpoint(uint32_t height, const crypto::Hash& hv) const + { + const std::lock_guard lock(m_points_lock); + + if(m_points.size() <= height) + return is_out_of_zone; + if(m_points[height] == hv) + return is_checkpointed; + else + return is_in_zone_failed; + } + + std::vector> get_checkpoint_targets() const + { + std::vector> rv; + rv.reserve(m_targets.size()); + for(auto it = m_targets.rbegin(); it != m_targets.rend(); ++it) + rv.emplace_back(it->first-1, it->second); + return rv; + } + + struct t_get_incomplete_checkpoint_target_rv { + crypto::Hash target_hash = NULL_HASH; + uint32_t start_height; + uint32_t end_height; + }; + + t_get_incomplete_checkpoint_target_rv get_incomplete_checkpoint_target() const + { + t_get_incomplete_checkpoint_target_rv rv; + size_t point_size = m_points.size(); + if(point_size >= m_targets.rbegin()->first) + return rv; + rv.start_height = 0; + for(const auto& p : m_targets) + { + if(point_size < p.first) + { + rv.end_height = p.first; + rv.target_hash = p.second; + return rv; + } + else + { + rv.start_height = p.first; + } + } + return rv; + } + + + private: + bool m_testnet; + logging::LoggerRef logger; + std::string m_save_file; + + mutable std::mutex m_points_lock; + std::map m_targets; /*NB uint32_t is size not height */ + std::unordered_set m_valid_point_sizes; + std::vector m_points; + + bool save_checkpoints(); + bool add_checkpoint_target(uint32_t height, const std::string &hash_str); + bool is_fsize_valid(uint32_t fsize) + { + if(fsize % sizeof(crypto::Hash) != 0) + return false; + fsize /= sizeof(crypto::Hash); + + return m_valid_point_sizes.find(fsize) != m_valid_point_sizes.end(); + } + }; +} diff --git a/src/CryptoNoteCore/Checkpoints.cpp b/src/CryptoNoteCore/Checkpoints.cpp deleted file mode 100644 index a75d6dce..00000000 --- a/src/CryptoNoteCore/Checkpoints.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) 2011-2017 The Cryptonote developers -// Copyright (c) 2017-2018 The Circle Foundation & Conceal Devs -// Copyright (c) 2018-2023 Conceal Network & Conceal Devs -// -// Copyright (c) 2016-2019, The Karbo developers - -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Checkpoints.h" -#include "../CryptoNoteConfig.h" -#include "Common/StringTools.h" -#include "Common/DnsTools.h" - -using namespace logging; - -namespace cn { -//--------------------------------------------------------------------------- -Checkpoints::Checkpoints(logging::ILogger &log) : logger(log, "checkpoints") {} -//--------------------------------------------------------------------------- -bool Checkpoints::add_checkpoint(uint32_t height, const std::string &hash_str) { - crypto::Hash h = NULL_HASH; - - if (!common::podFromHex(hash_str, h)) { - logger(ERROR) << "<< Checkpoints.cpp << " << "Incorrect hash in checkpoints"; - return false; - } - - if (!(0 == m_points.count(height))) { - logger(DEBUGGING) << "Checkpoint already exists for height " << height; - return false; - } - - m_points[height] = h; - - return true; -} -//--------------------------------------------------------------------------- -bool Checkpoints::is_in_checkpoint_zone(uint32_t height) const { - return !m_points.empty() && (height <= (--m_points.end())->first); -} -//--------------------------------------------------------------------------- -bool Checkpoints::check_block(uint32_t height, const crypto::Hash &h, bool &is_a_checkpoint) const { - auto it = m_points.find(height); - is_a_checkpoint = it != m_points.end(); - if (!is_a_checkpoint) - return true; - - if (it->second == h) { - return true; - } else { - logger(logging::ERROR) << "<< Checkpoints.cpp << " << "Checkpoint failed for height " << height - << ". Expected hash: " << it->second - << ", Fetched hash: " << h; - return false; - } -} -//--------------------------------------------------------------------------- -bool Checkpoints::check_block(uint32_t height, const crypto::Hash &h) const { - bool ignored; - return check_block(height, h, ignored); -} -//--------------------------------------------------------------------------- -bool Checkpoints::is_alternative_block_allowed(uint32_t blockchain_height, uint32_t block_height) const { - if (0 == block_height) - return false; - - uint32_t lowest_height = blockchain_height - cn::parameters::CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; - - if (blockchain_height < cn::parameters::CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW) - { - lowest_height = 0; - } - - if (block_height < lowest_height && !is_in_checkpoint_zone(block_height)) - { - logger(logging::DEBUGGING, logging::WHITE) - << "<< Checkpoints.cpp << " - << "Reorganization depth too deep : " << (blockchain_height - block_height) << ". Block Rejected"; - return false; - } - - auto it = m_points.upper_bound(blockchain_height); - if (it == m_points.begin()) - return true; - - --it; - uint32_t checkpoint_height = it->first; - return checkpoint_height < block_height; -} - -//--------------------------------------------------------------------------- - -std::vector Checkpoints::getCheckpointHeights() const { - std::vector checkpointHeights; - checkpointHeights.reserve(m_points.size()); - for (const auto& it : m_points) { - checkpointHeights.push_back(it.first); - } - - return checkpointHeights; -} - -bool Checkpoints::load_checkpoints_from_dns() -{ - std::string domain("checkpoints.conceal.id"); - if (m_testnet) - { - domain = "testpoints.conceal.gq"; - } - std::vectorrecords; - - logger(logging::DEBUGGING) << "<< Checkpoints.cpp << " << "Fetching DNS checkpoint records from " << domain; - - if (!common::fetch_dns_txt(domain, records)) { - logger(logging::DEBUGGING) << "<< Checkpoints.cpp << " << "Failed to lookup DNS checkpoint records from " << domain; - } - - for (const auto& record : records) { - uint32_t height; - crypto::Hash hash = NULL_HASH; - std::stringstream ss; - size_t del = record.find_first_of(':'); - std::string height_str = record.substr(0, del), hash_str = record.substr(del + 1, 64); - ss.str(height_str); - ss >> height; - char c; - if (del == std::string::npos) continue; - if ((ss.fail() || ss.get(c)) || !common::podFromHex(hash_str, hash)) { - logger(logging::INFO) << "<< Checkpoints.cpp << " << "Failed to parse DNS checkpoint record: " << record; - continue; - } - - if (!(0 == m_points.count(height))) { - logger(DEBUGGING) << "<< Checkpoints.cpp << " << "Checkpoint already exists for height: " << height << ". Ignoring DNS checkpoint."; - } else { - add_checkpoint(height, hash_str); - logger(DEBUGGING) << "<< Checkpoints.cpp << " << "Added DNS checkpoint: " << height_str << ":" << hash_str; - } - } - - return true; -} - -bool Checkpoints::load_checkpoints() -{ - if (m_testnet) - { - for (const auto &cp : cn::TESTNET_CHECKPOINTS) - { - add_checkpoint(cp.height, cp.blockId); - } - } - else - { - for (const auto &cp : cn::CHECKPOINTS) - { - add_checkpoint(cp.height, cp.blockId); - } - } - return true; -} - -bool Checkpoints::load_checkpoints_from_file(const std::string& fileName) { - std::ifstream file(fileName); - if (!file) { - logger(logging::ERROR, BRIGHT_RED) << "Could not load checkpoints file: " << fileName; - return false; - } - std::string indexString; - std::string hash; - uint32_t height; - while (std::getline(file, indexString, ','), std::getline(file, hash)) { - try { - height = std::stoi(indexString); - } catch (const std::invalid_argument &) { - logger(ERROR, BRIGHT_RED) << "Invalid checkpoint file format - " - << "could not parse height as a number"; - return false; - } - if (!add_checkpoint(height, hash)) { - return false; - } - } - logger(logging::INFO) << "Loaded " << m_points.size() << " checkpoints from " << fileName; - return true; -} - -void Checkpoints::set_testnet(bool testnet) { m_testnet = testnet; } - -} diff --git a/src/CryptoNoteCore/Checkpoints.h b/src/CryptoNoteCore/Checkpoints.h deleted file mode 100644 index 6de13aca..00000000 --- a/src/CryptoNoteCore/Checkpoints.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2011-2017 The Cryptonote developers -// Copyright (c) 2017-2018 The Circle Foundation & Conceal Devs -// Copyright (c) 2018-2023 Conceal Network & Conceal Devs -// -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#pragma once -#include -#include "CryptoNoteBasicImpl.h" -#include - -namespace cn -{ - class Checkpoints - { - public: - explicit Checkpoints(logging::ILogger& log); - - bool add_checkpoint(uint32_t height, const std::string& hash_str); - bool is_in_checkpoint_zone(uint32_t height) const; - bool load_checkpoints_from_file(const std::string& fileName); - bool load_checkpoints_from_dns(); - bool load_checkpoints(); - bool check_block(uint32_t height, const crypto::Hash& h) const; - bool check_block(uint32_t height, const crypto::Hash& h, bool& is_a_checkpoint) const; - bool is_alternative_block_allowed(uint32_t blockchain_height, uint32_t block_height) const; - std::vector getCheckpointHeights() const; - void set_testnet(bool testnet); - - private: - bool m_testnet = false; - std::map m_points; - logging::LoggerRef logger; - }; -} diff --git a/src/CryptoNoteCore/CheckpointsList.cpp b/src/CryptoNoteCore/CheckpointsList.cpp new file mode 100644 index 00000000..ca15b1ac --- /dev/null +++ b/src/CryptoNoteCore/CheckpointsList.cpp @@ -0,0 +1,209 @@ +// Copyright (c) 2011-2017 The Cryptonote developers +// Copyright (c) 2017-2018 The Circle Foundation & Conceal Devs +// Copyright (c) 2018-2023 Conceal Network & Conceal Devs +// +// Copyright (c) 2016-2019, The Karbo developers + +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CheckpointList.h" +#include "../CryptoNoteConfig.h" +#include "Common/StringTools.h" +#include "Common/DnsTools.h" +#include "crypto/hash.h" + +using namespace logging; + +namespace cn { + void CheckpointList::init_targets(bool is_testnet, const std::string& save_file) + { + m_testnet = is_testnet; + m_save_file = save_file; + + for (const auto &cp : m_testnet ? cn::TESTNET_CHECKPOINTS : cn::CHECKPOINTS) + { + add_checkpoint_target(cp.height, cp.blockId); + } + + const char* domain; + if (m_testnet) + domain = TESTNET_DNS_CHECKPOINT_DOMAIN; + else + domain = DNS_CHECKPOINT_DOMAIN; + + std::vectorrecords; + + logger(logging::DEBUGGING) << "<< CheckpointList.cpp << " << "Fetching DNS checkpoint records from " << domain; + + if (!common::fetch_dns_txt(domain, records)) { + logger(logging::DEBUGGING) << "<< CheckpointList.cpp << " << "Failed to lookup DNS checkpoint records from " << domain; + } + + for (const auto& record : records) { + uint32_t height; + crypto::Hash hash = NULL_HASH; + std::stringstream ss; + size_t del = record.find_first_of(':'); + std::string height_str = record.substr(0, del), hash_str = record.substr(del + 1, 64); + ss.str(height_str); + ss >> height; + char c; + if (del == std::string::npos) continue; + if ((ss.fail() || ss.get(c)) || !common::podFromHex(hash_str, hash)) { + logger(logging::INFO) << "<< CheckpointList.cpp << " << "Failed to parse DNS checkpoint record: " << record; + continue; + } + + if (!(0 == m_targets.count(height))) { + logger(DEBUGGING) << "<< CheckpointList.cpp << " << "Checkpoint already exists for height: " << height << ". Ignoring DNS checkpoint."; + } else { + add_checkpoint_target(height, hash_str); + logger(DEBUGGING) << "<< CheckpointList.cpp << " << "Added DNS checkpoint target: " << height_str << ":" << hash_str; + } + } + } + + bool CheckpointList::add_checkpoint_target(uint32_t height, const std::string &hash_str) { + crypto::Hash h = NULL_HASH; + + if (!common::podFromHex(hash_str, h)) { + logger(ERROR) << "<< Checkpoints.cpp << " << "Incorrect hash in checkpoints"; + return false; + } + + if (!(0 == m_targets.count(height))) { + logger(DEBUGGING) << "Checkpoint already exists for height " << height; + return false; + } + + height += 1; + m_targets[height] = h; + m_valid_point_sizes.insert(height); + + return true; + } + + bool CheckpointList::set_checkpoint_list(std::vector&& points) + { + const std::lock_guard lock(m_points_lock); + uint32_t point_size = points.size(); + if(m_valid_point_sizes.find(point_size) == m_valid_point_sizes.end()) + return false; + + crypto::Hash hv = crypto::cn_fast_hash(points.data(), points.size() * sizeof(crypto::Hash)); + if(hv != m_targets[point_size]) + { + logger(logging::ERROR) << "<< CheckpointList.cpp << " << "CheckpointList verification failed for height " << point_size-1 << + ". Expected hash: " << m_targets[point_size] << + ", Fetched hash: " << hv; + return false; + } + + m_points = std::move(points); + logger(logging::INFO) << "Loaded " << m_points.size() << " checkpoints from local index"; + + save_checkpoints(); + return true; + } + + bool CheckpointList::add_checkpoint_list(uint32_t start_height, std::vector& points) + { + const std::lock_guard lock(m_points_lock); + + if(m_points.size() != start_height) + return true; + + uint32_t point_size = points.size() + m_points.size(); + if(m_valid_point_sizes.find(point_size) == m_valid_point_sizes.end()) + return false; + + /* This copy wouldn't be needed with three funciton hash */ + std::vector new_points(m_points); + new_points.insert(std::end(new_points), std::begin(points), std::end(points)); + + crypto::Hash hv = crypto::cn_fast_hash(new_points.data(), new_points.size() * sizeof(crypto::Hash)); + if(hv != m_targets[point_size]) + { + logger(logging::ERROR) << "<< CheckpointList.cpp << " << "CheckpointList verification failed for height " << point_size-1 << + ". Expected hash: " << m_targets[point_size] << + ", Fetched hash: " << hv; + return false; + } + + m_points = std::move(new_points); + logger(logging::INFO) << "Loaded " << points.size() << " checkpoints from p2p, total " << m_points.size(); + + save_checkpoints(); + return true; + } + + bool CheckpointList::load_checkpoints_from_file() + { + std::ifstream file(m_save_file, std::ios::binary | std::ios::ate); + if (!file.is_open()) { + return false; + } + + uint64_t fsize = file.tellg(); + if(!is_fsize_valid(fsize)) { + logger(logging::ERROR) << "<< CheckpointList.cpp << " << "Invalid file size" << fsize; + return false; + } + uint32_t point_size = fsize / sizeof(crypto::Hash); + + file.seekg(0, std::ios::beg); + + std::vector points(point_size); + if (!file.read(reinterpret_cast(points.data()), fsize)) { + logger(logging::ERROR) << "<< CheckpointList.cpp << " << "error reading file"; + return false; + } + + crypto::Hash hv = crypto::cn_fast_hash(points.data(), points.size() * sizeof(crypto::Hash)); + if(hv != m_targets[point_size]) + { + logger(logging::ERROR) << "<< CheckpointList.cpp << " << "CheckpointList verification (from file) failed for height " << point_size-1 + << ". Expected hash: " << m_targets[point_size] + << ", Fetched hash: " << hv; + return false; + } + + const std::lock_guard lock(m_points_lock); + m_points = std::move(points); + logger(logging::INFO) << "Loaded " << m_points.size() << " checkpoints from disk " << m_save_file; + return true; + } + + bool CheckpointList::save_checkpoints() + { + std::ofstream file(m_save_file, std::ios::binary); + + if (!file.is_open()) { + logger(logging::ERROR) << "<< CheckpointList.cpp << " << "error opening file for write " << m_save_file; + return false; + } + + file.write(reinterpret_cast(m_points.data()), m_points.size() * sizeof(crypto::Hash)); + file.close(); + + if (!file) { + logger(logging::ERROR) << "<< CheckpointList.cpp << " << "error writing to file " << m_save_file; + return false; + } + + return true; + } +} diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index b9b83c3c..ee34f853 100644 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -87,10 +87,6 @@ void core::set_cryptonote_protocol(i_cryptonote_protocol* pprotocol) { } } //----------------------------------------------------------------------------------- -void core::set_checkpoints(Checkpoints&& chk_pts) { - m_blockchain.setCheckpoints(std::move(chk_pts)); -} -//----------------------------------------------------------------------------------- void core::init_options(boost::program_options::options_description& /*desc*/) { } diff --git a/src/CryptoNoteCore/Core.h b/src/CryptoNoteCore/Core.h index 11164284..193e1a84 100644 --- a/src/CryptoNoteCore/Core.h +++ b/src/CryptoNoteCore/Core.h @@ -83,6 +83,10 @@ namespace cn { virtual bool addMessageQueue(MessageQueue& messageQueue) override; virtual bool removeMessageQueue(MessageQueue& messageQueue) override; + + virtual CheckpointList& getCheckpointList() override { + return m_blockchain.getCheckpointList(); + } uint32_t get_current_blockchain_height(); bool have_block(const crypto::Hash& id) override; @@ -102,6 +106,10 @@ namespace cn { } virtual bool queryBlocks(const std::vector& block_ids, uint64_t timestamp, uint32_t& start_height, uint32_t& current_height, uint32_t& full_offset, std::vector& entries) override; + + virtual std::vector getBlockIds(uint32_t start_height, uint32_t end_height) override { + return m_blockchain.getBlockIds(start_height, end_height); + } virtual bool queryBlocksLite(const std::vector& knownBlockIds, uint64_t timestamp, uint32_t& resStartHeight, uint32_t& resCurrentHeight, uint32_t& resFullOffset, std::vector& entries) override; virtual crypto::Hash getBlockIdByHeight(uint32_t height) override; @@ -118,7 +126,6 @@ namespace cn { uint64_t difficultyAtHeight(uint64_t height); void set_cryptonote_protocol(i_cryptonote_protocol *pprotocol); - void set_checkpoints(Checkpoints &&chk_pts); std::vector getPoolTransactions() override; bool getPoolTransaction(const crypto::Hash &tx_hash, Transaction &transaction) override; diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index b493e982..a46051c1 100644 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -1392,6 +1392,7 @@ namespace cn blockIndexesFileName(parameters::CRYPTONOTE_BLOCKINDEXES_FILENAME); txPoolFileName(parameters::CRYPTONOTE_POOLDATA_FILENAME); blockchinIndicesFileName(parameters::CRYPTONOTE_BLOCKCHAIN_INDICES_FILENAME); + checkpointFileName(parameters::CRYPTONOTE_CHECKPOINT_FILENAME); testnet(false); } diff --git a/src/CryptoNoteCore/Currency.h b/src/CryptoNoteCore/Currency.h index a81f91c4..d70b1d40 100644 --- a/src/CryptoNoteCore/Currency.h +++ b/src/CryptoNoteCore/Currency.h @@ -148,6 +148,7 @@ namespace cn const std::string &blockIndexesFileName() const { return m_blockIndexesFileName; } const std::string &txPoolFileName() const { return m_txPoolFileName; } const std::string &blockchinIndicesFileName() const { return m_blockchinIndicesFileName; } + const std::string &checkpointFileName() const { return m_checkpointFileName; } bool isTestnet() const { return m_testnet; } @@ -290,6 +291,7 @@ namespace cn std::string m_blockIndexesFileName; std::string m_txPoolFileName; std::string m_blockchinIndicesFileName; + std::string m_checkpointFileName; static const std::vector REWARD_INCREASING_FACTOR; @@ -634,6 +636,11 @@ namespace cn m_currency.m_blockchinIndicesFileName = val; return *this; } + CurrencyBuilder &checkpointFileName(const std::string &val) + { + m_currency.m_checkpointFileName = val; + return *this; + } CurrencyBuilder &genesisCoinbaseTxHex(const std::string &val) { @@ -694,4 +701,4 @@ namespace cn } }; -} // namespace cn \ No newline at end of file +} // namespace cn diff --git a/src/CryptoNoteCore/ICore.h b/src/CryptoNoteCore/ICore.h index 91b883c1..faeb5ca5 100644 --- a/src/CryptoNoteCore/ICore.h +++ b/src/CryptoNoteCore/ICore.h @@ -27,6 +27,7 @@ struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response; struct NOTIFY_RESPONSE_GET_OBJECTS_request; struct NOTIFY_REQUEST_GET_OBJECTS_request; +class CheckpointList; class Currency; class IBlock; class ICoreObserver; @@ -65,6 +66,7 @@ class ICore { virtual void on_synchronized() = 0; virtual size_t addChain(const std::vector& chain) = 0; + virtual CheckpointList& getCheckpointList() = 0; virtual void get_blockchain_top(uint32_t& height, crypto::Hash& top_id) = 0; virtual std::vector findBlockchainSupplement(const std::vector& remoteBlockIds, size_t maxCount, uint32_t& totalBlockCount, uint32_t& startBlockIndex) = 0; @@ -83,6 +85,7 @@ class ICore { std::vector& deletedTxsIds) = 0; virtual bool queryBlocks(const std::vector& block_ids, uint64_t timestamp, uint32_t& start_height, uint32_t& current_height, uint32_t& full_offset, std::vector& entries) = 0; + virtual std::vector getBlockIds(uint32_t start_height, uint32_t end_height) = 0; virtual bool queryBlocksLite(const std::vector& block_ids, uint64_t timestamp, uint32_t& start_height, uint32_t& current_height, uint32_t& full_offset, std::vector& entries) = 0; diff --git a/src/CryptoNoteProtocol/CryptoNoteProtocolDefinitions.h b/src/CryptoNoteProtocol/CryptoNoteProtocolDefinitions.h index b9f62611..77244e9d 100644 --- a/src/CryptoNoteProtocol/CryptoNoteProtocolDefinitions.h +++ b/src/CryptoNoteProtocol/CryptoNoteProtocolDefinitions.h @@ -225,6 +225,9 @@ namespace cn typedef NOTIFY_NEW_LITE_BLOCK_request request; }; + /************************************************************************/ + /* */ + /************************************************************************/ struct NOTIFY_MISSING_TXS_request { crypto::Hash blockHash; @@ -244,5 +247,46 @@ namespace cn const static int ID = BC_COMMANDS_POOL_BASE + 10; typedef NOTIFY_MISSING_TXS_request request; }; + + /************************************************************************/ + /* */ + /************************************************************************/ + struct NOTIFY_REQUEST_CHECKPOINT_LIST_request + { + crypto::Hash target_hash; + uint32_t start_height; + uint32_t end_height; + + void serialize(ISerializer &s) + { + KV_MEMBER(target_hash) + KV_MEMBER(start_height) + KV_MEMBER(end_height) + } + }; + + struct NOTIFY_REQUEST_CHECKPOINT_LIST + { + const static int ID = BC_COMMANDS_POOL_BASE + 11; + typedef NOTIFY_REQUEST_CHECKPOINT_LIST_request request; + }; + + struct NOTIFY_RESPONSE_CHECKPOINT_LIST_request + { + uint32_t list_start_height; + std::vector checkpoint_list; + + void serialize(ISerializer &s) + { + KV_MEMBER(list_start_height) + serializeAsBinary(checkpoint_list, "checkpoint_list", s); + } + }; + + struct NOTIFY_RESPONSE_CHECKPOINT_LIST + { + const static int ID = BC_COMMANDS_POOL_BASE + 12; + typedef NOTIFY_RESPONSE_CHECKPOINT_LIST_request request; + }; } // namespace cn diff --git a/src/CryptoNoteProtocol/CryptoNoteProtocolHandler.cpp b/src/CryptoNoteProtocol/CryptoNoteProtocolHandler.cpp index beea9661..c3c17156 100644 --- a/src/CryptoNoteProtocol/CryptoNoteProtocolHandler.cpp +++ b/src/CryptoNoteProtocol/CryptoNoteProtocolHandler.cpp @@ -20,6 +20,7 @@ #include "CryptoNoteCore/Currency.h" #include "CryptoNoteCore/VerificationContext.h" #include "P2p/LevinProtocol.h" +#include "CryptoNoteCore/CheckpointList.h" using namespace logging; using namespace common; @@ -50,6 +51,7 @@ CryptoNoteProtocolHandler::CryptoNoteProtocolHandler(const Currency ¤cy, p m_core(rcore), m_synchronized(false), m_stop(false), + m_last_checkpoint_req(0), m_observedHeight(0), m_peersCount(0), logger(log, "protocol"), @@ -193,10 +195,10 @@ bool CryptoNoteProtocolHandler::process_payload_sync_data(const CORE_SYNC_DATA & { int64_t diff = static_cast(hshd.current_height) - static_cast(get_current_blockchain_height()); - logger(diff >= 0 ? (is_inital ? logging::INFO : DEBUGGING) : logging::TRACE) << context << "Unknown top block: " << get_current_blockchain_height() << " -> " << hshd.current_height - << std::endl - - << "Synchronization started"; + logger(diff >= 0 ? (is_inital ? logging::INFO : DEBUGGING) : logging::TRACE) << context + << "Unknown top block: " << get_current_blockchain_height() << " -> " << hshd.current_height + << std::endl + << "Synchronization started"; logger(DEBUGGING) << "Remote top block height: " << hshd.current_height << ", id: " << hshd.top_id; //let the socket to send response to handshake, but request callback, to let send request data after response @@ -213,6 +215,29 @@ bool CryptoNoteProtocolHandler::process_payload_sync_data(const CORE_SYNC_DATA & m_observerManager.notify(&ICryptoNoteProtocolObserver::peerCountUpdated, m_peersCount.load()); } + if (context.version < cn::P2P_CHECKPOINT_LIST_VERSION || context.m_checkpoints_not_in_sync || context.m_active_checkpoint_req) + return true; + + uint64_t time_now = time(nullptr); + uint64_t last_request = time_now - m_last_checkpoint_req.load(); + if (last_request > P2P_CHECKPOINT_LIST_RE_REQUEST) + return true; + + auto cl_status = m_core.getCheckpointList().get_incomplete_checkpoint_target(); + if ( cl_status.target_hash != NULL_HASH ) + { + NOTIFY_REQUEST_CHECKPOINT_LIST::request req = boost::value_initialized(); + req.target_hash = cl_status.target_hash; + req.start_height = cl_status.start_height; + req.end_height = cl_status.end_height; + + if (!post_notify(*m_p2p, req, context)) + return false; + + m_last_checkpoint_req = time_now; + context.m_active_checkpoint_req = true; + } + return true; } @@ -259,6 +284,8 @@ int CryptoNoteProtocolHandler::handleCommand(bool is_notify, int command, const HANDLE_NOTIFY(NOTIFY_NEW_TRANSACTIONS, &CryptoNoteProtocolHandler::handle_notify_new_transactions) HANDLE_NOTIFY(NOTIFY_REQUEST_GET_OBJECTS, &CryptoNoteProtocolHandler::handle_request_get_objects) HANDLE_NOTIFY(NOTIFY_RESPONSE_GET_OBJECTS, &CryptoNoteProtocolHandler::handle_response_get_objects) + HANDLE_NOTIFY(NOTIFY_REQUEST_CHECKPOINT_LIST, &CryptoNoteProtocolHandler::handle_request_checkpoint_list) + HANDLE_NOTIFY(NOTIFY_RESPONSE_CHECKPOINT_LIST, &CryptoNoteProtocolHandler::handle_response_checkpoint_list) HANDLE_NOTIFY(NOTIFY_REQUEST_CHAIN, &CryptoNoteProtocolHandler::handle_request_chain) HANDLE_NOTIFY(NOTIFY_RESPONSE_CHAIN_ENTRY, &CryptoNoteProtocolHandler::handle_response_chain_entry) HANDLE_NOTIFY(NOTIFY_REQUEST_TX_POOL, &CryptoNoteProtocolHandler::handle_request_tx_pool) @@ -1121,4 +1148,46 @@ int CryptoNoteProtocolHandler::doPushLiteBlock(NOTIFY_NEW_LITE_BLOCK::request ar return 1; } +int CryptoNoteProtocolHandler::handle_request_checkpoint_list(int command, NOTIFY_REQUEST_CHECKPOINT_LIST::request& arg, CryptoNoteConnectionContext& context) +{ + NOTIFY_RESPONSE_CHECKPOINT_LIST::request rsp; + rsp.list_start_height = arg.start_height; + rsp.checkpoint_list = m_core.getBlockIds(arg.start_height, arg.end_height); + + crypto::Hash hv = crypto::cn_fast_hash(rsp.checkpoint_list.data(), rsp.checkpoint_list.size() * sizeof(crypto::Hash)); + if ( hv != arg.target_hash || rsp.checkpoint_list.size() == 0) + { + logger(logging::ERROR) << context << " peer requested different hash for start_height " << arg.start_height + << " end_height " << arg.end_height << " checkpoint list size " << rsp.checkpoint_list.size() + << " I have hash " << hv << " peer wants " << arg.target_hash; + + rsp.checkpoint_list.clear(); + rsp.list_start_height = 0; + context.m_checkpoints_not_in_sync = true; + } + + if (!post_notify(*m_p2p, rsp, context)) + context.m_state = CryptoNoteConnectionContext::state_shutdown; + return 1; +} + +int CryptoNoteProtocolHandler::handle_response_checkpoint_list(int command, NOTIFY_RESPONSE_CHECKPOINT_LIST::request& arg, CryptoNoteConnectionContext& context) +{ + if( !context.m_active_checkpoint_req ) + { + context.m_state = CryptoNoteConnectionContext::state_shutdown; + return 1; + } + + m_last_checkpoint_req = 0; + context.m_active_checkpoint_req = false; + + if( arg.checkpoint_list.size() == 0 || !m_core.getCheckpointList().add_checkpoint_list(arg.list_start_height, arg.checkpoint_list) ) + { + context.m_checkpoints_not_in_sync = true; + } + + return 1; +} + }; // namespace cn diff --git a/src/CryptoNoteProtocol/CryptoNoteProtocolHandler.h b/src/CryptoNoteProtocol/CryptoNoteProtocolHandler.h index ccb1d1bf..7788817e 100644 --- a/src/CryptoNoteProtocol/CryptoNoteProtocolHandler.h +++ b/src/CryptoNoteProtocol/CryptoNoteProtocolHandler.h @@ -80,6 +80,8 @@ namespace cn int handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request& arg, CryptoNoteConnectionContext& context); int handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, CryptoNoteConnectionContext& context); int handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, CryptoNoteConnectionContext& context); + int handle_request_checkpoint_list(int command, NOTIFY_REQUEST_CHECKPOINT_LIST::request& arg, CryptoNoteConnectionContext& context); + int handle_response_checkpoint_list(int command, NOTIFY_RESPONSE_CHECKPOINT_LIST::request& arg, CryptoNoteConnectionContext& context); int handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, CryptoNoteConnectionContext& context); int handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, CryptoNoteConnectionContext& context); int handle_request_tx_pool(int command, NOTIFY_REQUEST_TX_POOL::request &arg, CryptoNoteConnectionContext &context); @@ -111,7 +113,9 @@ namespace cn IP2pEndpoint* m_p2p; std::atomic m_synchronized; std::atomic m_stop; - std::recursive_mutex m_sync_lock; + std::recursive_mutex m_sync_lock; + + std::atomic m_last_checkpoint_req; mutable std::mutex m_observedHeightMutex; uint32_t m_observedHeight; diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp index d805957a..ef7387e2 100644 --- a/src/Daemon/Daemon.cpp +++ b/src/Daemon/Daemon.cpp @@ -17,7 +17,7 @@ #include "Common/PathTools.h" #include "crypto/hash.h" #include "CryptoNoteConfig.h" -#include "CryptoNoteCore/Checkpoints.h" +#include "CryptoNoteCore/CheckpointList.h" #include "CryptoNoteCore/Core.h" #include "CryptoNoteCore/CoreConfig.h" #include "CryptoNoteCore/CryptoNoteTools.h" @@ -226,12 +226,6 @@ int main(int argc, char* argv[]) cn::Currency currency = currencyBuilder.currency(); cn::core ccore(currency, nullptr, logManager, vm["enable-blockchain-indexes"].as(), vm["enable-autosave"].as()); - cn::Checkpoints checkpoints(logManager); - checkpoints.set_testnet(coreConfig.testnet); - checkpoints.load_checkpoints(); - checkpoints.load_checkpoints_from_dns(); - ccore.set_checkpoints(std::move(checkpoints)); - NetNodeConfig netNodeConfig; netNodeConfig.init(vm); netNodeConfig.setTestnet(coreConfig.testnet); diff --git a/src/P2p/ConnectionContext.h b/src/P2p/ConnectionContext.h index 7ac24e29..fa4f3d76 100644 --- a/src/P2p/ConnectionContext.h +++ b/src/P2p/ConnectionContext.h @@ -27,6 +27,8 @@ struct CryptoNoteConnectionContext { uint32_t m_remote_port = 0; bool m_is_income = false; time_t m_started = 0; + bool m_checkpoints_not_in_sync = false; + bool m_active_checkpoint_req = false; enum state { state_befor_handshake = 0, //default state