def main(self): # If we're currently shutting down, just die. If not, loop forever, # to recover from possible errors caught by the huge try statement inside this loop. # Count how often the except for that try was hit recently. This will be reset if # there was no exception for at least 5 minutes since the last one. tries = 0 while not self.shutdown: try: # Record our starting timestamp, in order to back off if we repeatedly die starttime = time.time() # Exception container: If an exception occurs in the listener thread, the listener thread # will store it here and terminate, and the main thread will rethrow it and then restart. self.error = None self.hasheswithoutshare = 0 # Initialize megahashes per second to zero, will be measured later. self.stats.mhps = 0 # Job that the device is currently working on, or that is currently being uploaded. # This variable is used by BaseWorker to figure out the current work source for statistics. self.job = None # Job that was previously being procesed. Has been destroyed, but there might be some late nonces. self.oldjob = None # Open the serial port self.handle = serial.Serial(self.port, self.baudrate, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, 1, False, False, 5, False, None) # We keep control of the wakeup lock at all times unless we're sleeping self.wakeup.acquire() # Set validation success flag to false self.checksuccess = False # Start device response listener thread self.listenerthread = Thread(None, self._listener, self.settings.name + "_listener") self.listenerthread.daemon = True self.listenerthread.start() # Send validation job to device job = ValidationJob(self.core, unhexlify(b"00000001c3bf95208a646ee98a58cf97c3a0c4b7bf5de4c89ca04495000005200000000024d1fff8d5d73ae11140e4e48032cd88ee01d48c67147f9a09cd41fdec2e25824f5c038d1a0b350c5eb01f04")) self._sendjob(job) # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # Wait for the validation job to complete. The wakeup flag will be set by the listener # thread when the validation job completes. 60 seconds should be sufficient for devices # down to about 2.6MH/s, for slower devices this timeout will need to be increased. self.wakeup.wait(60) # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # Honor shutdown flag if self.shutdown: break # We woke up, but the validation job hasn't succeeded in the mean time. # This usually means that the wakeup timeout has expired. if not self.checksuccess: raise Exception("Timeout waiting for validation job to finish") # self.stats.mhps has now been populated by the listener thread self.core.log(self, "Running at %f MH/s\n" % self.stats.mhps, 300, "B") # Calculate the time that the device will need to process 2**32 nonces. # This is limited at 60 seconds in order to have some regular communication, # even with very slow devices (and e.g. detect if the device was unplugged). interval = min(60, 2**32 / 1000000. / self.stats.mhps) # Add some safety margin and take user's interval setting (if present) into account. self.jobinterval = min(self.settings.jobinterval, max(0.5, interval * 0.8 - 1)) self.core.log(self, "Job interval: %f seconds\n" % self.jobinterval, 400, "B") # Tell the MPBM core that our hash rate has changed, so that it can adjust its work buffer. self.jobspersecond = 1. / self.jobinterval self.core.notify_speed_changed(self) # Main loop, continues until something goes wrong or we're shutting down. while not self.shutdown: # Fetch a job, add 2 seconds safety margin to the requested minimum expiration time. # Blocks until one is available. Because of this we need to release the # wakeup lock temporarily in order to avoid possible deadlocks. self.wakeup.release() job = self.core.get_job(self, self.jobinterval + 2) self.wakeup.acquire() # If a new block was found while we were fetching that job, just discard it and get a new one. if job.canceled: job.destroy() continue # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # Upload the job to the device self._sendjob(job) # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # If the job was already caught by a long poll while we were uploading it, # jump back to the beginning of the main loop in order to immediately fetch new work. # Don't check for the canceled flag before the job was accepted by the device, # otherwise we might get out of sync. if self.job.canceled: continue # Wait while the device is processing the job. If nonces are sent by the device, they # will be processed by the listener thread. If the job gets canceled, we will be woken up. self.wakeup.wait(self.jobinterval) # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # If something went wrong... except Exception as e: # ...complain about it! self.core.log(self, "%s\n" % traceback.format_exc(), 100, "rB") # Make sure that the listener thread realizes that something went wrong self.error = e finally: # We're not doing productive work any more, update stats and destroy current job self._jobend() self.stats.mhps = 0 # Release the wake lock to allow the listener thread to move. Ignore it if that goes wrong. try: self.wakeup.release() except: pass # Close the serial port handle, otherwise we can't reopen it after restarting. # This should hopefully also make reads on that port from the listener thread fail, # so that the listener thread will realize that it's supposed to shut down. try: self.handle.close() except: pass # Wait for the listener thread to terminate. # If it doens't within 5 seconds, continue anyway. We can't do much about that. try: self.listenerthread.join(5) except: pass # Set MH/s to zero again, the listener thread might have overwritten that. self.stats.mhps = 0 # If we aren't shutting down, figure out if there have been many errors recently, # and if yes, wait a bit longer until restarting the worker. if not self.shutdown: tries += 1 if time.time() - starttime >= 300: tries = 0 with self.wakeup: if tries > 5: self.wakeup.wait(30) else: self.wakeup.wait(1)
def main(self): # If we're currently shutting down, just die. If not, loop forever, # to recover from possible errors caught by the huge try statement inside this loop. # Count how often the except for that try was hit recently. This will be reset if # there was no exception for at least 5 minutes since the last one. tries = 0 while not self.shutdown: try: # Record our starting timestamp, in order to back off if we repeatedly die starttime = time.time() # Initialize megahashes per second to zero, will be measured later. self.stats.mhps = 0 # Job that the device is currently working on, or that is currently being uploaded. # This variable is used by BaseWorker to figure out the current work source for statistics. self.job = None # Job that was previously being procesed. Has been destroyed, but there might be some late nonces. self.oldjob = None # We keep control of the wakeup lock at all times unless we're sleeping self.wakeup.acquire() # Eat up leftover wakeups self.wakeup.wait(0) # Honor shutdown flag (in case it was a real wakeup) if self.shutdown: break # Set validation success flag to false self.checksuccess = False # Set validation job second iteration flag to false self.seconditeration = False # Initialize hash rate tracking data self.lasttime = None self.lastnonce = None # Initialize malfunction tracking data self.recentshares = 0 self.recentinvalid = 0 # Configure core clock, if the bitstream supports that if self.firmware_rev > 0: self._set_speed(self.parent.settings.initialspeed) # Clear FPGA's nonce queue self.parent.clear_queue(self.fpga) # Send validation job to device job = ValidationJob(self.core, unhexlify(b"00000001c3bf95208a646ee98a58cf97c3a0c4b7bf5de4c89ca04495000005200000000024d1fff8d5d73ae11140e4e48032cd88ee01d48c67147f9a09cd41fdec2e25824f5c038d1a0b350c5eb01f04")) self._sendjob(job) # Wait for the validation job to complete. The wakeup flag will be set by the listener # thread when the validation job completes. 180 seconds should be sufficient for devices # down to about 50MH/s, for slower devices this timeout will need to be increased. if self.stats.speed: self.wakeup.wait((2**32 / 1000000. / self.stats.speed) * 1.1) else: self.wakeup.wait(180) # Honor shutdown flag if self.shutdown: break # We woke up, but the validation job hasn't succeeded in the mean time. # This usually means that the wakeup timeout has expired. if not self.checksuccess: raise Exception("Timeout waiting for validation job to finish") # self.stats.mhps has now been populated by the listener thread self.core.log(self, "Running at %f MH/s\n" % self.stats.mhps, 300, "B") self._update_job_interval() # Main loop, continues until something goes wrong or we're shutting down. while not self.shutdown: # Fetch a job, add 2 seconds safety margin to the requested minimum expiration time. # Blocks until one is available. Because of this we need to release the # wakeup lock temporarily in order to avoid possible deadlocks. self.wakeup.release() job = self.core.get_job(self, self.jobinterval + 2) self.wakeup.acquire() # If a new block was found while we were fetching that job, just discard it and get a new one. if job.canceled: job.destroy() continue # Upload the job to the device self._sendjob(job) # Go through the safety checks and reduce the clock if necessary self.safetycheck() # If the job was already caught by a long poll while we were uploading it, # jump back to the beginning of the main loop in order to immediately fetch new work. # Don't check for the canceled flag before the job was accepted by the device, # otherwise we might get out of sync. if self.job.canceled: continue # Wait while the device is processing the job. If nonces are sent by the device, they # will be processed by the listener thread. If the job gets canceled, we will be woken up. self.wakeup.wait(self.jobinterval) # If something went wrong... except Exception as e: # ...complain about it! self.core.log(self, "%s\n" % traceback.format_exc(), 100, "rB") finally: # We're not doing productive work any more, update stats and destroy current job self._jobend() self.stats.mhps = 0 try: self.wakeup.release() except: pass # If we aren't shutting down, figure out if there have been many errors recently, # and if yes, restart the parent worker as well. if not self.shutdown: tries += 1 if time.time() - starttime >= 300: tries = 0 with self.wakeup: if tries > 5: self.parent.async_restart() return else: self.wakeup.wait(1)
def main(self): # If we're currently shutting down, just die. If not, loop forever, # to recover from possible errors caught by the huge try statement inside this loop. # Count how often the except for that try was hit recently. This will be reset if # there was no exception for at least 5 minutes since the last one. tries = 0 while not self.shutdown: try: # Record our starting timestamp, in order to back off if we repeatedly die starttime = time.time() self.error = None # Initialize megahashes per second to zero, will be measured later. self.stats.mhps = 0 # Job that the device is currently working on, or that is currently being uploaded. # This variable is used by BaseWorker to figure out the current work source for statistics. self.job = None # Job that was previously being procesed. Has been destroyed, but there might be some late nonces. self.oldjob = None # We keep control of the wakeup lock at all times unless we're sleeping self.wakeup.acquire() # Eat up leftover wakeups self.wakeup.wait(0) # Honor shutdown flag (in case it was a real wakeup) if self.shutdown: break # Set validation success flag to false self.checksuccess = False # Initialize hash rate tracking data self.lasttime = None self.lastnonce = None # Initialize malfunction tracking data self.recentshares = 0 self.recentinvalid = 0 # Configure core clock, if the bitstream supports that self._set_speed(self.parent.settings.initialspeed) # Send validation job to device job = ValidationJob( self.core, unhexlify( b"00000001c3bf95208a646ee98a58cf97c3a0c4b7bf5de4c89ca04495000005200000000024d1fff8d5d73ae11140e4e48032cd88ee01d48c67147f9a09cd41fdec2e25824f5c038d1a0b350c5eb01f04" )) self._sendjob(job) # Wait for the validation job to complete. The wakeup flag will be # set by the listener thread when the validation job completes. self.wakeup.wait((100. / self.stats.mhps) + 1) # Honor shutdown flag if self.shutdown: break # We woke up, but the validation job hasn't succeeded in the mean time. # This usually means that the wakeup timeout has expired. if not self.checksuccess: raise Exception( "Timeout waiting for validation job to finish") # Main loop, continues until something goes wrong or we're shutting down. while not self.shutdown: # Fetch a job, add 2 seconds safety margin to the requested minimum expiration time. # Blocks until one is available. Because of this we need to release the # wakeup lock temporarily in order to avoid possible deadlocks. self.wakeup.release() job = self.core.get_job(self, self.jobinterval + 2) self.wakeup.acquire() if self.error: raise self.error # If a new block was found while we were fetching that job, just discard it and get a new one. if job.canceled: job.destroy() continue # Upload the job to the device self._sendjob(job) if self.error: raise self.error # Go through the safety checks and reduce the clock if necessary self.safetycheck() # If the job was already caught by a long poll while we were uploading it, # jump back to the beginning of the main loop in order to immediately fetch new work. # Don't check for the canceled flag before the job was accepted by the device, # otherwise we might get out of sync. if self.job.canceled: continue # Wait while the device is processing the job. If nonces are sent by the device, they # will be processed by the listener thread. If the job gets canceled, we will be woken up. self.wakeup.wait(self.jobinterval) if self.error: raise self.error # If something went wrong... except Exception as e: # ...complain about it! self.core.log(self, "%s\n" % traceback.format_exc(), 100, "rB") finally: # We're not doing productive work any more, update stats and destroy current job self._jobend() self.stats.mhps = 0 try: self.wakeup.release() except: pass # If we aren't shutting down, figure out if there have been many errors recently, # and if yes, restart the parent worker as well. if not self.shutdown: tries += 1 if time.time() - starttime >= 300: tries = 0 with self.wakeup: if tries > 5: self.parent.async_restart() return else: self.wakeup.wait(1)
def main(self): # If we're currently shutting down, just die. If not, loop forever, # to recover from possible errors caught by the huge try statement inside this loop. # Count how often the except for that try was hit recently. This will be reset if # there was no exception for at least 5 minutes since the last one. tries = 0 while not self.shutdown: try: # Record our starting timestamp, in order to back off if we repeatedly die starttime = time.time() # Exception container: If an exception occurs in the listener thread, the listener thread # will store it here and terminate, and the main thread will rethrow it and then restart. self.error = None # Initialize megahashes per second to zero, will be measured later. self.stats.mhps = 0 # Job that the device is currently working on (found nonces are coming from this one). # This variable is used by BaseWorker to figure out the current work source for statistics. self.job = None # Job that is currently being uploaded to the device but not yet being processed. self.nextjob = None # Open the serial port self.handle = serial.Serial(self.port, self.baudrate, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, 1, False, False, 5, False, None) # Send enough zero bytes to make sure that the device is not expecting data any more. # Command zero is a ping request, which is answered by a zero byte from the device. # This means that superfluous zero bytes (but at least one) will just bounce back to us. self.handle.write(struct.pack("45B", *([0] * 45))) # Read the device's response. # There should be at least one byte, and the last byte must be zero. # If not, something is wrong with the device or communication channel. data = self.handle.read(100) if len(data) == 0: raise Exception( "Failed to sync with mining device: Device does not respond" ) if data[-1:] != b"\0": raise Exception( "Failed to sync with mining device: Device sends garbage" ) # We keep control of the wakeup lock at all times unless we're sleeping self.wakeup.acquire() # Set validation success flag to false self.checksuccess = False # Start device response listener thread self.listenerthread = Thread(None, self._listener, self.settings.name + "_listener") self.listenerthread.daemon = True self.listenerthread.start() # Send validation job to device job = ValidationJob( self.core, unhexlify( b"00000001c3bf95208a646ee98a58cf97c3a0c4b7bf5de4c89ca04495000005200000000024d1fff8d5d73ae11140e4e48032cd88ee01d48c67147f9a09cd41fdec2e25824f5c038d1a0b350c5eb01f04" )) self._sendjob(job) # Wait for validation job to be accepted by the device self.wakeup.wait(1) # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # Honor shutdown flag if self.shutdown: break # If the job that was enqueued above has not been moved from nextjob to job by the # listener thread yet, something went wrong. Throw an exception to make everything restart. if self.nextjob != None: raise Exception("Timeout waiting for job ACK") # Wait for the validation job to complete. The wakeup flag will be set by the listener # thread when the validation job completes. 60 seconds should be sufficient for devices # down to about 1.3MH/s, for slower devices this timeout will need to be increased. self.wakeup.wait(60) # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # Honor shutdown flag if self.shutdown: break # We woke up, but the validation job hasn't succeeded in the mean time. # This usually means that the wakeup timeout has expired. if not self.checksuccess: raise Exception( "Timeout waiting for validation job to finish") # self.stats.mhps has now been populated by the listener thread self.core.log( self.settings.name + ": Running at %f MH/s\n" % self.stats.mhps, 300, "B") # Calculate the time that the device will need to process 2**32 nonces. # This is limited at 60 seconds in order to have some regular communication, # even with very slow devices (and e.g. detect if the device was unplugged). interval = min(60, 2**32 / 1000000. / self.stats.mhps) # Add some safety margin and take user's interval setting (if present) into account. self.jobinterval = min(self.settings.jobinterval, max(0.5, interval * 0.8 - 1)) self.core.log( self.settings.name + ": Job interval: %f seconds\n" % self.jobinterval, 400, "B") # Tell the MPBM core that our hash rate has changed, so that it can adjust its work buffer. self.jobspersecond = 1. / self.jobinterval self.core.notify_speed_changed(self) # Main loop, continues until something goes wrong or we're shutting down. while not self.shutdown: # Fetch a job, add 2 seconds safety margin to the requested minimum expiration time. # Blocks until one is available. Because of this we need to release the # wakeup lock temporarily in order to avoid possible deadlocks. self.wakeup.release() job = self.core.get_job(self, self.jobinterval + 2) self.wakeup.acquire() # If a new block was found while we were fetching that job, just discard it and get a new one. if job.canceled: job.destroy() continue # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # Upload the job to the device self._sendjob(job) # Wait for up to one second for the device to accept it self.wakeup.wait(1) # Honor shutdown flag if self.shutdown: break # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # If the job that was send above has not been moved from nextjob to job by the listener # thread yet, something went wrong. Throw an exception to make everything restart. if self.nextjob != None: raise Exception("Timeout waiting for job ACK") # If the job was already caught by a long poll while we were uploading it, # jump back to the beginning of the main loop in order to immediately fetch new work. # Don't check for the canceled flag before the job was accepted by the device, # otherwise we might get out of sync. if self.job.canceled: continue # Wait while the device is processing the job. If nonces are sent by the device, they # will be processed by the listener thread. If the job gets canceled, we will be woken up. self.wakeup.wait(self.jobinterval) # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # If something went wrong... except Exception as e: # ...complain about it! self.core.log( self.settings.name + ": %s\n" % traceback.format_exc(), 100, "rB") # Make sure that the listener thread realizes that something went wrong self.error = e finally: # We're not doing productive work any more, update stats and destroy current job self._jobend() self.stats.mhps = 0 # Release the wake lock to allow the listener thread to move. Ignore it if that goes wrong. try: self.wakeup.release() except: pass # Close the serial port handle, otherwise we can't reopen it after restarting. # This should hopefully also make reads on that port from the listener thread fail, # so that the listener thread will realize that it's supposed to shut down. try: self.handle.close() except: pass # Wait for the listener thread to terminate. # If it doens't within 5 seconds, continue anyway. We can't do much about that. try: self.listenerthread.join(5) except: pass # Set MH/s to zero again, the listener thread might have overwritten that. self.stats.mhps = 0 # If we aren't shutting down, figure out if there have been many errors recently, # and if yes, wait a bit longer until restarting the worker. if not self.shutdown: tries += 1 if time.time() - starttime >= 300: tries = 0 with self.wakeup: if tries > 5: self.wakeup.wait(30) else: self.wakeup.wait(1)
def main(self): # If we're currently shutting down, just die. If not, loop forever, # to recover from possible errors caught by the huge try statement inside this loop. # Count how often the except for that try was hit recently. This will be reset if # there was no exception for at least 5 minutes since the last one. tries = 0 while not self.shutdown: try: # Record our starting timestamp, in order to back off if we repeatedly die starttime = time.time() # Exception container: If an exception occurs in the listener thread, the listener thread # will store it here and terminate, and the main thread will rethrow it and then restart. self.error = None self.hasheswithoutshare = 0 # Initialize megahashes per second to zero, will be measured later. self.stats.mhps = 0 self.offset = 0 # Initialize clocking tracking data self.speed = 0 self.recentshares = 0 self.recentinvalid = 0 # Job that the device is currently working on, or that is currently being uploaded. # This variable is used by BaseWorker to figure out the current work source for statistics. self.job = None # Job that was previously being procesed. Has been destroyed, but there might be some late nonces. self.oldjob = None # Open the serial port import serial self.handle = serial.Serial(self.port, self.baudrate, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, 1, False, False, 5, False, None) # We keep control of the wakeup lock at all times unless we're sleeping self.wakeup.acquire() # Set validation success flag to false self.checksuccess = False # Start device response listener thread self.listenerthread = Thread(None, self._listener, self.settings.name + "_listener") self.listenerthread.daemon = True self.listenerthread.start() # Configure core clock self.initialramp = True self._set_speed(self.settings.initialspeed // 2.5) # Send validation job to device job = ValidationJob( self.core, unhexlify( b"00000001c3bf95208a646ee98a58cf97c3a0c4b7bf5de4c89ca04495000005200000000024d1fff8d5d73ae11140e4e48032cd88ee01d48c67147f9a09cd41fdec2e25824f5c038d1a0b350c5eb01f04" )) self._sendjob(job) # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # Wait for the validation job to complete. The wakeup flag will be set by the listener # thread when the validation job completes. 60 seconds should be sufficient for devices # down to about 2.6MH/s, for slower devices this timeout will need to be increased. self.wakeup.wait(60) # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # Honor shutdown flag if self.shutdown: break # We woke up, but the validation job hasn't succeeded in the mean time. # This usually means that the wakeup timeout has expired. if not self.checksuccess: raise Exception( "Timeout waiting for validation job to finish") # Main loop, continues until something goes wrong or we're shutting down. while not self.shutdown: # Fetch a job, add 2 seconds safety margin to the requested minimum expiration time. # Blocks until one is available. Because of this we need to release the # wakeup lock temporarily in order to avoid possible deadlocks. self.wakeup.release() job = self.core.get_job(self, self.jobinterval + 2) self.wakeup.acquire() # If the job could be interpreted as a command, ignore it. if job.data[68:72] == unhexlify(b"ffffffff"): job.destroy() continue # Go through the safety checks and adjust the clock if necessary self.safetycheck() # If a new block was found while we were fetching this job, just discard it and get a new one. if job.canceled: job.destroy() continue # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # Upload the job to the device self._sendjob(job) # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # If the job was already caught by a long poll while we were uploading it, # jump back to the beginning of the main loop in order to immediately fetch new work. # Don't check for the canceled flag before the job was accepted by the device, # otherwise we might get out of sync. if self.job.canceled: continue # Wait while the device is processing the job. If nonces are sent by the device, they # will be processed by the listener thread. If the job gets canceled, we will be woken up. self.wakeup.wait(self.jobinterval) # If an exception occurred in the listener thread, rethrow it if self.error != None: raise self.error # If something went wrong... except Exception as e: # ...complain about it! self.core.log(self, "%s\n" % traceback.format_exc(), 100, "rB") # Make sure that the listener thread realizes that something went wrong self.error = e finally: # We're not doing productive work any more, update stats and destroy current job self._jobend() self.stats.mhps = 0 # Release the wake lock to allow the listener thread to move. Ignore it if that goes wrong. try: self.wakeup.release() except: pass # Close the serial port handle, otherwise we can't reopen it after restarting. # This should hopefully also make reads on that port from the listener thread fail, # so that the listener thread will realize that it's supposed to shut down. try: self.handle.close() except: pass # Wait for the listener thread to terminate. # If it doens't within 5 seconds, continue anyway. We can't do much about that. try: self.listenerthread.join(5) except: pass # Set MH/s to zero again, the listener thread might have overwritten that. self.stats.mhps = 0 # If we aren't shutting down, figure out if there have been many errors recently, # and if yes, wait a bit longer until restarting the worker. if not self.shutdown: tries += 1 if time.time() - starttime >= 300: tries = 0 with self.wakeup: if tries > 5: self.wakeup.wait(30) else: self.wakeup.wait(1)