+ 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:
parent
f027202ac9
commit
b3b5e5bb50
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -26,6 +26,10 @@ class Unknown(Exception):
|
||||
class Invalid(Exception):
|
||||
pass
|
||||
|
||||
# communicator exceptions
|
||||
class OnlinePeerNeeded(Exception):
|
||||
pass
|
||||
|
||||
# crypto exceptions
|
||||
class InvalidPubkey(Exception):
|
||||
pass
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user