Browse Source

Some early refactoring to support async miners better.

cl-refactor
Gav Wood 10 years ago
parent
commit
6cf2a93e20
  1. 2
      exp/main.cpp
  2. 30
      libethcore/ProofOfWork.cpp
  3. 22
      libethcore/ProofOfWork.h
  4. 2
      libethereum/Client.cpp
  5. 4
      libethereum/Client.h
  6. 2
      libethereum/ClientBase.h
  7. 2
      libethereum/Interface.h
  8. 6
      libethereum/Miner.cpp
  9. 77
      libethereum/Miner.h
  10. 2
      libethereum/State.cpp
  11. 4
      libethereum/State.h
  12. 2
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  13. 2
      mix/MixClient.h
  14. 4
      test/blockchain.cpp

2
exp/main.cpp

@ -114,7 +114,7 @@ int main()
BlockInfo genesis = CanonBlockChain::genesis(); BlockInfo genesis = CanonBlockChain::genesis();
genesis.difficulty = 1 << 18; genesis.difficulty = 1 << 18;
cdebug << (h256)u256((bigint(1) << 256) / genesis.difficulty); cdebug << (h256)u256((bigint(1) << 256) / genesis.difficulty);
std::pair<MineInfo, Ethash::Proof> r; std::pair<MineInfo, Ethash::Solution> r;
while (!r.first.completed) while (!r.first.completed)
r = ecl.mine(genesis, 1000); r = ecl.mine(genesis, 1000);
cdebug << r.second.mixHash << r.second.nonce; cdebug << r.second.mixHash << r.second.nonce;

30
libethcore/ProofOfWork.cpp

@ -50,16 +50,16 @@ bool EthashPoW::verify(BlockInfo const& _header)
return Ethasher::verify(_header); return Ethasher::verify(_header);
} }
std::pair<MineInfo, EthashCPU::Proof> EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) std::pair<MineInfo, EthashCPU::Solution> EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue)
{ {
Ethasher::Miner m(_header); Ethasher::Miner m(_header);
std::pair<MineInfo, Proof> ret; std::pair<MineInfo, Solution> ret;
auto tid = std::this_thread::get_id(); auto tid = std::this_thread::get_id();
static std::mt19937_64 s_eng((time(0) + *reinterpret_cast<unsigned*>(m_last.data()) + std::hash<decltype(tid)>()(tid))); static std::mt19937_64 s_eng((time(0) + *reinterpret_cast<unsigned*>(m_last.data()) + std::hash<decltype(tid)>()(tid)));
uint64_t tryNonce = (uint64_t)(u64)(m_last = Nonce::random(s_eng)); uint64_t tryNonce = (uint64_t)(u64)(m_last = Nonce::random(s_eng));
h256 boundary = u256((bigint(1) << 256) / _header.difficulty); h256 boundary = _header.boundary();
ret.first.requirement = log2((double)(u256)boundary); ret.first.requirement = log2((double)(u256)boundary);
// 2^ 0 32 64 128 256 // 2^ 0 32 64 128 256
@ -68,7 +68,7 @@ std::pair<MineInfo, EthashCPU::Proof> EthashCPU::mine(BlockInfo const& _header,
// evaluate until we run out of time // evaluate until we run out of time
auto startTime = std::chrono::steady_clock::now(); auto startTime = std::chrono::steady_clock::now();
double best = 1e99; // high enough to be effectively infinity :) double best = 1e99; // high enough to be effectively infinity :)
Proof result; Solution result;
unsigned hashCount = 0; unsigned hashCount = 0;
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++) for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++)
{ {
@ -128,7 +128,7 @@ struct EthashCLHook: public ethash_cl_miner::search_hook
{ {
if (m_aborted) if (m_aborted)
return; return;
cdebug << "Attempting to abort"; // cdebug << "Attempting to abort";
m_abort = true; m_abort = true;
for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout)
std::this_thread::sleep_for(chrono::milliseconds(30)); std::this_thread::sleep_for(chrono::milliseconds(30));
@ -148,14 +148,14 @@ protected:
for (unsigned i = 0; i < _count; ++i) for (unsigned i = 0; i < _count; ++i)
m_found.push_back((Nonce)(u64)_nonces[i]); m_found.push_back((Nonce)(u64)_nonces[i]);
m_aborted = true; m_aborted = true;
cdebug << "Found nonces: " << vector<uint64_t>(_nonces, _nonces + _count); // cdebug << "Found nonces: " << vector<uint64_t>(_nonces, _nonces + _count);
return true; return true;
} }
virtual bool searched(uint64_t _startNonce, uint32_t _count) override virtual bool searched(uint64_t _startNonce, uint32_t _count) override
{ {
Guard l(x_all); Guard l(x_all);
cdebug << "Searched" << _count << "from" << _startNonce; // cdebug << "Searched" << _count << "from" << _startNonce;
m_total += _count; m_total += _count;
m_last = _startNonce + _count; m_last = _startNonce + _count;
if (m_abort) if (m_abort)
@ -184,7 +184,7 @@ EthashCL::~EthashCL()
{ {
} }
std::pair<MineInfo, Ethash::Proof> EthashCL::mine(BlockInfo const& _header, unsigned _msTimeout, bool) std::pair<MineInfo, Ethash::Solution> EthashCL::mine(BlockInfo const& _header, unsigned _msTimeout, bool)
{ {
if (!m_lastHeader || m_lastHeader.seedHash() != _header.seedHash()) if (!m_lastHeader || m_lastHeader.seedHash() != _header.seedHash())
{ {
@ -206,7 +206,14 @@ std::pair<MineInfo, Ethash::Proof> EthashCL::mine(BlockInfo const& _header, unsi
} }
m_lastHeader = _header; m_lastHeader = _header;
MineInfo mi;
Solution proof;
mi.requirement = log2((double)(u256)_header.boundary());
mi.best = 0;
std::this_thread::sleep_for(chrono::milliseconds(_msTimeout)); std::this_thread::sleep_for(chrono::milliseconds(_msTimeout));
mi.hashes += m_hook->fetchTotal();
auto found = m_hook->fetchFound(); auto found = m_hook->fetchFound();
if (!found.empty()) if (!found.empty())
{ {
@ -214,10 +221,13 @@ std::pair<MineInfo, Ethash::Proof> EthashCL::mine(BlockInfo const& _header, unsi
{ {
auto result = Ethasher::eval(_header, n); auto result = Ethasher::eval(_header, n);
if (result.value < _header.boundary()) if (result.value < _header.boundary())
return std::make_pair(MineInfo(true), EthashCL::Proof{n, result.mixHash}); {
mi.completed = true;
proof = Solution{n, result.mixHash};
}
} }
} }
return std::make_pair(MineInfo(false), EthashCL::Proof()); return std::make_pair(mi, proof);
} }
#endif #endif

22
libethcore/ProofOfWork.h

@ -54,23 +54,23 @@ struct MineInfo
class EthashPoW class EthashPoW
{ {
public: public:
struct Proof struct Solution
{ {
Nonce nonce; Nonce nonce;
h256 mixHash; h256 mixHash;
}; };
static bool verify(BlockInfo const& _header); static bool verify(BlockInfo const& _header);
static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; }
virtual unsigned defaultTimeout() const { return 100; } virtual unsigned defaultTimeout() const { return 100; }
virtual std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) = 0; virtual std::pair<MineInfo, Solution> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) = 0;
}; };
class EthashCPU: public EthashPoW class EthashCPU: public EthashPoW
{ {
public: public:
std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; std::pair<MineInfo, Solution> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override;
protected: protected:
Nonce m_last; Nonce m_last;
@ -85,7 +85,7 @@ public:
EthashCL(); EthashCL();
~EthashCL(); ~EthashCL();
std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; std::pair<MineInfo, Solution> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override;
unsigned defaultTimeout() const override { return 500; } unsigned defaultTimeout() const override { return 500; }
protected: protected:
@ -105,11 +105,11 @@ template <class Evaluator>
class ProofOfWorkEngine: public Evaluator class ProofOfWorkEngine: public Evaluator
{ {
public: public:
using Proof = Nonce; using Solution = Nonce;
static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; } static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; }
inline std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true); inline std::pair<MineInfo, Solution> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true);
static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r; } static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r; }
unsigned defaultTimeout() const { return 100; } unsigned defaultTimeout() const { return 100; }
protected: protected:
@ -127,7 +127,7 @@ using SHA3ProofOfWork = ProofOfWorkEngine<SHA3Evaluator>;
using ProofOfWork = Ethash; using ProofOfWork = Ethash;
template <class Evaluator> template <class Evaluator>
std::pair<MineInfo, typename ProofOfWorkEngine<Evaluator>::Proof> ProofOfWorkEngine<Evaluator>::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) std::pair<MineInfo, typename ProofOfWorkEngine<Evaluator>::Solution> ProofOfWorkEngine<Evaluator>::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue)
{ {
auto headerHashWithoutNonce = _header.headerHash(WithoutNonce); auto headerHashWithoutNonce = _header.headerHash(WithoutNonce);
auto difficulty = _header.difficulty; auto difficulty = _header.difficulty;
@ -145,11 +145,11 @@ std::pair<MineInfo, typename ProofOfWorkEngine<Evaluator>::Proof> ProofOfWorkEng
// evaluate until we run out of time // evaluate until we run out of time
auto startTime = std::chrono::steady_clock::now(); auto startTime = std::chrono::steady_clock::now();
double best = 1e99; // high enough to be effectively infinity :) double best = 1e99; // high enough to be effectively infinity :)
ProofOfWorkEngine<Evaluator>::Proof solution; ProofOfWorkEngine<Evaluator>::Solution solution;
unsigned h = 0; unsigned h = 0;
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, h++) for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, h++)
{ {
solution = (ProofOfWorkEngine<Evaluator>::Proof)s; solution = (ProofOfWorkEngine<Evaluator>::Solution)s;
auto e = (bigint)(u256)Evaluator::eval(headerHashWithoutNonce, solution); auto e = (bigint)(u256)Evaluator::eval(headerHashWithoutNonce, solution);
best = std::min<double>(best, log2((double)e)); best = std::min<double>(best, log2((double)e));
if (e <= d) if (e <= d)

2
libethereum/Client.cpp

@ -452,7 +452,7 @@ pair<h256, u256> Client::getWork()
return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty()); return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty());
} }
bool Client::submitWork(ProofOfWork::Proof const& _proof) bool Client::submitWork(ProofOfWork::Solution const& _proof)
{ {
Guard l(x_remoteMiner); Guard l(x_remoteMiner);
return m_remoteMiner.submitWork(_proof); return m_remoteMiner.submitWork(_proof);

4
libethereum/Client.h

@ -82,7 +82,7 @@ public:
h256 workHash() const { return m_state.info().headerHash(IncludeNonce::WithoutNonce); } h256 workHash() const { return m_state.info().headerHash(IncludeNonce::WithoutNonce); }
u256 const& difficulty() const { return m_state.info().difficulty; } u256 const& difficulty() const { return m_state.info().difficulty; }
bool submitWork(ProofOfWork::Proof const& _result) { return (m_isComplete = m_state.completeMine(_result)); } bool submitWork(ProofOfWork::Solution const& _result) { return (m_isComplete = m_state.completeMine(_result)); }
virtual bool isComplete() const override { return m_isComplete; } virtual bool isComplete() const override { return m_isComplete; }
virtual bytes const& blockData() const { return m_state.blockData(); } virtual bytes const& blockData() const { return m_state.blockData(); }
@ -216,7 +216,7 @@ public:
/// nonce (the 'work hash') and the difficulty to be met. /// nonce (the 'work hash') and the difficulty to be met.
virtual std::pair<h256, u256> getWork() override; virtual std::pair<h256, u256> getWork() override;
/// Submit the proof for the proof-of-work. /// Submit the proof for the proof-of-work.
virtual bool submitWork(ProofOfWork::Proof const& _proof) override; virtual bool submitWork(ProofOfWork::Solution const& _proof) override;
// Debug stuff: // Debug stuff:

2
libethereum/ClientBase.h

@ -150,7 +150,7 @@ public:
virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::hashrate")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::hashrate")); }
virtual eth::MineProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningProgress")); } virtual eth::MineProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningProgress")); }
virtual std::pair<h256, u256> getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::getWork")); } virtual std::pair<h256, u256> getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::getWork")); }
virtual bool submitWork(eth::ProofOfWork::Proof const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); } virtual bool submitWork(eth::ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); }
State asOf(BlockNumber _h) const; State asOf(BlockNumber _h) const;

2
libethereum/Interface.h

@ -190,7 +190,7 @@ public:
/// Get hash of the current block to be mined minus the nonce (the 'work hash'). /// Get hash of the current block to be mined minus the nonce (the 'work hash').
virtual std::pair<h256, u256> getWork() = 0; virtual std::pair<h256, u256> getWork() = 0;
/// Submit the nonce for the proof-of-work. /// Submit the nonce for the proof-of-work.
virtual bool submitWork(ProofOfWork::Proof const& _proof) = 0; virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0;
/// Check the progress of the mining. /// Check the progress of the mining.
virtual MineProgress miningProgress() const = 0; virtual MineProgress miningProgress() const = 0;

6
libethereum/Miner.cpp

@ -30,11 +30,9 @@ using namespace dev::eth;
Miner::~Miner() {} Miner::~Miner() {}
LocalMiner::LocalMiner(MinerHost* _host, unsigned _id): LocalMiner::LocalMiner(MinerHost* _host, unsigned _id)
AsyncMiner(_host, _id),
Worker("miner-" + toString(_id))
{ {
m_pow.reset(_host->turbo() ? new Ethash : (Ethash*)new EthashCPU); setup(_host, _id);
} }
void LocalMiner::setup(MinerHost* _host, unsigned _id) void LocalMiner::setup(MinerHost* _host, unsigned _id)

77
libethereum/Miner.h

@ -36,6 +36,15 @@ namespace dev
namespace eth namespace eth
{ {
struct WorkPackage
{
h256 boundary;
h256 headerHash; ///< When h256() means "pause until notified a new work package is available".
h256 seedHash;
};
static const WorkPackage NullWorkPackage;
/** /**
* @brief Describes the progress of a mining operation. * @brief Describes the progress of a mining operation.
*/ */
@ -57,6 +66,10 @@ struct MineProgress
class MinerHost class MinerHost
{ {
public: public:
// ============================= NEW API =============================
virtual WorkPackage const& getWork() const { return NullWorkPackage; }
// ============================= OLD API =============================
virtual void setupState(State& _s) = 0; ///< Reset the given State object to the one that should be being mined. 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 onProgressed() {} ///< Called once some progress has been made.
virtual void onComplete() {} ///< Called once a block is found. virtual void onComplete() {} ///< Called once a block is found.
@ -174,5 +187,69 @@ private:
std::list<MineInfo> m_mineHistory; ///< What the history of our mining? std::list<MineInfo> m_mineHistory; ///< What the history of our mining?
}; };
/**
* @brief A collective of Miners.
* Miners ask for work, then submit proofs
* @threadsafe
*/
class Farm: public MinerHost
{
public:
/**
* @brief Sets the current mining mission.
* @param _bi The block (header) we wish to be mining.
*/
void setWork(BlockInfo const& _bi);
/**
* @brief (Re)start miners for CPU only.
* @returns true if started properly.
*/
bool startCPU();
/**
* @brief (Re)start miners for GPU only.
* @returns true if started properly.
*/
bool startGPU();
/**
* @brief Stop all mining activities.
*/
void stop();
/**
* @brief Get information on the progress of mining this work package.
* @return The progress with mining so far.
*/
MineProgress const& mineProgress() const { ReadGuard l(x_progress); return m_progress; }
protected:
/**
* @brief Called by a Miner to retrieve a work package. Reimplemented from MinerHost.
* @return The work package to solve.
*/
virtual WorkPackage const& getWork() const override { ReadGuard l(x_work); return m_work; }
/**
* @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 .
*/
virtual bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp) = 0;
private:
mutable SharedMutex x_miners;
std::vector<std::shared_ptr<Miner>> m_miners;
mutable SharedMutex x_progress;
MineProgress m_progress;
mutable SharedMutex x_work;
WorkPackage m_work;
};
} }
} }

2
libethereum/State.cpp

@ -856,7 +856,7 @@ void State::commitToMine(BlockChain const& _bc)
m_committedToMine = true; m_committedToMine = true;
} }
bool State::completeMine(ProofOfWork::Proof const& _nonce) bool State::completeMine(ProofOfWork::Solution const& _nonce)
{ {
ProofOfWork::assignResult(_nonce, m_currentBlock); ProofOfWork::assignResult(_nonce, m_currentBlock);

4
libethereum/State.h

@ -162,7 +162,7 @@ public:
/// Pass in a solution to the proof-of-work. /// Pass in a solution to the proof-of-work.
/// @returns true iff the given nonce is a proof-of-work for this State's block. /// @returns true iff the given nonce is a proof-of-work for this State's block.
bool completeMine(ProofOfWork::Proof const& _result); bool completeMine(ProofOfWork::Solution const& _result);
/// Attempt to find valid nonce for block that this state represents. /// Attempt to find valid nonce for block that this state represents.
/// This function is thread-safe. You can safely have other interactions with this object while it is happening. /// This function is thread-safe. You can safely have other interactions with this object while it is happening.
@ -174,7 +174,7 @@ public:
m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock);
MineInfo ret; MineInfo ret;
typename ProofOfWork::Proof r; typename ProofOfWork::Solution r;
std::tie(ret, r) = _pow->mine(m_currentBlock, _pow->defaultTimeout(), true); std::tie(ret, r) = _pow->mine(m_currentBlock, _pow->defaultTimeout(), true);
if (!ret.completed) if (!ret.completed)

2
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -767,7 +767,7 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&
{ {
try try
{ {
return client()->submitWork(ProofOfWork::Proof{jsToFixed<Nonce::size>(_nonce), jsToFixed<32>(_mixHash)}); return client()->submitWork(ProofOfWork::Solution{jsToFixed<Nonce::size>(_nonce), jsToFixed<32>(_mixHash)});
} }
catch (...) catch (...)
{ {

2
mix/MixClient.h

@ -71,7 +71,7 @@ public:
uint64_t hashrate() const override; uint64_t hashrate() const override;
eth::MineProgress miningProgress() const override; eth::MineProgress miningProgress() const override;
std::pair<h256, u256> getWork() override { return std::pair<h256, u256>(); } std::pair<h256, u256> getWork() override { return std::pair<h256, u256>(); }
bool submitWork(eth::ProofOfWork::Proof const&) override { return false; } bool submitWork(eth::ProofOfWork::Solution const&) override { return false; }
virtual void flushTransactions() override {} virtual void flushTransactions() override {}
/// @returns the last mined block information /// @returns the last mined block information

4
test/blockchain.cpp

@ -587,7 +587,7 @@ void overwriteBlockHeader(BlockInfo& _currentBlockHeader, mObject& _blObj)
_currentBlockHeader = tmp; _currentBlockHeader = tmp;
ProofOfWork pow; ProofOfWork pow;
std::pair<MineInfo, Ethash::Proof> ret; std::pair<MineInfo, Ethash::Solution> ret;
while (!ProofOfWork::verify(_currentBlockHeader)) while (!ProofOfWork::verify(_currentBlockHeader))
{ {
ret = pow.mine(_currentBlockHeader, 1000, true); ret = pow.mine(_currentBlockHeader, 1000, true);
@ -632,7 +632,7 @@ BlockInfo constructBlock(mObject& _o)
void updatePoW(BlockInfo& _bi) void updatePoW(BlockInfo& _bi)
{ {
ProofOfWork pow; ProofOfWork pow;
std::pair<MineInfo, Ethash::Proof> ret; std::pair<MineInfo, Ethash::Solution> ret;
while (!ProofOfWork::verify(_bi)) while (!ProofOfWork::verify(_bi))
{ {
ret = pow.mine(_bi, 10000, true); ret = pow.mine(_bi, 10000, true);

Loading…
Cancel
Save