+ 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: if debug or developmentMode:
OnionrCommunicatorTimers(self, self.heartbeat, 10) 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 :) # Print nice header thing :)
if config.get('general.display_header', True): if config.get('general.display_header', True) and not self.shutdown:
self.header() self.header()
# Set timers, function reference, seconds # Set timers, function reference, seconds
OnionrCommunicatorTimers(self, self.daemonCommands, 5) OnionrCommunicatorTimers(self, self.daemonCommands, 5)
OnionrCommunicatorTimers(self, self.detectAPICrash, 5) OnionrCommunicatorTimers(self, self.detectAPICrash, 5)
OnionrCommunicatorTimers(self, self.getOnlinePeers, 60) peerPoolTimer = OnionrCommunicatorTimers(self, self.getOnlinePeers, 60)
OnionrCommunicatorTimers(self, self.lookupBlocks, 7) OnionrCommunicatorTimers(self, self.lookupBlocks, 7, requiresPeer=True)
OnionrCommunicatorTimers(self, self.getBlocks, 10) OnionrCommunicatorTimers(self, self.getBlocks, 10, requiresPeer=True)
OnionrCommunicatorTimers(self, self.clearOfflinePeer, 120) OnionrCommunicatorTimers(self, self.clearOfflinePeer, 120)
OnionrCommunicatorTimers(self, self.lookupKeys, 125) OnionrCommunicatorTimers(self, self.lookupKeys, 125, requiresPeer=True)
OnionrCommunicatorTimers(self, self.lookupAdders, 600) 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 # Main daemon loop, mainly for calling timers, don't do any complex operations here to avoid locking
try: try:
@ -227,8 +226,11 @@ class OnionrCommunicatorDaemon:
for i in range(needed): for i in range(needed):
if len(self.onlinePeers) == 0: if len(self.onlinePeers) == 0:
self.connectNewPeer(useBootstrap=True) self.connectNewPeer(useBootstrap=True)
if len(self.onlinePeers) == 0: if self.shutdown:
logger.warn('Could not connect to any peer.') break
else:
if len(self.onlinePeers) == 0:
logger.warn('Could not connect to any peer.')
self.decrementThreadCount('getOnlinePeers') self.decrementThreadCount('getOnlinePeers')
def addBootstrapListToPeerList(self, peerList): 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') logger.info(logger.colors.fg.lightgreen + '-> ' + str(message) + logger.colors.reset + logger.colors.fg.lightgreen + ' <-\n')
class OnionrCommunicatorTimers: 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.timerFunction = timerFunction
self.frequency = frequency self.frequency = frequency
self.threadAmount = threadAmount self.threadAmount = threadAmount
self.makeThread = makeThread self.makeThread = makeThread
self.requiresPeer = requiresPeer
self.daemonInstance = daemonInstance self.daemonInstance = daemonInstance
self.maxThreads = maxThreads self.maxThreads = maxThreads
self._core = self.daemonInstance._core self._core = self.daemonInstance._core
@ -371,25 +374,33 @@ class OnionrCommunicatorTimers:
self.count = 0 self.count = 0
def processTimer(self): def processTimer(self):
# mark how many instances of a thread we have (decremented at thread end) # mark how many instances of a thread we have (decremented at thread end)
self.count += 1
try: try:
self.daemonInstance.threadCounts[self.timerFunction.__name__] self.daemonInstance.threadCounts[self.timerFunction.__name__]
except KeyError: except KeyError:
self.daemonInstance.threadCounts[self.timerFunction.__name__] = 0 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.count == self.frequency:
if self.makeThread: try:
for i in range(self.threadAmount): if self.requiresPeer and len(self.daemonInstance.onlinePeers) == 0:
if self.daemonInstance.threadCounts[self.timerFunction.__name__] >= self.maxThreads: raise onionrexceptions.OnlinePeerNeeded
logger.warn(self.timerFunction.__name__ + ' has too many current threads to start anymore.') except onionrexceptions.OnlinePeerNeeded:
else: pass
self.daemonInstance.threadCounts[self.timerFunction.__name__] += 1
newThread = threading.Thread(target=self.timerFunction)
newThread.start()
else: else:
self.timerFunction() if self.makeThread:
self.count = 0 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 shouldRun = False
debug = True debug = True

View File

@ -25,7 +25,7 @@ import sys
if sys.version_info[0] == 2 or sys.version_info[1] < 5: if sys.version_info[0] == 2 or sys.version_info[1] < 5:
print('Error, Onionr requires Python 3.4+') print('Error, Onionr requires Python 3.4+')
sys.exit(1) 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 from threading import Thread
import api, core, config, logger, onionrplugins as plugins, onionrevents as events import api, core, config, logger, onionrplugins as plugins, onionrevents as events
import onionrutils import onionrutils
@ -604,7 +604,11 @@ class Onionr:
try: try:
events.event('daemon_stop', onionr = self) events.event('daemon_stop', onionr = self)
net = NetController(config.get('client.port', 59496)) net = NetController(config.get('client.port', 59496))
self.onionrCore.daemonQueueAdd('shutdown') try:
self.onionrCore.daemonQueueAdd('shutdown')
except sqlite3.OperationalError:
pass
net.killTor() net.killTor()
except Exception as e: except Exception as e:
logger.error('Failed to shutdown daemon.', error = e, timestamp = False) 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: with open(self._keyFile, 'w') as keyfile:
keyfile.write(self.pubKey + ',' + self.privKey) keyfile.write(self.pubKey + ',' + self.privKey)
with open(self.keyPowFile, 'w') as keyPowFile: 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') logger.info('Doing necessary work to insert our public key')
while True: while True:
time.sleep(0.2) time.sleep(0.2)

View File

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

View File

@ -21,6 +21,99 @@
import nacl.encoding, nacl.hash, nacl.utils, time, math, threading, binascii, logger, sys, base64, json import nacl.encoding, nacl.hash, nacl.utils, time, math, threading, binascii, logger, sys, base64, json
import core 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: class POW:
def __init__(self, metadata, data, threadCount = 5): def __init__(self, metadata, data, threadCount = 5):
self.foundHash = False self.foundHash = False