diff --git a/BitcoinMiner.py b/BitcoinMiner.py index 08a376c..329c154 100644 --- a/BitcoinMiner.py +++ b/BitcoinMiner.py @@ -123,6 +123,9 @@ def __init__(self, device, options): self.failback_attempt_count = 0 self.pool = None + self.queuesize = self.options.queuesize + self.currentworkpool = None + self.postdata = {'method': 'getwork', 'id': 'json'} self.connection = None @@ -189,16 +192,23 @@ def mine(self): if self.stop: return try: with self.lock: - update = self.update = (self.update or time() - self.lastWork > if_else(self.longPollActive, LONG_POLL_MAX_ASKRATE, self.options.askrate)) + update = self.update = (self.update or (self.workQueue.qsize() < self.queuesize - 1) or time() - self.lastWork > if_else(self.longPollActive, LONG_POLL_MAX_ASKRATE, self.options.askrate)) if update: work = self.getwork() if self.update: self.queueWork(work) + retry = [] while not self.resultQueue.empty(): result = self.resultQueue.get(False) with self.lock: rv = self.sendResult(result) + if rv is False: + retry.append(result) + if retry: + for result in retry: + self.resultQueue.put(result) + sleep(1) except Exception: self.sayLine("Unexpected error:") @@ -227,14 +237,17 @@ def sendResult(self, result): d = ''.join([d[:136], pack('I', long(result['data'][1])).encode('hex'), d[144:152], pack('I', long(result['output'][i])).encode('hex'), d[160:]]) hashid = pack('I', long(h[6])).encode('hex') accepted = self.getwork(d) - if accepted != None: + if accepted != None and accepted is not False: self.blockFound(hashid, accepted) self.shareCount[if_else(accepted, 1, 0)] += 1 + elif accepted is False: + self.sayLine('%s, %s', (hashid, 'ERROR (will resend)')) + return False - def connect(self, host, timeout): - if self.proto == 'https': - return httplib.HTTPSConnection(self.host, strict=True, timeout=timeout) - return httplib.HTTPConnection(self.host, strict=True, timeout=timeout) + def connect(self, host, timeout, proto='http'): + if proto == 'https': + return httplib.HTTPSConnection(host, strict=True, timeout=timeout) + return httplib.HTTPConnection(host, strict=True, timeout=timeout) def getwork(self, data=None): save_pool = None @@ -247,7 +260,7 @@ def getwork(self, data=None): self.sayLine("Attempting to fail back to primary pool") self.failback_getwork_count += 1 if not self.connection: - self.connection = self.connect(self.host, TIMEOUT) + self.connection = self.connect(self.host, TIMEOUT, self.proto) if data is None: self.getworkCount += 1 self.postdata['params'] = if_else(data, [data], []) @@ -281,6 +294,7 @@ def getwork(self, data=None): pool = self.servers[self.backup_pool_index] self.backup_pool_index += 1 self.setpool(pool) + return False def setpool(self, pool): self.pool = pool @@ -290,6 +304,11 @@ def setpool(self, pool): self.sayLine('Setting pool %s @ %s', (user, host)) self.headers = {"User-Agent": USER_AGENT, "Authorization": 'Basic ' + b64encode('%s:%s' % (user, pwd))} self.connection = None + with self.lock: + while not self.resultQueue.empty(): + self.resultQueue.get(False) + while not self.workQueue.empty(): + self.workQueue.get(False) def request(self, connection, url, headers, data=None): result = response = None @@ -309,7 +328,10 @@ def request(self, connection, url, headers, data=None): self.longPollURL = response.getheader('X-Long-Polling', '') self.updateTime = response.getheader('X-Roll-NTime', '') result = loads(response.read()) - if result['error']: raise RPCError(result['error']['message']) + if result['error']: + if result['error'].has_key('message'): + raise RPCError(result['error']['message']) + else: raise RPCError(result['error']) return (connection, result) finally: if not result or not response or (response.version == 10 and response.getheader('connection', '') != 'keep-alive') or response.getheader('connection', '') == 'close': @@ -332,8 +354,8 @@ def longPollThread(self): if url == '': url = '/' try: if not connection: - connection = self.connect(host, LONG_POLL_TIMEOUT) - self.sayLine("LP connected to %s", host) + connection = self.connect(host, LONG_POLL_TIMEOUT, parsedUrl.scheme) + self.sayLine("LP connected to %s%s", (host, url)) self.longPollActive = True (connection, result) = self.request(connection, url, self.headers) self.longPollActive = False @@ -367,12 +389,13 @@ def miningThread(self): while True: sleep(self.options.frameSleep) if self.stop: return - if (not work) or (not self.workQueue.empty()): + if not work: try: work = self.workQueue.get(True, 1) except Empty: continue else: if not work: continue + self.currentworkpool = self.pool noncesLeft = self.hashspace data = np.array(unpack('IIIIIIIIIIIIIIII', work['data'][128:].decode('hex')), dtype=np.uint32) @@ -381,6 +404,12 @@ def miningThread(self): targetQ= int(work['target'], 16) / 2**224 state2 = partial(state, data, f) calculateF(state, data, f, state2) + if self.lastBlock != work['data'][48:56]: + work = None + continue + if self.currentworkpool != self.pool: + work = None + continue self.miner.search( queue, (globalThreads, ), (self.options.worksize, ), state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7], @@ -439,7 +468,7 @@ def miningThread(self): self.update = True noncesLeft += 0xFFFFFFFFFFFF elif 0xFFFFFFFFFFF < noncesLeft < 0xFFFFFFFFFFFF: - self.sayLine('warning: job finished, miner is idle') + if self.workQueue.empty(): self.sayLine('warning: job finished, miner is idle') work = None elif now - lastNTime > 1: data[1] = bytereverse(bytereverse(data[1]) + 1) diff --git a/poclbm.py b/poclbm.py index 77d68db..26e7c70 100755 --- a/poclbm.py +++ b/poclbm.py @@ -19,6 +19,7 @@ parser.add_option('--failback', dest='failback', default=2, help='attempt to fail back to the primary pool every N getworks, default 2', type='int') parser.add_option('--verbose', dest='verbose', action='store_true', help='verbose output, suitable for redirection to log file') parser.add_option('--platform', dest='platform', default=-1, help='use platform by id', type='int') +parser.add_option('--queuesize', dest='queuesize', default=1, help='the size of work queue, default 1', type='int') (options, args) = parser.parse_args() platforms = cl.get_platforms()