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
2016-12-15 16:11:29 +01:00
from subprocess import call
2013-06-05 23:20:34 +02:00
import sys
2016-10-22 05:00:35 +02:00
import time
2017-01-11 14:27:19 +01:00
from configparser import BMConfigParser
2015-11-26 02:38:55 +01:00
from debug import logger
2017-01-11 17:00:00 +01:00
import paths
2015-06-20 09:54:15 +02:00
import openclpow
2017-02-08 13:41:56 +01:00
import queues
2015-11-26 02:38:55 +01:00
import tr
2015-11-05 20:41:41 +01:00
import os
import ctypes
2017-01-14 23:20:15 +01:00
import state
2016-12-15 16:11:29 +01:00
bitmsglib = ' bitmsghash.so '
2013-06-03 07:04:22 +02:00
def _set_idle ( ) :
2013-06-05 23:20:34 +02:00
if ' linux ' in sys . platform :
2017-01-11 18:13:00 +01:00
os . nice ( 20 )
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 ' )
2016-10-22 05:00:35 +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 ' )
2017-01-14 23:20:15 +01:00
while trialValue > target and state . shutdown == 0 :
2013-06-04 05:14:24 +02:00
nonce + = 1
trialValue , = unpack ( ' >Q ' , hashlib . sha512 ( hashlib . sha512 ( pack ( ' >Q ' , nonce ) + initialHash ) . digest ( ) ) . digest ( ) [ 0 : 8 ] )
2017-01-14 23:20:15 +01:00
if state . shutdown != 0 :
2016-10-05 20:06:47 +02:00
raise StopIteration ( " Interrupted " )
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
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 :
2017-01-11 14:27:19 +01:00
maxCores = BMConfigParser ( ) . getint ( ' bitmessagesettings ' , ' maxcores ' )
2013-05-30 22:25:42 +02:00
except :
maxCores = 99999
if pool_size > maxCores :
pool_size = maxCores
2016-06-30 23:03:39 +02:00
2013-05-29 22:01:12 +02:00
pool = Pool ( processes = pool_size )
result = [ ]
for i in range ( pool_size ) :
2016-10-22 05:00:35 +02:00
result . append ( pool . apply_async ( _pool_worker , args = ( i , initialHash , target , pool_size ) ) )
2016-06-30 23:03:39 +02:00
2013-05-29 22:01:12 +02:00
while True :
2017-01-14 23:20:15 +01:00
if state . shutdown > 0 :
2016-10-22 05:00:35 +02:00
try :
pool . terminate ( )
pool . join ( )
except :
pass
2016-10-05 20:06:47 +02:00
raise StopIteration ( " Interrupted " )
2013-05-30 22:25:42 +02:00
for i in range ( pool_size ) :
if result [ i ] . ready ( ) :
2016-10-05 20:06:47 +02:00
try :
result [ i ] . successful ( )
except AssertionError :
2016-10-22 05:00:35 +02:00
pool . terminate ( )
pool . join ( )
2016-10-05 20:06:47 +02:00
raise StopIteration ( " Interrupted " )
2013-05-30 22:25:42 +02:00
result = result [ i ] . get ( )
pool . terminate ( )
2016-10-22 05:00:35 +02:00
pool . join ( )
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 ] )
2017-01-14 23:20:15 +01:00
if state . shutdown != 0 :
2016-10-05 20:06:47 +02:00
raise StopIteration ( " Interrupted " )
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 :
2016-11-10 21:43:10 +01:00
deviceNames = " , " . join ( gpu . name for gpu in openclpow . enabledGpus )
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' updateStatusBar ' , ( tr . _translate ( " MainWindow " , ' Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. ' ) , 1 ) ) )
2015-11-26 02:38:55 +01:00
logger . error ( " Your GPUs ( %s ) did not calculate correctly, disabling OpenCL. Please report to the developers. " , deviceNames )
2016-11-10 21:43:10 +01:00
openclpow . enabledGpus = [ ]
2015-11-26 02:38:55 +01:00
raise Exception ( " GPU did not calculate correctly. " )
2017-01-14 23:20:15 +01:00
if state . shutdown != 0 :
2016-10-05 20:06:47 +02:00
raise StopIteration ( " Interrupted " )
2015-11-26 02:38:55 +01:00
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
2016-10-05 20:06:47 +02:00
def getPowType ( ) :
2016-11-10 21:43:10 +01:00
if openclpow . openclEnabled ( ) :
2016-10-05 20:06:47 +02:00
return " OpenCL "
if bmpow :
return " C "
return " python "
2016-12-15 16:11:29 +01:00
def notifyBuild ( tried = False ) :
global bmpow
if bmpow :
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' updateStatusBar ' , ( tr . _translate ( " proofofwork " , " C PoW module built successfully. " ) , 1 ) ) )
2016-12-15 16:11:29 +01:00
elif tried :
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' updateStatusBar ' , ( tr . _translate ( " proofofwork " , " Failed to build C PoW module. Please build it manually. " ) , 1 ) ) )
2016-12-15 16:11:29 +01:00
else :
2017-02-08 13:41:56 +01:00
queues . UISignalQueue . put ( ( ' updateStatusBar ' , ( tr . _translate ( " proofofwork " , " C PoW module unavailable. Please build it. " ) , 1 ) ) )
2016-12-15 16:11:29 +01:00
def buildCPoW ( ) :
global bmpow
if bmpow is not None :
return
2017-01-11 17:00:00 +01:00
if paths . frozen is not None :
2016-12-15 16:11:29 +01:00
notifyBuild ( False )
return
if sys . platform in [ " win32 " , " win64 " ] :
notifyBuild ( False )
return
try :
2017-01-11 17:00:00 +01:00
call ( [ " make " , " -C " , os . path . join ( paths . codePath ( ) , " bitmsghash " ) ] )
if os . path . exists ( os . path . join ( paths . codePath ( ) , " bitmsghash " , " bitmsghash.so " ) ) :
2016-12-15 16:11:29 +01:00
init ( )
notifyBuild ( True )
else :
notifyBuild ( True )
except :
notifyBuild ( True )
2013-06-05 23:20:34 +02:00
def run ( target , initialHash ) :
2017-01-14 23:20:15 +01:00
if state . shutdown != 0 :
2016-10-05 20:06:47 +02:00
raise
2015-09-30 10:22:41 +02:00
target = int ( target )
2016-11-10 21:43:10 +01:00
if openclpow . openclEnabled ( ) :
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 )
2016-10-05 20:06:47 +02:00
except StopIteration :
raise
2015-11-05 20:41:41 +01:00
except :
2015-11-09 17:15:05 +01:00
pass # fallback
if bmpow :
try :
return _doCPoW ( target , initialHash )
2016-10-05 20:06:47 +02:00
except StopIteration :
raise
2015-11-09 17:15:05 +01:00
except :
pass # fallback
2017-01-11 17:00:00 +01:00
if paths . frozen == " macosx_app " or not paths . frozen :
2015-11-29 19:14:26 +01:00
# 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 )
2016-10-05 20:06:47 +02:00
except StopIteration :
logger . error ( " Fast PoW got StopIteration " )
raise
2015-11-29 19:14:26 +01:00
except :
2016-10-05 20:06:47 +02:00
logger . error ( " Fast PoW got exception: " , exc_info = True )
2015-11-29 19:14:26 +01:00
pass #fallback
2016-04-17 20:31:25 +02:00
try :
return _doSafePoW ( target , initialHash )
2016-10-05 20:06:47 +02:00
except StopIteration :
raise
2016-04-17 20:31:25 +02:00
except :
pass #fallback
2015-12-17 22:58:52 +01:00
# init
2016-12-15 16:11:29 +01:00
def init ( ) :
global bitmsglib , bso , bmpow
if " win32 " == sys . platform :
if ctypes . sizeof ( ctypes . c_voidp ) == 4 :
bitmsglib = ' bitmsghash32.dll '
else :
bitmsglib = ' bitmsghash64.dll '
2015-12-17 22:58:52 +01:00
try :
2016-12-15 16:11:29 +01:00
# MSVS
2017-01-11 17:00:00 +01:00
bso = ctypes . WinDLL ( os . path . join ( paths . codePath ( ) , " bitmsghash " , bitmsglib ) )
2016-12-15 16:11:29 +01:00
logger . info ( " Loaded C PoW DLL (stdcall) %s " , bitmsglib )
2015-12-17 22:58:52 +01:00
bmpow = bso . BitmessagePOW
bmpow . restype = ctypes . c_ulonglong
_doCPoW ( 2 * * 63 , " " )
2016-12-15 16:11:29 +01:00
logger . info ( " Successfully tested C PoW DLL (stdcall) %s " , bitmsglib )
2015-12-17 22:58:52 +01:00
except :
logger . error ( " C PoW test fail. " , exc_info = True )
2016-12-15 16:11:29 +01:00
try :
# MinGW
2017-01-11 17:00:00 +01:00
bso = ctypes . CDLL ( os . path . join ( paths . codePath ( ) , " bitmsghash " , bitmsglib ) )
2016-12-15 16:11:29 +01:00
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 :
2017-01-11 17:00:00 +01:00
bso = ctypes . CDLL ( os . path . join ( paths . codePath ( ) , " bitmsghash " , bitmsglib ) )
2016-12-15 16:11:29 +01:00
logger . info ( " Loaded C PoW DLL %s " , bitmsglib )
except :
2015-12-17 22:58:52 +01:00
bso = None
2016-12-15 16:11:29 +01:00
if bso :
try :
bmpow = bso . BitmessagePOW
bmpow . restype = ctypes . c_ulonglong
except :
bmpow = None
else :
2015-12-17 22:58:52 +01:00
bmpow = None
2016-12-15 16:11:29 +01:00
init ( )
if bmpow is None :
buildCPoW ( )