2013-06-04 05:14:24 +02:00
#import shared
#import time
#from multiprocessing import Pool, cpu_count
2013-05-30 22:25:42 +02:00
import hashlib
from struct import unpack , pack
2013-06-05 23:20:34 +02:00
import sys
2015-11-26 02:38:55 +01:00
from debug import logger
from shared import config , frozen , codePath , shutdown , safeConfigGetBoolean , UISignalQueue
2015-06-20 09:54:15 +02:00
import openclpow
2015-11-26 02:38:55 +01:00
import tr
2015-11-05 20:41:41 +01:00
import os
import ctypes
2013-06-03 07:04:22 +02:00
def _set_idle ( ) :
2013-06-05 23:20:34 +02:00
if ' linux ' in sys . platform :
2013-06-18 18:56:03 +02:00
import os
2013-06-23 21:52:39 +02:00
os . nice ( 20 ) # @UndefinedVariable
2013-06-05 23:20:34 +02:00
else :
2013-06-18 18:56:03 +02:00
try :
sys . getwindowsversion ( )
2013-06-23 21:52:39 +02:00
import win32api , win32process , win32con # @UnresolvedImport
2013-06-18 18:56:03 +02:00
pid = win32api . GetCurrentProcessId ( )
handle = win32api . OpenProcess ( win32con . PROCESS_ALL_ACCESS , True , pid )
win32process . SetPriorityClass ( handle , win32process . IDLE_PRIORITY_CLASS )
except :
#Windows 64-bit
pass
2013-05-30 22:25:42 +02:00
2013-05-29 22:01:12 +02:00
def _pool_worker ( nonce , initialHash , target , pool_size ) :
2013-06-03 07:04:22 +02:00
_set_idle ( )
2013-08-20 10:43:30 +02:00
trialValue = float ( ' inf ' )
2013-05-29 22:01:12 +02:00
while trialValue > target :
2013-05-30 22:25:42 +02:00
nonce + = pool_size
trialValue , = unpack ( ' >Q ' , hashlib . sha512 ( hashlib . sha512 ( pack ( ' >Q ' , nonce ) + initialHash ) . digest ( ) ) . digest ( ) [ 0 : 8 ] )
2013-05-29 22:01:12 +02:00
return [ trialValue , nonce ]
2013-06-05 23:20:34 +02:00
def _doSafePoW ( target , initialHash ) :
2015-11-26 02:38:55 +01:00
logger . debug ( " Safe PoW start " )
2013-06-04 05:14:24 +02:00
nonce = 0
2013-08-20 10:43:30 +02:00
trialValue = float ( ' inf ' )
2013-06-04 05:14:24 +02:00
while trialValue > target :
nonce + = 1
trialValue , = unpack ( ' >Q ' , hashlib . sha512 ( hashlib . sha512 ( pack ( ' >Q ' , nonce ) + initialHash ) . digest ( ) ) . digest ( ) [ 0 : 8 ] )
2015-11-26 02:38:55 +01:00
logger . debug ( " Safe PoW done " )
2013-06-04 05:14:24 +02:00
return [ trialValue , nonce ]
2013-06-05 23:20:34 +02:00
def _doFastPoW ( target , initialHash ) :
2015-11-26 02:38:55 +01:00
logger . debug ( " Fast PoW start " )
2013-06-05 23:20:34 +02:00
import time
from multiprocessing import Pool , cpu_count
try :
2013-05-30 22:25:42 +02:00
pool_size = cpu_count ( )
2013-05-29 22:01:12 +02:00
except :
2013-05-30 22:25:42 +02:00
pool_size = 4
try :
maxCores = config . getint ( ' bitmessagesettings ' , ' maxcores ' )
except :
maxCores = 99999
if pool_size > maxCores :
pool_size = maxCores
2013-05-29 22:01:12 +02:00
pool = Pool ( processes = pool_size )
result = [ ]
for i in range ( pool_size ) :
2013-05-30 22:25:42 +02:00
result . append ( pool . apply_async ( _pool_worker , args = ( i , initialHash , target , pool_size ) ) )
2013-05-29 22:01:12 +02:00
while True :
2015-11-26 02:38:55 +01:00
if shutdown > = 1 :
2013-05-30 22:42:24 +02:00
pool . terminate ( )
2013-06-19 06:51:31 +02:00
while True :
time . sleep ( 10 ) # Don't let this thread return here; it will return nothing and cause an exception in bitmessagemain.py
2013-05-30 22:42:24 +02:00
return
2013-05-30 22:25:42 +02:00
for i in range ( pool_size ) :
if result [ i ] . ready ( ) :
result = result [ i ] . get ( )
pool . terminate ( )
2013-06-06 19:30:57 +02:00
pool . join ( ) #Wait for the workers to exit...
2015-11-26 02:38:55 +01:00
logger . debug ( " Fast PoW done " )
2013-05-30 22:25:42 +02:00
return result [ 0 ] , result [ 1 ]
2013-06-05 23:20:34 +02:00
time . sleep ( 0.2 )
2015-11-26 02:38:55 +01:00
2015-11-05 20:41:41 +01:00
def _doCPoW ( target , initialHash ) :
h = initialHash
m = target
out_h = ctypes . pointer ( ctypes . create_string_buffer ( h , 64 ) )
out_m = ctypes . c_ulonglong ( m )
2015-11-26 02:38:55 +01:00
logger . debug ( " C PoW start " )
2015-11-05 20:41:41 +01:00
nonce = bmpow ( out_h , out_m )
trialValue , = unpack ( ' >Q ' , hashlib . sha512 ( hashlib . sha512 ( pack ( ' >Q ' , nonce ) + initialHash ) . digest ( ) ) . digest ( ) [ 0 : 8 ] )
2015-11-26 02:38:55 +01:00
logger . debug ( " C PoW done " )
2015-11-05 20:41:41 +01:00
return [ trialValue , nonce ]
2013-05-29 22:01:12 +02:00
2015-10-02 15:04:16 +02:00
def _doGPUPoW ( target , initialHash ) :
2015-11-26 02:38:55 +01:00
logger . debug ( " GPU PoW start " )
2015-06-20 09:54:15 +02:00
nonce = openclpow . do_opencl_pow ( initialHash . encode ( " hex " ) , target )
2015-01-19 18:39:02 +01:00
trialValue , = unpack ( ' >Q ' , hashlib . sha512 ( hashlib . sha512 ( pack ( ' >Q ' , nonce ) + initialHash ) . digest ( ) ) . digest ( ) [ 0 : 8 ] )
#print "{} - value {} < {}".format(nonce, trialValue, target)
2015-11-26 02:38:55 +01:00
if trialValue > target :
deviceNames = " , " . join ( gpu . name for gpu in openclpow . gpus )
UISignalQueue . put ( ( ' updateStatusBar ' , tr . translateText ( " MainWindow " , ' Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. ' ) ) )
logger . error ( " Your GPUs ( %s ) did not calculate correctly, disabling OpenCL. Please report to the developers. " , deviceNames )
openclpow . ctx = False
raise Exception ( " GPU did not calculate correctly. " )
logger . debug ( " GPU PoW done " )
2015-01-19 18:39:02 +01:00
return [ trialValue , nonce ]
2015-12-15 12:14:21 +01:00
def estimate ( difficulty , format = False ) :
ret = difficulty / 10
if ret < 1 :
ret = 1
if format :
out = str ( int ( ret ) ) + " seconds "
if ret > 60 :
ret / = 60
out = str ( int ( ret ) ) + " minutes "
if ret > 60 :
ret / = 60
out = str ( int ( ret ) ) + " hours "
if ret > 24 :
ret / = 24
out = str ( int ( ret ) ) + " days "
if ret > 7 :
out = str ( int ( ret ) ) + " weeks "
if ret > 31 :
out = str ( int ( ret ) ) + " months "
if ret > 366 :
ret / = 366
out = str ( int ( ret ) ) + " years "
else :
return ret
2015-01-19 18:39:02 +01:00
2013-06-05 23:20:34 +02:00
def run ( target , initialHash ) :
2015-01-21 18:38:25 +01:00
target = int ( target )
2015-11-26 02:38:55 +01:00
if safeConfigGetBoolean ( ' bitmessagesettings ' , ' opencl ' ) and openclpow . has_opencl ( ) :
2015-10-02 15:04:16 +02:00
# trialvalue1, nonce1 = _doGPUPoW(target, initialHash)
# trialvalue, nonce = _doFastPoW(target, initialHash)
# print "GPU: %s, %s" % (trialvalue1, nonce1)
# print "Fast: %s, %s" % (trialvalue, nonce)
# return [trialvalue, nonce]
2015-11-05 20:41:41 +01:00
try :
return _doGPUPoW ( target , initialHash )
except :
2015-11-09 17:15:05 +01:00
pass # fallback
if bmpow :
try :
return _doCPoW ( target , initialHash )
except :
pass # fallback
2015-11-29 19:14:26 +01:00
if frozen == " macosx_app " or not frozen :
# on my (Peter Surda) Windows 10, Windows Defender
# does not like this and fights with PyBitmessage
# over CPU, resulting in very slow PoW
# added on 2015-11-29: multiprocesing.freeze_support() doesn't help
try :
return _doFastPoW ( target , initialHash )
except :
pass #fallback
2015-12-17 22:58:52 +01:00
return _doSafePoW ( target , initialHash )
# init
bitmsglib = ' bitmsghash.so '
if " win32 " == sys . platform :
if ctypes . sizeof ( ctypes . c_voidp ) == 4 :
bitmsglib = ' bitmsghash32.dll '
else :
bitmsglib = ' bitmsghash64.dll '
try :
# MSVS
bso = ctypes . WinDLL ( os . path . join ( codePath ( ) , " bitmsghash " , bitmsglib ) )
logger . info ( " Loaded C PoW DLL (stdcall) %s " , bitmsglib )
bmpow = bso . BitmessagePOW
bmpow . restype = ctypes . c_ulonglong
_doCPoW ( 2 * * 63 , " " )
logger . info ( " Successfully tested C PoW DLL (stdcall) %s " , bitmsglib )
except :
logger . error ( " C PoW test fail. " , exc_info = True )
try :
# MinGW
bso = ctypes . CDLL ( os . path . join ( codePath ( ) , " bitmsghash " , bitmsglib ) )
logger . info ( " Loaded C PoW DLL (cdecl) %s " , bitmsglib )
bmpow = bso . BitmessagePOW
bmpow . restype = ctypes . c_ulonglong
_doCPoW ( 2 * * 63 , " " )
logger . info ( " Successfully tested C PoW DLL (cdecl) %s " , bitmsglib )
except :
logger . error ( " C PoW test fail. " , exc_info = True )
bso = None
else :
try :
bso = ctypes . CDLL ( os . path . join ( codePath ( ) , " bitmsghash " , bitmsglib ) )
logger . info ( " Loaded C PoW DLL %s " , bitmsglib )
except :
bso = None
if bso :
try :
bmpow = bso . BitmessagePOW
bmpow . restype = ctypes . c_ulonglong
except :
bmpow = None
else :
bmpow = None