// Copyright (c) 2011-2016 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "Miner.h" #include #include "crypto/crypto.h" #include "CryptoNoteCore/CryptoNoteFormatUtils.h" #include namespace CryptoNote { Miner::Miner(System::Dispatcher& dispatcher, Logging::ILogger& logger) : m_dispatcher(dispatcher), m_miningStopped(dispatcher), m_state(MiningState::MINING_STOPPED), m_logger(logger, "Miner") { } Miner::~Miner() { assert(m_state != MiningState::MINING_IN_PROGRESS); } Block Miner::mine(const BlockMiningParameters& blockMiningParameters, size_t threadCount) { if (threadCount == 0) { throw std::runtime_error("Miner requires at least one thread"); } if (m_state == MiningState::MINING_IN_PROGRESS) { throw std::runtime_error("Mining is already in progress"); } m_state = MiningState::MINING_IN_PROGRESS; m_miningStopped.clear(); runWorkers(blockMiningParameters, threadCount); assert(m_state != MiningState::MINING_IN_PROGRESS); if (m_state == MiningState::MINING_STOPPED) { m_logger(Logging::DEBUGGING) << "Mining has been stopped"; throw System::InterruptedException(); } assert(m_state == MiningState::BLOCK_FOUND); return m_block; } void Miner::stop() { MiningState state = MiningState::MINING_IN_PROGRESS; if (m_state.compare_exchange_weak(state, MiningState::MINING_STOPPED)) { m_miningStopped.wait(); m_miningStopped.clear(); } } void Miner::runWorkers(BlockMiningParameters blockMiningParameters, size_t threadCount) { assert(threadCount > 0); m_logger(Logging::INFO) << "Starting mining for difficulty " << blockMiningParameters.difficulty; try { blockMiningParameters.blockTemplate.nonce = Crypto::rand(); for (size_t i = 0; i < threadCount; ++i) { m_workers.emplace_back(std::unique_ptr> ( new System::RemoteContext(m_dispatcher, std::bind(&Miner::workerFunc, this, blockMiningParameters.blockTemplate, blockMiningParameters.difficulty, threadCount))) ); blockMiningParameters.blockTemplate.nonce++; } m_workers.clear(); } catch (std::exception& e) { m_logger(Logging::ERROR) << "Error occured during mining: " << e.what(); m_state = MiningState::MINING_STOPPED; } m_miningStopped.set(); } void Miner::workerFunc(const Block& blockTemplate, difficulty_type difficulty, uint32_t nonceStep) { try { Block block = blockTemplate; Crypto::cn_context cryptoContext; while (m_state == MiningState::MINING_IN_PROGRESS) { Crypto::Hash hash; if (!get_block_longhash(cryptoContext, block, hash)) { //error occured m_logger(Logging::DEBUGGING) << "calculating long hash error occured"; m_state = MiningState::MINING_STOPPED; return; } if (check_hash(hash, difficulty)) { m_logger(Logging::INFO) << "Found block for difficulty " << difficulty; if (!setStateBlockFound()) { m_logger(Logging::DEBUGGING) << "block is already found or mining stopped"; return; } m_block = block; return; } block.nonce += nonceStep; } } catch (std::exception& e) { m_logger(Logging::ERROR) << "Miner got error: " << e.what(); m_state = MiningState::MINING_STOPPED; } } bool Miner::setStateBlockFound() { auto state = m_state.load(); for (;;) { switch (state) { case MiningState::BLOCK_FOUND: return false; case MiningState::MINING_IN_PROGRESS: if (m_state.compare_exchange_weak(state, MiningState::BLOCK_FOUND)) { return true; } break; case MiningState::MINING_STOPPED: return false; default: assert(false); return false; } } } } //namespace CryptoNote