diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e800877b..7f8a367c 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -54,6 +54,7 @@ from network.asyncore_pollchoose import set_rates import sound import re import bitmessage_icons_rc # Loads icon resources +import workprover.utils try: @@ -1876,11 +1877,17 @@ class MyForm(settingsmixin.SMainWindow): if status.speed == 0: self.ui.workProverSpeed.setText("") + self.ui.workProverSpeed.setToolTip("") else: self.ui.workProverSpeed.setText( _translate("MainWindow", "%1 kiH / s").arg("{:.1f}".format(status.speed / 1024)) ) + self.ui.workProverSpeed.setToolTip("Difficulty: {}, 80 % completion time: {:.1f} s".format( + status.difficulty, + workprover.utils.estimateMaximumIterationsCount(status.difficulty, .8) / status.speed + )) + def rerenderMessagelistFromLabels(self): for messagelist in (self.ui.tableWidgetInbox, self.ui.tableWidgetInboxChans, self.ui.tableWidgetInboxSubscriptions): for i in range(messagelist.rowCount()): diff --git a/src/workprover/__init__.py b/src/workprover/__init__.py index 54e3e52d..4ea0a74c 100644 --- a/src/workprover/__init__.py +++ b/src/workprover/__init__.py @@ -21,13 +21,14 @@ class Task(object): previous = None next = None - def __init__(self, headlessPayload, TTL, expiryTime, target): + def __init__(self, headlessPayload, TTL, expiryTime, target, difficulty): self.headlessPayload = headlessPayload self.TTL = TTL self.expiryTime = expiryTime self.target = target + self.difficulty = difficulty -Status = collections.namedtuple("Status", ["solverName", "solverStatus", "speed", "tasksCount"]) +Status = collections.namedtuple("Status", ["solverName", "solverStatus", "speed", "tasksCount", "difficulty"]) class WorkProver(threading.Thread): # Seed must be 32 bytes @@ -81,6 +82,7 @@ class WorkProver(threading.Thread): self.lastTime = utils.getTimePoint() self.timedIntervals = collections.deque() self.speed = 0 + self.totalDifficulty = 0 self.tasks = {} self.currentTaskID = None @@ -94,7 +96,7 @@ class WorkProver(threading.Thread): if self.solver is not None: status = self.solver.status - self.statusUpdated(Status(self.solverName, status, self.speed, len(self.tasks))) + self.statusUpdated(Status(self.solverName, status, self.speed, len(self.tasks), self.totalDifficulty)) def setSolver(self, name, configuration): if name is None and self.solverName is None: @@ -145,11 +147,12 @@ class WorkProver(threading.Thread): self.notifyStatus() def addTask(self, ID, headlessPayload, TTL, expiryTime, byteDifficulty, lengthExtension): - target = utils.calculateTarget(8 + 8 + len(headlessPayload), TTL, byteDifficulty, lengthExtension) + target, difficulty = utils.calculateTarget(8 + 8 + len(headlessPayload), TTL, byteDifficulty, lengthExtension) - task = Task(headlessPayload, TTL, expiryTime, target) + task = Task(headlessPayload, TTL, expiryTime, target, difficulty) self.tasks[ID] = task + self.totalDifficulty += difficulty if self.currentTaskID is None: task.previous = ID @@ -163,11 +166,14 @@ class WorkProver(threading.Thread): self.tasks[task.previous].next = ID self.tasks[task.next].previous = ID + self.notifyStatus() + def cancelTask(self, ID): if ID not in self.tasks: return task = self.tasks.pop(ID) + self.totalDifficulty -= task.difficulty if len(self.tasks) == 0: self.currentTaskID = None @@ -178,6 +184,8 @@ class WorkProver(threading.Thread): if self.currentTaskID == ID: self.currentTaskID = task.next + self.notifyStatus() + def nextTask(self): self.currentTaskID = self.tasks[self.currentTaskID].next diff --git a/src/workprover/test.py b/src/workprover/test.py index 6d36ade2..e2cba67e 100755 --- a/src/workprover/test.py +++ b/src/workprover/test.py @@ -44,6 +44,7 @@ byteDifficulty = 1000 lengthExtension = 1000 target = 0x00000f903320b7f6 +difficulty = 1078000 seed = binascii.unhexlify("3941c24a1256660a8f65d962954c406dab7bc449317fa087c4a3f1a3ca7d95fd") timeout = .5 @@ -56,8 +57,8 @@ class TestUtils(unittest.TestCase): self.assertEqual(utils.calculateDoubleHash(payload), doubleHash) def testCalculateTarget(self): - self.assertEqual(utils.calculateTarget(1000, 1015, 1000, 1000), 0x00000843bf57fed2) - self.assertEqual(utils.calculateTarget(1000, 1016, 1000, 1000), 0x00000842b4a960c2) + self.assertEqual(utils.calculateTarget(1000, 1015, 1000, 1000), (0x00000843bf57fed2, 2030000)) + self.assertEqual(utils.calculateTarget(1000, 1016, 1000, 1000), (0x00000842b4a960c2, 2031000)) def testCheckProof(self): self.assertFalse(utils.checkProof(nonce, initialHash, 0x000002fe91eba355)) @@ -75,8 +76,8 @@ class TestUtils(unittest.TestCase): utils.time.time = originalTime def testEstimateMaximumIterationsCount(self): - self.assertEqual(utils.estimateMaximumIterationsCount(0x000fffffffffffff, .1), 512) - self.assertEqual(utils.estimateMaximumIterationsCount(target, .8), 1735168) + self.assertEqual(utils.estimateMaximumIterationsCount(4096, .1), 512) + self.assertEqual(utils.estimateMaximumIterationsCount(difficulty, .8), 1735168) class TestSolver(unittest.TestCase): def setUp(self): @@ -135,6 +136,8 @@ class TestWorkProver(unittest.TestCase): linkID = next(iter(IDs)) for i in xrange(len(IDs)): + self.assertGreaterEqual(self.thread.totalDifficulty, 0) + self.assertIn(linkID, IDs) IDs.remove(linkID) diff --git a/src/workprover/utils.py b/src/workprover/utils.py index 012a5033..37cc9c3d 100644 --- a/src/workprover/utils.py +++ b/src/workprover/utils.py @@ -19,7 +19,7 @@ def calculateTarget(length, TTL, byteDifficulty, lengthExtension): difficulty = byteDifficulty * (adjustedLength + timeEquivalent) - return 2 ** 64 / difficulty + return 2 ** 64 / difficulty, difficulty def checkProof(nonce, initialHash, target): proof = nonce + initialHash @@ -34,13 +34,12 @@ def checkWorkSufficient(payload, byteDifficulty, lengthExtension): nonce = payload[: 8] initialHash = calculateInitialHash(payload[8: ]) - target = calculateTarget(len(payload), minimumTTL, byteDifficulty, lengthExtension) + target, difficulty = calculateTarget(len(payload), minimumTTL, byteDifficulty, lengthExtension) return checkProof(nonce, initialHash, target) -def estimateMaximumIterationsCount(target, probability): +def estimateMaximumIterationsCount(difficulty, probability): coefficient = -math.log(1 - probability) - difficulty = 2. ** 64 / target return int(coefficient * difficulty + 255) / 256 * 256