/* This file is part of cpp-ethereum. cpp-ethereum is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ /** @file Farm.h * @author Gav Wood * @date 2015 */ #pragma once #include #include #include #include #include #include #include #include #include namespace dev { namespace eth { /** * @brief A collective of Miners. * Miners ask for work, then submit proofs * @threadsafe */ template class GenericFarm: public GenericFarmFace { public: using WorkPackage = typename PoW::WorkPackage; using Solution = typename PoW::Solution; using Miner = GenericMiner; ~GenericFarm() { stop(); } /** * @brief Sets the current mining mission. * @param _bi The block (header) we wish to be mining. */ void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); } /** * @brief Sets the current mining mission. * @param _wp The work package we wish to be mining. */ void setWork(WorkPackage const& _wp) { WriteGuard l(x_minerWork); if (_wp.headerHash == m_work.headerHash) return; m_work = _wp; for (auto const& m: m_miners) m->setWork(m_work); resetTimer(); } /** * @brief (Re)start miners for CPU only. * @returns true if started properly. */ bool startCPU() { return start(); } /** * @brief (Re)start miners for GPU only. * @returns true if started properly. */ bool startGPU() { return start(); } /** * @brief Stop all mining activities. */ void stop() { WriteGuard l(x_minerWork); m_miners.clear(); m_work.reset(); m_isMining = false; } bool isMining() const { return m_isMining; } /** * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ MiningProgress const& miningProgress() const { MiningProgress p; p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); { ReadGuard l2(x_minerWork); for (auto const& i: m_miners) p.hashes += i->hashCount(); } ReadGuard l(x_progress); m_progress = p; return m_progress; } /** * @brief Reset the mining progess counter. */ void resetMiningProgress() { ETH_READ_GUARDED(x_minerWork) for (auto const& i: m_miners) i->resetHashCount(); resetTimer(); } using SolutionFound = std::function; /** * @brief Provides a valid header based upon that received previously with setWork(). * @param _bi The now-valid header. * @return true if the header was good and that the Farm should pause until more work is submitted. */ void onSolutionFound(SolutionFound const& _handler) { m_onSolutionFound = _handler; } WorkPackage work() const { ReadGuard l(x_minerWork); return m_work; } private: /** * @brief Called from a Miner to note a WorkPackage has a solution. * @param _p The solution. * @param _wp The WorkPackage that the Solution is for. * @return true iff the solution was good (implying that mining should be . */ bool submitProof(Solution const& _s, Miner* _m) override { if (m_onSolutionFound && m_onSolutionFound(_s)) { WriteGuard ul(x_minerWork); for (std::shared_ptr const& m: m_miners) if (m.get() != _m) m->setWork(); m_work.reset(); return true; } return false; } /** * @brief Start a number of miners. */ template bool start() { WriteGuard l(x_minerWork); if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) return true; m_miners.clear(); m_miners.reserve(MinerType::instances()); for (unsigned i = 0; i < MinerType::instances(); ++i) { m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); m_miners.back()->setWork(m_work); } m_isMining = true; resetTimer(); return true; } void resetTimer() { m_lastStart = std::chrono::steady_clock::now(); } mutable SharedMutex x_minerWork; std::vector> m_miners; WorkPackage m_work; std::atomic m_isMining = {false}; mutable SharedMutex x_progress; mutable MiningProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; }; } }