+ added POW announce for node (now POST)
* fixed bug where core hsAddress was not available on first startupmaster
parent
0ae052336c
commit
bc95d8855d
|
@ -404,6 +404,46 @@ class API:
|
||||||
|
|
||||||
resp = Response(resp)
|
resp = Response(resp)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
@app.route('/public/announce/', methods=['POST'])
|
||||||
|
def acceptAnnounce():
|
||||||
|
self.validateHost('public')
|
||||||
|
resp = 'failure'
|
||||||
|
powHash = ''
|
||||||
|
randomData = ''
|
||||||
|
newNode = ''
|
||||||
|
ourAdder = self._core.hsAddress.encode()
|
||||||
|
try:
|
||||||
|
newNode = request.form['node'].encode()
|
||||||
|
except KeyError:
|
||||||
|
logger.warn('No block specified for upload')
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
randomData = request.form['random']
|
||||||
|
randomData = base64.b64decode(randomData)
|
||||||
|
except KeyError:
|
||||||
|
logger.warn('No random data specified for upload')
|
||||||
|
else:
|
||||||
|
nodes = newNode + self._core.hsAddress.encode()
|
||||||
|
nodes = self._core._crypto.blake2bHash(nodes)
|
||||||
|
powHash = self._core._crypto.blake2bHash(randomData + nodes)
|
||||||
|
try:
|
||||||
|
powHash = powHash.decode()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
if powHash.startswith('0000'):
|
||||||
|
try:
|
||||||
|
newNode = newNode.decode()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
if self._core.addAddress(newNode):
|
||||||
|
resp = 'Success'
|
||||||
|
else:
|
||||||
|
logger.warn(newNode.decode() + ' failed to meet POW: ' + powHash)
|
||||||
|
resp = Response(resp)
|
||||||
|
return resp
|
||||||
|
|
||||||
@app.route('/public/')
|
@app.route('/public/')
|
||||||
def public_handler():
|
def public_handler():
|
||||||
# Public means it is publicly network accessible
|
# Public means it is publicly network accessible
|
||||||
|
@ -428,15 +468,6 @@ class API:
|
||||||
resp = Response(self._utils.getBlockDBHash())
|
resp = Response(self._utils.getBlockDBHash())
|
||||||
elif action == 'getBlockHashes':
|
elif action == 'getBlockHashes':
|
||||||
resp = Response('\n'.join(self._core.getBlockList()))
|
resp = Response('\n'.join(self._core.getBlockList()))
|
||||||
elif action == 'announce':
|
|
||||||
if data != '':
|
|
||||||
# TODO: require POW for this
|
|
||||||
if self._core.addAddress(data):
|
|
||||||
resp = Response('Success')
|
|
||||||
else:
|
|
||||||
resp = Response('')
|
|
||||||
else:
|
|
||||||
resp = Response('')
|
|
||||||
# setData should be something the communicator initiates, not this api
|
# setData should be something the communicator initiates, not this api
|
||||||
elif action == 'getData':
|
elif action == 'getData':
|
||||||
resp = ''
|
resp = ''
|
||||||
|
@ -488,6 +519,9 @@ class API:
|
||||||
logger.info('Starting client on ' + self.host + ':' + str(bindPort) + '...', timestamp=False)
|
logger.info('Starting client on ' + self.host + ':' + str(bindPort) + '...', timestamp=False)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
while len(self._core.hsAddress) == 0:
|
||||||
|
self._core.refreshFirstStartVars()
|
||||||
|
time.sleep(0.5)
|
||||||
self.http_server = WSGIServer((self.host, bindPort), app)
|
self.http_server = WSGIServer((self.host, bindPort), app)
|
||||||
self.http_server.serve_forever()
|
self.http_server.serve_forever()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|
|
@ -93,7 +93,7 @@ class OnionrCommunicatorDaemon:
|
||||||
OnionrCommunicatorTimers(self, self.clearOfflinePeer, 58)
|
OnionrCommunicatorTimers(self, self.clearOfflinePeer, 58)
|
||||||
OnionrCommunicatorTimers(self, self.lookupKeys, 60, requiresPeer=True)
|
OnionrCommunicatorTimers(self, self.lookupKeys, 60, requiresPeer=True)
|
||||||
OnionrCommunicatorTimers(self, self.lookupAdders, 60, requiresPeer=True)
|
OnionrCommunicatorTimers(self, self.lookupAdders, 60, requiresPeer=True)
|
||||||
announceTimer = OnionrCommunicatorTimers(self, self.daemonTools.announceNode, 305, requiresPeer=True)
|
announceTimer = OnionrCommunicatorTimers(self, self.daemonTools.announceNode, 305, requiresPeer=True, maxThreads=1)
|
||||||
cleanupTimer = OnionrCommunicatorTimers(self, self.peerCleanup, 300, requiresPeer=True)
|
cleanupTimer = OnionrCommunicatorTimers(self, self.peerCleanup, 300, requiresPeer=True)
|
||||||
|
|
||||||
# set loop to execute instantly to load up peer pool (replaced old pool init wait)
|
# set loop to execute instantly to load up peer pool (replaced old pool init wait)
|
||||||
|
@ -446,17 +446,10 @@ class OnionrCommunicatorDaemon:
|
||||||
|
|
||||||
def announce(self, peer):
|
def announce(self, peer):
|
||||||
'''Announce to peers our address'''
|
'''Announce to peers our address'''
|
||||||
announceCount = 0
|
if self.daemonTools.announceNode():
|
||||||
announceAmount = 2
|
logger.info('Successfully introduced node to ' + peer)
|
||||||
for peer in self.onlinePeers:
|
else:
|
||||||
announceCount += 1
|
logger.warn('Could not introduce node.')
|
||||||
if self.peerAction(peer, 'announce', self._core.hsAddress) == 'Success':
|
|
||||||
logger.info('Successfully introduced node to ' + peer)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if announceCount == announceAmount:
|
|
||||||
logger.warn('Could not introduce node. Try again soon')
|
|
||||||
break
|
|
||||||
|
|
||||||
def detectAPICrash(self):
|
def detectAPICrash(self):
|
||||||
'''exit if the api server crashes/stops'''
|
'''exit if the api server crashes/stops'''
|
||||||
|
|
|
@ -78,6 +78,12 @@ class Core:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def refreshFirstStartVars(self):
|
||||||
|
'''Hack to refresh some vars which may not be set on first start'''
|
||||||
|
if os.path.exists('data/hs/hostname'):
|
||||||
|
with open('data/hs/hostname', 'r') as hs:
|
||||||
|
self.hsAddress = hs.read().strip()
|
||||||
|
|
||||||
def addPeer(self, peerID, powID, name=''):
|
def addPeer(self, peerID, powID, name=''):
|
||||||
'''
|
'''
|
||||||
Adds a public key to the key database (misleading function name)
|
Adds a public key to the key database (misleading function name)
|
||||||
|
|
|
@ -40,7 +40,7 @@ except ImportError:
|
||||||
raise Exception("You need the PySocks module (for use with socks5 proxy to use Tor)")
|
raise Exception("You need the PySocks module (for use with socks5 proxy to use Tor)")
|
||||||
|
|
||||||
ONIONR_TAGLINE = 'Anonymous P2P Platform - GPLv3 - https://Onionr.VoidNet.Tech'
|
ONIONR_TAGLINE = 'Anonymous P2P Platform - GPLv3 - https://Onionr.VoidNet.Tech'
|
||||||
ONIONR_VERSION = '0.1.1' # for debugging and stuff
|
ONIONR_VERSION = '0.2.0' # for debugging and stuff
|
||||||
ONIONR_VERSION_TUPLE = tuple(ONIONR_VERSION.split('.')) # (MAJOR, MINOR, VERSION)
|
ONIONR_VERSION_TUPLE = tuple(ONIONR_VERSION.split('.')) # (MAJOR, MINOR, VERSION)
|
||||||
API_VERSION = '4' # increments of 1; only change when something fundemental about how the API works changes. This way other nodes know how to communicate without learning too much information about you.
|
API_VERSION = '4' # increments of 1; only change when something fundemental about how the API works changes. This way other nodes know how to communicate without learning too much information about you.
|
||||||
|
|
||||||
|
|
|
@ -17,13 +17,40 @@
|
||||||
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 onionrexceptions, onionrpeers
|
import onionrexceptions, onionrpeers, onionrproofs, base64
|
||||||
class DaemonTools:
|
class DaemonTools:
|
||||||
def __init__(self, daemon):
|
def __init__(self, daemon):
|
||||||
self.daemon = daemon
|
self.daemon = daemon
|
||||||
|
self.announceCache = {}
|
||||||
|
|
||||||
def announceNode(self):
|
def announceNode(self):
|
||||||
'''Announce our node to our peers'''
|
'''Announce our node to our peers'''
|
||||||
peer = self.daemon.pickOnlinePeer()
|
retData = False
|
||||||
self.daemon.peerAction(peer, 'announce', self.daemon._core.hsAddress)
|
|
||||||
self.daemon.decrementThreadCount('announceNode')
|
# Announce to random online peers
|
||||||
|
for i in self.daemon.onlinePeers:
|
||||||
|
if not i in self.announceCache:
|
||||||
|
peer = i
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
peer = self.daemon.pickOnlinePeer()
|
||||||
|
|
||||||
|
ourID = self.daemon._core.hsAddress.strip()
|
||||||
|
|
||||||
|
url = 'http://' + peer + '/public/announce/'
|
||||||
|
data = {'node': ourID}
|
||||||
|
|
||||||
|
combinedNodes = ourID + peer
|
||||||
|
|
||||||
|
if peer in self.announceCache:
|
||||||
|
data['random'] = self.announceCache[peer]
|
||||||
|
else:
|
||||||
|
proof = onionrproofs.DataPOW(combinedNodes, forceDifficulty=4)
|
||||||
|
data['random'] = base64.b64encode(proof.waitForResult()[1])
|
||||||
|
self.announceCache[peer] = data['random']
|
||||||
|
|
||||||
|
logger.info('Announcing node to ' + url)
|
||||||
|
if self.daemon._core._utils.doPostRequest(url, data) == 'Success':
|
||||||
|
retData = True
|
||||||
|
self.daemon.decrementThreadCount('announceNode')
|
||||||
|
return retData
|
Loading…
Reference in New Issue