PyBitmessage/src/proofofwork.py

277 lines
9.0 KiB
Python
Raw Normal View History

2013-06-04 03:14:24 +00:00
#import shared
#import time
#from multiprocessing import Pool, cpu_count
2013-05-30 20:25:42 +00:00
import hashlib
from struct import unpack, pack
from subprocess import call
import sys
import time
from debug import logger
import shared
import openclpow
import tr
import os
import ctypes
bitmsglib = 'bitmsghash.so'
2013-06-03 05:04:22 +00:00
def _set_idle():
if 'linux' in sys.platform:
2013-06-18 16:56:03 +00:00
import os
os.nice(20) # @UndefinedVariable
else:
2013-06-18 16:56:03 +00:00
try:
sys.getwindowsversion()
import win32api,win32process,win32con # @UnresolvedImport
2013-06-18 16:56:03 +00: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 20:25:42 +00:00
def _pool_worker(nonce, initialHash, target, pool_size):
2013-06-03 05:04:22 +00:00
_set_idle()
trialValue = float('inf')
while trialValue > target:
2013-05-30 20:25:42 +00:00
nonce += pool_size
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
return [trialValue, nonce]
def _doSafePoW(target, initialHash):
logger.debug("Safe PoW start")
2013-06-04 03:14:24 +00:00
nonce = 0
trialValue = float('inf')
while trialValue > target and shared.shutdown == 0:
2013-06-04 03:14:24 +00:00
nonce += 1
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
if shared.shutdown != 0:
raise StopIteration("Interrupted")
logger.debug("Safe PoW done")
2013-06-04 03:14:24 +00:00
return [trialValue, nonce]
def _doFastPoW(target, initialHash):
logger.debug("Fast PoW start")
from multiprocessing import Pool, cpu_count
try:
2013-05-30 20:25:42 +00:00
pool_size = cpu_count()
except:
2013-05-30 20:25:42 +00:00
pool_size = 4
try:
maxCores = shared.config.getint('bitmessagesettings', 'maxcores')
2013-05-30 20:25:42 +00:00
except:
maxCores = 99999
if pool_size > maxCores:
pool_size = maxCores
pool = Pool(processes=pool_size)
result = []
for i in range(pool_size):
result.append(pool.apply_async(_pool_worker, args=(i, initialHash, target, pool_size)))
while True:
if shared.shutdown > 0:
try:
pool.terminate()
pool.join()
except:
pass
raise StopIteration("Interrupted")
2013-05-30 20:25:42 +00:00
for i in range(pool_size):
if result[i].ready():
try:
result[i].successful()
except AssertionError:
pool.terminate()
pool.join()
raise StopIteration("Interrupted")
2013-05-30 20:25:42 +00:00
result = result[i].get()
pool.terminate()
pool.join()
logger.debug("Fast PoW done")
2013-05-30 20:25:42 +00:00
return result[0], result[1]
time.sleep(0.2)
def _doCPoW(target, initialHash):
h = initialHash
m = target
out_h = ctypes.pointer(ctypes.create_string_buffer(h, 64))
out_m = ctypes.c_ulonglong(m)
logger.debug("C PoW start")
nonce = bmpow(out_h, out_m)
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
if shared.shutdown != 0:
raise StopIteration("Interrupted")
logger.debug("C PoW done")
return [trialValue, nonce]
def _doGPUPoW(target, initialHash):
logger.debug("GPU PoW start")
nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target)
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
#print "{} - value {} < {}".format(nonce, trialValue, target)
if trialValue > target:
deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus)
shared.UISignalQueue.put(('updateStatusBar', (tr._translate("MainWindow",'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.'), 1)))
logger.error("Your GPUs (%s) did not calculate correctly, disabling OpenCL. Please report to the developers.", deviceNames)
openclpow.enabledGpus = []
raise Exception("GPU did not calculate correctly.")
if shared.shutdown != 0:
raise StopIteration("Interrupted")
logger.debug("GPU PoW done")
return [trialValue, nonce]
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
def getPowType():
if openclpow.openclEnabled():
return "OpenCL"
if bmpow:
return "C"
return "python"
def notifyBuild(tried=False):
global bmpow
if bmpow:
shared.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module built successfully."), 1)))
elif tried:
shared.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "Failed to build C PoW module. Please build it manually."), 1)))
else:
shared.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module unavailable. Please build it."), 1)))
def buildCPoW():
global bmpow
if bmpow is not None:
return
if shared.frozen is not None:
notifyBuild(False)
return
if sys.platform in ["win32", "win64"]:
notifyBuild(False)
return
try:
call(["make", "-C", os.path.join(shared.codePath(), "bitmsghash")])
if os.path.exists(os.path.join(shared.codePath(), "bitmsghash", "bitmsghash.so")):
init()
notifyBuild(True)
else:
notifyBuild(True)
except:
notifyBuild(True)
def run(target, initialHash):
if shared.shutdown != 0:
raise
2015-09-30 08:22:41 +00:00
target = int(target)
if openclpow.openclEnabled():
# 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]
try:
return _doGPUPoW(target, initialHash)
except StopIteration:
raise
except:
pass # fallback
if bmpow:
try:
return _doCPoW(target, initialHash)
except StopIteration:
raise
except:
pass # fallback
if shared.frozen == "macosx_app" or not shared.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 StopIteration:
logger.error("Fast PoW got StopIteration")
raise
except:
logger.error("Fast PoW got exception:", exc_info=True)
pass #fallback
try:
return _doSafePoW(target, initialHash)
except StopIteration:
raise
except:
pass #fallback
# init
def init():
global bitmsglib, bso, bmpow
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(shared.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(shared.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(shared.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
init()
if bmpow is None:
buildCPoW()