From c53036bd3fe4af53aa231f9e66045c3be583ed3e Mon Sep 17 00:00:00 2001 From: SChernykh <15806605+SChernykh@users.noreply.github.com> Date: Fri, 10 May 2024 15:20:27 +0200 Subject: [PATCH] Added `path` bitmap to `get_merkle_proof` --- src/block_template.cpp | 8 ++++---- src/block_template.h | 2 +- src/merge_mining_client.h | 2 +- src/merge_mining_client_json_rpc.cpp | 2 +- src/merge_mining_client_json_rpc.h | 2 +- src/merge_mining_client_tari.cpp | 2 +- src/merge_mining_client_tari.h | 2 +- src/merkle.cpp | 26 +++++++++++++++++++++++++- src/merkle.h | 4 +++- src/p2pool.cpp | 5 +++-- src/pool_block.cpp | 3 +++ src/pool_block.h | 1 + tests/src/merkle_tests.cpp | 5 ++++- 13 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/block_template.cpp b/src/block_template.cpp index 49d29579..6f614bd3 100644 --- a/src/block_template.cpp +++ b/src/block_template.cpp @@ -1303,14 +1303,14 @@ std::vector BlockTemplate::get_aux_chains(const uint32_t template_ return m_poolBlockTemplate->m_auxChains; } -bool BlockTemplate::get_aux_proof(const uint32_t template_id, uint32_t extra_nonce, const hash& h, std::vector& proof) const +bool BlockTemplate::get_aux_proof(const uint32_t template_id, uint32_t extra_nonce, const hash& h, std::vector& proof, uint32_t& path) const { ReadLock lock(m_lock); if (template_id != m_templateId) { const BlockTemplate* old = m_oldTemplates[template_id % array_size(&BlockTemplate::m_oldTemplates)]; if (old && (template_id == old->m_templateId)) { - return old->get_aux_proof(template_id, extra_nonce, h, proof); + return old->get_aux_proof(template_id, extra_nonce, h, proof, path); } return false; @@ -1346,7 +1346,7 @@ bool BlockTemplate::get_aux_proof(const uint32_t template_id, uint32_t extra_non std::vector> tree; merkle_hash_full_tree(hashes, tree); - return get_merkle_proof(tree, h, proof); + return get_merkle_proof(tree, h, proof, path); } std::vector BlockTemplate::get_block_template_blob(uint32_t template_id, uint32_t sidechain_extra_nonce, size_t& nonce_offset, size_t& extra_nonce_offset, size_t& merkle_root_offset, hash& merge_mining_root, const BlockTemplate** pThis) const @@ -1489,7 +1489,7 @@ void BlockTemplate::init_merge_mining_merkle_proof() std::vector> tree; merkle_hash_full_tree(hashes, tree); - get_merkle_proof(tree, m_poolBlockTemplate->m_sidechainId, m_poolBlockTemplate->m_merkleProof); + get_merkle_proof(tree, m_poolBlockTemplate->m_sidechainId, m_poolBlockTemplate->m_merkleProof, m_poolBlockTemplate->m_merkleProofPath); } } // namespace p2pool diff --git a/src/block_template.h b/src/block_template.h index ed816ed4..f519d162 100644 --- a/src/block_template.h +++ b/src/block_template.h @@ -49,7 +49,7 @@ class BlockTemplate uint32_t get_hashing_blobs(uint32_t extra_nonce_start, uint32_t count, std::vector& blobs, uint64_t& height, difficulty_type& difficulty, difficulty_type& aux_diff, difficulty_type& sidechain_difficulty, hash& seed_hash, size_t& nonce_offset, uint32_t& template_id) const; std::vector get_aux_chains(const uint32_t template_id) const; - bool get_aux_proof(const uint32_t template_id, uint32_t extra_nonce, const hash& h, std::vector& proof) const; + bool get_aux_proof(const uint32_t template_id, uint32_t extra_nonce, const hash& h, std::vector& proof, uint32_t& path) const; std::vector get_block_template_blob(uint32_t template_id, uint32_t sidechain_extra_nonce, size_t& nonce_offset, size_t& extra_nonce_offset, size_t& merkle_root_offset, hash& merge_mining_root, const BlockTemplate** pThis) const; diff --git a/src/merge_mining_client.h b/src/merge_mining_client.h index 9ab5f20a..e36d2964 100644 --- a/src/merge_mining_client.h +++ b/src/merge_mining_client.h @@ -38,7 +38,7 @@ class IMergeMiningClient virtual ~IMergeMiningClient() {} [[nodiscard]] virtual bool get_params(ChainParameters& out_params) const = 0; - virtual void submit_solution(const BlockTemplate* block_tpl, const uint8_t (&hashing_blob)[128], size_t nonce_offset, const hash& seed_hash, const std::vector& blob, const std::vector& merkle_proof) = 0; + virtual void submit_solution(const BlockTemplate* block_tpl, const uint8_t (&hashing_blob)[128], size_t nonce_offset, const hash& seed_hash, const std::vector& blob, const std::vector& merkle_proof, uint32_t merkle_proof_path) = 0; }; } // namespace p2pool diff --git a/src/merge_mining_client_json_rpc.cpp b/src/merge_mining_client_json_rpc.cpp index 5986daac..e58126b3 100644 --- a/src/merge_mining_client_json_rpc.cpp +++ b/src/merge_mining_client_json_rpc.cpp @@ -283,7 +283,7 @@ bool MergeMiningClientJSON_RPC::parse_merge_mining_get_job(const char* data, siz return true; } -void MergeMiningClientJSON_RPC::submit_solution(const BlockTemplate* /*block_tpl*/, const uint8_t (&/*hashing_blob*/)[128], size_t /*nonce_offset*/, const hash& /*seed_hash*/, const std::vector& blob, const std::vector& merkle_proof) +void MergeMiningClientJSON_RPC::submit_solution(const BlockTemplate* /*block_tpl*/, const uint8_t (&/*hashing_blob*/)[128], size_t /*nonce_offset*/, const hash& /*seed_hash*/, const std::vector& blob, const std::vector& merkle_proof, uint32_t /*merkle_proof_path*/) { ReadLock lock(m_lock); diff --git a/src/merge_mining_client_json_rpc.h b/src/merge_mining_client_json_rpc.h index e114cf79..2f24b54e 100644 --- a/src/merge_mining_client_json_rpc.h +++ b/src/merge_mining_client_json_rpc.h @@ -30,7 +30,7 @@ class MergeMiningClientJSON_RPC : public IMergeMiningClient ~MergeMiningClientJSON_RPC() override; bool get_params(ChainParameters& out_params) const override; - void submit_solution(const BlockTemplate* block_tpl, const uint8_t (&hashing_blob)[128], size_t nonce_offset, const hash& seed_hash, const std::vector& blob, const std::vector& merkle_proof) override; + void submit_solution(const BlockTemplate* block_tpl, const uint8_t (&hashing_blob)[128], size_t nonce_offset, const hash& seed_hash, const std::vector& blob, const std::vector& merkle_proof, uint32_t merkle_proof_path) override; private: static void loop(void* data); diff --git a/src/merge_mining_client_tari.cpp b/src/merge_mining_client_tari.cpp index 15caf9cb..07cbbfa4 100644 --- a/src/merge_mining_client_tari.cpp +++ b/src/merge_mining_client_tari.cpp @@ -125,7 +125,7 @@ bool MergeMiningClientTari::get_params(ChainParameters& out_params) const return true; } -void MergeMiningClientTari::submit_solution(const BlockTemplate* block_tpl, const uint8_t (&hashing_blob)[128], size_t nonce_offset, const hash& seed_hash, const std::vector& blob, const std::vector& /*merkle_proof*/) +void MergeMiningClientTari::submit_solution(const BlockTemplate* block_tpl, const uint8_t (&hashing_blob)[128], size_t nonce_offset, const hash& seed_hash, const std::vector& blob, const std::vector& /*merkle_proof*/, uint32_t /*merkle_proof_path*/) { Block block; { diff --git a/src/merge_mining_client_tari.h b/src/merge_mining_client_tari.h index bf6b4bcc..a626a7f3 100644 --- a/src/merge_mining_client_tari.h +++ b/src/merge_mining_client_tari.h @@ -31,7 +31,7 @@ class MergeMiningClientTari : public IMergeMiningClient, public nocopy_nomove ~MergeMiningClientTari() override; bool get_params(ChainParameters& out_params) const override; - void submit_solution(const BlockTemplate* block_tpl, const uint8_t (&hashing_blob)[128], size_t nonce_offset, const hash& seed_hash, const std::vector& blob, const std::vector& merkle_proof) override; + void submit_solution(const BlockTemplate* block_tpl, const uint8_t (&hashing_blob)[128], size_t nonce_offset, const hash& seed_hash, const std::vector& blob, const std::vector& merkle_proof, uint32_t merkle_proof_path) override; static constexpr char TARI_PREFIX[] = "tari://"; diff --git a/src/merkle.cpp b/src/merkle.cpp index f4175e0c..40628cbb 100644 --- a/src/merkle.cpp +++ b/src/merkle.cpp @@ -117,7 +117,7 @@ void merkle_hash_full_tree(const std::vector& hashes, std::vector>& tree, const hash& h, std::vector& proof) +bool get_merkle_proof(const std::vector>& tree, const hash& h, std::vector& proof, uint32_t& path) { if (tree.empty()) { return false; @@ -137,12 +137,14 @@ bool get_merkle_proof(const std::vector>& tree, const hash& h, } proof.clear(); + path = 0; if (count == 1) { return true; } else if (count == 2) { proof.emplace_back(hashes[index ^ 1]); + path = index & 1; } else { size_t cnt = 1; @@ -158,6 +160,7 @@ bool get_merkle_proof(const std::vector>& tree, const hash& h, return false; } proof.emplace_back(hashes[j]); + path = index & 1; index = (index >> 1) + k; } @@ -169,6 +172,7 @@ bool get_merkle_proof(const std::vector>& tree, const hash& h, return false; } proof.emplace_back(tree[i][j]); + path = (static_cast(path) << 1) | (index & 1); } } @@ -260,6 +264,26 @@ bool verify_merkle_proof(hash h, const std::vector& proof, size_t index, s return get_root_from_proof(h, proof, index, count) == root; } +bool verify_merkle_proof(hash h, const std::vector& proof, uint32_t path, const root_hash& root) +{ + for (size_t d = 0, depth = proof.size(); d < depth; ++d) { + hash tmp[2]; + + if ((path >> (depth - d - 1)) & 1) { + tmp[0] = proof[d]; + tmp[1] = h; + } + else { + tmp[0] = h; + tmp[1] = proof[d]; + } + + keccak(tmp[0].h, HASH_SIZE * 2, h.h); + } + + return h == root; +} + uint32_t get_aux_slot(const hash &id, uint32_t nonce, uint32_t n_aux_chains) { if (n_aux_chains <= 1) { diff --git a/src/merkle.h b/src/merkle.h index 433133ad..1f36c626 100644 --- a/src/merkle.h +++ b/src/merkle.h @@ -22,10 +22,12 @@ namespace p2pool { void merkle_hash(const std::vector& hashes, root_hash& root); void merkle_hash_full_tree(const std::vector& hashes, std::vector>& tree); -bool get_merkle_proof(const std::vector>& tree, const hash& h, std::vector& proof); +bool get_merkle_proof(const std::vector>& tree, const hash& h, std::vector& proof, uint32_t& path); root_hash get_root_from_proof(hash h, const std::vector& proof, size_t index, size_t count); + bool verify_merkle_proof(hash h, const std::vector& proof, size_t index, size_t count, const root_hash& root); +bool verify_merkle_proof(hash h, const std::vector& proof, uint32_t path, const root_hash& root); uint32_t get_aux_slot(const hash &id, uint32_t nonce, uint32_t n_aux_chains); bool find_aux_nonce(const std::vector& aux_id, uint32_t& nonce, uint32_t max_nonce = 0xFFFF); diff --git a/src/p2pool.cpp b/src/p2pool.cpp index d396acd7..a31cbf78 100644 --- a/src/p2pool.cpp +++ b/src/p2pool.cpp @@ -667,8 +667,9 @@ void p2pool::submit_aux_block(const hash& chain_id, uint32_t template_id, uint32 if (chain_id == params.aux_id) { std::vector proof; + uint32_t path; - if (m_blockTemplate->get_aux_proof(template_id, extra_nonce, params.aux_hash, proof)) { + if (m_blockTemplate->get_aux_proof(template_id, extra_nonce, params.aux_hash, proof, path)) { if (pool_block_debug()) { const MinerData data = miner_data(); const uint32_t n_aux_chains = static_cast(data.aux_chains.size() + 1); @@ -679,7 +680,7 @@ void p2pool::submit_aux_block(const hash& chain_id, uint32_t template_id, uint32 } } - c->submit_solution(block_tpl, hashing_blob, nonce_offset, seed_hash, blob, proof); + c->submit_solution(block_tpl, hashing_blob, nonce_offset, seed_hash, blob, proof, path); } else { LOGWARN(3, "submit_aux_block: failed to get merkle proof for chain_id " << chain_id); diff --git a/src/pool_block.cpp b/src/pool_block.cpp index 660991f8..bcdb8c84 100644 --- a/src/pool_block.cpp +++ b/src/pool_block.cpp @@ -48,6 +48,8 @@ PoolBlock::PoolBlock() , m_sidechainHeight(0) , m_difficulty{} , m_cumulativeDifficulty{} + , m_merkleProof{} + , m_merkleProofPath(0) , m_sidechainExtraBuf{} , m_sidechainId{} , m_depth(0) @@ -102,6 +104,7 @@ 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; memcpy(m_sidechainExtraBuf, b.m_sidechainExtraBuf, sizeof(m_sidechainExtraBuf)); m_sidechainId = b.m_sidechainId; m_depth = b.m_depth; diff --git a/src/pool_block.h b/src/pool_block.h index 4b538ede..ca6e90d6 100644 --- a/src/pool_block.h +++ b/src/pool_block.h @@ -134,6 +134,7 @@ struct PoolBlock // Merkle proof for merge mining std::vector m_merkleProof; + uint32_t m_merkleProofPath; // Arbitrary extra data uint32_t m_sidechainExtraBuf[4]; diff --git a/tests/src/merkle_tests.cpp b/tests/src/merkle_tests.cpp index 1e1c0c78..31ce7a2f 100644 --- a/tests/src/merkle_tests.cpp +++ b/tests/src/merkle_tests.cpp @@ -19,6 +19,7 @@ #include "keccak.h" #include "merkle.h" #include "pool_block.h" +#include "keccak.h" #include "gtest/gtest.h" namespace p2pool { @@ -74,9 +75,11 @@ TEST(merkle, tree) for (size_t i = 0, n = hashes.size(); i < n; ++i) { const hash& h = hashes[i]; std::vector proof; + uint32_t path; - ASSERT_TRUE(get_merkle_proof(tree, h, proof)); + ASSERT_TRUE(get_merkle_proof(tree, h, proof, path)); ASSERT_TRUE(verify_merkle_proof(h, proof, i, n, root)); + ASSERT_TRUE(verify_merkle_proof(h, proof, path, root)); } };