Testing proofofwork #2276

Merged
PeterSurda merged 10 commits from gitea-63 into v0.6 2025-01-21 04:03:38 +01:00
9 changed files with 319 additions and 220 deletions

View File

@ -20,6 +20,8 @@ ignore = E722,F841,W503
disable=invalid-name,bare-except,broad-except disable=invalid-name,bare-except,broad-except
# invalid-name: needs fixing during a large, project-wide refactor # invalid-name: needs fixing during a large, project-wide refactor
# bare-except,broad-except: Need fixing once thorough testing is easier # bare-except,broad-except: Need fixing once thorough testing is easier
max-args = 8
max-attributes = 8
[MASTER] [MASTER]
init-hook = import sys;sys.path.append('src') init-hook = import sys;sys.path.append('src')

View File

@ -1410,15 +1410,10 @@ class BMRPCDispatcher(object):
/ networkDefaultPayloadLengthExtraBytes, / networkDefaultPayloadLengthExtraBytes,
) )
powStartTime = time.time() powStartTime = time.time()
target = 2**64 / ( trialValue, nonce = proofofwork.calculate(
nonceTrialsPerByte * ( encryptedPayload, TTL,
len(encryptedPayload) + 8 + payloadLengthExtraBytes + (( nonceTrialsPerByte, payloadLengthExtraBytes
TTL * ( )
len(encryptedPayload) + 8 + payloadLengthExtraBytes
)) / (2 ** 16))
))
initialHash = hashlib.sha512(encryptedPayload).digest()
trialValue, nonce = proofofwork.run(target, initialHash)
logger.info( logger.info(
'(For msg message via API) Found proof of work %s\nNonce: %s\n' '(For msg message via API) Found proof of work %s\nNonce: %s\n'
'POW took %s seconds. %s nonce trials per second.', 'POW took %s seconds. %s nonce trials per second.',
@ -1429,9 +1424,7 @@ class BMRPCDispatcher(object):
inventoryHash = calculateInventoryHash(encryptedPayload) inventoryHash = calculateInventoryHash(encryptedPayload)
state.Inventory[inventoryHash] = ( state.Inventory[inventoryHash] = (
objectType, toStreamNumber, encryptedPayload, objectType, toStreamNumber, encryptedPayload, expiresTime, b'')
expiresTime, b''
)
logger.info( logger.info(
'Broadcasting inv for msg(API disseminatePreEncryptedMsg' 'Broadcasting inv for msg(API disseminatePreEncryptedMsg'
' command): %s', hexlify(inventoryHash)) ' command): %s', hexlify(inventoryHash))

View File

@ -217,36 +217,36 @@ class singleWorker(StoppableThread):
return privSigningKeyHex, privEncryptionKeyHex, \ return privSigningKeyHex, privEncryptionKeyHex, \
pubSigningKey, pubEncryptionKey pubSigningKey, pubEncryptionKey
def _doPOWDefaults(self, payload, TTL, @classmethod
log_prefix='', def _doPOWDefaults(
log_time=False): cls, payload, TTL,
target = 2 ** 64 / ( nonceTrialsPerByte=None, payloadLengthExtraBytes=None,
defaults.networkDefaultProofOfWorkNonceTrialsPerByte * ( log_prefix='', log_time=False
len(payload) + 8 ):
+ defaults.networkDefaultPayloadLengthExtraBytes + (( if not nonceTrialsPerByte:
TTL * ( nonceTrialsPerByte = \
len(payload) + 8 defaults.networkDefaultProofOfWorkNonceTrialsPerByte
+ defaults.networkDefaultPayloadLengthExtraBytes if not payloadLengthExtraBytes:
)) / (2 ** 16)) payloadLengthExtraBytes = \
)) defaults.networkDefaultPayloadLengthExtraBytes
initialHash = hashlib.sha512(payload).digest() cls.logger.info(
self.logger.info(
'%s Doing proof of work... TTL set to %s', log_prefix, TTL) '%s Doing proof of work... TTL set to %s', log_prefix, TTL)
if log_time: if log_time:
start_time = time.time() start_time = time.time()
trialValue, nonce = proofofwork.run(target, initialHash) trialValue, nonce = proofofwork.calculate(
self.logger.info( payload, TTL, nonceTrialsPerByte, payloadLengthExtraBytes)
cls.logger.info(
'%s Found proof of work %s Nonce: %s', '%s Found proof of work %s Nonce: %s',
log_prefix, trialValue, nonce log_prefix, trialValue, nonce
) )
try: try:
delta = time.time() - start_time delta = time.time() - start_time
self.logger.info( cls.logger.info(
'PoW took %.1f seconds, speed %s.', 'PoW took %.1f seconds, speed %s.',
delta, sizeof_fmt(nonce / delta) delta, sizeof_fmt(nonce / delta)
) )
except: # noqa:E722 # NameError except NameError: # no start_time - no logging
self.logger.warning("Proof of Work exception") pass
payload = pack('>Q', nonce) + payload payload = pack('>Q', nonce) + payload
return payload return payload
@ -1250,41 +1250,13 @@ class singleWorker(StoppableThread):
encryptedPayload += '\x00\x00\x00\x02' # object type: msg encryptedPayload += '\x00\x00\x00\x02' # object type: msg
encryptedPayload += encodeVarint(1) # msg version encryptedPayload += encodeVarint(1) # msg version
encryptedPayload += encodeVarint(toStreamNumber) + encrypted encryptedPayload += encodeVarint(toStreamNumber) + encrypted
target = 2 ** 64 / (
requiredAverageProofOfWorkNonceTrialsPerByte * (
len(encryptedPayload) + 8
+ requiredPayloadLengthExtraBytes + ((
TTL * (
len(encryptedPayload) + 8
+ requiredPayloadLengthExtraBytes
)) / (2 ** 16))
))
self.logger.info(
'(For msg message) Doing proof of work. Total required'
' difficulty: %f. Required small message difficulty: %f.',
float(requiredAverageProofOfWorkNonceTrialsPerByte)
/ defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
float(requiredPayloadLengthExtraBytes)
/ defaults.networkDefaultPayloadLengthExtraBytes
)
powStartTime = time.time() encryptedPayload = self._doPOWDefaults(
initialHash = hashlib.sha512(encryptedPayload).digest() encryptedPayload, TTL,
trialValue, nonce = proofofwork.run(target, initialHash) requiredAverageProofOfWorkNonceTrialsPerByte,
self.logger.info( requiredPayloadLengthExtraBytes,
'(For msg message) Found proof of work %s Nonce: %s', log_prefix='(For msg message)', log_time=True
trialValue, nonce
) )
try:
self.logger.info(
'PoW took %.1f seconds, speed %s.',
time.time() - powStartTime,
sizeof_fmt(nonce / (time.time() - powStartTime))
)
except: # noqa:E722
self.logger.warning("Proof of Work exception")
encryptedPayload = pack('>Q', nonce) + encryptedPayload
# Sanity check. The encryptedPayload size should never be # Sanity check. The encryptedPayload size should never be
# larger than 256 KiB. There should be checks elsewhere # larger than 256 KiB. There should be checks elsewhere

View File

@ -1,9 +1,10 @@
# pylint: disable=too-many-branches,too-many-statements,protected-access
""" """
Proof of work calculation Proof of work calculation
""" """
# pylint: disable=import-outside-toplevel
import ctypes import ctypes
import hashlib
import os import os
import subprocess # nosec B404 import subprocess # nosec B404
import sys import sys
@ -16,9 +17,13 @@ import openclpow
import paths import paths
import queues import queues
import state import state
import tr
from bmconfigparser import config from bmconfigparser import config
from debug import logger from debug import logger
from defaults import (
networkDefaultProofOfWorkNonceTrialsPerByte,
networkDefaultPayloadLengthExtraBytes)
from tr import _translate
bitmsglib = 'bitmsghash.so' bitmsglib = 'bitmsghash.so'
bmpow = None bmpow = None
@ -79,10 +84,13 @@ def _set_idle():
import win32api import win32api
import win32process import win32process
import win32con import win32con
pid = win32api.GetCurrentProcessId()
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid) handle = win32api.OpenProcess(
win32process.SetPriorityClass(handle, win32process.IDLE_PRIORITY_CLASS) win32con.PROCESS_ALL_ACCESS, True,
except: # nosec B110 # noqa:E722 # pylint:disable=bare-except win32api.GetCurrentProcessId())
win32process.SetPriorityClass(
handle, win32process.IDLE_PRIORITY_CLASS)
except: # nosec B110 # noqa:E722 pylint:disable=bare-except
# Windows 64-bit # Windows 64-bit
pass pass
@ -101,11 +109,11 @@ def _pool_worker(nonce, initialHash, target, pool_size):
while trialValue > target: while trialValue > target:
nonce += pool_size nonce += pool_size
trialValue = trial_value(nonce, initialHash) trialValue = trial_value(nonce, initialHash)
return [trialValue, nonce] return trialValue, nonce
def _doSafePoW(target, initialHash): def _doSafePoW(target, initialHash):
logger.debug("Safe PoW start") logger.debug('Safe PoW start')
nonce = 0 nonce = 0
trialValue = float('inf') trialValue = float('inf')
while trialValue > target and state.shutdown == 0: while trialValue > target and state.shutdown == 0:
@ -113,35 +121,33 @@ def _doSafePoW(target, initialHash):
trialValue = trial_value(nonce, initialHash) trialValue = trial_value(nonce, initialHash)
if state.shutdown != 0: if state.shutdown != 0:
raise StopIteration("Interrupted") raise StopIteration("Interrupted")
logger.debug("Safe PoW done") logger.debug('Safe PoW done')
return [trialValue, nonce] return trialValue, nonce
def _doFastPoW(target, initialHash): def _doFastPoW(target, initialHash):
logger.debug("Fast PoW start") # pylint:disable=bare-except
logger.debug('Fast PoW start')
from multiprocessing import Pool, cpu_count from multiprocessing import Pool, cpu_count
try: try:
pool_size = cpu_count() pool_size = cpu_count()
except: # noqa:E722 except: # noqa:E722
pool_size = 4 pool_size = 4
try: maxCores = config.safeGetInt('bitmessagesettings', 'maxcores', 99999)
maxCores = config.getint('bitmessagesettings', 'maxcores') pool_size = min(pool_size, maxCores)
except: # noqa:E722
maxCores = 99999
if pool_size > maxCores:
pool_size = maxCores
pool = Pool(processes=pool_size) pool = Pool(processes=pool_size)
result = [] result = []
for i in range(pool_size): for i in range(pool_size):
result.append(pool.apply_async(_pool_worker, args=(i, initialHash, target, pool_size))) result.append(pool.apply_async(
_pool_worker, args=(i, initialHash, target, pool_size)))
while True: while True:
if state.shutdown > 0: if state.shutdown != 0:
try: try:
pool.terminate() pool.terminate()
pool.join() pool.join()
except: # nosec B110 # noqa:E722 # pylint:disable=bare-except except: # nosec B110 # noqa:E722
pass pass
raise StopIteration("Interrupted") raise StopIteration("Interrupted")
for i in range(pool_size): for i in range(pool_size):
@ -155,7 +161,7 @@ def _doFastPoW(target, initialHash):
result = result[i].get() result = result[i].get()
pool.terminate() pool.terminate()
pool.join() pool.join()
logger.debug("Fast PoW done") logger.debug('Fast PoW done')
return result[0], result[1] return result[0], result[1]
time.sleep(0.2) time.sleep(0.2)
@ -166,70 +172,67 @@ def _doCPoW(target, initialHash):
m = target m = target
out_h = ctypes.pointer(ctypes.create_string_buffer(h, 64)) out_h = ctypes.pointer(ctypes.create_string_buffer(h, 64))
out_m = ctypes.c_ulonglong(m) out_m = ctypes.c_ulonglong(m)
logger.debug("C PoW start") logger.debug('C PoW start')
nonce = bmpow(out_h, out_m) nonce = bmpow(out_h, out_m)
trialValue = trial_value(nonce, initialHash) trialValue = trial_value(nonce, initialHash)
if state.shutdown != 0: if state.shutdown != 0:
raise StopIteration("Interrupted") raise StopIteration("Interrupted")
logger.debug("C PoW done") logger.debug('C PoW done')
return [trialValue, nonce] return trialValue, nonce
def _doGPUPoW(target, initialHash): def _doGPUPoW(target, initialHash):
logger.debug("GPU PoW start") logger.debug('GPU PoW start')
nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target) nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target)
trialValue = trial_value(nonce, initialHash) trialValue = trial_value(nonce, initialHash)
if trialValue > target: if trialValue > target:
deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus) deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus)
queues.UISignalQueue.put(( queues.UISignalQueue.put((
'updateStatusBar', ( 'updateStatusBar', (
tr._translate( _translate(
"MainWindow", "MainWindow",
'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.' "Your GPU(s) did not calculate correctly,"
), " disabling OpenCL. Please report to the developers."
1))) ), 1)
))
logger.error( logger.error(
"Your GPUs (%s) did not calculate correctly, disabling OpenCL. Please report to the developers.", 'Your GPUs (%s) did not calculate correctly, disabling OpenCL.'
deviceNames) ' Please report to the developers.', deviceNames)
openclpow.enabledGpus = [] openclpow.enabledGpus = []
raise Exception("GPU did not calculate correctly.") raise Exception("GPU did not calculate correctly.")
if state.shutdown != 0: if state.shutdown != 0:
raise StopIteration("Interrupted") raise StopIteration("Interrupted")
logger.debug("GPU PoW done") logger.debug('GPU PoW done')
return [trialValue, nonce] return trialValue, nonce
def estimate(difficulty, format=False): # pylint: disable=redefined-builtin # def estimate(difficulty, fmt=False):
""" # ret = difficulty / 10
.. todo: fix unused variable # if ret < 1:
""" # ret = 1
ret = difficulty / 10 #
if ret < 1: # if fmt:
ret = 1 # out = str(int(ret)) + " seconds"
# if ret > 60:
if format: # ret /= 60
# pylint: disable=unused-variable # out = str(int(ret)) + " minutes"
out = str(int(ret)) + " seconds" # if ret > 60:
if ret > 60: # ret /= 60
ret /= 60 # out = str(int(ret)) + " hours"
out = str(int(ret)) + " minutes" # if ret > 24:
if ret > 60: # ret /= 24
ret /= 60 # out = str(int(ret)) + " days"
out = str(int(ret)) + " hours" # if ret > 7:
if ret > 24: # out = str(int(ret)) + " weeks"
ret /= 24 # if ret > 31:
out = str(int(ret)) + " days" # out = str(int(ret)) + " months"
if ret > 7: # if ret > 366:
out = str(int(ret)) + " weeks" # ret /= 366
if ret > 31: # out = str(int(ret)) + " years"
out = str(int(ret)) + " months" # ret = None # Ensure legacy behaviour
if ret > 366: #
ret /= 366 # return ret
out = str(int(ret)) + " years"
ret = None # Ensure legacy behaviour
return ret
def getPowType(): def getPowType():
@ -243,25 +246,19 @@ def getPowType():
def notifyBuild(tried=False): def notifyBuild(tried=False):
"""Notify the user of the success or otherwise of building the PoW C module""" """
Notify the user of the success or otherwise of building the PoW C module
"""
if bmpow: if bmpow:
queues.UISignalQueue.put(('updateStatusBar', (tr._translate( queues.UISignalQueue.put(('updateStatusBar', (_translate(
"proofofwork", "C PoW module built successfully."), 1))) "proofofwork", "C PoW module built successfully."), 1)))
elif tried: elif tried:
queues.UISignalQueue.put( queues.UISignalQueue.put(('updateStatusBar', (_translate(
( "proofofwork",
'updateStatusBar', ( "Failed to build C PoW module. Please build it manually."), 1)))
tr._translate(
"proofofwork",
"Failed to build C PoW module. Please build it manually."
),
1
)
)
)
else: else:
queues.UISignalQueue.put(('updateStatusBar', (tr._translate( queues.UISignalQueue.put(('updateStatusBar', (_translate(
"proofofwork", "C PoW module unavailable. Please build it."), 1))) "proofofwork", "C PoW module unavailable. Please build it."), 1)))
@ -269,76 +266,71 @@ def buildCPoW():
"""Attempt to build the PoW C module""" """Attempt to build the PoW C module"""
if bmpow is not None: if bmpow is not None:
return return
if paths.frozen is not None: if paths.frozen or sys.platform.startswith('win'):
notifyBuild(False)
return
if sys.platform in ["win32", "win64"]:
notifyBuild(False) notifyBuild(False)
return return
try: try:
# GNU make
make_cmd = ['make', '-C', os.path.join(paths.codePath(), 'bitmsghash')]
if "bsd" in sys.platform: if "bsd" in sys.platform:
# BSD make # BSD make
subprocess.check_call([ # nosec B607, B603 make_cmd += ['-f', 'Makefile.bsd']
"make", "-C", os.path.join(paths.codePath(), "bitmsghash"),
'-f', 'Makefile.bsd']) subprocess.check_call(make_cmd) # nosec B603
else:
# GNU make
subprocess.check_call([ # nosec B607, B603
"make", "-C", os.path.join(paths.codePath(), "bitmsghash")])
if os.path.exists( if os.path.exists(
os.path.join(paths.codePath(), "bitmsghash", "bitmsghash.so") os.path.join(paths.codePath(), 'bitmsghash', 'bitmsghash.so')
): ):
init() init()
notifyBuild(True)
else:
notifyBuild(True)
except (OSError, subprocess.CalledProcessError): except (OSError, subprocess.CalledProcessError):
notifyBuild(True) pass
except: # noqa:E722 except: # noqa:E722
logger.warning( logger.warning(
'Unexpected exception rised when tried to build bitmsghash lib', 'Unexpected exception rised when tried to build bitmsghash lib',
exc_info=True) exc_info=True)
notifyBuild(True) notifyBuild(True)
def run(target, initialHash): def run(target, initialHash):
"""Run the proof of work thread""" """Run the proof of work calculation"""
if state.shutdown != 0: if state.shutdown != 0:
raise # pylint: disable=misplaced-bare-raise raise StopIteration("Interrupted")
target = int(target) target = int(target)
if openclpow.openclEnabled(): if openclpow.openclEnabled():
try: return _doGPUPoW(target, initialHash)
return _doGPUPoW(target, initialHash)
except StopIteration:
raise
except: # nosec B110 # noqa:E722 # pylint:disable=bare-except
pass # fallback
if bmpow: if bmpow:
try: return _doCPoW(target, initialHash)
return _doCPoW(target, initialHash)
except StopIteration:
raise
except: # nosec B110 # noqa:E722 # pylint:disable=bare-except
pass # fallback
if paths.frozen == "macosx_app" or not paths.frozen: if paths.frozen == "macosx_app" or not paths.frozen:
# on my (Peter Surda) Windows 10, Windows Defender # on my (Peter Surda) Windows 10, Windows Defender
# does not like this and fights with PyBitmessage # does not like this and fights with PyBitmessage
# over CPU, resulting in very slow PoW # over CPU, resulting in very slow PoW
# added on 2015-11-29: multiprocesing.freeze_support() doesn't help # added on 2015-11-29: multiprocesing.freeze_support() doesn't help
try: return _doFastPoW(target, initialHash)
return _doFastPoW(target, initialHash)
except StopIteration: return _doSafePoW(target, initialHash)
logger.error("Fast PoW got StopIteration")
raise
except: # noqa:E722 # pylint:disable=bare-except def getTarget(payloadLength, ttl, nonceTrialsPerByte, payloadLengthExtraBytes):
logger.error("Fast PoW got exception:", exc_info=True) """Get PoW target for given length, ttl and difficulty params"""
try: return 2 ** 64 / (
return _doSafePoW(target, initialHash) nonceTrialsPerByte * (
except StopIteration: payloadLength + 8 + payloadLengthExtraBytes + ((
raise ttl * (
except: # nosec B110 # noqa:E722 # pylint:disable=bare-except payloadLength + 8 + payloadLengthExtraBytes
pass # fallback )) / (2 ** 16))
))
def calculate(
payload, ttl,
nonceTrialsPerByte=networkDefaultProofOfWorkNonceTrialsPerByte,
payloadLengthExtraBytes=networkDefaultPayloadLengthExtraBytes
):
"""Do the PoW for the payload and TTL with optional difficulty params"""
return run(getTarget(
len(payload), ttl, nonceTrialsPerByte, payloadLengthExtraBytes),
hashlib.sha512(payload).digest())
def resetPoW(): def resetPoW():
@ -351,60 +343,63 @@ def resetPoW():
def init(): def init():
"""Initialise PoW""" """Initialise PoW"""
# pylint: disable=global-statement # pylint: disable=broad-exception-caught,global-statement
global bitmsglib, bmpow global bitmsglib, bmpow
openclpow.initCL() openclpow.initCL()
if sys.platform == "win32": if sys.platform.startswith('win'):
if ctypes.sizeof(ctypes.c_voidp) == 4: bitmsglib = (
bitmsglib = 'bitmsghash32.dll' 'bitmsghash32.dll' if ctypes.sizeof(ctypes.c_voidp) == 4 else
else: 'bitmsghash64.dll')
bitmsglib = 'bitmsghash64.dll' libfile = os.path.join(paths.codePath(), 'bitmsghash', bitmsglib)
try: try:
# MSVS # MSVS
bso = ctypes.WinDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib)) bso = ctypes.WinDLL(
logger.info("Loaded C PoW DLL (stdcall) %s", bitmsglib) os.path.join(paths.codePath(), 'bitmsghash', bitmsglib))
logger.info('Loaded C PoW DLL (stdcall) %s', bitmsglib)
bmpow = bso.BitmessagePOW bmpow = bso.BitmessagePOW
bmpow.restype = ctypes.c_ulonglong bmpow.restype = ctypes.c_ulonglong
_doCPoW(2**63, "") _doCPoW(2**63, "")
logger.info("Successfully tested C PoW DLL (stdcall) %s", bitmsglib) logger.info(
'Successfully tested C PoW DLL (stdcall) %s', bitmsglib)
except ValueError: except ValueError:
try: try:
# MinGW # MinGW
bso = ctypes.CDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib)) bso = ctypes.CDLL(libfile)
logger.info("Loaded C PoW DLL (cdecl) %s", bitmsglib) logger.info('Loaded C PoW DLL (cdecl) %s', bitmsglib)
bmpow = bso.BitmessagePOW bmpow = bso.BitmessagePOW
bmpow.restype = ctypes.c_ulonglong bmpow.restype = ctypes.c_ulonglong
_doCPoW(2**63, "") _doCPoW(2**63, "")
logger.info("Successfully tested C PoW DLL (cdecl) %s", bitmsglib) logger.info(
'Successfully tested C PoW DLL (cdecl) %s', bitmsglib)
except Exception as e: except Exception as e:
logger.error("Error: %s", e, exc_info=True) logger.error('Error: %s', e, exc_info=True)
bso = None
except Exception as e: except Exception as e:
logger.error("Error: %s", e, exc_info=True) logger.error('Error: %s', e, exc_info=True)
bso = None
else: else:
try: try:
bso = ctypes.CDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib)) bso = ctypes.CDLL(
os.path.join(paths.codePath(), 'bitmsghash', bitmsglib))
except OSError: except OSError:
import glob import glob
try: try:
bso = ctypes.CDLL(glob.glob(os.path.join( bso = ctypes.CDLL(glob.glob(os.path.join(
paths.codePath(), "bitmsghash", "bitmsghash*.so" paths.codePath(), 'bitmsghash', 'bitmsghash*.so'
))[0]) ))[0])
except (OSError, IndexError): except (OSError, IndexError):
bso = None bso = None
except: # noqa:E722 except Exception:
bso = None bso = None
else: else:
logger.info("Loaded C PoW DLL %s", bitmsglib) logger.info('Loaded C PoW DLL %s', bitmsglib)
if bso: if bso:
try: try:
bmpow = bso.BitmessagePOW bmpow = bso.BitmessagePOW
bmpow.restype = ctypes.c_ulonglong bmpow.restype = ctypes.c_ulonglong
except: # noqa:E722 except Exception:
bmpow = None logger.warning(
else: 'Failed to setup bmpow lib %s', bso, exc_info=True)
bmpow = None return
if bmpow is None: if bmpow is None:
buildCPoW() buildCPoW()

View File

@ -2,6 +2,7 @@
import os import os
import sys import sys
import time
import unittest import unittest
from pybitmessage import pathmagic from pybitmessage import pathmagic
@ -39,3 +40,5 @@ class TestPartialRun(unittest.TestCase):
# deactivate pathmagic # deactivate pathmagic
os.chdir(cls.dirs[0]) os.chdir(cls.dirs[0])
sys.path.remove(cls.dirs[1]) sys.path.remove(cls.dirs[1])
time.sleep(5)
cls.state.shutdown = 0

View File

@ -91,3 +91,12 @@ sample_privsigningkey_wif = \
b'5K42shDERM5g7Kbi3JT5vsAWpXMqRhWZpX835M2pdSoqQQpJMYm' b'5K42shDERM5g7Kbi3JT5vsAWpXMqRhWZpX835M2pdSoqQQpJMYm'
sample_privencryptionkey_wif = \ sample_privencryptionkey_wif = \
b'5HwugVWm31gnxtoYcvcK7oywH2ezYTh6Y4tzRxsndAeMi6NHqpA' b'5HwugVWm31gnxtoYcvcK7oywH2ezYTh6Y4tzRxsndAeMi6NHqpA'
# PoW
sample_pow_target = 54227212183
sample_pow_initial_hash = unhexlify(
'3758f55b5a8d902fd3597e4ce6a2d3f23daff735f65d9698c270987f4e67ad590'
'b93f3ffeba0ef2fd08a8dc2f87b68ae5a0dc819ab57f22ad2c4c9c8618a43b3'
)

View File

@ -3,9 +3,12 @@ Tests for openclpow module
""" """
import unittest import unittest
from binascii import hexlify
from pybitmessage import openclpow, proofofwork from pybitmessage import openclpow, proofofwork
from .samples import sample_pow_target, sample_pow_initial_hash
class TestOpenClPow(unittest.TestCase): class TestOpenClPow(unittest.TestCase):
""" """
@ -19,11 +22,8 @@ class TestOpenClPow(unittest.TestCase):
@unittest.skipUnless(openclpow.enabledGpus, "No GPUs found / enabled") @unittest.skipUnless(openclpow.enabledGpus, "No GPUs found / enabled")
def test_openclpow(self): def test_openclpow(self):
"""Check the working of openclpow module""" """Check the working of openclpow module"""
target_ = 54227212183 nonce = openclpow.do_opencl_pow(
initialHash = ( hexlify(sample_pow_initial_hash), sample_pow_target)
"3758f55b5a8d902fd3597e4ce6a2d3f23daff735f65d9698c270987f4e67ad590"
"b93f3ffeba0ef2fd08a8dc2f87b68ae5a0dc819ab57f22ad2c4c9c8618a43b3"
).decode("hex")
nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target_)
self.assertLess( self.assertLess(
nonce - proofofwork.trial_value(nonce, initialHash), target_) nonce - proofofwork.trial_value(nonce, sample_pow_initial_hash),
sample_pow_target)

View File

@ -0,0 +1,120 @@
"""
Tests for proofofwork module
"""
# pylint: disable=protected-access
import hashlib
import os
import time
import unittest
from struct import pack, unpack
from pybitmessage import proofofwork, protocol
from pybitmessage.defaults import (
networkDefaultProofOfWorkNonceTrialsPerByte,
networkDefaultPayloadLengthExtraBytes)
from .partial import TestPartialRun
from .samples import sample_pow_target, sample_pow_initial_hash
default_ttl = 7200
class TestProofofworkBase(TestPartialRun):
"""Basic test case for proofofwork"""
@classmethod
def setUpClass(cls):
proofofwork.init()
super(TestProofofworkBase, cls).setUpClass()
def setUp(self):
self.state.shutdown = 0
@staticmethod
def _make_sample_payload(TTL=default_ttl):
return pack('>Q', int(time.time() + TTL)) + os.urandom(166)
def test_calculate(self):
"""Ensure a calculated nonce has sufficient work for the protocol"""
payload = self._make_sample_payload()
nonce = proofofwork.calculate(payload, default_ttl)[1]
self.assertTrue(
protocol.isProofOfWorkSufficient(pack('>Q', nonce) + payload))
# pylint: disable=import-outside-toplevel
from class_singleWorker import singleWorker
self.assertTrue(protocol.isProofOfWorkSufficient(
singleWorker._doPOWDefaults(payload, default_ttl)))
@unittest.skipUnless(
os.getenv('BITMESSAGE_TEST_POW'), "BITMESSAGE_TEST_POW is not set")
class TestProofofwork(TestProofofworkBase):
"""The main test case for proofofwork"""
def _make_sample_data(self):
payload = self._make_sample_payload()
return payload, proofofwork.getTarget(
len(payload), default_ttl,
networkDefaultProofOfWorkNonceTrialsPerByte,
networkDefaultPayloadLengthExtraBytes
), hashlib.sha512(payload).digest()
def test_calculate(self):
"""Extended test for the main proofofwork call"""
# raise difficulty and TTL
TTL = 24 * 60 * 60
payload = self._make_sample_payload(TTL)
nonce = proofofwork.calculate(payload, TTL, 2000, 2000)[1]
self.assertTrue(
protocol.isProofOfWorkSufficient(
pack('>Q', nonce) + payload, 2000, 2000,
int(time.time()) + TTL - 3600))
# pylint: disable=import-outside-toplevel
from class_singleWorker import singleWorker
# pylint: disable=no-member
with self.assertLogs('default') as cm:
self.assertTrue(protocol.isProofOfWorkSufficient(
singleWorker._doPOWDefaults(payload, TTL, log_prefix='+')))
self.assertEqual(
cm.output[0],
'INFO:default:+ Doing proof of work... TTL set to %s' % TTL)
self.assertEqual(
cm.output[1][:34], 'INFO:default:+ Found proof of work')
with self.assertLogs('default') as cm:
self.assertTrue(protocol.isProofOfWorkSufficient(
singleWorker._doPOWDefaults(payload, TTL, log_time=True)))
self.assertEqual(cm.output[2][:22], 'INFO:default:PoW took ')
with self.assertRaises(StopIteration):
self.state.shutdown = 1
proofofwork.calculate(payload, TTL)
def test_CPoW(self):
"""Do PoW with parameters from test_openclpow and check the result"""
nonce = proofofwork._doCPoW(
sample_pow_target, sample_pow_initial_hash)[0]
trial_value, = unpack(
'>Q', hashlib.sha512(hashlib.sha512(
pack('>Q', nonce) + sample_pow_initial_hash
).digest()).digest()[0:8])
self.assertLess((nonce - trial_value), sample_pow_target)
def test_SafePoW(self):
"""Do python PoW for a sample payload and check by protocol"""
payload, target, initial_hash = self._make_sample_data()
nonce = proofofwork._doSafePoW(target, initial_hash)[1]
self.assertTrue(
protocol.isProofOfWorkSufficient(pack('>Q', nonce) + payload))
def test_FastPoW(self):
"""Do python multiprocessing PoW for a sample payload and check"""
payload, target, initial_hash = self._make_sample_data()
nonce = proofofwork._doFastPoW(target, initial_hash)[1]
self.assertTrue(
protocol.isProofOfWorkSufficient(pack('>Q', nonce) + payload))

View File

@ -50,6 +50,11 @@ commands = python pybitmessage/bitmessagemain.py -t
[testenv:py35] [testenv:py35]
skip_install = true skip_install = true
[testenv:py36]
setenv =
BITMESSAGE_TEST_POW = true
{[testenv]setenv}
[testenv:reset] [testenv:reset]
skip_install = true skip_install = true
deps = coverage deps = coverage