New POW calculation module #1284

Open
Kleshni wants to merge 38 commits from Kleshni/POW into v0.6
7 changed files with 28 additions and 44 deletions
Showing only changes of commit 8e1259d06c - Show all commits

View File

@ -25,6 +25,7 @@ import state
import tr
from debug import logger
import l10n
import workprover.utils
class objectProcessor(threading.Thread):
@ -610,13 +611,13 @@ class objectProcessor(threading.Thread):
and not BMConfigParser().has_section(toAddress):
# If I'm not friendly with this person:
if not shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(fromAddress):
requiredNonceTrialsPerByte = BMConfigParser().getint(
toAddress, 'noncetrialsperbyte')
requiredPayloadLengthExtraBytes = BMConfigParser().getint(
toAddress, 'payloadlengthextrabytes')
if not protocol.isProofOfWorkSufficient(
data, requiredNonceTrialsPerByte,
requiredPayloadLengthExtraBytes):
byteDifficulty = BMConfigParser().getint(toAddress, "noncetrialsperbyte")
lengthExtension = BMConfigParser().getint(toAddress, "payloadlengthextrabytes")
byteDifficulty = max(defaults.networkDefaultProofOfWorkNonceTrialsPerByte, byteDifficulty)
lengthExtension = max(defaults.networkDefaultPayloadLengthExtraBytes, lengthExtension)
if not workprover.utils.checkWorkSufficient(data, byteDifficulty, lengthExtension):
logger.info(
'Proof of work in msg is insufficient only because'
' it does not meet our higher requirement.')

View File

@ -56,8 +56,6 @@ def signal_handler(signal, frame):
# on Windows this isn't triggered, but it's fine,
# it has its own process termination thing
raise SystemExit
if "PoolWorker" in process.name:
raise SystemExit
if process.name == "ForkingSolver":
return
if threading.current_thread().name not in ("PyBitmessage", "MainThread"):

View File

@ -7,6 +7,8 @@ from inventory import Inventory
from network.dandelion import Dandelion
import protocol
import state
import workprover.utils
import defaults
class BMObjectInsufficientPOWError(Exception):
errorCodes = ("Insufficient proof of work")
@ -52,7 +54,11 @@ class BMObject(object):
def checkProofOfWorkSufficient(self):
# Let us check to make sure that the proof of work is sufficient.
if not protocol.isProofOfWorkSufficient(self.data):
if not workprover.utils.checkWorkSufficient(
self.data,
defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
defaults.networkDefaultPayloadLengthExtraBytes
):
logger.info('Proof of work is insufficient.')
raise BMObjectInsufficientPOWError()

View File

@ -30,6 +30,7 @@ from helper_sql import sqlExecute
from version import softwareVersion
import inventory
import queues
import workprover.utils
# Service flags
@ -187,35 +188,6 @@ def checkSocksIP(host):
state.socksIP = BMConfigParser().get("bitmessagesettings", "sockshostname")
return state.socksIP == host
def isProofOfWorkSufficient(data,
nonceTrialsPerByte=0,
payloadLengthExtraBytes=0,
recvTime=0):
"""
Validate an object's Proof of Work using method described in:
https://bitmessage.org/wiki/Proof_of_work
Arguments:
int nonceTrialsPerByte (default: from default.py)
int payloadLengthExtraBytes (default: from default.py)
float recvTime (optional) UNIX epoch time when object was
received from the network (default: current system time)
Returns:
True if PoW valid and sufficient, False in all other cases
"""
if nonceTrialsPerByte < defaults.networkDefaultProofOfWorkNonceTrialsPerByte:
nonceTrialsPerByte = defaults.networkDefaultProofOfWorkNonceTrialsPerByte
if payloadLengthExtraBytes < defaults.networkDefaultPayloadLengthExtraBytes:
payloadLengthExtraBytes = defaults.networkDefaultPayloadLengthExtraBytes
endOfLifeTime, = unpack('>Q', data[8:16])
TTL = endOfLifeTime - (int(recvTime) if recvTime else int(time.time()))
if TTL < 300:
TTL = 300
POW, = unpack('>Q', hashlib.sha512(hashlib.sha512(data[
:8] + hashlib.sha512(data[8:]).digest()).digest()).digest()[0:8])
return POW <= 2 ** 64 / (nonceTrialsPerByte *
(len(data) + payloadLengthExtraBytes +
((TTL * (len(data) + payloadLengthExtraBytes)) / (2 ** 16))))
# Packet creation
@ -406,7 +378,11 @@ def checkAndShareObjectWithPeers(payload):
return None
if not isProofOfWorkSufficient(payload):
if not workprover.utils.checkWorkSufficient(
payload,
defaults.networkDefaultProofOfWorkNonceTrialsPerByte,
defaults.networkDefaultPayloadLengthExtraBytes
):
logger.info("Proof of work is insufficient")
return None

View File

@ -316,8 +316,6 @@ class singleWorker(threading.Thread, helper_threading.StoppableThread):
self.sendRawObject(*arguments)
elif command == "cancelRawObject":
self.cancelRawObject(*arguments)
elif command == "resetPoW":
pass
elif command == "GPUError":
self.handleGPUError(*arguments)
elif command == "taskDone":

View File

@ -69,9 +69,11 @@ class TestUtils(unittest.TestCase):
utils.time.time = lambda: expiryTime - 293757.5
self.assertFalse(utils.checkWorkSufficient(payload, byteDifficulty, lengthExtension))
self.assertFalse(utils.checkWorkSufficient(payload, byteDifficulty, lengthExtension, expiryTime - 293757.5))
utils.time.time = lambda: expiryTime - 293757
self.assertTrue(utils.checkWorkSufficient(payload, byteDifficulty, lengthExtension))
self.assertTrue(utils.checkWorkSufficient(payload, byteDifficulty, lengthExtension, expiryTime - 293757))
utils.time.time = originalTime

View File

@ -27,9 +27,12 @@ def checkProof(nonce, initialHash, target):
return trial <= target
def checkWorkSufficient(payload, byteDifficulty, lengthExtension):
def checkWorkSufficient(payload, byteDifficulty, lengthExtension, receivedTime = None):
if receivedTime is None:
receivedTime = int(time.time())
expiryTime, = struct.unpack(">Q", payload[8: 16])
minimumTTL = max(300, expiryTime - int(time.time()))
minimumTTL = max(300, expiryTime - receivedTime)
nonce = payload[: 8]
initialHash = calculateInitialHash(payload[8: ])