/* 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 Miner.h * @author Alex Leverington * @author Gav Wood * @date 2014 */ #pragma once #include #include #include #include #include #include #include "State.h" namespace dev { namespace eth { /** * @brief Describes the progress of a mining operation. */ struct MineProgress { void combine(MineProgress const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); current = std::max(current, _m.current); hashes += _m.hashes; ms = std::max(ms, _m.ms); } double requirement = 0; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash. double best = 1e99; ///< The PoW achievement - as the second logarithm of the minimum found hash. double current = 0; ///< The most recent PoW achievement - as the second logarithm of the presently found hash. unsigned hashes = 0; ///< Total number of hashes computed. unsigned ms = 0; ///< Total number of milliseconds of mining thus far. }; /** * @brief Class for hosting one or more Miners. * @warning Must be implemented in a threadsafe manner since it will be called from multiple * miner threads. */ class MinerHost { public: virtual void setupState(State& _s) = 0; ///< Reset the given State object to the one that should be being mined. virtual void onProgressed() {} ///< Called once some progress has been made. virtual void onComplete() {} ///< Called once a block is found. virtual bool turbo() const = 0; ///< @returns true iff the Miner should mine as fast as possible. virtual bool force() const = 0; ///< @returns true iff the Miner should mine regardless of the number of transactions. }; class Miner { public: virtual ~Miner(); virtual void noteStateChange() = 0; virtual bool isComplete() const = 0; virtual bytes const& blockData() const = 0; }; class AsyncMiner: public Miner { public: /// Null constructor. AsyncMiner(): m_host(nullptr) {} /// Constructor. AsyncMiner(MinerHost* _host, unsigned _id = 0): m_host(_host), m_id(_id) {} /// Setup its basics. void setup(MinerHost* _host, unsigned _id = 0) { m_host = _host; m_id = _id; } /// Start mining. virtual void start() {} /// Stop mining. virtual void stop() {} /// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force(). virtual bool isRunning() { return false; } protected: MinerHost* m_host = nullptr; ///< Our host. unsigned m_id = 0; ///< Our unique id. }; /** * @brief Implements Miner. * To begin mining, use start() & stop(). noteStateChange() can be used to reset the mining and set up the * State object according to the host. Use isRunning() to determine if the miner has been start()ed. * Use isComplete() to determine if the miner has finished mining. * * blockData() can be used to retrieve the complete block, ready for insertion into the BlockChain. * * Information on the mining can be queried through miningProgress() and miningHistory(). * @threadsafe * @todo Signal Miner to restart once with condition variables. */ class LocalMiner: public AsyncMiner, Worker { public: /// Null constructor. LocalMiner() {} /// Constructor. LocalMiner(MinerHost* _host, unsigned _id = 0); /// Move-constructor. LocalMiner(LocalMiner&& _m): Worker((Worker&&)_m) { std::swap(m_host, _m.m_host); } /// Move-assignment. LocalMiner& operator=(LocalMiner&& _m) { Worker::operator=((Worker&&)_m); std::swap(m_host, _m.m_host); return *this; } /// Destructor. Stops miner. ~LocalMiner() { stop(); } /// Setup its basics. void setup(MinerHost* _host, unsigned _id = 0); /// Start mining. void start() { startWorking(); } /// Stop mining. void stop() { stopWorking(); } /// Call to notify Miner of a state change. virtual void noteStateChange() override { m_miningStatus = Preparing; } /// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force(). bool isRunning() { return isWorking(); } /// @returns true if mining is complete. virtual bool isComplete() const override { return m_miningStatus == Mined; } /// @returns the internal State object. virtual bytes const& blockData() const override { return m_mineState.blockData(); } /// Check the progress of the mining. MineProgress miningProgress() const { Guard l(x_mineInfo); return m_mineProgress; } /// Get and clear the mining history. std::list miningHistory() { Guard l(x_mineInfo); auto ret = m_mineHistory; m_mineHistory.clear(); return ret; } /// @returns the state on which we mined. State const& state() const { return m_mineState; } private: /// Do some work on the mining. virtual void doWork(); enum MiningStatus { Waiting, Preparing, Mining, Mined, Stopping, Stopped }; MiningStatus m_miningStatus = Waiting; ///< TODO: consider mutex/atomic variable. State m_mineState; ///< The state on which we are mining, generally equivalent to m_postMine. mutable std::mutex x_mineInfo; ///< Lock for the mining progress & history. MineProgress m_mineProgress; ///< What's our progress? std::list m_mineHistory; ///< What the history of our mining? }; } }