@ -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,14 +41,100 @@ 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 )
{
return Ethasher : : verify ( _header ) ;
bigint boundary = ( bigint ( 1 ) < < 256 ) / _header . difficulty ;
u256 e ( eval ( _header , _header . nonce ) ) ;
return e < = boundary ;
}
h256 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 h256 ( r . result , h256 : : ConstructFromPointer ) ;
}
std : : pair < MineInfo , Ethash : : Proof > Ethash : : mine ( BlockInfo const & _header , unsigned _msTimeout , bool _continue , bool _turbo )
{
Ethasher : : Miner m ( _header ) ;
auto h = _header . headerHash ( WithoutNonce ) ;
auto p = Ethasher : : params ( _header ) ;
auto d = Ethasher : : get ( ) - > full ( _header ) ;
std : : pair < MineInfo , Proof > ret ;
static std : : mt19937_64 s_eng ( ( time ( 0 ) + * reinterpret_cast < unsigned * > ( m_last . data ( ) ) ) ) ;
@ -66,15 +152,17 @@ 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 + + )
{
u256 val ( m . mine ( tryNonce ) ) ;
ethash_compute_full ( & ethashReturn , d , & p , h . data ( ) , tryNonce ) ;
u256 val ( h256 ( ethashReturn . result , h256 : : ConstructFromPointer ) ) ;
best = std : : min < double > ( best , log2 ( ( double ) val ) ) ;
if ( val < = boundary )
{
ret . first . completed = true ;
result . mixHash = m . lastMixHash ( ) ;
result . mixHash = * reinterpret_cast < h256 const * > ( ethashReturn . mix_hash ) ;
result . nonce = u64 ( tryNonce ) ;
break ;
}