Testing proofofwork #2276
|
@ -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')
|
||||||
|
|
17
src/api.py
17
src/api.py
|
@ -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))
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(
|
||||||
(
|
|
||||||
'updateStatusBar', (
|
|
||||||
tr._translate(
|
|
||||||
"proofofwork",
|
"proofofwork",
|
||||||
"Failed to build C PoW module. Please build it manually."
|
"Failed to build C PoW module. Please build it manually."), 1)))
|
||||||
),
|
|
||||||
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,31 +266,24 @@ 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',
|
||||||
|
@ -302,43 +292,45 @@ def buildCPoW():
|
||||||
|
|
||||||
|
|
||||||
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:
|
|
||||||
logger.error("Fast PoW got StopIteration")
|
|
||||||
raise
|
|
||||||
except: # noqa:E722 # pylint:disable=bare-except
|
|
||||||
logger.error("Fast PoW got exception:", exc_info=True)
|
|
||||||
try:
|
|
||||||
return _doSafePoW(target, initialHash)
|
return _doSafePoW(target, initialHash)
|
||||||
except StopIteration:
|
|
||||||
raise
|
|
||||||
except: # nosec B110 # noqa:E722 # pylint:disable=bare-except
|
def getTarget(payloadLength, ttl, nonceTrialsPerByte, payloadLengthExtraBytes):
|
||||||
pass # fallback
|
"""Get PoW target for given length, ttl and difficulty params"""
|
||||||
|
return 2 ** 64 / (
|
||||||
|
nonceTrialsPerByte * (
|
||||||
|
payloadLength + 8 + payloadLengthExtraBytes + ((
|
||||||
|
ttl * (
|
||||||
|
payloadLength + 8 + payloadLengthExtraBytes
|
||||||
|
)) / (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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
|
)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
120
src/tests/test_proofofwork.py
Normal file
120
src/tests/test_proofofwork.py
Normal 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))
|
5
tox.ini
5
tox.ini
|
@ -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
|
||||||
|
|
Reference in New Issue
Block a user