From fa53bdea553a2c01eb4afe8df96662255bf2d278 Mon Sep 17 00:00:00 2001 From: SChernykh <15806605+SChernykh@users.noreply.github.com> Date: Fri, 24 Apr 2026 17:51:08 +0200 Subject: [PATCH] More fixes and refactoring --- src/block_template.cpp | 5 +++-- src/merge_mining_client.cpp | 8 ++++---- src/merge_mining_client_json_rpc.cpp | 7 +++++++ src/merge_mining_client_tari.cpp | 15 ++++++++++++--- src/pool_block.cpp | 4 +--- src/pool_block.h | 4 +++- src/pool_block_parser.inl | 25 ++++++++++++++++--------- tests/src/hash_tests.cpp | 5 +++++ 8 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/block_template.cpp b/src/block_template.cpp index fa1eddf..603e776 100644 --- a/src/block_template.cpp +++ b/src/block_template.cpp @@ -1560,7 +1560,8 @@ void BlockTemplate::init_merge_mining_merkle_proof() } root_hash root; - if (!merkle_hash_with_proof(hashes, aux_slot, m_poolBlockTemplate->m_merkleProof, m_poolBlockTemplate->m_merkleProofPath, root)) { + uint32_t merkle_proof_path; + if (!merkle_hash_with_proof(hashes, aux_slot, m_poolBlockTemplate->m_merkleProof, merkle_proof_path, root)) { LOGERR(1, "init_merge_mining_merkle_proof: merkle_hash_with_proof failed. Fix the code!"); return; } @@ -1577,7 +1578,7 @@ void BlockTemplate::init_merge_mining_merkle_proof() return; } - if ((proof != m_poolBlockTemplate->m_merkleProof) || (path != m_poolBlockTemplate->m_merkleProofPath)) { + if ((proof != m_poolBlockTemplate->m_merkleProof) || (path != merkle_proof_path)) { LOGERR(1, "init_merge_mining_merkle_proof: merkle_hash_with_proof and get_merkle_proof returned different results. Fix the code!"); } } diff --git a/src/merge_mining_client.cpp b/src/merge_mining_client.cpp index ff83526..55ef592 100644 --- a/src/merge_mining_client.cpp +++ b/src/merge_mining_client.cpp @@ -125,14 +125,14 @@ void MergeMiningClientShared::on_external_block(const PoolBlock& block) { const std::vector& v = i.second; - const uint8_t* p = v.data(); - const uint8_t* e = v.data() + v.size(); - - if (p + HASH_SIZE > e) { + if (v.size() < HASH_SIZE) { LOGWARN(3, "on_external_block: sanity check failed - invalid merge mining extra data " << '1'); return; } + const uint8_t* p = v.data(); + const uint8_t* e = v.data() + v.size(); + memcpy(data.h, p, HASH_SIZE); p += HASH_SIZE; diff --git a/src/merge_mining_client_json_rpc.cpp b/src/merge_mining_client_json_rpc.cpp index d0491fd..a9fdfe7 100644 --- a/src/merge_mining_client_json_rpc.cpp +++ b/src/merge_mining_client_json_rpc.cpp @@ -41,6 +41,13 @@ MergeMiningClientJSON_RPC::MergeMiningClientJSON_RPC(p2pool* pool, const std::st const size_t k = host.find_last_of(':'); if (k != std::string::npos) { m_host = host.substr(0, k); + + // Handle IPv6 addresses + if ((m_host.length() > 2) && (m_host.find_first_of(':') != std::string::npos) && (m_host.front() == '[') && (m_host.back() == ']')) { + m_host.erase(m_host.begin()); + m_host.pop_back(); + } + m_port = static_cast(std::stol(host.substr(k + 1), nullptr, 10)); } diff --git a/src/merge_mining_client_tari.cpp b/src/merge_mining_client_tari.cpp index dc2e00c..7a9ace4 100644 --- a/src/merge_mining_client_tari.cpp +++ b/src/merge_mining_client_tari.cpp @@ -94,15 +94,15 @@ MergeMiningClientTari::MergeMiningClientTari(p2pool* pool, std::string host, con uv_mutex_init_checked(&m_workerLock); uv_cond_init_checked(&m_workerCond); + uv_mutex_init_checked(&m_pushBlockLock); + uv_cond_init_checked(&m_pushBlockCond); + int err = uv_thread_create(&m_worker, run_wrapper, this); if (err) { LOGERR(1, "failed to start worker thread, error " << uv_err_name(err)); throw std::exception(); } - uv_mutex_init_checked(&m_pushBlockLock); - uv_cond_init_checked(&m_pushBlockCond); - std::ifstream f("tari_nodes.txt"); if (f.is_open()) { @@ -851,6 +851,8 @@ void MergeMiningClientTari::push_blocks_to(const std::string& node_address) LOGINFO(4, node_address << " is at block height " << tip_info.metadata().best_block_height()); } + std::string prev_header_hash; + while (!m_pushBlockStop) { Block block; { @@ -865,6 +867,13 @@ void MergeMiningClientTari::push_blocks_to(const std::string& node_address) } const std::string& h = block.header().hash(); + + // Don't push the same block twice + if (h == prev_header_hash) { + continue; + } + prev_header_hash = h; + LOGINFO(4, "Pushing block " << log::hex_buf(h.data(), h.size()) << " to " << node_address); grpc::ClientContext ctx; diff --git a/src/pool_block.cpp b/src/pool_block.cpp index ca4cb45..a64bc7c 100644 --- a/src/pool_block.cpp +++ b/src/pool_block.cpp @@ -51,7 +51,6 @@ PoolBlock::PoolBlock() , m_difficulty{} , m_cumulativeDifficulty{} , m_merkleProof{} - , m_merkleProofPath(0) , m_mergeMiningExtra{} , m_sidechainExtraBuf{} , m_sidechainId{} @@ -108,7 +107,6 @@ PoolBlock& PoolBlock::operator=(const PoolBlock& b) m_difficulty = b.m_difficulty; m_cumulativeDifficulty = b.m_cumulativeDifficulty; m_merkleProof = b.m_merkleProof; - m_merkleProofPath = b.m_merkleProofPath; m_mergeMiningExtra = b.m_mergeMiningExtra; memcpy(m_sidechainExtraBuf, b.m_sidechainExtraBuf, sizeof(m_sidechainExtraBuf)); m_sidechainId = b.m_sidechainId; @@ -200,7 +198,7 @@ std::vector PoolBlock::serialize_mainchain_data(size_t* header_size, si } *(p++) = TX_EXTRA_NONCE; - *(p++) = static_cast(extra_nonce_size); + writeVarint(extra_nonce_size, [&p](uint8_t value) { *(p++) = value; }); if (!extra_nonce) { extra_nonce = &m_extraNonce; diff --git a/src/pool_block.h b/src/pool_block.h index 1048734..ab80969 100644 --- a/src/pool_block.h +++ b/src/pool_block.h @@ -62,6 +62,9 @@ static constexpr difficulty_type MAX_CUMULATIVE_DIFFICULTY{ 13019633956666736640 // 1000 years at 1 block/second. It should be enough for any normal use. static constexpr uint64_t MAX_SIDECHAIN_HEIGHT = 31556952000ULL; +// Taken from Monero's cryptonote_config.h +static constexpr uint64_t CRYPTONOTE_MAX_BLOCK_NUMBER = 500000000ULL; + // Limited by the format of the Merkle tree parameters in tx_extra static constexpr uint64_t MERGE_MINING_MAX_CHAINS = 256; static constexpr uint64_t LOG2_MERGE_MINING_MAX_CHAINS = 8; @@ -140,7 +143,6 @@ struct PoolBlock // Merkle proof for merge mining std::vector m_merkleProof; - uint32_t m_merkleProofPath; // Merge mining extra data // diff --git a/src/pool_block_parser.inl b/src/pool_block_parser.inl index b58a49c..56e5255 100644 --- a/src/pool_block_parser.inl +++ b/src/pool_block_parser.inl @@ -79,11 +79,13 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si uint64_t unlock_height; READ_VARINT(unlock_height); + if (unlock_height > CRYPTONOTE_MAX_BLOCK_NUMBER) return __LINE__; EXPECT_BYTE(1); EXPECT_BYTE(TXIN_GEN); READ_VARINT(m_txinGenHeight); + if (m_txinGenHeight > CRYPTONOTE_MAX_BLOCK_NUMBER) return __LINE__; if (m_majorVersion != sidechain.network_major_version(m_txinGenHeight)) return __LINE__; if (unlock_height != m_txinGenHeight + MINER_REWARD_UNLOCK_TIME) return __LINE__; @@ -99,8 +101,8 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si if (num_outputs > 0) { // Outputs are in the buffer, just read them // Each output is at least 34 bytes, exit early if there's not enough data left - // 1 byte for reward, 1 byte for tx_type, 32 bytes for eph_pub_key - constexpr uint64_t MIN_OUTPUT_SIZE = 34; + // 1 byte for reward, 1 byte for tx_type, 32 bytes for eph_pub_key, 1 byte for view_tag + constexpr uint64_t MIN_OUTPUT_SIZE = 35; if (num_outputs > std::numeric_limits::max() / MIN_OUTPUT_SIZE) return __LINE__; if (static_cast(data_end - data) < num_outputs * MIN_OUTPUT_SIZE) return __LINE__; @@ -123,6 +125,8 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si } t.m_reward = reward; + + if (total_reward + reward < total_reward) return __LINE__; total_reward += reward; EXPECT_BYTE(TXOUT_TO_TAGGED_KEY); @@ -269,6 +273,12 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si const int transactions_blob_size = static_cast(num_transactions) * HASH_SIZE; const int transactions_blob_size_diff = transactions_blob_size - transactions_actual_blob_size; + const int data_size = static_cast((data_end - data_begin) + outputs_blob_size_diff + transactions_blob_size_diff); + + if (data_size > static_cast(MAX_BLOCK_SIZE)) { + return __LINE__; + } + #if POOL_BLOCK_DEBUG m_mainChainDataDebug.reserve((data - data_begin) + outputs_blob_size_diff + transactions_blob_size_diff); m_mainChainDataDebug.assign(data_begin, data_begin + outputs_offset); @@ -413,9 +423,11 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si if (static_cast(data_end - data) < n) return __LINE__; std::vector t; - t.resize(n); - READ_BUF(t.data(), n); + if (n > 0) { + t.resize(n); + READ_BUF(t.data(), n); + } m_mergeMiningExtra.emplace(chain_id, std::move(t)); } @@ -449,11 +461,6 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si hash check; const std::vector& consensus_id = sidechain.consensus_id(); - const int data_size = static_cast((data_end - data_begin) + outputs_blob_size_diff + transactions_blob_size_diff); - - if (data_size > static_cast(MAX_BLOCK_SIZE)) { - return __LINE__; - } keccak_custom( [nonce_offset, extra_nonce_offset, mm_root_hash_offset, data_begin, data_size, &consensus_id, &outputs_blob, outputs_blob_size_diff, outputs_offset, outputs_blob_size, transactions_blob, transactions_blob_size_diff, transactions_offset, transactions_blob_size](int offset) -> uint8_t diff --git a/tests/src/hash_tests.cpp b/tests/src/hash_tests.cpp index 6079ee0..55646d7 100644 --- a/tests/src/hash_tests.cpp +++ b/tests/src/hash_tests.cpp @@ -38,6 +38,11 @@ TEST(hash, constructor) for (uint8_t i = 0; i < HASH_SIZE; ++i) { ASSERT_EQ(h2.h[i], i); } + + hash h3{ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F" }; + for (uint8_t i = 0; i < HASH_SIZE; ++i) { + ASSERT_EQ(h3.h[i], i); + } } TEST(hash, compare)