Added `path` bitmap to `get_merkle_proof`

merge-mining
SChernykh 2024-05-10 15:20:27 +02:00
parent e986e5dc2e
commit f67009f133
13 changed files with 53 additions and 16 deletions

View File

@ -1303,14 +1303,14 @@ std::vector<AuxChainData> 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<hash>& proof) const
bool BlockTemplate::get_aux_proof(const uint32_t template_id, uint32_t extra_nonce, const hash& h, std::vector<hash>& 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<std::vector<hash>> tree;
merkle_hash_full_tree(hashes, tree);
return get_merkle_proof(tree, h, proof);
return get_merkle_proof(tree, h, proof, path);
}
std::vector<uint8_t> 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<std::vector<hash>> 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

View File

@ -49,7 +49,7 @@ public:
uint32_t get_hashing_blobs(uint32_t extra_nonce_start, uint32_t count, std::vector<uint8_t>& 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<AuxChainData> 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<hash>& proof) const;
bool get_aux_proof(const uint32_t template_id, uint32_t extra_nonce, const hash& h, std::vector<hash>& proof, uint32_t& path) const;
std::vector<uint8_t> 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;

View File

@ -38,7 +38,7 @@ public:
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<uint8_t>& blob, const std::vector<hash>& 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<uint8_t>& blob, const std::vector<hash>& merkle_proof, uint32_t merkle_proof_path) = 0;
};
} // namespace p2pool

View File

@ -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<uint8_t>& blob, const std::vector<hash>& 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<uint8_t>& blob, const std::vector<hash>& merkle_proof, uint32_t /*merkle_proof_path*/)
{
ReadLock lock(m_lock);

View File

@ -30,7 +30,7 @@ public:
~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<uint8_t>& blob, const std::vector<hash>& 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<uint8_t>& blob, const std::vector<hash>& merkle_proof, uint32_t merkle_proof_path) override;
private:
static void loop(void* data);

View File

@ -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<uint8_t>& blob, const std::vector<hash>& /*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<uint8_t>& blob, const std::vector<hash>& /*merkle_proof*/, uint32_t /*merkle_proof_path*/)
{
Block block;
{

View File

@ -31,7 +31,7 @@ public:
~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<uint8_t>& blob, const std::vector<hash>& 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<uint8_t>& blob, const std::vector<hash>& merkle_proof, uint32_t merkle_proof_path) override;
static constexpr char TARI_PREFIX[] = "tari://";

View File

@ -117,7 +117,7 @@ void merkle_hash_full_tree(const std::vector<hash>& hashes, std::vector<std::vec
}
}
bool get_merkle_proof(const std::vector<std::vector<hash>>& tree, const hash& h, std::vector<hash>& proof)
bool get_merkle_proof(const std::vector<std::vector<hash>>& tree, const hash& h, std::vector<hash>& proof, uint32_t& path)
{
if (tree.empty()) {
return false;
@ -137,12 +137,14 @@ bool get_merkle_proof(const std::vector<std::vector<hash>>& 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<std::vector<hash>>& 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<std::vector<hash>>& tree, const hash& h,
return false;
}
proof.emplace_back(tree[i][j]);
path = (static_cast<uint64_t>(path) << 1) | (index & 1);
}
}
@ -260,6 +264,26 @@ bool verify_merkle_proof(hash h, const std::vector<hash>& proof, size_t index, s
return get_root_from_proof(h, proof, index, count) == root;
}
bool verify_merkle_proof(hash h, const std::vector<hash>& 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) {

View File

@ -22,10 +22,12 @@ namespace p2pool {
void merkle_hash(const std::vector<hash>& hashes, root_hash& root);
void merkle_hash_full_tree(const std::vector<hash>& hashes, std::vector<std::vector<hash>>& tree);
bool get_merkle_proof(const std::vector<std::vector<hash>>& tree, const hash& h, std::vector<hash>& proof);
bool get_merkle_proof(const std::vector<std::vector<hash>>& tree, const hash& h, std::vector<hash>& proof, uint32_t& path);
root_hash get_root_from_proof(hash h, const std::vector<hash>& proof, size_t index, size_t count);
bool verify_merkle_proof(hash h, const std::vector<hash>& proof, size_t index, size_t count, const root_hash& root);
bool verify_merkle_proof(hash h, const std::vector<hash>& 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<hash>& aux_id, uint32_t& nonce, uint32_t max_nonce = 0xFFFF);

View File

@ -667,19 +667,23 @@ void p2pool::submit_aux_block(const hash& chain_id, uint32_t template_id, uint32
if (chain_id == params.aux_id) {
std::vector<hash> 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<uint32_t>(data.aux_chains.size() + 1);
const uint32_t index = get_aux_slot(params.aux_id, data.aux_nonce, n_aux_chains);
if (!verify_merkle_proof(params.aux_hash, proof, index, n_aux_chains, merge_mining_root)) {
LOGERR(0, "submit_aux_block: verify_merkle_proof failed for chain_id " << chain_id);
LOGERR(0, "submit_aux_block: verify_merkle_proof (1) failed for chain_id " << chain_id);
}
if (!verify_merkle_proof(params.aux_hash, proof, path, merge_mining_root)) {
LOGERR(0, "submit_aux_block: verify_merkle_proof (2) failed for chain_id " << chain_id);
}
}
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);

View File

@ -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;

View File

@ -134,6 +134,7 @@ struct PoolBlock
// Merkle proof for merge mining
std::vector<hash> m_merkleProof;
uint32_t m_merkleProofPath;
// Arbitrary extra data
uint32_t m_sidechainExtraBuf[4];

View File

@ -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<hash> 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));
}
};