+ re-added old pow system as a different class for things like ed25519 keys

* no longer run communicator threads if they need peers and we have none connected
This commit is contained in:
Kevin Froman 2018-07-09 02:02:33 -05:00
parent f027202ac9
commit b3b5e5bb50
No known key found for this signature in database
GPG Key ID: 0D414D0FE405B63B
5 changed files with 140 additions and 28 deletions

View File

@ -67,23 +67,22 @@ class OnionrCommunicatorDaemon:
if debug or developmentMode:
OnionrCommunicatorTimers(self, self.heartbeat, 10)
# Initalize peer online list
logger.warn('Onionr is starting up and is not yet ready to recieve commands.')
self.getOnlinePeers()
# Print nice header thing :)
if config.get('general.display_header', True):
if config.get('general.display_header', True) and not self.shutdown:
self.header()
# Set timers, function reference, seconds
OnionrCommunicatorTimers(self, self.daemonCommands, 5)
OnionrCommunicatorTimers(self, self.detectAPICrash, 5)
OnionrCommunicatorTimers(self, self.getOnlinePeers, 60)
OnionrCommunicatorTimers(self, self.lookupBlocks, 7)
OnionrCommunicatorTimers(self, self.getBlocks, 10)
peerPoolTimer = OnionrCommunicatorTimers(self, self.getOnlinePeers, 60)
OnionrCommunicatorTimers(self, self.lookupBlocks, 7, requiresPeer=True)
OnionrCommunicatorTimers(self, self.getBlocks, 10, requiresPeer=True)
OnionrCommunicatorTimers(self, self.clearOfflinePeer, 120)
OnionrCommunicatorTimers(self, self.lookupKeys, 125)
OnionrCommunicatorTimers(self, self.lookupAdders, 600)
OnionrCommunicatorTimers(self, self.lookupKeys, 125, requiresPeer=True)
OnionrCommunicatorTimers(self, self.lookupAdders, 600, requiresPeer=True)
# set loop to execute instantly to load up peer pool (replaced old pool init wait)
peerPoolTimer.count = (peerPoolTimer.frequency - 1)
# Main daemon loop, mainly for calling timers, don't do any complex operations here to avoid locking
try:
@ -227,8 +226,11 @@ class OnionrCommunicatorDaemon:
for i in range(needed):
if len(self.onlinePeers) == 0:
self.connectNewPeer(useBootstrap=True)
if len(self.onlinePeers) == 0:
logger.warn('Could not connect to any peer.')
if self.shutdown:
break
else:
if len(self.onlinePeers) == 0:
logger.warn('Could not connect to any peer.')
self.decrementThreadCount('getOnlinePeers')
def addBootstrapListToPeerList(self, peerList):
@ -358,11 +360,12 @@ class OnionrCommunicatorDaemon:
logger.info(logger.colors.fg.lightgreen + '-> ' + str(message) + logger.colors.reset + logger.colors.fg.lightgreen + ' <-\n')
class OnionrCommunicatorTimers:
def __init__(self, daemonInstance, timerFunction, frequency, makeThread=True, threadAmount=1, maxThreads=5):
def __init__(self, daemonInstance, timerFunction, frequency, makeThread=True, threadAmount=1, maxThreads=5, requiresPeer=False):
self.timerFunction = timerFunction
self.frequency = frequency
self.threadAmount = threadAmount
self.makeThread = makeThread
self.requiresPeer = requiresPeer
self.daemonInstance = daemonInstance
self.maxThreads = maxThreads
self._core = self.daemonInstance._core
@ -371,25 +374,33 @@ class OnionrCommunicatorTimers:
self.count = 0
def processTimer(self):
# mark how many instances of a thread we have (decremented at thread end)
self.count += 1
try:
self.daemonInstance.threadCounts[self.timerFunction.__name__]
except KeyError:
self.daemonInstance.threadCounts[self.timerFunction.__name__] = 0
# execute thread if it is time
# execute thread if it is time, and we are not missing *required* online peer
if self.count == self.frequency:
if self.makeThread:
for i in range(self.threadAmount):
if self.daemonInstance.threadCounts[self.timerFunction.__name__] >= self.maxThreads:
logger.warn(self.timerFunction.__name__ + ' has too many current threads to start anymore.')
else:
self.daemonInstance.threadCounts[self.timerFunction.__name__] += 1
newThread = threading.Thread(target=self.timerFunction)
newThread.start()
try:
if self.requiresPeer and len(self.daemonInstance.onlinePeers) == 0:
raise onionrexceptions.OnlinePeerNeeded
except onionrexceptions.OnlinePeerNeeded:
pass
else:
self.timerFunction()
self.count = 0
if self.makeThread:
for i in range(self.threadAmount):
if self.daemonInstance.threadCounts[self.timerFunction.__name__] >= self.maxThreads:
logger.warn(self.timerFunction.__name__ + ' has too many current threads to start anymore.')
else:
self.daemonInstance.threadCounts[self.timerFunction.__name__] += 1
newThread = threading.Thread(target=self.timerFunction)
newThread.start()
else:
self.timerFunction()
self.count = -1 # negative 1 because its incremented at bottom
self.count += 1
shouldRun = False
debug = True

View File

@ -25,7 +25,7 @@ import sys
if sys.version_info[0] == 2 or sys.version_info[1] < 5:
print('Error, Onionr requires Python 3.4+')
sys.exit(1)
import os, base64, random, getpass, shutil, subprocess, requests, time, platform, datetime, re, json, getpass
import os, base64, random, getpass, shutil, subprocess, requests, time, platform, datetime, re, json, getpass, sqlite3
from threading import Thread
import api, core, config, logger, onionrplugins as plugins, onionrevents as events
import onionrutils
@ -604,7 +604,11 @@ class Onionr:
try:
events.event('daemon_stop', onionr = self)
net = NetController(config.get('client.port', 59496))
self.onionrCore.daemonQueueAdd('shutdown')
try:
self.onionrCore.daemonQueueAdd('shutdown')
except sqlite3.OperationalError:
pass
net.killTor()
except Exception as e:
logger.error('Failed to shutdown daemon.', error = e, timestamp = False)

View File

@ -59,7 +59,7 @@ class OnionrCrypto:
with open(self._keyFile, 'w') as keyfile:
keyfile.write(self.pubKey + ',' + self.privKey)
with open(self.keyPowFile, 'w') as keyPowFile:
proof = onionrproofs.POW(self.pubKey)
proof = onionrproofs.DataPOW(self.pubKey)
logger.info('Doing necessary work to insert our public key')
while True:
time.sleep(0.2)

View File

@ -26,6 +26,10 @@ class Unknown(Exception):
class Invalid(Exception):
pass
# communicator exceptions
class OnlinePeerNeeded(Exception):
pass
# crypto exceptions
class InvalidPubkey(Exception):
pass

View File

@ -21,6 +21,99 @@
import nacl.encoding, nacl.hash, nacl.utils, time, math, threading, binascii, logger, sys, base64, json
import core
class DataPOW:
def __init__(self, data, threadCount = 5):
self.foundHash = False
self.difficulty = 0
self.data = data
self.threadCount = threadCount
dataLen = sys.getsizeof(data)
self.difficulty = math.floor(dataLen / 1000000)
if self.difficulty <= 2:
self.difficulty = 4
try:
self.data = self.data.encode()
except AttributeError:
pass
self.data = nacl.hash.blake2b(self.data)
logger.info('Computing POW (difficulty: %s)...' % self.difficulty)
self.mainHash = '0' * 70
self.puzzle = self.mainHash[0:min(self.difficulty, len(self.mainHash))]
myCore = core.Core()
for i in range(max(1, threadCount)):
t = threading.Thread(name = 'thread%s' % i, target = self.pow, args = (True,myCore))
t.start()
return
def pow(self, reporting = False, myCore = None):
startTime = math.floor(time.time())
self.hashing = True
self.reporting = reporting
iFound = False # if current thread is the one that found the answer
answer = ''
heartbeat = 200000
hbCount = 0
while self.hashing:
rand = nacl.utils.random()
token = nacl.hash.blake2b(rand + self.data).decode()
#print(token)
if self.puzzle == token[0:self.difficulty]:
self.hashing = False
iFound = True
break
if iFound:
endTime = math.floor(time.time())
if self.reporting:
logger.debug('Found token after %s seconds: %s' % (endTime - startTime, token), timestamp=True)
logger.debug('Random value was: %s' % base64.b64encode(rand).decode())
self.result = (token, rand)
def shutdown(self):
self.hashing = False
self.puzzle = ''
def changeDifficulty(self, newDiff):
self.difficulty = newDiff
def getResult(self):
'''
Returns the result then sets to false, useful to automatically clear the result
'''
try:
retVal = self.result
except AttributeError:
retVal = False
self.result = False
return retVal
def waitForResult(self):
'''
Returns the result only when it has been found, False if not running and not found
'''
result = False
try:
while True:
result = self.getResult()
if not self.hashing:
break
else:
time.sleep(2)
except KeyboardInterrupt:
self.shutdown()
logger.warn('Got keyboard interrupt while waiting for POW result, stopping')
return result
class POW:
def __init__(self, metadata, data, threadCount = 5):
self.foundHash = False