Browse Source

* Removed hard coded data dir in daemon launch

* Documented subprocess pow better
* Calculate block size better for pow
+ Added monero donation address
Kevin Froman 3 years ago
No known key found for this signature in database GPG Key ID: D414D0FE405B63B
  1. 8
  2. 4
  3. 11
  4. 63


@ -69,12 +69,14 @@ More docs coming soon.
The following applies to Ubuntu Bionic. Other distros may have different package or command names.
`$ sudo apt install python3-pip python3-dev tor`
* Have python3.6+, python3-pip, Tor (daemon, not browser) installed (python3-dev recommended)
* Clone the git repo: `$ git clone`
* cd into install direction: `$ cd onionr/`
* Install the Python dependencies ([virtualenv strongly recommended]( `$ pip3 install --require-hashes -r requirements.txt`
(--require-hashes is intended to prevent exploitation via compromise of Pypi/CA certificates)
(--require-hashes is intended to prevent exploitation via compromise of PyPi/CA certificates)
## Help out
@ -95,7 +97,9 @@ Contribute money:
Donating at least $5 gets you cool Onionr stickers. Get in touch if you want them.
Bitcoin: [1onion55FXzm6h8KQw3zFw2igpHcV7LPq](bitcoin:1onion55FXzm6h8KQw3zFw2igpHcV7LPq) (Contact us for privacy coins like Monero)
Bitcoin: [1onion55FXzm6h8KQw3zFw2igpHcV7LPq](bitcoin:1onion55FXzm6h8KQw3zFw2igpHcV7LPq) (Contact us for a unique address or for other coins)
Monero: 4B5BA24d1P3R5aWEpkGY5TP7buJJcn2aSGBVRQCHhpiahxeB4aWsu15XwmuTjC6VF62NApZeJGTS248RMVECP8aW73Uj2ax
USD (Card/Paypal): [Ko-Fi](


@ -29,9 +29,9 @@ def daemon(o_inst):
# remove runcheck if it exists
if os.path.isfile('data/.runcheck'):
if os.path.isfile('%s/.runcheck' % (o_inst.onionrCore.dataDir,)):
logger.debug('Runcheck file found on daemon start, deleting in advance.')
os.remove('%s/.runcheck' % (o_inst.onionrCore.dataDir,))
Thread(target=api.API, args=(o_inst, o_inst.debug, onionr.API_VERSION)).start()
Thread(target=api.PublicAPI, args=[o_inst.getClientApi()]).start()


@ -53,14 +53,9 @@ def getDifficultyForNewBlock(data, ourBlock=True):
dataSize = 0
if isinstance(data, onionrblockapi.Block):
dataSize = len(data.getRaw().encode('utf-8'))
elif isinstance(data, str):
dataSize = len(data.encode('utf-8'))
elif isinstance(data, bytes):
dataSize = len(data)
elif isinstance(data, int):
dataSize = data
raise ValueError('not Block, str, or int')
dataSize = len(onionrutils.OnionrUtils.strToBytes(data))
if ourBlock:
minDifficulty = config.get('general.minimum_send_pow', 4)
@ -131,8 +126,6 @@ class DataPOW:
for i in range(max(1, threadCount)):
t = threading.Thread(name = 'thread%s' % i, target = self.pow, args = (True,myCore))
def pow(self, reporting = False, myCore = None):
startTime = math.floor(time.time())


@ -1,34 +1,39 @@
#!/usr/bin/env python3
import subprocess, sys, os
import multiprocessing, threading, time, json, math, binascii
import subprocess, os
import multiprocessing, threading, time, json, math
from multiprocessing import Pipe, Process
import core, onionrblockapi, config, onionrutils, logger, onionrproofs
class SubprocessPOW:
def __init__(self, data, metadata, core_inst=None, subprocCount=None):
def __init__(self, data, metadata, core_inst=None, subproc_count=None):
Onionr proof of work using multiple processes
Accepts block data, block metadata
and optionally an onionr core library instance.
if subproc_count is not set, os.cpu_count() is used to determine the number of processes
Do to Python GIL multiprocessing or use of external libraries is necessary to accelerate CPU bound tasks
# Option to accept existing core instance to save memory
if core_inst is None:
core_inst = core.Core()
if subprocCount is None:
subprocCount = os.cpu_count()
self.subprocCount = subprocCount
# No known benefit to using more processes than there are cores.
# Note: os.cpu_count perhaps not always accurate
if subproc_count is None:
subproc_count = os.cpu_count()
self.subproc_count = subproc_count
self.result = ''
self.shutdown = False
self.core_inst = core_inst = data
self.metadata = metadata
dataLen = len(data) + len(json.dumps(metadata))
# dump dict to measure bytes of json metadata. Cannot reuse later because the pow token must be added
json_metadata = json.dumps(metadata).encode()
#if forceDifficulty > 0:
# self.difficulty = forceDifficulty
# Calculate difficulty. Dumb for now, may use good algorithm in the future.
self.difficulty = onionrproofs.getDifficultyForNewBlock(dataLen)
try: =
except AttributeError:
pass = onionrutils.OnionrUtils.strToBytes(data)
# Calculate difficulty. Dumb for now, may use good algorithm in the future.
self.difficulty = onionrproofs.getDifficultyForNewBlock(bytes(json_metadata + b'\n' +'Computing POW (difficulty: %s)...' % self.difficulty)
@ -38,9 +43,10 @@ class SubprocessPOW:
self.payload = None
def start(self):
startTime = self.core_inst._utils.getEpoch()
for x in range(self.subprocCount):
# Create a new thread for each subprocess
for x in range(self.subproc_count):
# Monitor the processes for a payload, shut them down when its found
while True:
if self.payload is None:
@ -49,6 +55,7 @@ class SubprocessPOW:
return self.payload
def _spawn_proc(self):
# Create a child proof of work process, wait for data and send shutdown signal when its found
parent_conn, child_conn = Pipe()
p = Process(target=self.do_pow, args=(child_conn,))
@ -67,24 +74,24 @@ class SubprocessPOW:
self.payload = payload
def do_pow(self, pipe):
nonce = int(binascii.hexlify(os.urandom(2)), 16)
nonce = -10000000 # Start nonce at negative 10 million so that the chosen nonce is likely to be small in length
nonceStart = nonce
data =
metadata = self.metadata
puzzle = self.puzzle
difficulty = self.difficulty
mcore = core.Core()
mcore = core.Core() # I think we make a new core here because of multiprocess bugs
while True:
# Break if shutdown received
if pipe.poll() and pipe.recv() == 'shutdown':
# Load nonce into block metadata
metadata['pow'] = nonce
# Serialize metadata, combine with block data
payload = json.dumps(metadata).encode() + b'\n' + data
# Check sha3_256 hash of block, compare to puzzle. Send payload if puzzle finished
token = mcore._crypto.sha3Hash(payload)
# on some versions, token is bytes
token = token.decode()
except AttributeError:
if pipe.poll() and pipe.recv() == 'shutdown':
token = onionrutils.OnionrUtils.bytesToStr(token) # ensure token is string
if puzzle == token[0:difficulty]: