-
-
Save rZn/cefeea434ce270266115d069166f4d04 to your computer and use it in GitHub Desktop.
Revisions
-
YoRyan revised this gist
Apr 9, 2018 . No changes.There are no files selected for viewing
-
YoRyan revised this gist
Jan 26, 2018 . No changes.There are no files selected for viewing
-
YoRyan revised this gist
Jan 26, 2018 . No changes.There are no files selected for viewing
-
Ryan A Young revised this gist
Jan 26, 2018 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -159,8 +159,8 @@ def main(): # dict of device id -> excavator worker id worker_status = {} device_algorithm = lambda device: [a for a in algorithm_status.keys() if device in algorithm_status[a][1]][0] def dispatch_device(device, algo, ports): if algo in algorithm_status: -
Ryan A Young revised this gist
Jan 26, 2018 . 1 changed file with 61 additions and 32 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,9 +5,12 @@ # Example usage: # $ excavator -p 3456 & # $ python3 excavator-driver.py # History: # 2017-12-03: initial version # 2018-01-25: group devices by common algorithm; wait for excavator on startup __author__ = "Ryan Young" __email__ = "[email protected]" __license__ = "public domain" @@ -21,7 +24,7 @@ import urllib.request from time import sleep WALLET_ADDR = '32RPicPbRK18S2fzY4cEwNUy17iygJyPjF' WORKER_NAME = 'worker1' REGION = 'usa' # eu, usa, hk, jp, in, br @@ -134,50 +137,79 @@ def do_excavator_command(method, params): else: raise ExcavatorAPIError(response_data) def excavator_algorithm_params(algo, ports): """Return the required list of parameters to add an algorithm to excavator. algo -- the algorithm to run ports -- algorithm port information from NiceHash """ AUTH = '%s.%s:x' % (WALLET_ADDR, WORKER_NAME) stratum = lambda algo: '%s.%s.nicehash.com:%s' % (algo, REGION, ports[algo]) return [algo] + sum([[stratum(multi_algo), AUTH] for multi_algo in algo.split('_')], []) def main(): """Main program.""" logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO) # dict of algorithm name -> (excavator id, [attached devices]) algorithm_status = {} # dict of device id -> excavator worker id worker_status = {} device_algorithm = lambda device: [a for a in algorithm_status.keys() if device in algorithm_status[a][1]][0] def dispatch_device(device, algo, ports): if algo in algorithm_status: algo_id = algorithm_status[algo][0] algorithm_status[algo][1].append(device) else: response = do_excavator_command('algorithm.add', excavator_algorithm_params(algo, ports)) algo_id = response['algorithm_id'] algorithm_status[algo] = (algo_id, [device]) response = do_excavator_command('worker.add', [str(algo_id), str(device)]) worker_status[device] = response['worker_id'] def free_device(device): algo = device_algorithm(device) algorithm_status[algo][1].remove(device) worker_id = worker_status[device] worker_status.pop(device) do_excavator_command('worker.free', [str(worker_id)]) if len(algorithm_status[algo][1]) == 0: # no more devices attached algo_id = algorithm_status[algo][0] algorithm_status.pop(algo) do_excavator_command('algorithm.remove', [str(algo_id)]) def sigint_handler(signum, frame): logging.info('cleaning up!') active_devices = list(worker_status.keys()) for device in active_devices: free_device(device) sys.exit(0) signal.signal(signal.SIGINT, sigint_handler) def contact_excavator(): try: do_excavator_command('message', ['%s connected' % sys.argv[0]]) except (socket.timeout, socket.error): return False else: return True logging.info('connecting to excavator at %s:%d' % EXCAVATOR_ADDRESS) while not contact_excavator(): sleep(5) while True: try: paying, ports = nicehash_multialgo_info() @@ -195,25 +227,22 @@ def sigint_handler(signum, frame): payrates = nicehash_mbtc_per_day(device, paying) best_algo = max(payrates.keys(), key=lambda algo: payrates[algo]) if device not in worker_status: logging.info('device %s initial algorithm is %s (%.2f mBTC/day)' % (device, best_algo, payrates[best_algo])) dispatch_device(device, best_algo, ports) else: current_algo = device_algorithm(device) if current_algo != best_algo and \ (payrates[current_algo] == 0 or \ payrates[best_algo]/payrates[current_algo] >= 1.0 + PROFIT_SWITCH_THRESHOLD): logging.info('switching device %s to %s (%.2f mBTC/day)' % (device, best_algo, payrates[best_algo])) free_device(device) dispatch_device(device, best_algo, ports) sleep(UPDATE_INTERVAL) if __name__ == '__main__': -
Ryan A Young revised this gist
Jan 17, 2018 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -144,6 +144,7 @@ def add_excavator_algorithm(algo, device, ports): AUTH = '%s.%s:x' % (WALLET_ADDR, WORKER_NAME) stratum = lambda algo: '%s.%s.nicehash.com:%s' % (algo, REGION, ports[algo]) add_params = [algo] + sum([[stratum(multi_algo), AUTH] for multi_algo in algo.split('_')], []) response = do_excavator_command('algorithm.add', add_params) -
Ryan A Young revised this gist
Jan 17, 2018 . 1 changed file with 2 additions and 12 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -144,18 +144,8 @@ def add_excavator_algorithm(algo, device, ports): AUTH = '%s.%s:x' % (WALLET_ADDR, WORKER_NAME) stratum = lambda algo: '%s.%s.nicehash.com:%s' % (algo, REGION, ports[algo]) add_params = [algo] + sum([[stratum(multi_algo), AUTH] for multi_algo in algo.split('_')], []) response = do_excavator_command('algorithm.add', add_params) algo_id = response['algorithm_id'] -
Ryan A Young revised this gist
Jan 17, 2018 . 1 changed file with 8 additions and 16 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -92,22 +92,14 @@ def nicehash_mbtc_per_day(device, paying): benchmarks = BENCHMARKS[device] pay = lambda algo, speed: paying[algo]*speed*(24*60*60)*1e-11 def pay_benched(algo): if '_' in algo: return sum([pay(multi_algo, benchmarks[algo][i]) for i, multi_algo in enumerate(algo.split('_'))]) else: return pay(algo, benchmarks[algo]) return dict([(algo, pay_benched(algo)) for algo in benchmarks.keys()]) def do_excavator_command(method, params): """Sends a command to excavator, returns the JSON-encoded response. -
Ryan A Young revised this gist
Jan 16, 2018 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -104,8 +104,8 @@ def nicehash_mbtc_per_day(device, paying): ['equihash', 'pascal', 'decred', 'sia', 'lbry', 'blake2s', 'lyra2rev2', 'cryptonight', 'daggerhashimoto', 'neoscrypt', 'nist5']]) payrates['daggerhashimoto_pascal'] = dual_dp payrates['daggerhashimoto_decred'] = dual_dd payrates['daggerhashimoto_sia'] = dual_ds return payrates -
Ryan A Young revised this gist
Jan 16, 2018 . 1 changed file with 22 additions and 29 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -36,20 +36,21 @@ BENCHMARKS = {} # device 0: GTX 1060 6GB BENCHMARKS[0] = { 'equihash': 325.964731, 'pascal': 687.796633e6, 'decred': 1.896621e9, 'sia': 1.205557e9, 'lbry': 185.736261e6, 'blake2s': 2.767859e9, 'lyra2rev2': 26.157357e6, 'cryptonight': 443.131955, 'daggerhashimoto': 19.965252e6, 'daggerhashimoto_pascal': [8.847941e6, 495.485485e6], 'daggerhashimoto_decred': [19.843944e6, 714.382018e6], 'daggerhashimoto_sia': [19.908869e6, 254.833522e6], # test manually 'neoscrypt': 732.554438e3, 'nist5': 32.031877e6 } PROFIT_SWITCH_THRESHOLD = 0.1 @@ -99,21 +100,13 @@ def nicehash_mbtc_per_day(device, paying): + pay('decred', benchmarks['daggerhashimoto_decred'][1]) dual_ds = pay('daggerhashimoto', benchmarks['daggerhashimoto_sia'][0]) \ + pay('sia', benchmarks['daggerhashimoto_sia'][1]) payrates = dict([(algo, pay_benched(algo)) for algo in ['equihash', 'pascal', 'decred', 'sia', 'lbry', 'blake2s', 'lyra2rev2', 'cryptonight', 'daggerhashimoto', 'neoscrypt', 'nist5']]) payrates['daggerhashimoto_pascal'] = dual_dp, payrates['daggerhashimoto_decred'] = dual_dd, payrates['daggerhashimoto_sia'] = dual_ds return payrates def do_excavator_command(method, params): @@ -241,4 +234,4 @@ def sigint_handler(signum, frame): sleep(UPDATE_INTERVAL) if __name__ == '__main__': main() -
YoRyan revised this gist
Jan 8, 2018 . 1 changed file with 4 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -220,7 +220,8 @@ def sigint_handler(signum, frame): best_algo = max(payrates.keys(), key=lambda algo: payrates[algo]) if device not in device_status: logging.info('device %s initial algorithm is %s (%.2f mBTC/day)' % (device, best_algo, payrates[best_algo])) new_algo_id = add_excavator_algorithm(best_algo, device, ports) device_status[device] = (best_algo, new_algo_id) @@ -231,7 +232,8 @@ def sigint_handler(signum, frame): if current_algo != best_algo and \ (payrates[current_algo] == 0 or \ payrates[best_algo]/payrates[current_algo] >= 1.0 + PROFIT_SWITCH_THRESHOLD): logging.info('switching device %s to %s (%.2f mBTC/day)' % (device, best_algo, payrates[best_algo])) remove_excavator_algorithm(current_algo_id) new_algo_id = add_excavator_algorithm(best_algo, device, ports) -
YoRyan revised this gist
Dec 31, 2017 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -229,8 +229,8 @@ def sigint_handler(signum, frame): current_algo_id = device_status[device][1] if current_algo != best_algo and \ (payrates[current_algo] == 0 or \ payrates[best_algo]/payrates[current_algo] >= 1.0 + PROFIT_SWITCH_THRESHOLD): logging.info('switching device %s to %s' % (device, best_algo)) remove_excavator_algorithm(current_algo_id) -
YoRyan revised this gist
Dec 31, 2017 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -229,6 +229,7 @@ def sigint_handler(signum, frame): current_algo_id = device_status[device][1] if current_algo != best_algo and \ payrates[current_algo] != 0 and \ payrates[best_algo]/payrates[current_algo] >= 1.0 + PROFIT_SWITCH_THRESHOLD: logging.info('switching device %s to %s' % (device, best_algo)) -
YoRyan revised this gist
Dec 29, 2017 . 1 changed file with 2 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -212,16 +212,15 @@ def sigint_handler(signum, frame): % (err.code, err.reason)) except socket.timeout: logging.warning('failed to retrieve NiceHash stats: timed out') except (json.decoder.JSONDecodeError, KeyError): logging.warning('failed to parse NiceHash stats') else: for device in BENCHMARKS.keys(): payrates = nicehash_mbtc_per_day(device, paying) best_algo = max(payrates.keys(), key=lambda algo: payrates[algo]) if device not in device_status: logging.info('device %s initial algorithm is %s' % (device, best_algo)) new_algo_id = add_excavator_algorithm(best_algo, device, ports) device_status[device] = (best_algo, new_algo_id) -
YoRyan revised this gist
Dec 28, 2017 . 1 changed file with 9 additions and 6 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,8 +4,9 @@ """Cross-platform controller for NiceHash Excavator for Nvidia.""" # Example usage: # $ excavator -p 3456 & # $ sleep 5 # $ python3 excavator-driver.py __author__ = "Ryan Young" __email__ = "[email protected]" @@ -20,13 +21,13 @@ import urllib.request from time import sleep WALLET_ADDR = '3DzJYbtHt9QdZzQiDnq5tZD8VsDuwRnbdJ' WORKER_NAME = 'worker1' REGION = 'usa' # eu, usa, hk, jp, in, br EXCAVATOR_ADDRESS = ('127.0.0.1', 3456) # copy the numbers from excavator-benchmark (test one device at a time with -d <n>) # convert to the base unit, H/s # x H/s -> x # x kH/s -> x*1e3 @@ -47,8 +48,8 @@ 'daggerhashimoto_pascal': [8.298873e6, 464.739199e6], 'daggerhashimoto_decred': [20.258170e6, 729.296593e6], 'daggerhashimoto_sia': [21.359257e6, 273.398483e6], # test manually 'neoscrypt': 618.769067e3 } PROFIT_SWITCH_THRESHOLD = 0.1 @@ -211,6 +212,8 @@ def sigint_handler(signum, frame): % (err.code, err.reason)) except socket.timeout: logging.warning('failed to retrieve NiceHash stats: timed out') except json.decoder.JSONDecodeError: logging.warning('failed to parse NiceHash stats') else: for device in BENCHMARKS.keys(): payrates = nicehash_mbtc_per_day(device, paying) -
YoRyan revised this gist
Dec 4, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -72,7 +72,7 @@ def nicehash_multialgo_info(): """Retrieves pay rates and connection ports for every algorithm from the NiceHash API.""" response = urllib.request.urlopen('https://api.nicehash.com/api?method=simplemultialgo.info', None, NICEHASH_TIMEOUT) query = json.loads(response.read().decode('ascii')) #json.load(response) paying = {} ports = {} for algorithm in query['result']['simplemultialgo']: -
YoRyan revised this gist
Dec 4, 2017 . 1 changed file with 43 additions and 39 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,7 +4,7 @@ """Cross-platform controller for NiceHash Excavator for Nvidia.""" # Example usage: # $ excavator -p 3456 & # $ python3 excavator-driver.py __author__ = "Ryan Young" @@ -27,23 +27,28 @@ EXCAVATOR_ADDRESS = ('127.0.0.1', 3456) # copy the numbers from excavator-benchmark # convert to the base unit, H/s # x H/s -> x # x kH/s -> x*1e3 # x MH/s -> x*1e6 # x GH/s -> x*1e9 BENCHMARKS = {} # device 0: GTX 1060 6GB BENCHMARKS[0] = { 'equihash': 300.363149, 'pascal': 673.490293e6, 'decred': 1.734736e9, 'sia': 1.070054e9, 'lbry': 179.286648e6, 'blake2s': 2.509039e9, 'lyra2rev2': 25.908014e6, 'cryptonight': 435.366891, 'daggerhashimoto': 22.009473e6, 'daggerhashimoto_pascal': [8.298873e6, 464.739199e6], 'daggerhashimoto_decred': [20.258170e6, 729.296593e6], 'daggerhashimoto_sia': [21.359257e6, 273.398483e6], 'neoscrypt': 618.769067e3 # test manually } PROFIT_SWITCH_THRESHOLD = 0.1 @@ -67,7 +72,7 @@ def nicehash_multialgo_info(): """Retrieves pay rates and connection ports for every algorithm from the NiceHash API.""" response = urllib.request.urlopen('https://api.nicehash.com/api?method=simplemultialgo.info', None, NICEHASH_TIMEOUT) query = json.load(response) paying = {} ports = {} for algorithm in query['result']['simplemultialgo']: @@ -76,35 +81,34 @@ def nicehash_multialgo_info(): ports[name] = int(algorithm['port']) return paying, ports def nicehash_mbtc_per_day(device, paying): """Calculates the BTC/day amount for every algorithm. device -- excavator device id for benchmarks paying -- algorithm pay information from NiceHash """ benchmarks = BENCHMARKS[device] pay = lambda algo, speed: paying[algo]*speed*(24*60*60)*1e-11 pay_benched = lambda algo: pay(algo, benchmarks[algo]) dual_dp = pay('daggerhashimoto', benchmarks['daggerhashimoto_pascal'][0]) \ + pay('pascal', benchmarks['daggerhashimoto_pascal'][1]) dual_dd = pay('daggerhashimoto', benchmarks['daggerhashimoto_decred'][0]) \ + pay('decred', benchmarks['daggerhashimoto_decred'][1]) dual_ds = pay('daggerhashimoto', benchmarks['daggerhashimoto_sia'][0]) \ + pay('sia', benchmarks['daggerhashimoto_sia'][1]) payrates = { 'equihash': pay_benched('equihash'), 'pascal': pay_benched('pascal'), 'decred': pay_benched('decred'), 'sia': pay_benched('sia'), 'lbry': pay_benched('lbry'), 'blake2s': pay_benched('blake2s'), 'lyra2rev2': pay_benched('lyra2rev2'), 'cryptonight': pay_benched('cryptonight'), 'daggerhashimoto': pay_benched('daggerhashimoto'), 'neoscrypt': pay_benched('neoscrypt'), 'daggerhashimoto_pascal': dual_dp, 'daggerhashimoto_decred': dual_dd, 'daggerhashimoto_sia': dual_ds @@ -209,7 +213,7 @@ def sigint_handler(signum, frame): logging.warning('failed to retrieve NiceHash stats: timed out') else: for device in BENCHMARKS.keys(): payrates = nicehash_mbtc_per_day(device, paying) best_algo = max(payrates.keys(), key=lambda algo: payrates[algo]) if device not in device_status: -
YoRyan revised this gist
Dec 4, 2017 . 1 changed file with 14 additions and 14 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -30,20 +30,20 @@ BENCHMARKS = {} # GTX 1060 6GB BENCHMARKS[0] = { 'equihash': 300.363149, # H/s 'pascal': 673.490293, # MH/s 'decred': 1.734736, # GH/s 'sia': 1.070054, # GH/s 'lbry': 179.286648, # MH/s 'blake2s': 0, #2.509039, # GH/s 'lyra2rev2': 25.908014, # MH/s 'cryptonight': 435.366891, # H/s 'daggerhashimoto': 22.009473, # MH/s 'daggerhashimoto_pascal': [8.298873, 464.739199], # MH/s, MH/s 'daggerhashimoto_decred': [20.258170, 729.296593], # MH/s 'daggerhashimoto_sia': [21.359257, 273.398483], # MH/s 'neoscrypt': 618.769067 # H/s # test manually } PROFIT_SWITCH_THRESHOLD = 0.1 -
YoRyan revised this gist
Dec 4, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -67,7 +67,7 @@ def nicehash_multialgo_info(): """Retrieves pay rates and connection ports for every algorithm from the NiceHash API.""" response = urllib.request.urlopen('https://api.nicehash.com/api?method=simplemultialgo.info', None, NICEHASH_TIMEOUT) query = json.loads(response.read().decode('ascii')) #json.load(response) paying = {} ports = {} for algorithm in query['result']['simplemultialgo']: -
YoRyan revised this gist
Dec 4, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -20,7 +20,7 @@ import urllib.request from time import sleep WALLET_ADDR = '1BQSMa5mfDNzut5PN9xgtJe3wqaqGEEerD' WORKER_NAME = 'worker1' REGION = 'usa' # eu, usa, hk, jp, in, br -
YoRyan revised this gist
Dec 3, 2017 . 1 changed file with 5 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,6 +3,10 @@ """Cross-platform controller for NiceHash Excavator for Nvidia.""" # Example usage: # $ /opt/excavator/bin/excavator -p 3456 & # $ python3 excavator-driver.py __author__ = "Ryan Young" __email__ = "[email protected]" __license__ = "public domain" @@ -18,7 +22,7 @@ WALLET_ADDR = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' WORKER_NAME = 'worker1' REGION = 'usa' # eu, usa, hk, jp, in, br EXCAVATOR_ADDRESS = ('127.0.0.1', 3456) -
YoRyan revised this gist
Dec 3, 2017 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -149,8 +149,7 @@ def add_excavator_algorithm(algo, device, ports): """ AUTH = '%s.%s:x' % (WALLET_ADDR, WORKER_NAME) stratum = lambda algo: '%s.%s.nicehash.com:%s' % (algo, REGION, ports[algo]) if algo == 'daggerhashimoto_decred': add_params = [algo, stratum('daggerhashimoto'), AUTH, stratum('decred'), AUTH] @@ -180,7 +179,8 @@ def remove_excavator_algorithm(algo_id): def main(): """Main program.""" logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO) device_status = {} -
YoRyan created this gist
Dec 3, 2017 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,231 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """Cross-platform controller for NiceHash Excavator for Nvidia.""" __author__ = "Ryan Young" __email__ = "[email protected]" __license__ = "public domain" import json import logging import signal import socket import sys import urllib.error import urllib.request from time import sleep WALLET_ADDR = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' WORKER_NAME = 'worker1' REGION = 'usa' EXCAVATOR_ADDRESS = ('127.0.0.1', 3456) # copy the numbers from excavator-benchmark BENCHMARKS = {} # GTX 1060 6GB BENCHMARKS[0] = { 'equihash': 300.363149, 'pascal': 673.490293, 'decred': 1.734736, 'sia': 1.070054, 'lbry': 179.286648, 'blake2s': 0, #2.509039, 'lyra2rev2': 25.908014, 'cryptonight': 435.366891, 'daggerhashimoto': 22.009473, 'daggerhashimoto_pascal': [8.298873, 464.739199], 'daggerhashimoto_decred': [20.258170, 729.296593], 'daggerhashimoto_sia': [21.359257, 273.398483], 'neoscrypt': 618.769067 # test manually } PROFIT_SWITCH_THRESHOLD = 0.1 UPDATE_INTERVAL = 60 EXCAVATOR_TIMEOUT = 10 NICEHASH_TIMEOUT = 20 ### here be dragons class ExcavatorError(Exception): pass class ExcavatorAPIError(ExcavatorError): """Exception returned by excavator.""" def __init__(self, response): self.response = response self.error = response['error'] def nicehash_multialgo_info(): """Retrieves pay rates and connection ports for every algorithm from the NiceHash API.""" response = urllib.request.urlopen('https://api.nicehash.com/api?method=simplemultialgo.info', None, NICEHASH_TIMEOUT) query = json.load(response) paying = {} ports = {} for algorithm in query['result']['simplemultialgo']: name = algorithm['name'] paying[name] = float(algorithm['paying']) ports[name] = int(algorithm['port']) return paying, ports def nicehash_btc_per_day(device, paying): """Calculates the BTC/day amount for every algorithm. device -- excavator device id for benchmarks paying -- algorithm pay information from NiceHash """ benchmarks = BENCHMARKS[device] payrate = lambda algo, speed: paying[algo]*speed payrate_benched = lambda algo: payrate(algo, benchmarks[algo]) # use the same (somewhat nonsensical) btc/solution units from the web interface dual_dp = payrate('daggerhashimoto', benchmarks['daggerhashimoto_pascal'][0]*(1e-3*24*60*60)) \ + payrate('pascal', benchmarks['daggerhashimoto_pascal'][1]*(1e-6*24*60*60*1e3)) dual_dd = payrate('daggerhashimoto', benchmarks['daggerhashimoto_decred'][0]*(1e-3*24*60*60)) \ + payrate('decred', benchmarks['daggerhashimoto_decred'][1]*(1e-6*24*60*60*1e3)) dual_ds = payrate('daggerhashimoto', benchmarks['daggerhashimoto_sia'][0]*(1e-3*24*60*60)) \ + payrate('sia', benchmarks['daggerhashimoto_sia'][1]*(1e-6*24*60*60*1e3)) payrates = { 'equihash': payrate_benched('equihash')*(1e-6*24*60*60*1e-3), 'pascal': payrate_benched('pascal')*(1e-6*24*60*60*1e3), 'decred': payrate_benched('decred')*(1e-3*24*60*60*1e3), 'sia': payrate_benched('sia')*(1e-3*24*60*60*1e3), 'lbry': payrate_benched('lbry')*(1e-6*24*60*60*1e3), 'blake2s': payrate_benched('blake2s')*(1e-3*24*60*60*1e3), 'lyra2rev2': payrate_benched('lyra2rev2')*(1e-6*24*60*60*1e3), 'cryptonight': payrate_benched('cryptonight')*(1e-6*24*60*60*1e-3), 'daggerhashimoto': payrate_benched('daggerhashimoto')*(1e-3*24*60*60), 'neoscrypt': payrate_benched('neoscrypt')*(24*60*60*1e-6), 'daggerhashimoto_pascal': dual_dp, 'daggerhashimoto_decred': dual_dd, 'daggerhashimoto_sia': dual_ds } return payrates def do_excavator_command(method, params): """Sends a command to excavator, returns the JSON-encoded response. method -- name of the command to execute params -- list of arguments for the command """ BUF_SIZE = 1024 command = { 'id': 1, 'method': method, 'params': params } s = socket.create_connection(EXCAVATOR_ADDRESS, EXCAVATOR_TIMEOUT) # send newline-terminated command s.sendall((json.dumps(command).replace('\n', '\\n') + '\n').encode()) response = '' while True: chunk = s.recv(BUF_SIZE).decode() # excavator responses are newline-terminated too if '\n' in chunk: response += chunk[:chunk.index('\n')] break else: response += chunk s.close() response_data = json.loads(response) if response_data['error'] is None: return response_data else: raise ExcavatorAPIError(response_data) def add_excavator_algorithm(algo, device, ports): """Runs an algorithm on a device, returns the new excavator algorithm id. algo -- the algorithm to run device -- excavator device id of the target device ports -- algorithm port information from NiceHash """ AUTH = '%s.%s:x' % (WALLET_ADDR, WORKER_NAME) stratum = lambda algo: '%s.%s.nicehash.com:%s' \ % (algo, REGION, ports[algo]) if algo == 'daggerhashimoto_decred': add_params = [algo, stratum('daggerhashimoto'), AUTH, stratum('decred'), AUTH] elif algo == 'daggerhashimoto_pascal': add_params = [algo, stratum('daggerhashimoto'), AUTH, stratum('pascal'), AUTH] elif algo == 'daggerhashimoto_sia': add_params = [algo, stratum('daggerhashimoto'), AUTH, stratum('sia'), AUTH] else: add_params = [algo, stratum(algo), AUTH] response = do_excavator_command('algorithm.add', add_params) algo_id = response['algorithm_id'] do_excavator_command('worker.add', [str(algo_id), str(device)]) return algo_id def remove_excavator_algorithm(algo_id): """Removes an algorithm from excavator and all (one) associated workers. algo_id -- excavator algorithm id to remove """ do_excavator_command('algorithm.remove', [str(algo_id)]) def main(): """Main program.""" logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO) device_status = {} def sigint_handler(signum, frame): logging.info('cleaning up!') for device in device_status: current_algo_id = device_status[device][1] remove_excavator_algorithm(current_algo_id) sys.exit(0) signal.signal(signal.SIGINT, sigint_handler) while True: try: paying, ports = nicehash_multialgo_info() except urllib.error.URLError as err: logging.warning('failed to retrieve NiceHash stats: %s' % err.reason) except urllib.error.HTTPError as err: logging.warning('server error retrieving NiceHash stats: %s %s' % (err.code, err.reason)) except socket.timeout: logging.warning('failed to retrieve NiceHash stats: timed out') else: for device in BENCHMARKS.keys(): payrates = nicehash_btc_per_day(device, paying) best_algo = max(payrates.keys(), key=lambda algo: payrates[algo]) if device not in device_status: logging.info('device %s initial algorithm is %s' % (device, best_algo)) new_algo_id = add_excavator_algorithm(best_algo, device, ports) device_status[device] = (best_algo, new_algo_id) else: current_algo = device_status[device][0] current_algo_id = device_status[device][1] if current_algo != best_algo and \ payrates[best_algo]/payrates[current_algo] >= 1.0 + PROFIT_SWITCH_THRESHOLD: logging.info('switching device %s to %s' % (device, best_algo)) remove_excavator_algorithm(current_algo_id) new_algo_id = add_excavator_algorithm(best_algo, device, ports) device_status[device] = (best_algo, new_algo_id) sleep(UPDATE_INTERVAL) if __name__ == '__main__': main()