mirror of
https://github.com/SChernykh/p2pool.git
synced 2024-12-22 11:29:23 +00:00
Init and update merkle tree root
This commit is contained in:
parent
2d1158af64
commit
0b711cbe65
8 changed files with 158 additions and 18 deletions
|
@ -28,6 +28,7 @@
|
||||||
#include "side_chain.h"
|
#include "side_chain.h"
|
||||||
#include "pool_block.h"
|
#include "pool_block.h"
|
||||||
#include "params.h"
|
#include "params.h"
|
||||||
|
#include "merkle.h"
|
||||||
#include <zmq.hpp>
|
#include <zmq.hpp>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
@ -662,11 +663,14 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
|
||||||
m_poolBlockTemplate->m_extraNonce = 0;
|
m_poolBlockTemplate->m_extraNonce = 0;
|
||||||
m_poolBlockTemplate->m_sidechainId = {};
|
m_poolBlockTemplate->m_sidechainId = {};
|
||||||
|
|
||||||
// TODO: fill in merkle tree data here
|
m_poolBlockTemplate->m_merkleTreeData = PoolBlock::encode_merkle_tree_data(static_cast<uint32_t>(data.aux_chains.size() + 1), data.aux_nonce);
|
||||||
m_poolBlockTemplate->m_merkleTreeDataSize = 1;
|
m_poolBlockTemplate->m_merkleTreeDataSize = 0;
|
||||||
m_poolBlockTemplate->m_merkleTreeData = 0;
|
writeVarint(m_poolBlockTemplate->m_merkleTreeData, [this](uint8_t) { ++m_poolBlockTemplate->m_merkleTreeDataSize; });
|
||||||
m_poolBlockTemplate->m_merkleRoot = {};
|
m_poolBlockTemplate->m_merkleRoot = {};
|
||||||
|
|
||||||
|
m_poolBlockTemplate->m_auxChains = data.aux_chains;
|
||||||
|
m_poolBlockTemplate->m_auxNonce = data.aux_nonce;
|
||||||
|
|
||||||
const std::vector<uint8_t> sidechain_data = m_poolBlockTemplate->serialize_sidechain_data();
|
const std::vector<uint8_t> sidechain_data = m_poolBlockTemplate->serialize_sidechain_data();
|
||||||
const std::vector<uint8_t>& consensus_id = m_sidechain->consensus_id();
|
const std::vector<uint8_t>& consensus_id = m_sidechain->consensus_id();
|
||||||
|
|
||||||
|
@ -697,11 +701,7 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
|
||||||
LOGINFO(6, "blob size = " << m_fullDataBlob.size());
|
LOGINFO(6, "blob size = " << m_fullDataBlob.size());
|
||||||
|
|
||||||
m_poolBlockTemplate->m_sidechainId = calc_sidechain_hash(0);
|
m_poolBlockTemplate->m_sidechainId = calc_sidechain_hash(0);
|
||||||
|
init_merge_mining_merkle_root();
|
||||||
// TODO: fill in merkle tree data here
|
|
||||||
m_poolBlockTemplate->m_merkleTreeDataSize = 1;
|
|
||||||
m_poolBlockTemplate->m_merkleTreeData = 0;
|
|
||||||
m_poolBlockTemplate->m_merkleRoot = m_poolBlockTemplate->m_sidechainId;
|
|
||||||
|
|
||||||
if (pool_block_debug()) {
|
if (pool_block_debug()) {
|
||||||
const size_t sidechain_hash_offset = m_extraNonceOffsetInTemplate + m_poolBlockTemplate->m_extraNonceSize + 2 + m_poolBlockTemplate->m_merkleTreeDataSize;
|
const size_t sidechain_hash_offset = m_extraNonceOffsetInTemplate + m_poolBlockTemplate->m_extraNonceSize + 2 + m_poolBlockTemplate->m_merkleTreeDataSize;
|
||||||
|
@ -1312,10 +1312,10 @@ bool BlockTemplate::submit_sidechain_block(uint32_t template_id, uint32_t nonce,
|
||||||
m_poolBlockTemplate->m_sidechainId = calc_sidechain_hash(extra_nonce);
|
m_poolBlockTemplate->m_sidechainId = calc_sidechain_hash(extra_nonce);
|
||||||
m_poolBlockTemplate->m_sidechainExtraBuf[3] = extra_nonce;
|
m_poolBlockTemplate->m_sidechainExtraBuf[3] = extra_nonce;
|
||||||
|
|
||||||
// TODO: fill in merkle tree data here
|
const uint32_t n_aux_chains = static_cast<uint32_t>(m_poolBlockTemplate->m_auxChains.size() + 1);
|
||||||
m_poolBlockTemplate->m_merkleTreeDataSize = 1;
|
const uint32_t aux_slot = get_aux_slot(m_sidechain->consensus_hash(), m_poolBlockTemplate->m_auxNonce, n_aux_chains);
|
||||||
m_poolBlockTemplate->m_merkleTreeData = 0;
|
|
||||||
m_poolBlockTemplate->m_merkleRoot = m_poolBlockTemplate->m_sidechainId;
|
m_poolBlockTemplate->m_merkleRoot = get_root_from_proof(m_poolBlockTemplate->m_sidechainId, m_poolBlockTemplate->m_merkleProof, aux_slot, n_aux_chains);
|
||||||
|
|
||||||
if (pool_block_debug()) {
|
if (pool_block_debug()) {
|
||||||
std::vector<uint8_t> buf = m_poolBlockTemplate->serialize_mainchain_data();
|
std::vector<uint8_t> buf = m_poolBlockTemplate->serialize_mainchain_data();
|
||||||
|
@ -1368,4 +1368,38 @@ bool BlockTemplate::submit_sidechain_block(uint32_t template_id, uint32_t nonce,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlockTemplate::init_merge_mining_merkle_root()
|
||||||
|
{
|
||||||
|
const uint32_t n_aux_chains = static_cast<uint32_t>(m_poolBlockTemplate->m_auxChains.size() + 1);
|
||||||
|
|
||||||
|
if (n_aux_chains == 1) {
|
||||||
|
m_poolBlockTemplate->m_merkleRoot = m_poolBlockTemplate->m_sidechainId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<hash> hashes(n_aux_chains);
|
||||||
|
|
||||||
|
for (const AuxChainData& aux_data : m_poolBlockTemplate->m_auxChains) {
|
||||||
|
const uint32_t aux_slot = get_aux_slot(aux_data.unique_id, m_poolBlockTemplate->m_auxNonce, n_aux_chains);
|
||||||
|
hashes[aux_slot] = aux_data.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t aux_slot = get_aux_slot(m_sidechain->consensus_hash(), m_poolBlockTemplate->m_auxNonce, n_aux_chains);
|
||||||
|
hashes[aux_slot] = m_poolBlockTemplate->m_sidechainId;
|
||||||
|
|
||||||
|
std::vector<std::vector<hash>> tree;
|
||||||
|
merkle_hash_full_tree(hashes, tree);
|
||||||
|
m_poolBlockTemplate->m_merkleRoot = tree.back().front();
|
||||||
|
|
||||||
|
std::vector<std::pair<bool, hash>> proof;
|
||||||
|
get_merkle_proof(tree, m_poolBlockTemplate->m_sidechainId, proof);
|
||||||
|
|
||||||
|
m_poolBlockTemplate->m_merkleProof.clear();
|
||||||
|
m_poolBlockTemplate->m_merkleProof.reserve(proof.size());
|
||||||
|
|
||||||
|
for (const auto& p : proof) {
|
||||||
|
m_poolBlockTemplate->m_merkleProof.push_back(p.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace p2pool
|
} // namespace p2pool
|
||||||
|
|
|
@ -132,6 +132,8 @@ private:
|
||||||
|
|
||||||
std::vector<uint32_t> m_knapsack;
|
std::vector<uint32_t> m_knapsack;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void init_merge_mining_merkle_root();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace p2pool
|
} // namespace p2pool
|
||||||
|
|
11
src/common.h
11
src/common.h
|
@ -383,6 +383,13 @@ struct TxMempoolData
|
||||||
uint64_t time_received;
|
uint64_t time_received;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AuxChainData
|
||||||
|
{
|
||||||
|
hash unique_id;
|
||||||
|
hash data;
|
||||||
|
difficulty_type difficulty;
|
||||||
|
};
|
||||||
|
|
||||||
struct MinerData
|
struct MinerData
|
||||||
{
|
{
|
||||||
FORCEINLINE MinerData()
|
FORCEINLINE MinerData()
|
||||||
|
@ -394,6 +401,7 @@ struct MinerData
|
||||||
, median_weight(0)
|
, median_weight(0)
|
||||||
, already_generated_coins(0)
|
, already_generated_coins(0)
|
||||||
, median_timestamp(0)
|
, median_timestamp(0)
|
||||||
|
, aux_nonce(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
uint8_t major_version;
|
uint8_t major_version;
|
||||||
|
@ -406,6 +414,9 @@ struct MinerData
|
||||||
uint64_t median_timestamp;
|
uint64_t median_timestamp;
|
||||||
std::vector<TxMempoolData> tx_backlog;
|
std::vector<TxMempoolData> tx_backlog;
|
||||||
|
|
||||||
|
std::vector<AuxChainData> aux_chains;
|
||||||
|
uint32_t aux_nonce;
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point time_received;
|
std::chrono::high_resolution_clock::time_point time_received;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -194,10 +194,10 @@ bool verify_merkle_proof(hash h, const std::vector<std::pair<bool, hash>>& proof
|
||||||
return (h == root);
|
return (h == root);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verify_merkle_proof(hash h, const std::vector<hash>& proof, size_t index, size_t count, const hash& root)
|
hash get_root_from_proof(hash h, const std::vector<hash>& proof, size_t index, size_t count)
|
||||||
{
|
{
|
||||||
if (index >= count) {
|
if (index >= count) {
|
||||||
return false;
|
return hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
hash tmp[2];
|
hash tmp[2];
|
||||||
|
@ -206,7 +206,7 @@ bool verify_merkle_proof(hash h, const std::vector<hash>& proof, size_t index, s
|
||||||
}
|
}
|
||||||
else if (count == 2) {
|
else if (count == 2) {
|
||||||
if (proof.empty()) {
|
if (proof.empty()) {
|
||||||
return false;
|
return hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index & 1) {
|
if (index & 1) {
|
||||||
|
@ -233,7 +233,7 @@ bool verify_merkle_proof(hash h, const std::vector<hash>& proof, size_t index, s
|
||||||
index -= k;
|
index -= k;
|
||||||
|
|
||||||
if (proof.empty()) {
|
if (proof.empty()) {
|
||||||
return false;
|
return hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index & 1) {
|
if (index & 1) {
|
||||||
|
@ -253,7 +253,7 @@ bool verify_merkle_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 false;
|
return hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index & 1) {
|
if (index & 1) {
|
||||||
|
@ -269,7 +269,12 @@ bool verify_merkle_proof(hash h, const std::vector<hash>& proof, size_t index, s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (h == root);
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool verify_merkle_proof(hash h, const std::vector<hash>& proof, size_t index, size_t count, const hash& root)
|
||||||
|
{
|
||||||
|
return get_root_from_proof(h, proof, index, count) == 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)
|
||||||
|
@ -292,4 +297,38 @@ uint32_t get_aux_slot(const hash &id, uint32_t nonce, uint32_t n_aux_chains)
|
||||||
return *reinterpret_cast<uint32_t*>(res.h) % n_aux_chains;
|
return *reinterpret_cast<uint32_t*>(res.h) % n_aux_chains;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool find_aux_nonce(const std::vector<hash>& aux_id, uint32_t& nonce, uint32_t max_nonce)
|
||||||
|
{
|
||||||
|
const uint32_t n_aux_chains = static_cast<uint32_t>(aux_id.size());
|
||||||
|
|
||||||
|
if (n_aux_chains <= 1) {
|
||||||
|
nonce = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<bool> slots;
|
||||||
|
|
||||||
|
for (uint32_t i = 0;; ++i) {
|
||||||
|
slots.assign(n_aux_chains, false);
|
||||||
|
|
||||||
|
uint32_t j;
|
||||||
|
for (j = 0; j < n_aux_chains; ++j) {
|
||||||
|
const uint32_t k = get_aux_slot(aux_id[j], i, n_aux_chains);
|
||||||
|
if (slots[k]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
slots[k] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j >= n_aux_chains) {
|
||||||
|
nonce = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == max_nonce) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace p2pool
|
} // namespace p2pool
|
||||||
|
|
|
@ -24,8 +24,11 @@ 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<std::pair<bool, hash>>& proof);
|
bool get_merkle_proof(const std::vector<std::vector<hash>>& tree, const hash& h, std::vector<std::pair<bool, hash>>& proof);
|
||||||
bool verify_merkle_proof(hash h, const std::vector<std::pair<bool, hash>>& proof, const hash& root);
|
bool verify_merkle_proof(hash h, const std::vector<std::pair<bool, hash>>& proof, const hash& 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 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);
|
||||||
|
|
||||||
} // namespace p2pool
|
} // namespace p2pool
|
||||||
|
|
|
@ -58,6 +58,7 @@ PoolBlock::PoolBlock()
|
||||||
, m_precalculated(false)
|
, m_precalculated(false)
|
||||||
, m_localTimestamp(seconds_since_epoch())
|
, m_localTimestamp(seconds_since_epoch())
|
||||||
, m_receivedTimestamp(0)
|
, m_receivedTimestamp(0)
|
||||||
|
, m_auxNonce(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +114,9 @@ PoolBlock& PoolBlock::operator=(const PoolBlock& b)
|
||||||
m_localTimestamp = seconds_since_epoch();
|
m_localTimestamp = seconds_since_epoch();
|
||||||
m_receivedTimestamp = b.m_receivedTimestamp;
|
m_receivedTimestamp = b.m_receivedTimestamp;
|
||||||
|
|
||||||
|
m_auxChains = b.m_auxChains;
|
||||||
|
m_auxNonce = b.m_auxNonce;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,6 +290,11 @@ void PoolBlock::reset_offchain_data()
|
||||||
|
|
||||||
m_localTimestamp = seconds_since_epoch();
|
m_localTimestamp = seconds_since_epoch();
|
||||||
m_receivedTimestamp = 0;
|
m_receivedTimestamp = 0;
|
||||||
|
|
||||||
|
m_auxChains.clear();
|
||||||
|
m_auxChains.shrink_to_fit();
|
||||||
|
|
||||||
|
m_auxNonce = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const hash& seed_hash, hash& pow_hash, bool force_light_mode)
|
bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const hash& seed_hash, hash& pow_hash, bool force_light_mode)
|
||||||
|
|
|
@ -148,6 +148,9 @@ struct PoolBlock
|
||||||
uint64_t m_localTimestamp;
|
uint64_t m_localTimestamp;
|
||||||
uint64_t m_receivedTimestamp;
|
uint64_t m_receivedTimestamp;
|
||||||
|
|
||||||
|
std::vector<AuxChainData> m_auxChains;
|
||||||
|
uint32_t m_auxNonce;
|
||||||
|
|
||||||
std::vector<uint8_t> serialize_mainchain_data(size_t* header_size = nullptr, size_t* miner_tx_size = nullptr, int* outputs_offset = nullptr, int* outputs_blob_size = nullptr, const uint32_t* nonce = nullptr, const uint32_t* extra_nonce = nullptr) const;
|
std::vector<uint8_t> serialize_mainchain_data(size_t* header_size = nullptr, size_t* miner_tx_size = nullptr, int* outputs_offset = nullptr, int* outputs_blob_size = nullptr, const uint32_t* nonce = nullptr, const uint32_t* extra_nonce = nullptr) const;
|
||||||
std::vector<uint8_t> serialize_sidechain_data() const;
|
std::vector<uint8_t> serialize_sidechain_data() const;
|
||||||
|
|
||||||
|
@ -176,6 +179,15 @@ struct PoolBlock
|
||||||
|
|
||||||
hash calculate_tx_key_seed() const;
|
hash calculate_tx_key_seed() const;
|
||||||
|
|
||||||
|
static FORCEINLINE uint64_t encode_merkle_tree_data(uint32_t n_aux_chains, uint32_t nonce)
|
||||||
|
{
|
||||||
|
uint32_t n_bits = 1U;
|
||||||
|
while (((1U << n_bits) < n_aux_chains) && (n_bits < 8)) {
|
||||||
|
++n_bits;
|
||||||
|
}
|
||||||
|
return (n_bits - 1U) | ((n_aux_chains - 1U) << 3U) | (static_cast<uint64_t>(nonce) << (3U + n_bits));
|
||||||
|
}
|
||||||
|
|
||||||
FORCEINLINE void decode_merkle_tree_data(uint32_t& mm_n_aux_chains, uint32_t& mm_nonce) const
|
FORCEINLINE void decode_merkle_tree_data(uint32_t& mm_n_aux_chains, uint32_t& mm_nonce) const
|
||||||
{
|
{
|
||||||
const uint32_t k = static_cast<uint32_t>(m_merkleTreeData);
|
const uint32_t k = static_cast<uint32_t>(m_merkleTreeData);
|
||||||
|
|
|
@ -243,4 +243,34 @@ TEST(merkle, aux_slot)
|
||||||
ASSERT_EQ(get_aux_slot(id, 1, std::numeric_limits<uint32_t>::max()), 1080669337U);
|
ASSERT_EQ(get_aux_slot(id, 1, std::numeric_limits<uint32_t>::max()), 1080669337U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(merkle, aux_nonce)
|
||||||
|
{
|
||||||
|
std::vector<hash> aux_id;
|
||||||
|
uint32_t nonce;
|
||||||
|
|
||||||
|
ASSERT_TRUE(find_aux_nonce(aux_id, nonce));
|
||||||
|
ASSERT_EQ(nonce, 0);
|
||||||
|
|
||||||
|
uint8_t data[] = "aux0";
|
||||||
|
|
||||||
|
const uint32_t nonces[] = { 0, 0, 0, 7, 16, 56, 1, 287, 1423, 1074 };
|
||||||
|
hash h;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 10; ++i, ++data[sizeof(data) - 2]) {
|
||||||
|
keccak(data, sizeof(data) - 1, h.h);
|
||||||
|
aux_id.push_back(h);
|
||||||
|
|
||||||
|
ASSERT_TRUE(find_aux_nonce(aux_id, nonce));
|
||||||
|
ASSERT_EQ(nonce, nonces[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
h = aux_id.front();
|
||||||
|
|
||||||
|
aux_id.clear();
|
||||||
|
aux_id.push_back(h);
|
||||||
|
aux_id.push_back(h);
|
||||||
|
|
||||||
|
ASSERT_FALSE(find_aux_nonce(aux_id, nonce));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue