Skip to content
This repository
Browse code

initial for multi_miner

  • Loading branch information...
commit f1ce310af8e7bf508dc4983e45d477b9986355ff 1 parent 557945e
m0mchil authored
55 BitcoinMiner.py
@@ -7,7 +7,6 @@
7 7 from threading import Thread
8 8 from time import sleep, time
9 9 from util import *
10   -import log
11 10 import pyopencl as cl
12 11
13 12 ADL_PRESENT = False
@@ -25,26 +24,22 @@
25 24
26 25
27 26 class BitcoinMiner():
28   - def __init__(self, device, options, version, transport):
  27 + def __init__(self, device, options):
29 28 self.output_size = 0x100
30 29 self.options = options
31   - self.version = version
  30 +
32 31 (self.defines, self.rate_divisor, self.hashspace) = if_else(self.options.vectors, ('-DVECTORS', 500, 0x7FFFFFFF), ('', 1000, 0xFFFFFFFF))
33 32 self.defines += (' -DOUTPUT_SIZE=' + str(self.output_size))
34 33 self.defines += (' -DOUTPUT_MASK=' + str(self.output_size - 1))
35 34
36 35 self.device = device
37   - self.options.rate = if_else(self.options.verbose, max(self.options.rate, 60), max(self.options.rate, 0.1))
38   - self.options.askrate = max(self.options.askrate, 1)
39   - self.options.askrate = min(self.options.askrate, 10)
40 36 self.options.frames = max(self.options.frames, 3)
41 37
42   - self.update_time = False
  38 + self.update_time_counter = 1
43 39 self.share_count = [0, 0]
44 40 self.work_queue = Queue()
45   - self.transport = transport(self)
46   - log.verbose = self.options.verbose
47   - log.quiet = self.options.quiet
  41 +
  42 + self.update = True
48 43
49 44 if ADL_PRESENT:
50 45 self.adapterIndex = self.get_adapter_info()[self.options.device].iAdapterIndex
@@ -52,29 +47,11 @@ def __init__(self, device, options, version, transport):
52 47 def start(self):
53 48 self.should_stop = False
54 49 Thread(target=self.mining_thread).start()
55   - self.transport.loop()
56 50
57 51 def stop(self, message = None):
58 52 if message: print '\n%s' % message
59   - self.transport.stop()
60 53 self.should_stop = True
61 54
62   - def say_status(self, rate, estimated_rate):
63   - rate = Decimal(rate) / 1000
64   - estimated_rate = Decimal(estimated_rate) / 1000
65   - total_shares = self.share_count[1] + self.share_count[0]
66   - total_shares_estimator = max(total_shares, total_shares, 1)
67   - say_quiet('[%.03f MH/s (~%d MH/s)] [Rej: %d/%d (%.02f%%)]', (rate, round(estimated_rate), self.share_count[0], total_shares, float(self.share_count[0]) * 100 / total_shares_estimator))
68   -
69   - def diff1_found(self, hash, target):
70   - if self.options.verbose and target < 0xFFFF0000L:
71   - say_line('checking %s <= %s', (hash, target))
72   -
73   - def share_found(self, hash, accepted, is_block):
74   - self.share_count[if_else(accepted, 1, 0)] += 1
75   - if self.options.verbose or is_block:
76   - say_line('%s%s, %s', (if_else(is_block, 'block ', ''), hash, if_else(accepted, 'accepted', '_rejected_')))
77   -
78 55 def mining_thread(self):
79 56 self.load_kernel()
80 57 frame = 1.0 / self.options.frames
@@ -141,8 +118,8 @@ def mining_thread(self):
141 118
142 119 t = now - last_rated
143 120 if t > self.options.rate:
144   - rate = int((threads_run / t) / self.rate_divisor)
145   -
  121 + self.rate = int((threads_run / t) / self.rate_divisor)
  122 + self.rate = Decimal(self.rate) / 1000
146 123 if accept_hist:
147 124 LAH = accept_hist.pop()
148 125 if LAH[1] != self.share_count[1]:
@@ -151,9 +128,10 @@ def mining_thread(self):
151 128 while (accept_hist[0][0] < now - self.options.estimate):
152 129 accept_hist.pop(0)
153 130 new_accept = self.share_count[1] - accept_hist[0][1]
154   - estimated_rate = Decimal(new_accept) * (work.targetQ) / min(int(now - start_time), self.options.estimate) / 1000
  131 + self.estimated_rate = Decimal(new_accept) * (work.targetQ) / min(int(now - start_time), self.options.estimate) / 1000
  132 + self.estimated_rate = Decimal(self.estimated_rate) / 1000
155 133
156   - self.say_status(rate, estimated_rate)
  134 + self.servers.status_updated()
157 135 last_rated = now; threads_run = 0
158 136
159 137 queue.finish()
@@ -170,13 +148,14 @@ def mining_thread(self):
170 148 result.job_id = work.job_id
171 149 result.extranonce2 = work.extranonce2
172 150 result.server = work.server
173   - self.transport.put(result)
  151 + result.miner = self
  152 + self.servers.put(result)
174 153 output.fill(0)
175 154 cl.enqueue_write_buffer(queue, output_buffer, output)
176 155
177   - if not self.update_time:
178   - if nonces_left < (self.transport.timeout + 1) * global_threads * self.options.frames:
179   - self.transport.update = True
  156 + if not self.servers.update_time:
  157 + if nonces_left < 3 * global_threads * self.options.frames:
  158 + self.update = True
180 159 nonces_left += 0xFFFFFFFFFFFF
181 160 elif 0xFFFFFFFFFFF < nonces_left < 0xFFFFFFFFFFFF:
182 161 say_line('warning: job finished, miner is idle')
@@ -186,6 +165,10 @@ def mining_thread(self):
186 165 state2 = partial(state, work.merkle_end, work.time, work.difficulty, f)
187 166 calculateF(state, work.merkle_end, work.time, work.difficulty, f, state2)
188 167 last_n_time = now
  168 + self.update_time_counter += 1
  169 + if self.update_time_counter >= self.servers.max_update_time:
  170 + self.update = True
  171 + self.update_time_counter = 1
189 172
190 173 def load_kernel(self):
191 174 self.context = cl.Context([self.device], None, None)
62 HttpTransport.py
@@ -23,7 +23,6 @@ def __init__(self, servers, server):
23 23
24 24 self.connection = self.lp_connection = None
25 25 self.long_poll_timeout = 3600
26   - self.long_poll_max_askrate = 60 - self.servers.timeout
27 26 self.max_redirects = 3
28 27
29 28 self.postdata = {'method': 'getwork', 'id': 'json'}
@@ -47,11 +46,11 @@ def loop(self):
47 46
48 47 try:
49 48 with self.servers.lock:
50   - update = self.servers.update = (self.servers.update or (time() - self.servers.last_work) > if_else(self.long_poll_active, self.long_poll_max_askrate, self.config.askrate))
51   - if update:
52   - work = self.getwork()
53   - if self.servers.update:
54   - self.queue_work(work)
  49 + miner = self.servers.updatable_miner()
  50 + while miner:
  51 + work = self.getwork()
  52 + self.queue_work(work, miner)
  53 + miner = self.servers.updatable_miner()
55 54
56 55 while not self.result_queue.empty():
57 56 result = self.result_queue.get(False)
@@ -63,7 +62,7 @@ def loop(self):
63 62 traceback.print_exc()
64 63 break
65 64
66   - def ensure_connected(self, connection, proto, host, timeout):
  65 + def ensure_connected(self, connection, proto, host):
67 66 if connection != None and connection.sock != None:
68 67 return connection, False
69 68
@@ -71,7 +70,7 @@ def ensure_connected(self, connection, proto, host, timeout):
71 70 else: connector = httplib.HTTPConnection
72 71
73 72 if not self.config.proxy:
74   - return connector(host, strict=True, timeout=timeout), True
  73 + return connector(host, strict=True), True
75 74
76 75 host, port = host.split(':')
77 76
@@ -83,7 +82,6 @@ def ensure_connected(self, connection, proto, host, timeout):
83 82
84 83 connection = connector(host, strict=True)
85 84 connection.sock = socks.socksocket()
86   - #connection.sock.settimeout(timeout)
87 85
88 86 proxy_type = socks.PROXY_TYPE_SOCKS5
89 87 if proxy_proto == 'http':
@@ -104,18 +102,7 @@ def request(self, connection, url, headers, data=None, timeout=0):
104 102 try:
105 103 if data: connection.request('POST', url, data, headers)
106 104 else: connection.request('GET', url, headers=headers)
107   - if timeout:
108   - start = time()
109   - connection.sock.settimeout(min(timeout, 5))
110   - response = None
111   - while not response:
112   - if self.should_stop or time() - start > timeout: return
113   - try:
114   - response = connection.getresponse()
115   - except socket.timeout:
116   - pass
117   - else:
118   - response = connection.getresponse()
  105 + response = self.timeout_response(connection, timeout)
119 106 if response.status == httplib.UNAUTHORIZED:
120 107 say_line('Wrong username or password for %s', self.servers.server_name())
121 108 raise NotAuthorized()
@@ -125,10 +112,10 @@ def request(self, connection, url, headers, data=None, timeout=0):
125 112 url = response.getheader('Location', '')
126 113 if r == 0 or url == '': raise HTTPException('Too much or bad redirects')
127 114 connection.request('GET', url, headers=headers)
128   - response = connection.getresponse();
  115 + response = self.timeout_response(connection, timeout)
129 116 r -= 1
130 117 self.long_poll_url = response.getheader('X-Long-Polling', '')
131   - self.servers.miner.update_time = bool(response.getheader('X-Roll-NTime', ''))
  118 + self.servers.update_time = bool(response.getheader('X-Roll-NTime', ''))
132 119 hostList = response.getheader('X-Host-List', '')
133 120 self.stratum_header = response.getheader('x-stratum', '')
134 121 if (not self.config.nsf) and hostList: self.servers.add_servers(loads(hostList))
@@ -142,9 +129,24 @@ def request(self, connection, url, headers, data=None, timeout=0):
142 129 connection.close()
143 130 connection = None
144 131
  132 + def timeout_response(self, connection, timeout):
  133 + if timeout:
  134 + start = time()
  135 + connection.sock.settimeout(5)
  136 + response = None
  137 + while not response:
  138 + if self.should_stop or time() - start > timeout: return
  139 + try:
  140 + response = connection.getresponse()
  141 + except socket.timeout:
  142 + pass
  143 + return response
  144 + else:
  145 + return connection.getresponse()
  146 +
145 147 def getwork(self, data=None):
146   - try:
147   - self.connection = self.ensure_connected(self.connection, self.proto, self.host, self.servers.timeout)[0]
  148 + try:
  149 + self.connection = self.ensure_connected(self.connection, self.proto, self.host)[0]
148 150 self.postdata['params'] = if_else(data, [data], [])
149 151 (self.connection, result) = self.request(self.connection, '/', self.headers, dumps(self.postdata))
150 152
@@ -158,7 +160,7 @@ def send_internal(self, result, nonce):
158 160 data = ''.join([result.header.encode('hex'), pack('III', long(result.time), long(result.difficulty), long(nonce)).encode('hex'), '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'])
159 161 accepted = self.getwork(data)
160 162 if accepted != None:
161   - self.servers.report(nonce, accepted)
  163 + self.servers.report(result.miner, nonce, accepted)
162 164
163 165 def long_poll_thread(self):
164 166 last_host = None
@@ -179,7 +181,7 @@ def long_poll_thread(self):
179 181 if url == '': url = '/'
180 182 try:
181 183 if host != last_host: self.close_lp_connection()
182   - self.lp_connection, changed = self.ensure_connected(self.lp_connection, proto, host, self.long_poll_timeout)
  184 + self.lp_connection, changed = self.ensure_connected(self.lp_connection, proto, host)
183 185 if changed:
184 186 say_line("LP connected to %s", self.servers.server_name())
185 187 last_host = host
@@ -215,14 +217,12 @@ def close_lp_connection(self):
215 217 self.lp_connection.close()
216 218 self.lp_connection = None
217 219
218   - def queue_work(self, work):
  220 + def queue_work(self, work, miner=None):
219 221 if work:
220 222 if not 'target' in work:
221 223 work['target'] = '0000000000000000000000000000000000000000000000000000ffff00000000'
222 224
223   - self.servers.queue_work(self, work['data'], work['target'])
224   - else:
225   - self.servers.queue_work(self, work)
  225 + self.servers.queue_work(self, work['data'], work['target'], miner)
226 226
227 227 def detect_stratum(self):
228 228 work = self.getwork()
63 Servers.py
@@ -7,13 +7,13 @@
7 7 import log
8 8
9 9 class Servers(object):
10   - def __init__(self, miner):
  10 + def __init__(self, config):
11 11 self.lock = RLock()
12   - self.miner = miner
13   - self.config = miner.options
14   - self.update = True
  12 + self.miners = []
  13 + self.config = config
15 14 self.last_work = 0
16   - self.timeout = 5
  15 + self.update_time = True
  16 + self.max_update_time = config.max_update_time
17 17
18 18 self.backup_server_index = 1
19 19 self.errors = 0
@@ -23,7 +23,7 @@ def __init__(self, miner):
23 23 self.save_server = None
24 24 self.server_map = {}
25 25
26   - self.user_agent = 'poclbm/' + miner.version
  26 + self.user_agent = 'poclbm/' + config.version
27 27
28 28 self.difficulty = 0
29 29 self.true_target = None
@@ -71,6 +71,16 @@ def parse_server(self, server, mailAsUser=True):
71 71
72 72 return (proto, user, pwd, host, name)
73 73
  74 + def add_miner(self, miner):
  75 + self.miners.append(miner)
  76 + miner.servers = self
  77 +
  78 + def updatable_miner(self):
  79 + for miner in self.miners:
  80 + if miner.update:
  81 + miner.update = False
  82 + return miner
  83 +
74 84 def loop(self):
75 85 self.should_stop = False
76 86 if not self.servers:
@@ -148,6 +158,9 @@ def decode(self, server, block_header, target, job_id = None, extranonce2 = None
148 158 job.server = server
149 159
150 160 calculateF(job.state, job.merkle_end, job.time, job.difficulty, job.f, job.state2)
  161 +
  162 + if job.difficulty != self.difficulty:
  163 + self.set_difficulty(job.difficulty)
151 164
152 165 return job
153 166
@@ -158,20 +171,14 @@ def set_difficulty(self, difficulty):
158 171 true_target = ''.join(list(chunks(true_target, 2))[::-1])
159 172 self.true_target = np.array(unpack('IIIIIIII', true_target.decode('hex')), dtype=np.uint32)
160 173
161   - def process(self, work):
162   - if work:
163   - if work.difficulty != self.difficulty:
164   - self.set_difficulty(work.difficulty)
165   -
166 174 def send(self, result, send_callback):
167   - for i in xrange(self.miner.output_size):
  175 + for i in xrange(result.miner.output_size):
168 176 if result.nonce[i]:
169 177 h = hash(result.state, result.merkle_end, result.time, result.difficulty, result.nonce[i])
170 178 if h[7] != 0:
171 179 say_line('Verification failed, check hardware!')
172   - #self.miner.stop()
173 180 else:
174   - self.miner.diff1_found(bytereverse(h[6]), result.target[6])
  181 + self.diff1_found(bytereverse(h[6]), result.target[6])
175 182 if belowOrEquals(h[:7], result.target[:7]):
176 183 is_block = belowOrEquals(h[:7], self.true_target[:7])
177 184 hash6 = pack('I', long(h[6])).encode('hex')
@@ -179,9 +186,24 @@ def send(self, result, send_callback):
179 186 self.sent[result.nonce[i]] = (is_block, hash6, hash5)
180 187 return send_callback(result, result.nonce[i])
181 188
182   - def report(self, nonce, accepted):
  189 + def diff1_found(self, hash, target):
  190 + if self.config.verbose and target < 0xFFFF0000L:
  191 + say_line('checking %s <= %s', (hash, target))
  192 +
  193 + def status_updated(self):
  194 + rate = sum([m.rate for m in self.miners])
  195 + estimated_rate = sum([m.estimated_rate for m in self.miners])
  196 + rejected_shares = sum([m.share_count[0] for m in self.miners])
  197 + total_shares = rejected_shares + sum([m.share_count[1] for m in self.miners])
  198 + total_shares_estimator = max(total_shares, 1)
  199 + say_quiet('[%.03f MH/s (~%d MH/s)] [Rej: %d/%d (%.02f%%)]', (rate, round(estimated_rate), rejected_shares, total_shares, float(rejected_shares) * 100 / total_shares_estimator))
  200 +
  201 + def report(self, miner, nonce, accepted):
183 202 is_block, hash6, hash5 = self.sent[nonce]
184   - self.miner.share_found(if_else(is_block, hash6 + hash5, hash6), accepted, is_block)
  203 + miner.share_count[if_else(accepted, 1, 0)] += 1
  204 + hash = if_else(is_block, hash6 + hash5, hash6)
  205 + if self.config.verbose or is_block:
  206 + say_line('%s%s, %s', (if_else(is_block, 'block ', ''), hash, if_else(accepted, 'accepted', '_rejected_')))
185 207 del self.sent[nonce]
186 208
187 209 def set_server_by_index(self, server_index):
@@ -202,11 +224,14 @@ def add_servers(self, hosts):
202 224 server = (server[0], server[1], server[2], ''.join([host['host'], ':', str(host['port'])]), server[4])
203 225 self.servers.insert(self.backup_server_index, server)
204 226
205   - def queue_work(self, server, block_header, target = None, job_id = None, extranonce2 = None):
  227 + def queue_work(self, server, block_header, target = None, job_id = None, extranonce2 = None, miner=None):
206 228 work = self.decode(server, block_header, target, job_id, extranonce2)
207   - self.process(work)
208 229 with self.lock:
209   - self.miner.work_queue.put(work)
  230 + if not miner:
  231 + miner = self.miners[0]
  232 + for i in xrange(1, len(self.miners)):
  233 + self.miners[i].update = True
  234 + miner.work_queue.put(work)
210 235 if work:
211 236 self.update = False; self.last_work = time()
212 237 if self.last_block != work.header[25:29]:
37 StratumTransport.py
@@ -16,13 +16,11 @@
16 16
17 17
18 18 BASE_DIFFICULTY = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
19   -MAX_JOB_AGE = 60
20 19
21 20
22 21 class StratumTransport(Transport):
23 22 def __init__(self, servers, server):
24 23 super(StratumTransport, self).__init__(servers, server)
25   - self.servers.miner.update_time = True
26 24 self.handler = None
27 25 self.socket = None
28 26 self.channel_map = {}
@@ -40,12 +38,17 @@ def __init__(self, servers, server):
40 38 def loop(self):
41 39 super(StratumTransport, self).loop()
42 40
  41 + self.servers.update_time = True
  42 +
43 43 while True:
44 44 if self.should_stop: return
45 45
46   - if self.current_job and ((time() - self.current_job.time) > MAX_JOB_AGE):
47   - self.current_job = self.refresh_job(self.current_job)
48   - self.queue_work(self.current_job)
  46 + if self.current_job:
  47 + miner = self.servers.updatable_miner()
  48 + while miner:
  49 + self.current_job = self.refresh_job(self.current_job)
  50 + self.queue_work(self.current_job, miner)
  51 + miner = self.servers.updatable_miner()
49 52
50 53 if self.check_failback():
51 54 return True
@@ -59,7 +62,6 @@ def loop(self):
59 62
60 63 if not self.config.proxy:
61 64 self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
62   - self.socket.settimeout(self.servers.timeout)
63 65 self.socket.connect((address, int(port)))
64 66 else:
65 67 proxy_proto, user, pwd, proxy_host, name = self.config.proxy
@@ -141,7 +143,7 @@ def increment_nonce(self, nonce):
141 143 return '00' * self.extranonce2_size
142 144 return ('%0' + str(self.extranonce2_size * 2) +'x') % next_nonce
143 145
144   - def queue_message(self, message):
  146 + def handle_message(self, message):
145 147
146 148 #Miner API
147 149 if 'method' in message:
@@ -206,12 +208,14 @@ def queue_message(self, message):
206 208 #check if this is submit confirmation (message id should be in submits dictionary)
207 209 #cleanup if necessary
208 210 elif message['id'] in self.submits:
209   - self.servers.report(self.submits[message['id']][0], message['result'])
  211 + miner, nonce, time = self.submits[message['id']]
  212 + accepted = message['result']
  213 + self.servers.report(miner, nonce, accepted)
210 214 del self.submits[message['id']]
211 215 if time() - self.last_submits_cleanup > 3600:
212 216 now = time()
213 217 for key, value in self.submits.items():
214   - if now - value[1] > 3600:
  218 + if now - value[2] > 3600:
215 219 del self.submits[key]
216 220 self.last_submits_cleanup = now
217 221
@@ -246,7 +250,7 @@ def send_internal(self, result, nonce):
246 250 ntime = pack('I', long(result.time)).encode('hex')
247 251 hex_nonce = pack('I', long(nonce)).encode('hex')
248 252 id = job_id + hex_nonce
249   - self.submits[id] = (nonce, time())
  253 + self.submits[id] = (result.miner, nonce, time())
250 254 return self.send_message({'params': [user, job_id, extranonce2, ntime, hex_nonce], 'id': id, 'method': u'mining.submit'})
251 255
252 256 def send_message(self, message):
@@ -255,7 +259,7 @@ def send_message(self, message):
255 259 #self.handler.push(data)
256 260
257 261 #there is some bug with asyncore's send mechanism
258   - #so we send data manually
  262 + #so we send data 'manually'
259 263 #note that this is not thread safe
260 264 if not self.handler:
261 265 return False
@@ -270,12 +274,9 @@ def send_message(self, message):
270 274 self.stop()
271 275
272 276
273   - def queue_work(self, work):
274   - if work:
275   - target = ''.join(list(chunks('%064x' % self.pool_difficulty, 2))[::-1])
276   - self.servers.queue_work(self, work.block_header, target, work.job_id, work.extranonce2)
277   - else:
278   - self.servers.queue_work(self, work)
  277 + def queue_work(self, work, miner=None):
  278 + target = ''.join(list(chunks('%064x' % self.pool_difficulty, 2))[::-1])
  279 + self.servers.queue_work(self, work.block_header, target, work.job_id, work.extranonce2, miner)
279 280
280 281 class Handler(asynchat.async_chat):
281 282 def __init__(self, socket, map, parent):
@@ -299,5 +300,5 @@ def collect_incoming_data(self, data):
299 300
300 301 def found_terminator(self):
301 302 message = loads(self.data)
302   - self.parent.queue_message(message)
  303 + self.parent.handle_message(message)
303 304 self.data = ''
18 poclbm.py
@@ -4,6 +4,7 @@
4 4 from optparse import OptionGroup, OptionParser
5 5 from time import sleep
6 6 import Servers
  7 +import log
7 8 import pyopencl as cl
8 9 import socket
9 10
@@ -32,7 +33,6 @@ def socketwrap(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
32 33 group = OptionGroup(parser, "Miner Options")
33 34 group.add_option('-r', '--rate', dest='rate', default=1, help='hash rate display interval in seconds, default=1 (60 with --verbose)', type='float')
34 35 group.add_option('-e', '--estimate', dest='estimate', default=900, help='estimated rate time window in seconds, default 900 (15 minutes)', type='int')
35   -group.add_option('-a', '--askrate', dest='askrate', default=5, help='how many seconds between getwork requests, default 5, max 10', type='int')
36 36 group.add_option('-t', '--tolerance', dest='tolerance', default=2, help='use fallback pool only after N consecutive connection errors, default 2', type='int')
37 37 group.add_option('-b', '--failback', dest='failback', default=60, help='attempt to fail back to the primary pool after N seconds, default 60', type='int')
38 38 group.add_option('--cutoff_temp', dest='cutoff_temp',default=95, help='(requires github.com/mjmvisser/adl3) temperature at which to skip kernel execution, in C, default=95', type='float')
@@ -51,6 +51,14 @@ def socketwrap(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
51 51
52 52 (options, options.servers) = parser.parse_args()
53 53
  54 +log.verbose = options.verbose
  55 +log.quiet = options.quiet
  56 +
  57 +options.rate = if_else(options.verbose, max(options.rate, 60), max(options.rate, 0.1))
  58 +
  59 +options.version = VERSION
  60 +
  61 +options.max_update_time = 60
54 62
55 63 platforms = cl.get_platforms()
56 64
@@ -70,6 +78,7 @@ def socketwrap(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
70 78 print '[%d]\t%s' % (i, devices[i].name)
71 79 sys.exit()
72 80
  81 +servers = None
73 82 miner = None
74 83 try:
75 84 #init adl
@@ -82,12 +91,17 @@ def socketwrap(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
82 91 pass
83 92 #end init adl
84 93
85   - miner = BitcoinMiner(devices[options.device], options, VERSION, Servers.Servers)
  94 + servers = Servers.Servers(options)
  95 +
  96 + miner = BitcoinMiner(devices[options.device], options)
  97 + servers.add_miner(miner)
86 98 miner.start()
  99 + servers.loop()
87 100 except KeyboardInterrupt:
88 101 print '\nbye'
89 102 finally:
90 103 if miner: miner.stop()
  104 + if servers: servers.stop()
91 105
92 106 #adl shutdown
93 107 try:

0 comments on commit f1ce310

Please sign in to comment.
Something went wrong with that request. Please try again.