mirror of
https://github.com/SChernykh/p2pool.git
synced 2024-12-22 19:39:22 +00:00
Better type checking for Merkle root hashes
This commit is contained in:
parent
c4153a9a2a
commit
3c510598fa
10 changed files with 42 additions and 24 deletions
|
@ -201,8 +201,16 @@ struct alignas(uint64_t) hash
|
||||||
friend std::istream& operator>>(std::istream& s, hash& d);
|
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(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<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
|
struct
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
|
|
|
@ -23,13 +23,13 @@
|
||||||
|
|
||||||
namespace p2pool {
|
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 size_t count = hashes.size();
|
||||||
const uint8_t* h = hashes[0].h;
|
const uint8_t* h = hashes[0].h;
|
||||||
|
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
root = hashes[0];
|
root = root_hash(hashes[0]);
|
||||||
}
|
}
|
||||||
else if (count == 2) {
|
else if (count == 2) {
|
||||||
keccak(h, HASH_SIZE * 2, root.h);
|
keccak(h, HASH_SIZE * 2, root.h);
|
||||||
|
@ -175,21 +175,21 @@ bool get_merkle_proof(const std::vector<std::vector<hash>>& tree, const hash& h,
|
||||||
return true;
|
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) {
|
if (count == 1) {
|
||||||
return h;
|
return root_hash(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index >= count) {
|
if (index >= count) {
|
||||||
return hash();
|
return root_hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
hash tmp[2];
|
hash tmp[2];
|
||||||
|
|
||||||
if (count == 2) {
|
if (count == 2) {
|
||||||
if (proof.empty()) {
|
if (proof.empty()) {
|
||||||
return hash();
|
return root_hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index & 1) {
|
if (index & 1) {
|
||||||
|
@ -216,7 +216,7 @@ hash get_root_from_proof(hash h, const std::vector<hash>& proof, size_t index, s
|
||||||
index -= k;
|
index -= k;
|
||||||
|
|
||||||
if (proof.empty()) {
|
if (proof.empty()) {
|
||||||
return hash();
|
return root_hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index & 1) {
|
if (index & 1) {
|
||||||
|
@ -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) {
|
for (; cnt >= 2; ++proof_index, index >>= 1, cnt >>= 1) {
|
||||||
if (proof_index >= proof.size()) {
|
if (proof_index >= proof.size()) {
|
||||||
return hash();
|
return root_hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index & 1) {
|
if (index & 1) {
|
||||||
|
@ -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;
|
return get_root_from_proof(h, proof, index, count) == root;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,13 @@
|
||||||
|
|
||||||
namespace p2pool {
|
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);
|
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);
|
||||||
|
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
uint32_t get_aux_slot(const hash &id, uint32_t nonce, uint32_t n_aux_chains);
|
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);
|
bool find_aux_nonce(const std::vector<hash>& aux_id, uint32_t& nonce, uint32_t max_nonce = 0xFFFF);
|
||||||
|
|
|
@ -456,7 +456,7 @@ void p2pool::handle_chain_main(ChainMain& data, const char* extra)
|
||||||
}
|
}
|
||||||
update_median_timestamp();
|
update_median_timestamp();
|
||||||
|
|
||||||
hash merkle_root;
|
root_hash merkle_root;
|
||||||
if (extra) {
|
if (extra) {
|
||||||
const size_t n = strlen(extra);
|
const size_t n = strlen(extra);
|
||||||
if (n >= HASH_SIZE * 2) {
|
if (n >= HASH_SIZE * 2) {
|
||||||
|
@ -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 nonce_offset = 0;
|
||||||
size_t extra_nonce_offset = 0;
|
size_t extra_nonce_offset = 0;
|
||||||
size_t merkle_root_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);
|
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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
keccak(reinterpret_cast<uint8_t*>(hashes), HASH_SIZE * 3, tmp.h);
|
||||||
memcpy(h, tmp.h, HASH_SIZE);
|
memcpy(h, tmp.h, HASH_SIZE);
|
||||||
|
|
||||||
merkle_hash(m_transactions, tmp);
|
root_hash tmp_root;
|
||||||
memcpy(blob + blob_size, tmp.h, HASH_SIZE);
|
merkle_hash(m_transactions, tmp_root);
|
||||||
|
memcpy(blob + blob_size, tmp_root.h, HASH_SIZE);
|
||||||
}
|
}
|
||||||
blob_size += HASH_SIZE;
|
blob_size += HASH_SIZE;
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ struct PoolBlock
|
||||||
|
|
||||||
uint32_t m_merkleTreeDataSize;
|
uint32_t m_merkleTreeDataSize;
|
||||||
uint64_t m_merkleTreeData;
|
uint64_t m_merkleTreeData;
|
||||||
hash m_merkleRoot;
|
root_hash m_merkleRoot;
|
||||||
|
|
||||||
// All block transaction hashes including the miner transaction hash at index 0
|
// All block transaction hashes including the miner transaction hash at index 0
|
||||||
std::vector<hash> m_transactions;
|
std::vector<hash> m_transactions;
|
||||||
|
|
|
@ -63,7 +63,7 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
|
||||||
, m_poolName(pool_name ? pool_name : "default")
|
, m_poolName(pool_name ? pool_name : "default")
|
||||||
, m_targetBlockTime(10)
|
, m_targetBlockTime(10)
|
||||||
, m_minDifficulty(MIN_DIFFICULTY, 0)
|
, m_minDifficulty(MIN_DIFFICULTY, 0)
|
||||||
, m_chainWindowSize(2160)
|
, m_chainWindowSize(216)
|
||||||
, m_unclePenalty(20)
|
, m_unclePenalty(20)
|
||||||
, m_precalcFinished(false)
|
, m_precalcFinished(false)
|
||||||
#ifdef DEV_TEST_SYNC
|
#ifdef DEV_TEST_SYNC
|
||||||
|
@ -735,7 +735,7 @@ PoolBlock* SideChain::find_block(const hash& id) const
|
||||||
return nullptr;
|
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);
|
ReadLock lock(m_sidechainLock);
|
||||||
|
|
||||||
|
@ -2120,7 +2120,7 @@ void SideChain::prune_old_blocks()
|
||||||
|
|
||||||
auto it3 = m_blocksByMerkleRoot.find(block->m_merkleRoot);
|
auto it3 = m_blocksByMerkleRoot.find(block->m_merkleRoot);
|
||||||
if (it3 != m_blocksByMerkleRoot.end()) {
|
if (it3 != m_blocksByMerkleRoot.end()) {
|
||||||
m_blocksByMerkleRoot.erase(it2);
|
m_blocksByMerkleRoot.erase(it3);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOGERR(1, "m_blocksByHeight and m_blocksByMerkleRoot are inconsistent at height " << height << ". Fix the code!");
|
LOGERR(1, "m_blocksByHeight and m_blocksByMerkleRoot are inconsistent at height " << height << ". Fix the code!");
|
||||||
|
|
|
@ -55,7 +55,7 @@ public:
|
||||||
void get_missing_blocks(unordered_set<hash>& missing_blocks) const;
|
void get_missing_blocks(unordered_set<hash>& missing_blocks) const;
|
||||||
|
|
||||||
PoolBlock* find_block(const hash& id) 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);
|
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;
|
const PoolBlock* get_block_blob(const hash& id, std::vector<uint8_t>& blob) const;
|
||||||
|
@ -118,7 +118,7 @@ private:
|
||||||
std::atomic<PoolBlock*> m_chainTip;
|
std::atomic<PoolBlock*> m_chainTip;
|
||||||
std::map<uint64_t, std::vector<PoolBlock*>> m_blocksByHeight;
|
std::map<uint64_t, std::vector<PoolBlock*>> m_blocksByHeight;
|
||||||
unordered_map<hash, PoolBlock*> m_blocksById;
|
unordered_map<hash, PoolBlock*> m_blocksById;
|
||||||
unordered_map<hash, PoolBlock*> m_blocksByMerkleRoot;
|
unordered_map<root_hash, PoolBlock*> m_blocksByMerkleRoot;
|
||||||
|
|
||||||
uv_mutex_t m_seenWalletsLock;
|
uv_mutex_t m_seenWalletsLock;
|
||||||
unordered_map<hash, uint64_t> m_seenWallets;
|
unordered_map<hash, uint64_t> m_seenWallets;
|
||||||
|
|
|
@ -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>
|
template<size_t N>
|
||||||
struct hash<std::array<uint8_t, N>>
|
struct hash<std::array<uint8_t, N>>
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,7 +32,7 @@ TEST(merkle, tree)
|
||||||
keccak(data, sizeof(data) - 1, input[i].h);
|
keccak(data, sizeof(data) - 1, input[i].h);
|
||||||
}
|
}
|
||||||
|
|
||||||
hash root;
|
root_hash root;
|
||||||
std::vector<hash> hashes(1, input[0]);
|
std::vector<hash> hashes(1, input[0]);
|
||||||
|
|
||||||
auto check_full_tree = [&hashes, &root]() {
|
auto check_full_tree = [&hashes, &root]() {
|
||||||
|
|
Loading…
Reference in a new issue