Refactored merge mining code

This commit is contained in:
SChernykh
2026-04-24 11:01:59 +02:00
parent eaee503d05
commit 54e0d3f3eb
8 changed files with 372 additions and 292 deletions
+7 -236
View File
@@ -34,13 +34,7 @@ using namespace tari::rpc;
namespace p2pool {
MergeMiningClientTari::MergeMiningClientTari(p2pool* pool, std::string host, const std::string& wallet)
: m_chainParams{}
, m_chainParamsTimestamp(0)
, m_previousAuxHashes{}
, m_previousAuxHashesIndex(0)
, m_previousAuxHashesFoundIndex(std::numeric_limits<uint32_t>::max())
, m_auxWallet(wallet)
, m_pool(pool)
: MergeMiningClientShared(pool, wallet)
, m_tariJobParams{}
, m_server(new TariServer(pool->params().m_socks5Proxy, pool->params().m_socks5ProxyType))
, m_hostStr(host)
@@ -78,8 +72,6 @@ MergeMiningClientTari::MergeMiningClientTari(p2pool* pool, std::string host, con
throw std::exception();
}
uv_rwlock_init_checked(&m_chainParamsLock);
if (!m_server->start()) {
throw std::exception();
}
@@ -170,8 +162,6 @@ MergeMiningClientTari::~MergeMiningClientTari()
m_TariNode.reset();
m_channel.reset();
uv_rwlock_destroy(&m_chainParamsLock);
uv_mutex_destroy(&m_workerLock);
uv_cond_destroy(&m_workerCond);
@@ -207,230 +197,6 @@ bool MergeMiningClientTari::get_params(ChainParameters& out_params) const
return true;
}
void MergeMiningClientTari::on_external_block(const PoolBlock& block)
{
#ifdef WITH_MERGE_MINING_DONATION
// The rest of the code is needed only when this node is sending donation messages
if (m_pool->params().m_authorKeyFile.empty()) {
return;
}
// Sanity check
if (block.m_transactions.empty() || block.m_hashingBlob.empty() || (block.m_hashingBlob.size() > 128)) {
LOGWARN(3, "on_external_block: sanity check failed - " << block.m_transactions.size() << " transactions, hashing blob size = " << block.m_hashingBlob.size());
return;
}
ChainParameters chain_params;
uint64_t previous_aux_hashes[NUM_PREVIOUS_HASHES];
{
ReadLock lock(m_chainParamsLock);
chain_params = m_chainParams;
memcpy(previous_aux_hashes, m_previousAuxHashes, sizeof(m_previousAuxHashes));
}
// Don't continue if our aux chain is not there
if (block.m_mergeMiningExtra.find(chain_params.aux_id) == block.m_mergeMiningExtra.end()) {
return;
}
// All aux chains in this block + the P2Pool sidechain
std::vector<hash> aux_ids;
// All aux chains in this block
std::vector<AuxChainData> aux_chains;
aux_ids.reserve(block.m_mergeMiningExtra.size() + 1);
aux_chains.reserve(block.m_mergeMiningExtra.size() + 1);
uint64_t mm_extra_size = 0;
for (const auto& i : block.m_mergeMiningExtra) {
// Filter aux chain data only
if ((i.first == keccak_subaddress_viewpub) || (i.first == keccak_onion_address_v3) || (i.first == keccak_i2p_b32_address)) {
continue;
}
++mm_extra_size;
hash data;
difficulty_type diff;
{
const std::vector<uint8_t>& v = i.second;
const uint8_t* p = v.data();
const uint8_t* e = v.data() + v.size();
if (p + HASH_SIZE > e) {
LOGWARN(3, "on_external_block: sanity check failed - invalid merge mining extra data " << '1');
return;
}
memcpy(data.h, p, HASH_SIZE);
p += HASH_SIZE;
p = readVarint(p, e, diff.lo);
if (!p) {
LOGWARN(3, "on_external_block: sanity check failed - invalid merge mining extra data " << '2');
diff.lo = 0;
}
else {
p = readVarint(p, e, diff.hi);
if (!p) {
LOGWARN(3, "on_external_block: sanity check failed - invalid merge mining extra data " << '3');
diff.hi = 0;
}
}
}
// If it's our aux chain, check that it's the same job and that there is enough PoW
if (i.first == chain_params.aux_id) {
if ((data != chain_params.aux_hash) || (diff != chain_params.aux_diff)) {
uint32_t index = std::numeric_limits<uint32_t>::max();
for (uint32_t k = 0; k < NUM_PREVIOUS_HASHES; ++k) {
if (previous_aux_hashes[k] == *data.u64()) {
index = k;
break;
}
}
m_previousAuxHashesFoundIndex = index;
if (index == std::numeric_limits<uint32_t>::max()) {
LOGINFO(4, "External aux job solution found, but it's for another miner");
return;
}
LOGINFO(4, "External aux job solution found, but it's stale");
chain_params.aux_hash = data;
chain_params.aux_diff = diff;
}
else {
m_previousAuxHashesFoundIndex = std::numeric_limits<uint32_t>::max();
}
if (!diff.check_pow(block.m_powHash)) {
LOGINFO(4, "External aux job solution found, but it doesn't have enough PoW (block diff = " << block.m_difficulty << ", Tari diff = " << diff << ')');
return;
}
}
aux_ids.emplace_back(i.first);
aux_chains.emplace_back(i.first, data, diff);
}
aux_ids.emplace_back(m_pool->side_chain().consensus_hash());
LOGINFO(0, log::LightGreen() << "External aux job solution found. Processing it!");
// coinbase_merkle_proof
root_hash root;
std::vector<hash> proof;
uint32_t path;
#ifdef WITH_INDEXED_HASHES
std::vector<hash> transactions;
transactions.reserve(block.m_transactions.size());
for (const auto& h : block.m_transactions) {
transactions.emplace_back(h);
}
#else
const std::vector<hash>& transactions = block.m_transactions;
#endif
if (!merkle_hash_with_proof(transactions, 0, proof, path, root)) {
LOGWARN(3, "on_external_block: merkle_hash_with_proof failed for coinbase transaction");
return;
}
if (!verify_merkle_proof(transactions[0], proof, path, root)) {
LOGWARN(3, "on_external_block: verify_merkle_proof failed for coinbase transaction");
return;
}
std::vector<uint8_t> coinbase_merkle_proof;
coinbase_merkle_proof.reserve(proof.size() * HASH_SIZE);
for (const hash& h : proof) {
coinbase_merkle_proof.insert(coinbase_merkle_proof.end(), h.h, h.h + HASH_SIZE);
}
// hashing_blob
uint8_t hashing_blob[128] = {};
memcpy(hashing_blob, block.m_hashingBlob.data(), block.m_hashingBlob.size());
// nonce_offset and blob
size_t header_size = 0;
const std::vector<uint8_t> blob = block.serialize_mainchain_data(&header_size);
if (header_size <= NONCE_SIZE) {
LOGWARN(3, "on_external_block: invalid header_size");
return;
}
const uint32_t nonce_offset = static_cast<uint32_t>(header_size - NONCE_SIZE);
// aux_merkle_proof, aux_merkle_proof_path
std::vector<hash> aux_merkle_proof;
uint32_t aux_merkle_proof_path = 0;
const hash sidechain_id = block.m_sidechainId;
const uint32_t n_aux_chains = static_cast<uint32_t>(mm_extra_size + 1);
std::vector<hash> hashes(n_aux_chains);
uint32_t aux_nonce;
if (!find_aux_nonce(aux_ids, aux_nonce, 1000)) {
LOGWARN(3, "on_external_block: failed to find aux_nonce");
return;
}
for (const AuxChainData& aux_data : aux_chains) {
const uint32_t aux_slot = get_aux_slot(aux_data.unique_id, aux_nonce, n_aux_chains);
if (!hashes[aux_slot].empty()) {
LOGWARN(3, "on_external_block: found an incorrect aux_nonce " << '1');
return;
}
hashes[aux_slot] = aux_data.data;
}
const uint32_t aux_slot = get_aux_slot(m_pool->side_chain().consensus_hash(), aux_nonce, n_aux_chains);
if (!hashes[aux_slot].empty()) {
LOGWARN(3, "on_external_block: found an incorrect aux_nonce " << '2');
return;
}
hashes[aux_slot] = sidechain_id;
if (!merkle_hash_with_proof(hashes, chain_params.aux_hash, aux_merkle_proof, aux_merkle_proof_path, root)) {
LOGWARN(3, "on_external_block: merkle_hash_with_proof failed for the aux hash");
return;
}
if (root != block.m_merkleRoot) {
LOGWARN(3, "on_external_block: merkle root didn't match");
return;
}
if (!verify_merkle_proof(chain_params.aux_hash, aux_merkle_proof, aux_merkle_proof_path, root)) {
LOGWARN(3, "on_external_block: verify_merkle_proof failed for the aux hash");
return;
}
submit_solution(coinbase_merkle_proof, hashing_blob, nonce_offset, block.m_seed, blob, aux_merkle_proof, aux_merkle_proof_path);
#else // WITH_MERGE_MINING_DONATION
(void) block;
#endif // WITH_MERGE_MINING_DONATION
}
void MergeMiningClientTari::submit_solution(const std::vector<uint8_t>& coinbase_merkle_proof, 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;
@@ -820,7 +586,7 @@ void MergeMiningClientTari::run()
const uint32_t index = (m_previousAuxHashesIndex++) % NUM_PREVIOUS_HASHES;
m_previousAuxHashes[index] = *m_chainParams.aux_hash.u64();
m_previousAuxHashes[index] = m_chainParams.aux_hash;
m_previousTariBlocks[index] = std::move(m_tariBlock);
std::copy(mm_hash.begin(), mm_hash.end(), m_chainParams.aux_hash.h);
@@ -1119,4 +885,9 @@ void MergeMiningClientTari::push_blocks_to(const std::string& node_address)
}
}
const char* MergeMiningClientTari::get_log_category() const
{
return log_category_prefix;
}
} // namespace p2pool