From 32dc235aa5b2fa0de3fa2e7a7cc5ff84d134f521 Mon Sep 17 00:00:00 2001 From: SChernykh Date: Wed, 12 Jul 2023 00:25:37 +0200 Subject: [PATCH] SideChain: fix for out of order blocks --- src/side_chain.cpp | 32 ++++++++++++++++++++++++++++++- src/side_chain.h | 1 + tests/src/main.cpp | 2 ++ tests/src/pool_block_tests.cpp | 35 ++++++++++++++++++++++++++++------ 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/side_chain.cpp b/src/side_chain.cpp index cb6a05c..b492300 100644 --- a/src/side_chain.cpp +++ b/src/side_chain.cpp @@ -1762,7 +1762,7 @@ void SideChain::update_chain_tip(const PoolBlock* block) " is not a longer chain than " << tip->m_sidechainId << ", height " << tip->m_sidechainHeight); } - else if (block->m_sidechainHeight + UNCLE_BLOCK_DEPTH > tip->m_sidechainHeight) { + else if (m_pool && (block->m_sidechainHeight + UNCLE_BLOCK_DEPTH > tip->m_sidechainHeight)) { LOGINFO(4, "possible uncle block: id = " << log::Gray() << block->m_sidechainId << log::NoColor() << ", height = " << log::Gray() << block->m_sidechainHeight); m_pool->update_block_template_async(); @@ -1970,6 +1970,36 @@ void SideChain::update_depths(PoolBlock* block) verify_loop(block); } + for (size_t i = 1; i <= UNCLE_BLOCK_DEPTH; ++i) { + auto it = m_blocksByHeight.find(block->m_sidechainHeight + i); + if (it == m_blocksByHeight.end()) { + continue; + } + for (PoolBlock* child : it->second) { + const uint64_t old_depth = child->m_depth; + + if (child->m_parent == block->m_sidechainId) { + if (i != 1) { + LOGWARN(3, "Block " << block->m_sidechainId << ": m_sidechainHeight is inconsistent with child's m_sidechainHeight."); + return; + } + else if (block->m_depth > 0) { + update_depth(child, block->m_depth - 1); + } + } + + if (std::find(child->m_uncles.begin(), child->m_uncles.end(), block->m_sidechainId) != child->m_uncles.end()) { + if (block->m_depth > i) { + update_depth(child, block->m_depth - i); + } + } + + if (child->m_depth > old_depth) { + blocks_to_update.push_back(child); + } + } + } + auto it = m_blocksById.find(block->m_parent); if (it != m_blocksById.end()) { if (it->second->m_sidechainHeight + 1 != block->m_sidechainHeight) { diff --git a/src/side_chain.h b/src/side_chain.h index 8746cdc..e5dc0bb 100644 --- a/src/side_chain.h +++ b/src/side_chain.h @@ -84,6 +84,7 @@ public: #ifdef P2POOL_UNIT_TESTS difficulty_type m_testMainChainDiff; + const unordered_map& blocksById() const { return m_blocksById; } #endif static bool split_reward(uint64_t reward, const std::vector& shares, std::vector& rewards); diff --git a/tests/src/main.cpp b/tests/src/main.cpp index cbe2556..aa42574 100644 --- a/tests/src/main.cpp +++ b/tests/src/main.cpp @@ -18,9 +18,11 @@ #include "gtest/gtest.h" void p2pool_usage() {} +namespace p2pool { void set_main_thread(); } int main(int argc, char** argv) { + p2pool::set_main_thread(); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/tests/src/pool_block_tests.cpp b/tests/src/pool_block_tests.cpp index 345c304..28e416d 100644 --- a/tests/src/pool_block_tests.cpp +++ b/tests/src/pool_block_tests.cpp @@ -130,14 +130,14 @@ TEST(pool_block, verify) const char* m_fileName; uint64_t m_txinGenHeight; uint64_t m_sidechainHeight; + bool m_shuffle; } tests[2] = { - { "default", "sidechain_dump.dat", 2870010, 4957203 }, - { "mini", "sidechain_dump_mini.dat", 2870010, 4414446 }, + { "default", "sidechain_dump.dat", 2870010, 4957203, true }, + { "mini", "sidechain_dump_mini.dat", 2870010, 4414446, false }, }; for (const STest& t : tests) { - PoolBlock b; SideChain sidechain(nullptr, NetworkType::Mainnet, t.m_poolName); // Difficulty of block 2869248 @@ -151,17 +151,40 @@ TEST(pool_block, verify) f.read(reinterpret_cast(buf.data()), buf.size()); ASSERT_EQ(f.good(), true); + std::vector blocks; for (const uint8_t *p = buf.data(), *e = buf.data() + buf.size(); p < e;) { ASSERT_TRUE(p + sizeof(uint32_t) <= e); const uint32_t n = *reinterpret_cast(p); p += sizeof(uint32_t); ASSERT_TRUE(p + n <= e); - ASSERT_EQ(b.deserialize(p, n, sidechain, nullptr, false), 0); + + PoolBlock* b = new PoolBlock(); + ASSERT_EQ(b->deserialize(p, n, sidechain, nullptr, false), 0); p += n; - ASSERT_TRUE(sidechain.add_block(b)); - ASSERT_TRUE(sidechain.find_block(b.m_sidechainId) != nullptr); + blocks.push_back(b); + } + + if (t.m_shuffle) { + std::mt19937_64 rng; + + for (uint64_t i = 0, k, n = blocks.size(); i < n - 1; ++i) { + umul128(rng(), n - i, &k); + std::swap(blocks[i], blocks[i + k]); + } + } + + for (uint64_t i = 0, n = blocks.size(); i < n; ++i) { + ASSERT_TRUE(sidechain.add_block(*blocks[i])); + ASSERT_TRUE(sidechain.find_block(blocks[i]->m_sidechainId) != nullptr); + delete blocks[i]; + } + + for (auto it = sidechain.blocksById().begin(); it != sidechain.blocksById().end(); ++it) { + const PoolBlock* b = it->second; + ASSERT_TRUE(b->m_verified); + ASSERT_FALSE(b->m_invalid); } const PoolBlock* tip = sidechain.chainTip();