Skip to content

Commit

Permalink
Better type checking for Merkle root hashes
Browse files Browse the repository at this point in the history
  • Loading branch information
SChernykh committed Dec 23, 2023
1 parent c4153a9 commit 3c51059
Show file tree
Hide file tree
Showing 10 changed files with 42 additions and 24 deletions.
8 changes: 8 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,16 @@ struct alignas(uint64_t) hash
friend std::istream& operator>>(std::istream& s, hash& d);
};

struct root_hash : public hash
{
FORCEINLINE root_hash() : hash() {}
explicit FORCEINLINE root_hash(const hash& h) : hash(h) {}
};

static_assert(sizeof(hash) == HASH_SIZE, "struct hash has invalid size, check your compiler options");
static_assert(sizeof(root_hash) == HASH_SIZE, "struct root_hash has invalid size, check your compiler options");
static_assert(std::is_standard_layout<hash>::value, "struct hash is not a POD, check your compiler options");
static_assert(std::is_standard_layout<root_hash>::value, "struct root_hash is not a POD, check your compiler options");

struct
#ifdef __GNUC__
Expand Down
20 changes: 10 additions & 10 deletions src/merkle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@

namespace p2pool {

void merkle_hash(const std::vector<hash>& hashes, hash& root)
void merkle_hash(const std::vector<hash>& hashes, root_hash& root)
{
const size_t count = hashes.size();
const uint8_t* h = hashes[0].h;

if (count == 1) {
root = hashes[0];
root = root_hash(hashes[0]);
}
else if (count == 2) {
keccak(h, HASH_SIZE * 2, root.h);
Expand Down Expand Up @@ -175,21 +175,21 @@ bool get_merkle_proof(const std::vector<std::vector<hash>>& tree, const hash& h,
return true;
}

hash get_root_from_proof(hash h, const std::vector<hash>& proof, size_t index, size_t count)
root_hash get_root_from_proof(hash h, const std::vector<hash>& proof, size_t index, size_t count)
{
if (count == 1) {
return h;
return root_hash(h);
}

if (index >= count) {
return hash();
return root_hash();
}

hash tmp[2];

if (count == 2) {
if (proof.empty()) {
return hash();
return root_hash();
}

if (index & 1) {
Expand All @@ -216,7 +216,7 @@ hash get_root_from_proof(hash h, const std::vector<hash>& proof, size_t index, s
index -= k;

if (proof.empty()) {
return hash();
return root_hash();
}

if (index & 1) {
Expand All @@ -236,7 +236,7 @@ hash get_root_from_proof(hash h, const std::vector<hash>& proof, size_t index, s

for (; cnt >= 2; ++proof_index, index >>= 1, cnt >>= 1) {
if (proof_index >= proof.size()) {
return hash();
return root_hash();
}

if (index & 1) {
Expand All @@ -252,10 +252,10 @@ hash get_root_from_proof(hash h, const std::vector<hash>& proof, size_t index, s
}
}

return h;
return root_hash(h);
}

bool verify_merkle_proof(hash h, const std::vector<hash>& proof, size_t index, size_t count, const hash& root)
bool verify_merkle_proof(hash h, const std::vector<hash>& proof, size_t index, size_t count, const root_hash& root)
{
return get_root_from_proof(h, proof, index, count) == root;
}
Expand Down
6 changes: 3 additions & 3 deletions src/merkle.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@

namespace p2pool {

void merkle_hash(const std::vector<hash>& hashes, hash& root);
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);

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 hash& root);
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);

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);
Expand Down
4 changes: 2 additions & 2 deletions src/p2pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ void p2pool::handle_chain_main(ChainMain& data, const char* extra)
}
update_median_timestamp();

hash merkle_root;
root_hash merkle_root;
if (extra) {
const size_t n = strlen(extra);
if (n >= HASH_SIZE * 2) {
Expand Down Expand Up @@ -610,7 +610,7 @@ void p2pool::submit_aux_block(const hash& chain_id, uint32_t template_id, uint32
size_t nonce_offset = 0;
size_t extra_nonce_offset = 0;
size_t merkle_root_offset = 0;
hash merge_mining_root;
root_hash merge_mining_root;

std::vector<uint8_t> blob = m_blockTemplate->get_block_template_blob(template_id, extra_nonce, nonce_offset, extra_nonce_offset, merkle_root_offset, merge_mining_root);

Expand Down
5 changes: 3 additions & 2 deletions src/pool_block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,9 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const
keccak(reinterpret_cast<uint8_t*>(hashes), HASH_SIZE * 3, tmp.h);
memcpy(h, tmp.h, HASH_SIZE);

merkle_hash(m_transactions, tmp);
memcpy(blob + blob_size, tmp.h, HASH_SIZE);
root_hash tmp_root;
merkle_hash(m_transactions, tmp_root);
memcpy(blob + blob_size, tmp_root.h, HASH_SIZE);
}
blob_size += HASH_SIZE;

Expand Down
2 changes: 1 addition & 1 deletion src/pool_block.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ struct PoolBlock

uint32_t m_merkleTreeDataSize;
uint64_t m_merkleTreeData;
hash m_merkleRoot;
root_hash m_merkleRoot;

// All block transaction hashes including the miner transaction hash at index 0
std::vector<hash> m_transactions;
Expand Down
6 changes: 3 additions & 3 deletions src/side_chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
, m_poolName(pool_name ? pool_name : "default")
, m_targetBlockTime(10)
, m_minDifficulty(MIN_DIFFICULTY, 0)
, m_chainWindowSize(2160)
, m_chainWindowSize(216)
, m_unclePenalty(20)
, m_precalcFinished(false)
#ifdef DEV_TEST_SYNC
Expand Down Expand Up @@ -735,7 +735,7 @@ PoolBlock* SideChain::find_block(const hash& id) const
return nullptr;
}

PoolBlock* SideChain::find_block_by_merkle_root(const hash& merkle_root) const
PoolBlock* SideChain::find_block_by_merkle_root(const root_hash& merkle_root) const
{
ReadLock lock(m_sidechainLock);

Expand Down Expand Up @@ -2120,7 +2120,7 @@ void SideChain::prune_old_blocks()

auto it3 = m_blocksByMerkleRoot.find(block->m_merkleRoot);
if (it3 != m_blocksByMerkleRoot.end()) {
m_blocksByMerkleRoot.erase(it2);
m_blocksByMerkleRoot.erase(it3);
}
else {
LOGERR(1, "m_blocksByHeight and m_blocksByMerkleRoot are inconsistent at height " << height << ". Fix the code!");
Expand Down
4 changes: 2 additions & 2 deletions src/side_chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class SideChain : public nocopy_nomove
void get_missing_blocks(unordered_set<hash>& missing_blocks) const;

PoolBlock* find_block(const hash& id) const;
PoolBlock* find_block_by_merkle_root(const hash& merkle_root) const;
PoolBlock* find_block_by_merkle_root(const root_hash& merkle_root) const;
void watch_mainchain_block(const ChainMain& data, const hash& possible_merkle_root);

const PoolBlock* get_block_blob(const hash& id, std::vector<uint8_t>& blob) const;
Expand Down Expand Up @@ -118,7 +118,7 @@ class SideChain : public nocopy_nomove
std::atomic<PoolBlock*> m_chainTip;
std::map<uint64_t, std::vector<PoolBlock*>> m_blocksByHeight;
unordered_map<hash, PoolBlock*> m_blocksById;
unordered_map<hash, PoolBlock*> m_blocksByMerkleRoot;
unordered_map<root_hash, PoolBlock*> m_blocksByMerkleRoot;

uv_mutex_t m_seenWalletsLock;
unordered_map<hash, uint64_t> m_seenWallets;
Expand Down
9 changes: 9 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,15 @@ struct hash<p2pool::hash>
}
};

template<>
struct hash<p2pool::root_hash>
{
FORCEINLINE size_t operator()(const p2pool::root_hash& value) const noexcept
{
return hash_bytes(value.h, p2pool::HASH_SIZE);
}
};

template<size_t N>
struct hash<std::array<uint8_t, N>>
{
Expand Down
2 changes: 1 addition & 1 deletion tests/src/merkle_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ TEST(merkle, tree)
keccak(data, sizeof(data) - 1, input[i].h);
}

hash root;
root_hash root;
std::vector<hash> hashes(1, input[0]);

auto check_full_tree = [&hashes, &root]() {
Expand Down

0 comments on commit 3c51059

Please sign in to comment.