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();
genesis.difficulty = 1 << 18;
cdebug << (h256)u256((bigint(1) << 256) / genesis.difficulty);
std::pair<MineInfo, Ethash::Proof> r;
std::pair<MineInfo, Ethash::Solution> r;
while (!r.first.completed)
r = ecl.mine(genesis, 1000);
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);
}
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);
std::pair<MineInfo, Proof> ret;
std::pair<MineInfo, Solution> ret;
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)));
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);
// 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
auto startTime = std::chrono::steady_clock::now();
double best = 1e99; // high enough to be effectively infinity :)
Proof result;
Solution result;
unsigned hashCount = 0;
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)
return;
cdebug << "Attempting to abort";
// cdebug << "Attempting to abort";
m_abort = true;
for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout)
std::this_thread::sleep_for(chrono::milliseconds(30));
@ -148,14 +148,14 @@ protected:
for (unsigned i = 0; i < _count; ++i)
m_found.push_back((Nonce)(u64)_nonces[i]);
m_aborted = true;
cdebug << "Found nonces: " << vector<uint64_t>(_nonces, _nonces + _count);
// cdebug << "Found nonces: " << vector<uint64_t>(_nonces, _nonces + _count);
return true;
}
virtual bool searched(uint64_t _startNonce, uint32_t _count) override
{
Guard l(x_all);
cdebug << "Searched" << _count << "from" << _startNonce;
// cdebug << "Searched" << _count << "from" << _startNonce;
m_total += _count;
m_last = _startNonce + _count;
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())
{
@ -206,7 +206,14 @@ std::pair<MineInfo, Ethash::Proof> EthashCL::mine(BlockInfo const& _header, unsi
}
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));
mi.hashes += m_hook->fetchTotal();
auto found = m_hook->fetchFound();
if (!found.empty())
{
@ -214,10 +221,13 @@ std::pair<MineInfo, Ethash::Proof> EthashCL::mine(BlockInfo const& _header, unsi
{
auto result = Ethasher::eval(_header, n);
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

22
libethcore/ProofOfWork.h

@ -54,23 +54,23 @@ struct MineInfo
class EthashPoW
{
public:
struct Proof
struct Solution
{
Nonce nonce;
h256 mixHash;
};
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 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
{
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:
Nonce m_last;
@ -85,7 +85,7 @@ public:
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; }
protected:
@ -105,11 +105,11 @@ template <class Evaluator>
class ProofOfWorkEngine: public Evaluator
{
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; }
inline std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true);
static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r; }
inline std::pair<MineInfo, Solution> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true);
static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r; }
unsigned defaultTimeout() const { return 100; }
protected:
@ -127,7 +127,7 @@ using SHA3ProofOfWork = ProofOfWorkEngine<SHA3Evaluator>;
using ProofOfWork = Ethash;
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 difficulty = _header.difficulty;
@ -145,11 +145,11 @@ std::pair<MineInfo, typename ProofOfWorkEngine<Evaluator>::Proof> ProofOfWorkEng
// evaluate until we run out of time
auto startTime = std::chrono::steady_clock::now();
double best = 1e99; // high enough to be effectively infinity :)
ProofOfWorkEngine<Evaluator>::Proof solution;
ProofOfWorkEngine<Evaluator>::Solution solution;
unsigned h = 0;
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);
best = std::min<double>(best, log2((double)e));
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());
}
bool Client::submitWork(ProofOfWork::Proof const& _proof)
bool Client::submitWork(ProofOfWork::Solution const& _proof)
{
Guard l(x_remoteMiner);
return m_remoteMiner.submitWork(_proof);

4
libethereum/Client.h

@ -82,7 +82,7 @@ public:
h256 workHash() const { return m_state.info().headerHash(IncludeNonce::WithoutNonce); }
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 bytes const& blockData() const { return m_state.blockData(); }
@ -216,7 +216,7 @@ public:
/// nonce (the 'work hash') and the difficulty to be met.
virtual std::pair<h256, u256> getWork() override;
/// 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:

2
libethereum/ClientBase.h

@ -150,7 +150,7 @@ public:
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 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;

2
libethereum/Interface.h

@ -190,7 +190,7 @@ public:
/// Get hash of the current block to be mined minus the nonce (the 'work hash').
virtual std::pair<h256, u256> getWork() = 0;
/// 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.
virtual MineProgress miningProgress() const = 0;

6
libethereum/Miner.cpp

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

77
libethereum/Miner.h

@ -36,6 +36,15 @@ namespace dev
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.
*/
@ -57,6 +66,10 @@ struct MineProgress
class MinerHost
{
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 onProgressed() {} ///< Called once some progress has been made.
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?
};
/**
* @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;
}
bool State::completeMine(ProofOfWork::Proof const& _nonce)
bool State::completeMine(ProofOfWork::Solution const& _nonce)
{
ProofOfWork::assignResult(_nonce, m_currentBlock);

4
libethereum/State.h

@ -162,7 +162,7 @@ public:
/// 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.
bool completeMine(ProofOfWork::Proof const& _result);
bool completeMine(ProofOfWork::Solution const& _result);
/// 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.
@ -174,7 +174,7 @@ public:
m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock);
MineInfo ret;
typename ProofOfWork::Proof r;
typename ProofOfWork::Solution r;
std::tie(ret, r) = _pow->mine(m_currentBlock, _pow->defaultTimeout(), true);
if (!ret.completed)

2
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -767,7 +767,7 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&
{
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 (...)
{

2
mix/MixClient.h

@ -71,7 +71,7 @@ public:
uint64_t hashrate() const override;
eth::MineProgress miningProgress() const override;
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 {}
/// @returns the last mined block information

4
test/blockchain.cpp

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

Loading…
Cancel
Save