Merge branch 'mergenick' into mergenickmaster

This commit is contained in:
Kevin Froman 2019-09-10 21:08:35 -05:00
commit b47da779cb
6 changed files with 29 additions and 97 deletions

View File

@ -44,12 +44,6 @@ if sys.version_info[0] == 2 or sys.version_info[1] < onionrvalues.MIN_PY_VERSION
sys.stderr.write('Error, Onionr requires Python 3.%s+\n' % (onionrvalues.MIN_PY_VERSION,)) sys.stderr.write('Error, Onionr requires Python 3.%s+\n' % (onionrvalues.MIN_PY_VERSION,))
sys.exit(1) sys.exit(1)
# Ensure Python interpreter is not optimized TODO: Remove asserts and replace with ifs
from utils import detectoptimization
if detectoptimization.detect_optimization():
sys.stderr.write('Error, Onionr cannot be run with an optimized Python interpreter\n')
sys.exit(2)
# Create Onionr data directories, must be done before most imports # Create Onionr data directories, must be done before most imports
from utils import createdirs from utils import createdirs
createdirs.create_dirs() createdirs.create_dirs()
@ -65,4 +59,4 @@ def onionr_main():
return return
if __name__ == "__main__": if __name__ == "__main__":
onionr_main() onionr_main()

View File

@ -65,7 +65,7 @@ def announce_node(daemon):
data['random'] = existingRand data['random'] = existingRand
else: else:
daemon.announceProgress[peer] = True daemon.announceProgress[peer] = True
proof = onionrproofs.DataPOW(combinedNodes, forceDifficulty=onionrvalues.ANNOUNCE_POW) proof = onionrproofs.DataPOW(combinedNodes, minDifficulty=onionrvalues.ANNOUNCE_POW)
del daemon.announceProgress[peer] del daemon.announceProgress[peer]
try: try:
data['random'] = base64.b64encode(proof.waitForResult()[1]) data['random'] = base64.b64encode(proof.waitForResult()[1])

View File

@ -19,7 +19,7 @@ def verify_POW(blockContent):
except AttributeError: except AttributeError:
pass pass
difficulty = onionrproofs.getDifficultyForNewBlock(blockContent, ourBlock=False) difficulty = onionrproofs.getDifficultyForNewBlock(blockContent)
if difficulty < int(config.get('general.minimum_block_pow')): if difficulty < int(config.get('general.minimum_block_pow')):
difficulty = int(config.get('general.minimum_block_pow')) difficulty = int(config.get('general.minimum_block_pow'))

View File

@ -17,91 +17,64 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
''' '''
import multiprocessing, nacl.encoding, nacl.hash, nacl.utils, time, math, threading, binascii, sys, json import multiprocessing, nacl.encoding, nacl.hash, nacl.utils, time, math, threading, binascii, sys, json, sys
import config, logger, onionrblockapi, storagecounter import config, logger, onionrblockapi, storagecounter
from onionrutils import bytesconverter from onionrutils import bytesconverter
from onionrcrypto import hashers from onionrcrypto import hashers
config.reload() config.reload()
def getDifficultyModifier(): def getDifficultyModifier():
'''returns the difficulty modifier for block storage based '''returns the difficulty modifier for block storage based
on a variety of factors, currently only disk use. on a variety of factors, currently only disk use.
''' '''
retData = 0 percentUse = storagecounter.StorageCounter().getPercent()
useFunc = storagecounter.StorageCounter().get_percent difficultyIncrease = math.floor(4 * percentUse) # difficulty increase is a step function
percentUse = useFunc() return difficultyIncrease
if percentUse >= 0.50: def getDifficultyForNewBlock(data):
retData += 1
elif percentUse >= 0.75:
retData += 2
elif percentUse >= 0.95:
retData += 3
return retData
def getDifficultyForNewBlock(data, ourBlock=True):
''' '''
Get difficulty for block. Accepts size in integer, Block instance, or str/bytes full block contents Get difficulty for block. Accepts size in integer, Block instance, or str/bytes full block contents
''' '''
retData = 0
dataSize = 0
if isinstance(data, onionrblockapi.Block): if isinstance(data, onionrblockapi.Block):
dataSize = len(data.getRaw().encode('utf-8')) dataSizeInBytes = len(bytesconverter.str_to_bytes(data.getRaw()))
else: else:
dataSize = len(bytesconverter.str_to_bytes(data)) dataSizeInBytes = len(bytesconverter.str_to_bytes(data))
if ourBlock: minDifficulty = config.get('general.minimum_send_pow', 4)
minDifficulty = config.get('general.minimum_send_pow', 4) totalDifficulty = max(minDifficulty, math.floor(dataSizeInBytes / 1000000.0)) + getDifficultyModifier()
else:
minDifficulty = config.get('general.minimum_block_pow', 4)
retData = max(minDifficulty, math.floor(dataSize / 100000)) + getDifficultyModifier() return totalDifficulty
return retData return retData
def getHashDifficulty(h: str): def getHashDifficulty(h: str):
''' '''
Return the amount of leading zeroes in a hex hash string (h) Return the amount of leading zeroes in a hex hash string (hexHash)
''' '''
difficulty = 0 return len(h) - len(h.lstrip('0'))
for character in h:
if character == '0':
difficulty += 1
else:
break
return difficulty
def hashMeetsDifficulty(h): def hashMeetsDifficulty(hexHash):
''' '''
Return bool for a hash string to see if it meets pow difficulty defined in config Return bool for a hash string to see if it meets pow difficulty defined in config
''' '''
hashDifficulty = getHashDifficulty(h) hashDifficulty = getHashDifficulty(hexHash)
try: try:
expected = int(config.get('general.minimum_block_pow')) expected = int(config.get('general.minimum_block_pow'))
except TypeError: except TypeError:
raise ValueError('Missing general.minimum_block_pow config') raise ValueError('Missing general.minimum_block_pow config')
if hashDifficulty >= expected:
return True return hashDifficulty >= expected
else:
return False
class DataPOW: class DataPOW:
def __init__(self, data, forceDifficulty=0, threadCount = 1): def __init__(self, data, minDifficulty = 0, threadCount = 1):
self.foundHash = False
self.difficulty = 0
self.data = data self.data = data
self.threadCount = threadCount self.threadCount = threadCount
self.difficulty = max(minDifficulty, getDifficultyForNewBlock(data))
self.rounds = 0 self.rounds = 0
self.hashing = False self.hashing = False
self.foundHash = False
if forceDifficulty == 0:
dataLen = sys.getsizeof(data)
self.difficulty = math.floor(dataLen / 1000000)
if self.difficulty <= 2:
self.difficulty = 4
else:
self.difficulty = forceDifficulty
try: try:
self.data = self.data.encode() self.data = self.data.encode()
@ -124,9 +97,6 @@ class DataPOW:
self.hashing = True self.hashing = True
self.reporting = reporting self.reporting = reporting
iFound = False # if current thread is the one that found the answer iFound = False # if current thread is the one that found the answer
answer = ''
heartbeat = 200000
hbCount = 0
while self.hashing: while self.hashing:
rand = nacl.utils.random() rand = nacl.utils.random()
@ -183,7 +153,7 @@ class DataPOW:
return result return result
class POW: class POW:
def __init__(self, metadata, data, threadCount = 1, forceDifficulty=0): def __init__(self, metadata, data, threadCount = 1, minDifficulty=0):
self.foundHash = False self.foundHash = False
self.difficulty = 0 self.difficulty = 0
self.data = data self.data = data
@ -198,8 +168,8 @@ class POW:
except AttributeError: except AttributeError:
pass pass
if forceDifficulty > 0: if minDifficulty > 0:
self.difficulty = forceDifficulty self.difficulty = minDifficulty
else: else:
# Calculate difficulty. Dumb for now, may use good algorithm in the future. # Calculate difficulty. Dumb for now, may use good algorithm in the future.
self.difficulty = getDifficultyForNewBlock(bytes(json_metadata + b'\n' + self.data)) self.difficulty = getDifficultyForNewBlock(bytes(json_metadata + b'\n' + self.data))
@ -218,10 +188,7 @@ class POW:
self.hashing = True self.hashing = True
self.reporting = reporting self.reporting = reporting
iFound = False # if current thread is the one that found the answer iFound = False # if current thread is the one that found the answer
answer = '' nonce = int(binascii.hexlify(nacl.utils.random(64)), 16)
hbCount = 0
nonce = int(binascii.hexlify(nacl.utils.random(2)), 16)
startNonce = nonce
while self.hashing: while self.hashing:
#token = nacl.hash.blake2b(rand + self.data).decode() #token = nacl.hash.blake2b(rand + self.data).decode()
self.metadata['pow'] = nonce self.metadata['pow'] = nonce

View File

@ -1,27 +0,0 @@
'''
Onionr - Private P2P Communication
Detect if Python is being run in optimized mode or not, which has security considerations for assert statements
'''
'''
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
'''
def detect_optimization():
'''Returns true if Python is run in optimized mode (-o), based on optimization ignoring assert statements'''
try:
assert True is False
except AssertionError:
return False
return True

View File

@ -1,6 +1,4 @@
import netcontroller import netcontroller
def has_tor(): def has_tor():
if netcontroller.tor_binary() is None: return netcontroller.tor_binary() is not None
return False
return True