|
|
@ -30,8 +30,8 @@ |
|
|
|
#include <libdevcrypto/CryptoPP.h> |
|
|
|
#include <libdevcrypto/FileSystem.h> |
|
|
|
#include <libdevcore/Common.h> |
|
|
|
#include <libethash/ethash.h> |
|
|
|
#include "BlockInfo.h" |
|
|
|
#include "Ethasher.h" |
|
|
|
#include "ProofOfWork.h" |
|
|
|
using namespace std; |
|
|
|
using namespace std::chrono; |
|
|
@ -41,100 +41,14 @@ namespace dev |
|
|
|
namespace eth |
|
|
|
{ |
|
|
|
|
|
|
|
class Ethasher |
|
|
|
{ |
|
|
|
public: |
|
|
|
Ethasher() {} |
|
|
|
|
|
|
|
static Ethasher* get() { if (!s_this) s_this = new Ethasher(); return s_this; } |
|
|
|
|
|
|
|
bytes const& cache(BlockInfo const& _header) |
|
|
|
{ |
|
|
|
RecursiveGuard l(x_this); |
|
|
|
if (!m_caches.count(_header.seedHash)) |
|
|
|
{ |
|
|
|
try { |
|
|
|
boost::filesystem::create_directories(getDataDir() + "/ethashcache"); |
|
|
|
} catch (...) {} |
|
|
|
std::string memoFile = getDataDir() + "/ethashcache/" + toHex(_header.seedHash.ref().cropped(0, 4)) + ".cache"; |
|
|
|
m_caches[_header.seedHash] = contents(memoFile); |
|
|
|
if (m_caches[_header.seedHash].empty()) |
|
|
|
{ |
|
|
|
ethash_params p = params((unsigned)_header.number); |
|
|
|
m_caches[_header.seedHash].resize(p.cache_size); |
|
|
|
ethash_prep_light(m_caches[_header.seedHash].data(), &p, _header.seedHash.data()); |
|
|
|
writeFile(memoFile, m_caches[_header.seedHash]); |
|
|
|
} |
|
|
|
} |
|
|
|
return m_caches[_header.seedHash]; |
|
|
|
} |
|
|
|
|
|
|
|
byte const* full(BlockInfo const& _header) |
|
|
|
{ |
|
|
|
RecursiveGuard l(x_this); |
|
|
|
if (!m_fulls.count(_header.seedHash)) |
|
|
|
{ |
|
|
|
if (!m_fulls.empty()) |
|
|
|
{ |
|
|
|
delete [] m_fulls.begin()->second.data(); |
|
|
|
m_fulls.erase(m_fulls.begin()); |
|
|
|
} |
|
|
|
std::string memoFile = getDataDir() + "/ethashcache/" + toHex(_header.seedHash.ref().cropped(0, 4)) + ".full"; |
|
|
|
m_fulls[_header.seedHash] = contentsNew(memoFile); |
|
|
|
if (!m_fulls[_header.seedHash]) |
|
|
|
{ |
|
|
|
ethash_params p = params((unsigned)_header.number); |
|
|
|
m_fulls[_header.seedHash] = bytesRef(new byte[p.full_size], p.full_size); |
|
|
|
auto c = cache(_header); |
|
|
|
ethash_prep_full(m_fulls[_header.seedHash].data(), &p, c.data()); |
|
|
|
writeFile(memoFile, m_fulls[_header.seedHash]); |
|
|
|
} |
|
|
|
} |
|
|
|
return m_fulls[_header.seedHash].data(); |
|
|
|
} |
|
|
|
|
|
|
|
static ethash_params params(BlockInfo const& _header) |
|
|
|
{ |
|
|
|
return params((unsigned)_header.number); |
|
|
|
} |
|
|
|
|
|
|
|
static ethash_params params(unsigned _n) |
|
|
|
{ |
|
|
|
ethash_params p; |
|
|
|
p.cache_size = ethash_get_cachesize(_n); |
|
|
|
p.full_size = ethash_get_datasize(_n); |
|
|
|
return p; |
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
static Ethasher* s_this; |
|
|
|
RecursiveMutex x_this; |
|
|
|
std::map<h256, bytes> m_caches; |
|
|
|
std::map<h256, bytesRef> m_fulls; |
|
|
|
}; |
|
|
|
|
|
|
|
Ethasher* Ethasher::s_this = nullptr; |
|
|
|
|
|
|
|
bool Ethash::verify(BlockInfo const& _header) |
|
|
|
{ |
|
|
|
bigint boundary = (bigint(1) << 256) / _header.difficulty; |
|
|
|
auto e = eval(_header, _header.nonce); |
|
|
|
return (u256)e.value <= boundary && e.mixHash == _header.mixHash; |
|
|
|
} |
|
|
|
|
|
|
|
Ethash::Result Ethash::eval(BlockInfo const& _header, Nonce const& _nonce) |
|
|
|
{ |
|
|
|
auto p = Ethasher::params(_header); |
|
|
|
ethash_return_value r; |
|
|
|
ethash_compute_light(&r, Ethasher::get()->cache(_header).data(), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce); |
|
|
|
return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; |
|
|
|
return Ethasher::verify(_header); |
|
|
|
} |
|
|
|
|
|
|
|
std::pair<MineInfo, Ethash::Proof> Ethash::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue, bool _turbo) |
|
|
|
{ |
|
|
|
auto h = _header.headerHash(WithoutNonce); |
|
|
|
auto p = Ethasher::params(_header); |
|
|
|
auto d = Ethasher::get()->full(_header); |
|
|
|
Ethasher::Miner m(_header); |
|
|
|
|
|
|
|
std::pair<MineInfo, Proof> ret; |
|
|
|
static std::mt19937_64 s_eng((time(0) + *reinterpret_cast<unsigned*>(m_last.data()))); |
|
|
@ -152,17 +66,15 @@ std::pair<MineInfo, Ethash::Proof> Ethash::mine(BlockInfo const& _header, unsign |
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100)); |
|
|
|
double best = 1e99; // high enough to be effectively infinity :)
|
|
|
|
Proof result; |
|
|
|
ethash_return_value ethashReturn; |
|
|
|
unsigned hashCount = 0; |
|
|
|
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++) |
|
|
|
{ |
|
|
|
ethash_compute_full(ðashReturn, d, &p, h.data(), tryNonce); |
|
|
|
u256 val(h256(ethashReturn.result, h256::ConstructFromPointer)); |
|
|
|
u256 val(m.mine(tryNonce)); |
|
|
|
best = std::min<double>(best, log2((double)val)); |
|
|
|
if (val <= boundary) |
|
|
|
{ |
|
|
|
ret.first.completed = true; |
|
|
|
result.mixHash = h256(ethashReturn.mix_hash, h256::ConstructFromPointer); |
|
|
|
result.mixHash = m.lastMixHash(); |
|
|
|
result.nonce = u64(tryNonce); |
|
|
|
break; |
|
|
|
} |
|
|
|