void MinerManager::eventLoop() { size_t blocksMined = 0; for (;;) { m_logger(Logging::DEBUGGING) << "waiting for event"; MinerEvent event = waitEvent(); switch (event.type) { case MinerEventType::BLOCK_MINED: { m_logger(Logging::DEBUGGING) << "got BLOCK_MINED event"; stopBlockchainMonitoring(); if (submitBlock(m_minedBlock, m_config.daemonHost, m_config.daemonPort)) { m_lastBlockTimestamp = m_minedBlock.timestamp; if (m_config.blocksLimit != 0 && ++blocksMined == m_config.blocksLimit) { m_logger(Logging::INFO) << "Miner mined requested " << m_config.blocksLimit << " blocks. Quitting"; return; } } BlockMiningParameters params = requestMiningParameters(m_dispatcher, m_config.daemonHost, m_config.daemonPort, m_config.miningAddress); adjustBlockTemplate(params.blockTemplate); startBlockchainMonitoring(); startMining(params); break; } case MinerEventType::BLOCKCHAIN_UPDATED: { m_logger(Logging::DEBUGGING) << "got BLOCKCHAIN_UPDATED event"; stopMining(); stopBlockchainMonitoring(); BlockMiningParameters params = requestMiningParameters(m_dispatcher, m_config.daemonHost, m_config.daemonPort, m_config.miningAddress); adjustBlockTemplate(params.blockTemplate); startBlockchainMonitoring(); startMining(params); break; } default: assert(false); return; } } }
bool MergedMiner::mine(std::string address1, std::string wallet1, std::string address2, std::string wallet2, size_t threads) { epee::net_utils::http::http_simple_client httpClient1; epee::net_utils::http::http_simple_client httpClient2; Miner miner; BlockTemplate blockTemplate1; BlockTemplate blockTemplate2; cryptonote::block block1; cryptonote::block block2; cryptonote::difficulty_type difficulty1; cryptonote::difficulty_type difficulty2; std::future<bool> request1; std::future<bool> request2; std::future<bool> mining; crypto::hash hash; std::chrono::steady_clock::time_point time1; uint64_t prefix1; cryptonote::account_public_address walletAddress1; if (!get_account_address_from_str(prefix1, walletAddress1, wallet1)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to parse donor wallet address"); return false; } uint64_t prefix2; cryptonote::account_public_address walletAddress2; if (!address2.empty() && !get_account_address_from_str(prefix2, walletAddress2, wallet2)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to parse acceptor wallet address"); return false; } m_blockCount = 0; for (;;) { miner.getHashCount(); if (m_stopped) { if (mining.valid()) { miner.stop(); mining.wait(); } return true; } request1 = std::async(std::launch::async, getBlockTemplate, &httpClient1, &address1, &wallet1, MERGE_MINING_TAG_RESERVED_SIZE, &blockTemplate1); if (!address2.empty()) { request2 = std::async(std::launch::async, getBlockTemplate, &httpClient2, &address2, &wallet2, MERGE_MINING_TAG_RESERVED_SIZE, &blockTemplate2); } if (!request1.get()) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to get donor block"); continue; } if (!address2.empty()) { if (!request2.get()) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to get acceptor block"); continue; } if (blockTemplate2.block.major_version != BLOCK_MAJOR_VERSION_2) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Unsupported block version received from acceptor network, merged mining is not possible"); if (mining.valid()) { miner.stop(); mining.wait(); } return false; } } if (mining.valid()) { miner.stop(); if (mining.get()) { if (cryptonote::check_hash(hash, difficulty1)) { if (submitBlock(httpClient1, address1, block1)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Submitted donor block"); } else { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to submit donor block"); } } if (!address2.empty() && cryptonote::check_hash(hash, difficulty2)) { if (!mergeBlocks(block1, block2)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Internal error"); return false; } if (submitBlock(httpClient2, address2, block2)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Submitted acceptor block"); } else { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Failed to submit acceptor block"); } } } std::chrono::steady_clock::time_point time2 = std::chrono::steady_clock::now(); std::ostringstream stream; stream << "Hashrate: " << miner.getHashCount() / std::chrono::duration_cast<std::chrono::duration<double>>(time2 - time1).count(); std::lock_guard<std::mutex> lock(m_mutex); m_messages.push(stream.str()); time1 = time2; miner.start(); } else { time1 = std::chrono::steady_clock::now(); } block1 = blockTemplate1.block; difficulty1 = blockTemplate1.difficulty; cryptonote::difficulty_type difficulty = difficulty1; if (!address2.empty()) { block2 = blockTemplate2.block; difficulty2 = blockTemplate2.difficulty; difficulty = std::min(difficulty, difficulty2); if (!fillExtra(block1, block2)) { std::lock_guard<std::mutex> lock(m_mutex); m_messages.push("Internal error"); return false; } } mining = std::async(std::launch::async, &Miner::findNonce, &miner, &block1, blockTemplate1.height, difficulty, threads, &hash); for (size_t i = 0; i < 50; ++i) { if (m_stopped || mining.wait_for(std::chrono::milliseconds(100)) == std::future_status::ready) { break; } } } }