diff --git a/src/merge_mining_client_tari.cpp b/src/merge_mining_client_tari.cpp index 07cbbfa..506852d 100644 --- a/src/merge_mining_client_tari.cpp +++ b/src/merge_mining_client_tari.cpp @@ -21,6 +21,7 @@ #include "p2pool.h" #include "params.h" #include "block_template.h" +#include "keccak.h" LOG_CATEGORY(MergeMiningClientTari) @@ -32,6 +33,7 @@ MergeMiningClientTari::MergeMiningClientTari(p2pool* pool, std::string host, con : m_chainParams{} , m_auxWallet(wallet) , m_pool(pool) + , m_tariJobParams{} , m_server(new TariServer(pool->params().m_socks5Proxy)) , m_hostStr(host) , m_workerStop(0) @@ -125,7 +127,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& blob, const std::vector& /*merkle_proof*/, uint32_t /*merkle_proof_path*/) +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& blob, const std::vector& merkle_proof, uint32_t merkle_proof_path) { Block block; { @@ -169,7 +171,68 @@ void MergeMiningClientTari::submit_solution(const BlockTemplate* block_tpl, cons // Path bitmap (always 0 for the coinbase tx) data.append(1, 0); - // TODO: serialize coinbase_tx_hasher, coinbase_tx_extra, aux_chain_merkle_proof + // coinbase_tx_hasher + const uint8_t* coinbase_tx = blob.data() + nonce_offset + sizeof(uint32_t); + + const uint8_t* p = coinbase_tx; + const uint8_t* e = blob.data() + blob.size(); + + uint64_t k; + + p += 1; // TX_VERSION + p = readVarint(p, e, k); if (!p) return; // unlock height + p += 2; // '1', TXIN_GEN + p = readVarint(p, e, k); if (!p) return; // txinGenHeight + p = readVarint(p, e, k); if (!p) return; // num_outputs + + for (uint64_t i = 0; i < k; ++i) { + uint64_t reward; + p = readVarint(p, e, reward); if (!p) return; + p += 1 + HASH_SIZE + 1; // tx_type, public key, view tag + } + + std::array keccak_state = {}; + + size_t offset = p - coinbase_tx; + + uint32_t tx_extra_size; + p = readVarint(p, e, tx_extra_size); if (!p) return; + + p = coinbase_tx; + + while (offset >= KeccakParams::HASH_DATA_AREA) { + for (size_t i = 0; i < KeccakParams::HASH_DATA_AREA / sizeof(uint64_t); ++i) { + keccak_state[i] ^= read_unaligned(reinterpret_cast(p) + i); + } + keccakf(keccak_state); + p += KeccakParams::HASH_DATA_AREA; + offset -= KeccakParams::HASH_DATA_AREA; + } + + for (size_t i = 0; i < offset; ++i, ++p) { + reinterpret_cast(keccak_state.data())[i] ^= *p; + } + + // coinbase_tx_hasher.buffer + data.append(reinterpret_cast(keccak_state.data()), sizeof(keccak_state)); + + // coinbase_tx_hasher.offset + data.append(1, static_cast(offset)); + + // coinbase_tx_hasher.rate + data.append(1, static_cast(KeccakParams::HASH_DATA_AREA)); + + // coinbase_tx_hasher.mode + data.append(1, 1); + + // coinbase_tx_extra + data.append(reinterpret_cast(&tx_extra_size), sizeof(tx_extra_size)); + data.append(reinterpret_cast(p), tx_extra_size); + + // aux_chain_merkle_proof + data.append(1, static_cast(merkle_proof.size())); + data.append(reinterpret_cast(merkle_proof.data()), merkle_proof.size() * HASH_SIZE); + writeVarint(merkle_proof_path, [&data](uint8_t value) { data.append(1, value); }); pow->set_pow_data(data); } @@ -208,8 +271,6 @@ void MergeMiningClientTari::run() MutexLock lock(m_workerLock); - LOGINFO(6, "Getting new block template from Tari node"); - GetNewBlockTemplateWithCoinbasesRequest request; PowAlgo* algo = new PowAlgo(); algo->set_pow_algo(PowAlgo_PowAlgos_POW_ALGOS_RANDOMX); @@ -255,26 +316,44 @@ void MergeMiningClientTari::run() } if (ok) { + TariJobParams job_params; + + job_params.height = response.block().header().height(); + job_params.diff = response.miner_data().target_difficulty(); + job_params.reward = response.miner_data().reward(); + job_params.fees = response.miner_data().total_fees(); + + hash chain_id; { WriteLock lock2(m_chainParamsLock); - if (m_chainParams.aux_id.empty()) { - LOGINFO(1, m_hostStr << " uses chain_id " << log::LightCyan() << log::hex_buf(id.data(), id.size())); - std::copy(id.begin(), id.end(), m_chainParams.aux_id.h); + if (job_params != m_tariJobParams) { + m_tariJobParams = job_params; + + if (m_chainParams.aux_id.empty()) { + LOGINFO(1, m_hostStr << " uses chain_id " << log::LightCyan() << log::hex_buf(id.data(), id.size())); + std::copy(id.begin(), id.end(), m_chainParams.aux_id.h); + } + + chain_id = m_chainParams.aux_id; + + std::copy(mm_hash.begin(), mm_hash.end(), m_chainParams.aux_hash.h); + m_chainParams.aux_diff = static_cast(response.miner_data().target_difficulty()); + + m_tariBlock = response.block(); + + LOGINFO(5, "Tari block template: height = " << job_params.height + << ", diff = " << job_params.diff + << ", reward = " << job_params.reward + << ", fees = " << job_params.fees + << ", hash = " << log::hex_buf(mm_hash.data(), mm_hash.size()) + ); } - - std::copy(mm_hash.begin(), mm_hash.end(), m_chainParams.aux_hash.h); - m_chainParams.aux_diff = static_cast(response.miner_data().target_difficulty()); - - m_tariBlock = response.block(); } - LOGINFO(6, "Tari block template: height = " << response.block().header().height() - << ", diff = " << response.miner_data().target_difficulty() - << ", reward = " << response.miner_data().reward() - << ", fees = " << response.miner_data().total_fees() - << ", hash = " << log::hex_buf(mm_hash.data(), mm_hash.size()) - ); + if (!chain_id.empty()) { + m_pool->update_aux_data(chain_id); + } } } diff --git a/src/merge_mining_client_tari.h b/src/merge_mining_client_tari.h index a626a7f..976ac75 100644 --- a/src/merge_mining_client_tari.h +++ b/src/merge_mining_client_tari.h @@ -43,6 +43,21 @@ private: std::string m_auxWallet; p2pool* m_pool; + struct TariJobParams + { + uint64_t height; + uint64_t diff; + uint64_t reward; + uint64_t fees; + + FORCEINLINE bool operator!=(const TariJobParams& job) const { + static_assert(sizeof(TariJobParams) == sizeof(uint64_t) * 4, "Invalid TariJobParams size"); + return memcmp(this, &job, sizeof(TariJobParams)) != 0; + } + }; + + TariJobParams m_tariJobParams; + private: static constexpr uint64_t BUF_SIZE = 16384;