Advertisement
Guest User

Untitled

a guest
Dec 2nd, 2018
162
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.72 KB | None | 0 0
  1. # Python3
  2. #
  3. # Returns list of live tested nodes sorted by latency
  4. #
  5.  
  6. # (BTS) litepresence1
  7.  
  8. '''
  9. license: WTFPL
  10. '''
  11.  
  12. from multiprocessing import Process, Value, Array
  13. from bitshares.blockchain import Blockchain
  14. from bitshares import BitShares
  15. from datetime import datetime
  16. import requests
  17. import time
  18. import sys
  19. import os
  20.  
  21. sys.stdout.write('\x1b]2;' + 'Bitshares Latency' + '\x07')
  22.  
  23. ID = '4018d7844c78f6a6c41c6a552b898022310fc5dec06da467ee7905a8dad512c8'
  24.  
  25.  
  26. def nodes(timeout=20, pings=999999, crop=99, noprint=False, write=False,
  27.           include=False, exclude=False, suffix=True, master=False):
  28.  
  29.     # timeout : seconds to ping until abort per node
  30.     # pings   : number of good nodes to find until satisfied (0 none, 999 all)
  31.     # suffix  : checks each node for no suffix plus with /ws or /wss
  32.     # noprint : disables printing, only returns list of good nodes
  33.     # master  : check only nodes listed in bitshares/ui/master
  34.     # crop    : return only best nodes
  35.     # write   : maintains an output file nodes.txt with list of best nodes
  36.  
  37.     # include and exclude custom nodes
  38.     included, excluded = [], []
  39.     if include:
  40.         included = ['api.bts.mobi', 'status200.bitshares.apasia.tech']
  41.  
  42.     if exclude:
  43.         excluded = []
  44.  
  45.     # web scraping methods
  46.     def clean(raw):
  47.         return ((str(raw).replace('"', " "))
  48.                 .replace("'", " ")).replace(',', ' ')
  49.  
  50.     def parse(cleaned):
  51.         return [t for t in cleaned.split() if t.startswith('wss')]
  52.  
  53.     def validate(parsed):
  54.         v = parsed
  55.         for i in range(len(v)):
  56.             if v[i].endswith('/'):
  57.                 v[i] = v[i][:-1]
  58.         for i in range(len(v)):
  59.             if v[i].endswith('/ws'):
  60.                 v[i] = v[i][:-3]
  61.         for i in range(len(v)):
  62.             if v[i].endswith('/wss'):
  63.                 v[i] = v[i][:-4]
  64.         # these are known to require /ws extension
  65.         ws = ['wss://relinked.com',
  66.               'wss://bitshares.crypto.fans',
  67.               'wss://this.uptick.rocks']
  68.         if suffix:
  69.             wss = [(i + '/wss') for i in v]
  70.             ws = [(i + '/ws') for i in v]
  71.             v = v + wss + ws
  72.         else:
  73.             for i in range(len(v)):
  74.                 if v[i] in ws:
  75.                     v[i] += '/ws'
  76.                 else:
  77.                     v[i] += '/wss'
  78.         return v
  79.  
  80.     # ping the blockchain and return latency
  81.            
  82.     def ping(n, num, arr):
  83.  
  84.         try:
  85.             start = time.time()
  86.             chain = Blockchain(
  87.                 bitshares_instance=BitShares(n, num_retries=0), mode='head')
  88.  
  89.             # print(n,chain.rpc.chain_params["chain_id"])
  90.             ping_latency = time.time() - start
  91.             current_block = chain.get_current_block_num()
  92.             blocktimestamp = abs(
  93.                 chain.block_timestamp(current_block))  # + utc_offset)
  94.             block_latency = time.time() - blocktimestamp
  95.             # print (blocktimestamp)
  96.             # print (time.time())
  97.             # print (block_latency)
  98.             # print (ping_latency)
  99.             # print (time.ctime())
  100.             # print (utc_offset)
  101.             # print (chain.get_network())
  102.             if chain.get_network()['chain_id'] != ID:
  103.                 num.value = 333333
  104.             elif block_latency < (ping_latency + 4):
  105.                 num.value = ping_latency
  106.             else:
  107.                 num.value = 111111
  108.         except:
  109.             num.value = 222222
  110.             pass
  111.  
  112.     # Disable / Enable printing
  113.     def blockPrint():
  114.         if noprint:
  115.             sys.stdout = open(os.devnull, 'w')
  116.  
  117.     def enablePrint():
  118.         if noprint:
  119.             sys.stdout = sys.__stdout__
  120.  
  121.     # gather list of nodes from github
  122.     blockPrint()
  123.     begin = time.time()
  124.     utc_offset = (datetime.fromtimestamp(begin) -
  125.                   datetime.utcfromtimestamp(begin)).total_seconds()
  126.     print ('=====================================')
  127.     print(('found %s nodes stored in script' % len(included)))
  128.     urls = []
  129.     # scrape from github
  130.     git = 'https://raw.githubusercontent.com'
  131.     url = git + '/bitshares/bitshares-ui/master/app/api/apiConfig.js'
  132.     urls.append(url)
  133.     if not master:
  134.         url = git + '/bitshares/bitshares-ui/staging/app/api/apiConfig.js'
  135.         urls.append(url)
  136.         url = git + '/CryptoBridge/cryptobridge-ui/'
  137.         url += 'e5214ad63a41bd6de1333fd98d717b37e1a52f77/app/api/apiConfig.js'
  138.         urls.append(url)
  139.         url = git + '/litepresence/extinction-event/master/bitshares-nodes.py'
  140.         urls.append(url)
  141.  
  142.     # searched selected sites for Bitshares nodes
  143.    
  144.  
  145.  
  146.     validated = [] + included
  147.  
  148.  
  149.  
  150.  
  151.  
  152.     for u in urls:
  153.         attempts = 3
  154.         while attempts > 0:
  155.             try:
  156.                 raw = requests.get(u).text
  157.                 v = validate(parse(clean(raw)))
  158.                 print(('found %s nodes at %s' % (len(v), u[:65])))
  159.                 validated += v
  160.                 attempts = 0
  161.             except:
  162.                 print(('failed to connect to %s' % u))
  163.                 attempts -= 1
  164.                 pass
  165.  
  166.     # remove known bad nodes from test
  167.     if len(excluded):
  168.         excluded = sorted(excluded)
  169.         print(('remove %s known bad nodes' % len(excluded)))
  170.         validated = [i for i in validated if i not in excluded]
  171.  
  172.     #manual timeout and validated list
  173.     if 0:
  174.         timeout = 30
  175.         validated = ['wss://b.mrx.im', 'wss://b.mrx.im/ws', 'wss://b.mrx.im/wss']
  176.  
  177.  
  178.     # final sanitization
  179.     validated = sorted(list(set(validate(parse(clean(validated))))))
  180.  
  181.  
  182.     #validated = validated[-15:]
  183.  
  184.     # attempt to contact each websocket
  185.     print ('=====================================')
  186.     print(('found %s total nodes - no duplicates' % len(validated)))
  187.     print ('=====================================')
  188.     print (validated)
  189.     pinging = min(pings, len(validated))
  190.     if pinging:
  191.         print ('=====================================')
  192.         enablePrint()
  193.         print(('%s pinging %s nodes; timeout %s sec; est %.1f minutes' % (
  194.             time.ctime(), pinging, timeout, timeout * len(validated) / 60.0)))
  195.         blockPrint()
  196.         print ('=====================================')
  197.         pinged, timed, down, stale, expired, testnet = [], [], [], [], [], []
  198.         for n in validated:
  199.             if len(pinged) < pinging:
  200.                 # use multiprocessing module to enforce timeout
  201.                 num = Value('d', 999999)
  202.                 arr = Array('i', list(range(0)))
  203.                 p = Process(target=ping, args=(n, num, arr))
  204.                 p.start()
  205.                 p.join(timeout)
  206.                 if p.is_alive() or (num.value > timeout):
  207.                     p.terminate()
  208.                     p.join()
  209.                     if num.value == 111111:  # head block is stale
  210.                         stale.append(n)
  211.                     elif num.value == 222222:  # connect failed
  212.                         down.append(n)
  213.                     elif num.value == 333333:  # connect failed
  214.                         testnet.append(n)
  215.                     elif num.value == 999999:  # timeout reached
  216.                         expired.append(n)
  217.                 else:
  218.                     pinged.append(n)        # connect success
  219.                     timed.append(num.value)  # connect success time
  220.                 print(('ping:', ('%.2f' % num.value), n))
  221.  
  222.         # sort websockets by latency
  223.         pinged = [x for _, x in sorted(zip(timed, pinged))]
  224.         timed = sorted(timed)
  225.         unknown = sorted(
  226.             list(set(validated).difference(
  227.                 pinged + down + stale + expired + testnet)))
  228.  
  229.         unique = []
  230.         for i in pinged:
  231.             if i.strip('/ws') not in [j.strip('/ws') for j in unique]:
  232.                 unique.append(i)
  233.         unique = sorted(unique)
  234.  
  235.         # report outcome
  236.         print('')
  237.         print((len(pinged), 'of', len(validated),
  238.                'nodes are active with latency less than', timeout))
  239.         print('')
  240.         print(('fastest node', pinged[0], 'with latency', ('%.2f' % timed[0])))
  241.         if len(excluded):
  242.             for i in range(len(excluded)):
  243.                 print(((i+1), 'EXCLUDED', excluded[i]))
  244.         if len(unknown):
  245.             for i in range(len(unknown)):
  246.                 print(((i+1), 'UNTESTED', unknown[i]))
  247.         if len(testnet):
  248.             for i in range(len(testnet)):
  249.                 print(((i+1), 'TESTNET', testnet[i]))
  250.         if len(expired):
  251.             for i in range(len(expired)):
  252.                 print(((i+1), 'TIMEOUT', expired[i]))
  253.         if len(stale):
  254.             for i in range(len(stale)):
  255.                 print(((i+1), 'STALE', stale[i]))
  256.         if len(down):
  257.             for i in range(len(down)):
  258.                 print(((i+1),'DOWN', down[i]))
  259.         if len(pinged):
  260.             for i in range(len(pinged)):
  261.                 print(((i+1), 'GOOD PING', '%.2f' % timed[i], pinged[i]))
  262.         if len(unique):
  263.             for i in range(len(unique)):
  264.                 print(((i+1), 'UNIQUE:', unique[i]))
  265.         print('UNIQUE LIST:')
  266.         print(unique)
  267.  
  268.         ret = pinged[:crop]
  269.         #print (pinged[0])
  270.         #print (ret[0])
  271.         #print (timed[0])
  272.     else:
  273.         ret = validated[:crop]
  274.  
  275.     print ('')
  276.     enablePrint()
  277.     elapsed = time.time()-begin
  278.     print ('elapsed:', ('%.1f' % elapsed),
  279.             'fastest:', ('%.3f' % timed[0]), ret[0])
  280.  
  281.     print (ret)
  282.  
  283.     if write and (len(ret) == crop):
  284.         opened = 0
  285.         while not opened:
  286.             try:
  287.                 with open('nodes.txt', 'w+') as file:
  288.                     file.write(str(ret))
  289.  
  290.                 opened = 1
  291.             except:
  292.                 pass
  293.     return (ret)
  294.  
  295. def loop():
  296.  
  297.     while 1:
  298.         try:
  299.             nodes(timeout=10, pings=999, crop=10, noprint=False, write=True,
  300.                 include=True, exclude=False, suffix=True, master=False)
  301.             time.sleep(900)
  302.  
  303.         # no matter what happens just keep verifying book
  304.         except Exception as e:
  305.             print (type(e).__name__, e.args, e)
  306.             pass
  307.  
  308. def update():
  309.  
  310.     print('Acquiring low latency connection to Bitshares DEX'+
  311.             ', this may take a few minutes...')
  312.     updated = 0
  313.     try:
  314.         while not updated:
  315.             nodes(timeout=6, pings=999, crop=999, noprint=False, write=True,
  316.                 include=False, exclude=False, suffix=True, master=False)
  317.             updated = 1
  318.  
  319.     # not satisfied until verified once
  320.     except Exception as e:
  321.         print (type(e).__name__, e.args, e)
  322.         pass
  323.  
  324.     print('')
  325.     print('DEX CONNECTION ESTABLISHED - will refresh every 10 minutes')
  326.     print('')
  327.  
  328. if __name__ == '__main__':
  329.  
  330.  
  331.         loop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement