+ 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)
|
||||
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/')
|
||||
def public_handler():
|
||||
# Public means it is publicly network accessible
|
||||
|
@ -428,15 +468,6 @@ class API:
|
|||
resp = Response(self._utils.getBlockDBHash())
|
||||
elif action == 'getBlockHashes':
|
||||
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
|
||||
elif action == 'getData':
|
||||
resp = ''
|
||||
|
@ -488,6 +519,9 @@ class API:
|
|||
logger.info('Starting client on ' + self.host + ':' + str(bindPort) + '...', timestamp=False)
|
||||
|
||||
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.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
|
|
|
@ -93,7 +93,7 @@ class OnionrCommunicatorDaemon:
|
|||
OnionrCommunicatorTimers(self, self.clearOfflinePeer, 58)
|
||||
OnionrCommunicatorTimers(self, self.lookupKeys, 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)
|
||||
|
||||
# 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):
|
||||
'''Announce to peers our address'''
|
||||
announceCount = 0
|
||||
announceAmount = 2
|
||||
for peer in self.onlinePeers:
|
||||
announceCount += 1
|
||||
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
|
||||
if self.daemonTools.announceNode():
|
||||
logger.info('Successfully introduced node to ' + peer)
|
||||
else:
|
||||
logger.warn('Could not introduce node.')
|
||||
|
||||
def detectAPICrash(self):
|
||||
'''exit if the api server crashes/stops'''
|
||||
|
|
|
@ -78,6 +78,12 @@ class Core:
|
|||
sys.exit(1)
|
||||
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=''):
|
||||
'''
|
||||
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)")
|
||||
|
||||
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)
|
||||
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
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
import onionrexceptions, onionrpeers
|
||||
import onionrexceptions, onionrpeers, onionrproofs, base64
|
||||
class DaemonTools:
|
||||
def __init__(self, daemon):
|
||||
self.daemon = daemon
|
||||
self.announceCache = {}
|
||||
|
||||
def announceNode(self):
|
||||
'''Announce our node to our peers'''
|
||||
peer = self.daemon.pickOnlinePeer()
|
||||
self.daemon.peerAction(peer, 'announce', self.daemon._core.hsAddress)
|
||||
retData = False
|
||||
|
||||
# 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