From fdd3ff0a9d896dff4ad2190abd987cae267b1533 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Tue, 12 Mar 2019 13:23:46 -0500 Subject: [PATCH] multiprocess pow progress --- onionr/core.py | 5 +- onionr/onionrproofs.py | 2 + onionr/static-data/www/shared/sites.js | 18 +++++ onionr/subprocesspow.py | 92 ++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 onionr/static-data/www/shared/sites.js create mode 100755 onionr/subprocesspow.py diff --git a/onionr/core.py b/onionr/core.py index c0682a98..2794aba4 100755 --- a/onionr/core.py +++ b/onionr/core.py @@ -23,7 +23,7 @@ import deadsimplekv as simplekv import onionrutils, onionrcrypto, onionrproofs, onionrevents as events, onionrexceptions import onionrblacklist from onionrusers import onionrusers -import dbcreator, onionrstorage, serializeddata +import dbcreator, onionrstorage, serializeddata, subprocesspow from etc import onionrvalues if sys.version_info < (3, 6): @@ -787,8 +787,7 @@ class Core: metadata['expire'] = expire # send block data (and metadata) to POW module to get tokenized block data - proof = onionrproofs.POW(metadata, data) - payload = proof.waitForResult() + payload = subprocesspow.SubprocessPOW(data, metadata, self).start() if payload != False: try: retData = self.setData(payload) diff --git a/onionr/onionrproofs.py b/onionr/onionrproofs.py index 496573d0..62dc215c 100755 --- a/onionr/onionrproofs.py +++ b/onionr/onionrproofs.py @@ -244,6 +244,7 @@ class POW: answer = '' hbCount = 0 nonce = int(binascii.hexlify(nacl.utils.random(2)), 16) + startNonce = nonce while self.hashing: #token = nacl.hash.blake2b(rand + self.data).decode() self.metadata['powRandomToken'] = nonce @@ -258,6 +259,7 @@ class POW: self.hashing = False iFound = True self.result = payload + print('count', nonce - startNonce) break nonce += 1 diff --git a/onionr/static-data/www/shared/sites.js b/onionr/static-data/www/shared/sites.js new file mode 100644 index 00000000..ab5c01a8 --- /dev/null +++ b/onionr/static-data/www/shared/sites.js @@ -0,0 +1,18 @@ +function checkHex(str) { + regexp = /^[0-9a-fA-F]+$/ + if (regexp.test(str)){ + return true + } + return false +} + +document.getElementById('openSite').onclick = function(){ + var hash = document.getElementById('siteViewer').value + + if (checkHex(hash) && hash.length == 64){ + window.location.href = '/site/' + hash + } + else{ + alert('Invalid site hash') + } +} \ No newline at end of file diff --git a/onionr/subprocesspow.py b/onionr/subprocesspow.py new file mode 100755 index 00000000..a2fee7c6 --- /dev/null +++ b/onionr/subprocesspow.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +import subprocess, sys, os +import multiprocessing, threading, time, json, math, binascii +from multiprocessing import Pipe, Process +import core, onionrblockapi, config, onionrutils, logger, onionrproofs + +class SubprocessPOW: + def __init__(self, data, metadata, core_inst=None, subprocCount=None): + if core_inst is None: + core_inst = core.Core() + if subprocCount is None: + subprocCount = os.cpu_count() + self.subprocCount = subprocCount + self.result = '' + self.shutdown = False + self.core_inst = core_inst + self.data = data + self.metadata = metadata + + dataLen = len(data) + len(json.dumps(metadata)) + + #if forceDifficulty > 0: + # self.difficulty = forceDifficulty + #else: + # Calculate difficulty. Dumb for now, may use good algorithm in the future. + self.difficulty = onionrproofs.getDifficultyForNewBlock(dataLen) + + try: + self.data = self.data.encode() + except AttributeError: + pass + + logger.info('Computing POW (difficulty: %s)...' % self.difficulty) + + self.mainHash = '0' * 64 + self.puzzle = self.mainHash[0:min(self.difficulty, len(self.mainHash))] + self.shutdown = False + self.payload = None + + def start(self): + startTime = self.core_inst._utils.getEpoch() + for x in range(self.subprocCount): + threading.Thread(target=self._spawn_proc).start() + while True: + if self.payload is None: + time.sleep(0.1) + else: + self.shutdown = True + return self.payload + + def _spawn_proc(self): + parent_conn, child_conn = Pipe() + p = Process(target=self.do_pow, args=(child_conn,)) + p.start() + p.join() + payload = None + try: + while True: + data = parent_conn.recv() + if len(data) >= 1: + payload = data + break + except KeyboardInterrupt: + pass + finally: + parent_conn.send('shutdown') + self.payload = payload + + def do_pow(self, pipe): + nonce = int(binascii.hexlify(os.urandom(2)), 16) + nonceStart = nonce + data = self.data + metadata = self.metadata + puzzle = self.puzzle + difficulty = self.difficulty + mcore = core.Core() + while True: + metadata['powRandomToken'] = nonce + payload = json.dumps(metadata).encode() + b'\n' + data + token = mcore._crypto.sha3Hash(payload) + try: + # on some versions, token is bytes + token = token.decode() + except AttributeError: + pass + if pipe.poll() and pipe.recv() == 'shutdown': + break + if puzzle == token[0:difficulty]: + pipe.send(payload) + break + nonce += 1 + \ No newline at end of file