From eef90da7ae83654450f160751a2ecea5352f6643 Mon Sep 17 00:00:00 2001 From: SChernykh Date: Fri, 24 Mar 2023 11:50:39 +0100 Subject: [PATCH] SideChain: stricter checks of alternative chains --- src/side_chain.cpp | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/side_chain.cpp b/src/side_chain.cpp index 9deb33b..b78ab05 100644 --- a/src/side_chain.cpp +++ b/src/side_chain.cpp @@ -1776,11 +1776,32 @@ bool SideChain::is_longer_chain(const PoolBlock* block, const PoolBlock* candida uint64_t candidate_mainchain_height = 0; uint64_t candidate_mainchain_min_height = 0; - hash mainchain_prev_id; + + unordered_set current_chain_monero_blocks, candidate_chain_monero_blocks; + { + const uint64_t k = m_chainWindowSize * m_targetBlockTime * 2 / MONERO_BLOCK_TIME; + current_chain_monero_blocks.reserve(k); + candidate_chain_monero_blocks.reserve(k); + } for (uint64_t i = 0; (i < m_chainWindowSize) && (old_chain || new_chain); ++i) { if (old_chain) { block_total_diff += old_chain->m_difficulty; + + for (const hash& uncle : old_chain->m_uncles) { + auto it = m_blocksById.find(uncle); + if (it != m_blocksById.end()) { + block_total_diff += it->second->m_difficulty; + } + } + + ChainMain data; + const hash& h = old_chain->m_prevId; + + if ((current_chain_monero_blocks.count(h) == 0) && m_pool->chainmain_get_by_hash(h, data)) { + current_chain_monero_blocks.insert(h); + } + old_chain = get_parent(old_chain); } @@ -1788,9 +1809,18 @@ bool SideChain::is_longer_chain(const PoolBlock* block, const PoolBlock* candida candidate_mainchain_min_height = candidate_mainchain_min_height ? std::min(candidate_mainchain_min_height, new_chain->m_txinGenHeight) : new_chain->m_txinGenHeight; candidate_total_diff += new_chain->m_difficulty; + for (const hash& uncle : new_chain->m_uncles) { + auto it = m_blocksById.find(uncle); + if (it != m_blocksById.end()) { + candidate_total_diff += it->second->m_difficulty; + } + } + ChainMain data; - if ((new_chain->m_prevId != mainchain_prev_id) && m_pool->chainmain_get_by_hash(new_chain->m_prevId, data)) { - mainchain_prev_id = new_chain->m_prevId; + const hash& h = new_chain->m_prevId; + + if ((candidate_chain_monero_blocks.count(h) == 0) && m_pool->chainmain_get_by_hash(h, data)) { + candidate_chain_monero_blocks.insert(h); candidate_mainchain_height = std::max(candidate_mainchain_height, data.height); } @@ -1802,7 +1832,7 @@ bool SideChain::is_longer_chain(const PoolBlock* block, const PoolBlock* candida return false; } - // Final check: candidate chain must be built on top of recent mainchain blocks + // Candidate chain must be built on top of recent mainchain blocks MinerData data = m_pool->miner_data(); if (candidate_mainchain_height + 10 < data.height) { LOGWARN(3, "received a longer alternative chain but it's stale: height " << candidate_mainchain_height << ", current height " << data.height); @@ -1815,6 +1845,12 @@ bool SideChain::is_longer_chain(const PoolBlock* block, const PoolBlock* candida return false; } + // Candidate chain must have been mined on top of at least half as many known Monero blocks, compared to the current chain + if (candidate_chain_monero_blocks.size() * 2 < current_chain_monero_blocks.size()) { + LOGWARN(3, "received a longer alternative chain but it wasn't mined on current Monero blockchain: only " << candidate_chain_monero_blocks.size() << '/' << current_chain_monero_blocks.size() << " blocks found"); + return false; + } + LOGINFO(3, "received a longer alternative chain: height " << log::Gray() << block->m_sidechainHeight << log::NoColor() << " -> " << log::Gray() << candidate->m_sidechainHeight << log::NoColor() << ", cumulative difficulty " <<