Added estimated POW time tooltip
This commit is contained in:
parent
a27b5e9055
commit
2c7d677ccf
|
@ -54,6 +54,7 @@ from network.asyncore_pollchoose import set_rates
|
||||||
import sound
|
import sound
|
||||||
import re
|
import re
|
||||||
import bitmessage_icons_rc # Loads icon resources
|
import bitmessage_icons_rc # Loads icon resources
|
||||||
|
import workprover.utils
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -1876,11 +1877,17 @@ class MyForm(settingsmixin.SMainWindow):
|
||||||
|
|
||||||
if status.speed == 0:
|
if status.speed == 0:
|
||||||
self.ui.workProverSpeed.setText("")
|
self.ui.workProverSpeed.setText("")
|
||||||
|
self.ui.workProverSpeed.setToolTip("")
|
||||||
else:
|
else:
|
||||||
self.ui.workProverSpeed.setText(
|
self.ui.workProverSpeed.setText(
|
||||||
_translate("MainWindow", "%1 kiH / s").arg("{:.1f}".format(status.speed / 1024))
|
_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):
|
def rerenderMessagelistFromLabels(self):
|
||||||
for messagelist in (self.ui.tableWidgetInbox, self.ui.tableWidgetInboxChans, self.ui.tableWidgetInboxSubscriptions):
|
for messagelist in (self.ui.tableWidgetInbox, self.ui.tableWidgetInboxChans, self.ui.tableWidgetInboxSubscriptions):
|
||||||
for i in range(messagelist.rowCount()):
|
for i in range(messagelist.rowCount()):
|
||||||
|
|
|
@ -21,13 +21,14 @@ class Task(object):
|
||||||
previous = None
|
previous = None
|
||||||
next = None
|
next = None
|
||||||
|
|
||||||
def __init__(self, headlessPayload, TTL, expiryTime, target):
|
def __init__(self, headlessPayload, TTL, expiryTime, target, difficulty):
|
||||||
self.headlessPayload = headlessPayload
|
self.headlessPayload = headlessPayload
|
||||||
self.TTL = TTL
|
self.TTL = TTL
|
||||||
self.expiryTime = expiryTime
|
self.expiryTime = expiryTime
|
||||||
self.target = target
|
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):
|
class WorkProver(threading.Thread):
|
||||||
# Seed must be 32 bytes
|
# Seed must be 32 bytes
|
||||||
|
@ -81,6 +82,7 @@ class WorkProver(threading.Thread):
|
||||||
self.lastTime = utils.getTimePoint()
|
self.lastTime = utils.getTimePoint()
|
||||||
self.timedIntervals = collections.deque()
|
self.timedIntervals = collections.deque()
|
||||||
self.speed = 0
|
self.speed = 0
|
||||||
|
self.totalDifficulty = 0
|
||||||
|
|
||||||
self.tasks = {}
|
self.tasks = {}
|
||||||
self.currentTaskID = None
|
self.currentTaskID = None
|
||||||
|
@ -94,7 +96,7 @@ class WorkProver(threading.Thread):
|
||||||
if self.solver is not None:
|
if self.solver is not None:
|
||||||
status = self.solver.status
|
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):
|
def setSolver(self, name, configuration):
|
||||||
if name is None and self.solverName is None:
|
if name is None and self.solverName is None:
|
||||||
|
@ -145,11 +147,12 @@ class WorkProver(threading.Thread):
|
||||||
self.notifyStatus()
|
self.notifyStatus()
|
||||||
|
|
||||||
def addTask(self, ID, headlessPayload, TTL, expiryTime, byteDifficulty, lengthExtension):
|
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.tasks[ID] = task
|
||||||
|
self.totalDifficulty += difficulty
|
||||||
|
|
||||||
if self.currentTaskID is None:
|
if self.currentTaskID is None:
|
||||||
task.previous = ID
|
task.previous = ID
|
||||||
|
@ -163,11 +166,14 @@ class WorkProver(threading.Thread):
|
||||||
self.tasks[task.previous].next = ID
|
self.tasks[task.previous].next = ID
|
||||||
self.tasks[task.next].previous = ID
|
self.tasks[task.next].previous = ID
|
||||||
|
|
||||||
|
self.notifyStatus()
|
||||||
|
|
||||||
def cancelTask(self, ID):
|
def cancelTask(self, ID):
|
||||||
if ID not in self.tasks:
|
if ID not in self.tasks:
|
||||||
return
|
return
|
||||||
|
|
||||||
task = self.tasks.pop(ID)
|
task = self.tasks.pop(ID)
|
||||||
|
self.totalDifficulty -= task.difficulty
|
||||||
|
|
||||||
if len(self.tasks) == 0:
|
if len(self.tasks) == 0:
|
||||||
self.currentTaskID = None
|
self.currentTaskID = None
|
||||||
|
@ -178,6 +184,8 @@ class WorkProver(threading.Thread):
|
||||||
if self.currentTaskID == ID:
|
if self.currentTaskID == ID:
|
||||||
self.currentTaskID = task.next
|
self.currentTaskID = task.next
|
||||||
|
|
||||||
|
self.notifyStatus()
|
||||||
|
|
||||||
def nextTask(self):
|
def nextTask(self):
|
||||||
self.currentTaskID = self.tasks[self.currentTaskID].next
|
self.currentTaskID = self.tasks[self.currentTaskID].next
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ byteDifficulty = 1000
|
||||||
lengthExtension = 1000
|
lengthExtension = 1000
|
||||||
|
|
||||||
target = 0x00000f903320b7f6
|
target = 0x00000f903320b7f6
|
||||||
|
difficulty = 1078000
|
||||||
|
|
||||||
seed = binascii.unhexlify("3941c24a1256660a8f65d962954c406dab7bc449317fa087c4a3f1a3ca7d95fd")
|
seed = binascii.unhexlify("3941c24a1256660a8f65d962954c406dab7bc449317fa087c4a3f1a3ca7d95fd")
|
||||||
timeout = .5
|
timeout = .5
|
||||||
|
@ -56,8 +57,8 @@ class TestUtils(unittest.TestCase):
|
||||||
self.assertEqual(utils.calculateDoubleHash(payload), doubleHash)
|
self.assertEqual(utils.calculateDoubleHash(payload), doubleHash)
|
||||||
|
|
||||||
def testCalculateTarget(self):
|
def testCalculateTarget(self):
|
||||||
self.assertEqual(utils.calculateTarget(1000, 1015, 1000, 1000), 0x00000843bf57fed2)
|
self.assertEqual(utils.calculateTarget(1000, 1015, 1000, 1000), (0x00000843bf57fed2, 2030000))
|
||||||
self.assertEqual(utils.calculateTarget(1000, 1016, 1000, 1000), 0x00000842b4a960c2)
|
self.assertEqual(utils.calculateTarget(1000, 1016, 1000, 1000), (0x00000842b4a960c2, 2031000))
|
||||||
|
|
||||||
def testCheckProof(self):
|
def testCheckProof(self):
|
||||||
self.assertFalse(utils.checkProof(nonce, initialHash, 0x000002fe91eba355))
|
self.assertFalse(utils.checkProof(nonce, initialHash, 0x000002fe91eba355))
|
||||||
|
@ -75,8 +76,8 @@ class TestUtils(unittest.TestCase):
|
||||||
utils.time.time = originalTime
|
utils.time.time = originalTime
|
||||||
|
|
||||||
def testEstimateMaximumIterationsCount(self):
|
def testEstimateMaximumIterationsCount(self):
|
||||||
self.assertEqual(utils.estimateMaximumIterationsCount(0x000fffffffffffff, .1), 512)
|
self.assertEqual(utils.estimateMaximumIterationsCount(4096, .1), 512)
|
||||||
self.assertEqual(utils.estimateMaximumIterationsCount(target, .8), 1735168)
|
self.assertEqual(utils.estimateMaximumIterationsCount(difficulty, .8), 1735168)
|
||||||
|
|
||||||
class TestSolver(unittest.TestCase):
|
class TestSolver(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -135,6 +136,8 @@ class TestWorkProver(unittest.TestCase):
|
||||||
linkID = next(iter(IDs))
|
linkID = next(iter(IDs))
|
||||||
|
|
||||||
for i in xrange(len(IDs)):
|
for i in xrange(len(IDs)):
|
||||||
|
self.assertGreaterEqual(self.thread.totalDifficulty, 0)
|
||||||
|
|
||||||
self.assertIn(linkID, IDs)
|
self.assertIn(linkID, IDs)
|
||||||
|
|
||||||
IDs.remove(linkID)
|
IDs.remove(linkID)
|
||||||
|
|
|
@ -19,7 +19,7 @@ def calculateTarget(length, TTL, byteDifficulty, lengthExtension):
|
||||||
|
|
||||||
difficulty = byteDifficulty * (adjustedLength + timeEquivalent)
|
difficulty = byteDifficulty * (adjustedLength + timeEquivalent)
|
||||||
|
|
||||||
return 2 ** 64 / difficulty
|
return 2 ** 64 / difficulty, difficulty
|
||||||
|
|
||||||
def checkProof(nonce, initialHash, target):
|
def checkProof(nonce, initialHash, target):
|
||||||
proof = nonce + initialHash
|
proof = nonce + initialHash
|
||||||
|
@ -34,13 +34,12 @@ def checkWorkSufficient(payload, byteDifficulty, lengthExtension):
|
||||||
nonce = payload[: 8]
|
nonce = payload[: 8]
|
||||||
initialHash = calculateInitialHash(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)
|
return checkProof(nonce, initialHash, target)
|
||||||
|
|
||||||
def estimateMaximumIterationsCount(target, probability):
|
def estimateMaximumIterationsCount(difficulty, probability):
|
||||||
coefficient = -math.log(1 - probability)
|
coefficient = -math.log(1 - probability)
|
||||||
difficulty = 2. ** 64 / target
|
|
||||||
|
|
||||||
return int(coefficient * difficulty + 255) / 256 * 256
|
return int(coefficient * difficulty + 255) / 256 * 256
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user