예제 #1
0
 def getwork(self):
     conn = http_client.HTTPConnection(self.host, self.port, True,
                                       self.getworktimeout)
     req = json.dumps({
         "method": "getwork",
         "params": [],
         "id": 0
     }).encode("utf_8")
     headers = {
         "User-Agent": self.useragent,
         "Content-type": "application/json",
         "Content-Length": len(req)
     }
     if self.auth != None: headers["Authorization"] = self.auth
     conn.request("POST", self.path, req, headers)
     response = conn.getresponse()
     with self.statlock:
         if not self.longpolling:
             self.longpolling = False
             headers = response.getheaders()
             for h in headers:
                 if h[0].lower() == "x-long-polling":
                     url = h[1]
                     try:
                         if url[0] == "/":
                             url = "http://" + self.host + ":" + str(
                                 self.port) + url
                         if url[:7] != "http://":
                             raise Exception("Long poll URL isn't HTTP!")
                         parts = url[7:].split("/", 1)
                         if len(parts) == 2: path = "/" + parts[1]
                         else: path = "/"
                         parts = parts[0].split(":")
                         if len(parts) != 2:
                             raise Exception(
                                 "Long poll URL contains host but no port!")
                         host = parts[0]
                         port = parts[1]
                         self.miner.log(
                             "Found long polling URL for %s: %s\n" %
                             (self.name, url), "g")
                         self.longpolling = True
                         self.longpollingthread = threading.Thread(
                             None, self.longpollingworker,
                             self.name + "_longpolling", (host, port, path))
                         self.longpollingthread.daemon = True
                         self.longpollingthread.start()
                     except:
                         self.miner.log(
                             "Invalid long polling URL for %s: %s\n" %
                             (self.name, url), "y")
                     break
     response = json.loads(response.read().decode("utf_8"))
     state = binascii.unhexlify(
         response["result"]["midstate"].encode("ascii"))
     data = binascii.unhexlify(response["result"]["data"].encode("ascii"))
     target = binascii.unhexlify(
         response["result"]["target"].encode("ascii"))
     return common.Job(self.miner, self, self.longpollepoch, state, data,
                       target)
예제 #2
0
 def longpollingworker(self, host, port, path):
     while True:
         try:
             conn = http_client.HTTPConnection(host, port, True,
                                               self.longpolltimeout)
             headers = {"User-Agent": self.useragent}
             if self.auth != None: headers["Authorization"] = self.auth
             conn.request("GET", path, None, headers)
             data = conn.getresponse().read().decode("utf_8")
             response = json.loads(data)
             state = binascii.unhexlify(
                 response["result"]["midstate"].encode("ascii"))
             data = binascii.unhexlify(
                 response["result"]["data"].encode("ascii"))
             target = binascii.unhexlify(
                 response["result"]["target"].encode("ascii"))
             job = common.Job(self.miner, self, self.longpollepoch, state,
                              data, target)
             self.miner.newblock(job)
         except Exception as e:
             self.miner.log("%s long poll failed: %s\n" % (self.name, e),
                            "y")
             time.sleep(3)
             pass
    def main(self):

        # Loop forever. If anything fails, restart threads.
        while True:
            try:

                # 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.mhps = 0

                # Job that the device is currently working on (found nonces are coming from this one).
                self.job = None

                # Job that is currently being uploaded to the device but not yet being processed.
                self.nextjob = None

                # Get handle for the serial port
                self.handle = serial.Serial(self.port, self.baudrate,
                                            serial.EIGHTBITS,
                                            serial.PARITY_NONE,
                                            serial.STOPBITS_ONE, 1, False,
                                            False, None, 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
                # Initialize job cancellation (long poll) flag to false
                self.canceled = False

                # Start device response listener thread
                self.listenerthread = threading.Thread(None, self.listener,
                                                       self.name + "_listener")
                self.listenerthread.daemon = True
                self.listenerthread.start()

                # Send validation job to device
                job = common.Job(
                    self.miner, None, None,
                    binascii.unhexlify(
                        b"1625cbf1a5bc6ba648d1218441389e00a9dc79768a2fc6f2b79c70cf576febd0"
                    ), b"\0" * 64 +
                    binascii.unhexlify(b"4c0afa494de837d81a269421"), None,
                    binascii.unhexlify(b"7bc2b302"))
                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 1520KH/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
                # 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.mhps has now been populated by the listener thread
                self.miner.log(
                    self.name + ": Running at %f MH/s\n" % self.mhps, "B")
                # Calculate the time that the device will need to process 2**32 nonces.
                # This is limited at 30 seconds so that new transactions can be included into the block
                # by the work source. (Requirement of the bitcoin protocol and enforced by most pools.)
                interval = min(30, 2**32 / 1000000. / self.mhps)
                # Add some safety margin and take user's interval setting (if present) into account.
                self.jobinterval = min(self.jobinterval,
                                       max(0.5, interval * 0.8 - 1))
                self.miner.log(
                    self.name +
                    ": Job interval: %f seconds\n" % self.jobinterval, "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.miner.updatehashrate(self)

                # Main loop, continues until something goes wrong.
                while True:

                    # Fetch a job. Blocks until one is available. Because of this we need to release the
                    # wake lock temporarily in order to avoid possible deadlocks.
                    self.canceled = False
                    self.wakeup.release()
                    job = self.miner.getjob(self)
                    # Doesn't need acquisition of the statlock because we're the only one who modifies this.
                    self.jobsaccepted = self.jobsaccepted + 1
                    self.wakeup.acquire()

                    # If a new block was found while we were fetching that job,
                    # check the long poll epoch to verify that the work that we got isn't stale.
                    # If it is, just discard it and get a new one.
                    if self.canceled == True:
                        if job.longpollepoch != job.pool.blockchain.longpollepoch:
                            continue
                    self.canceled = False

                    # If an exception occurred in the listener thread, rethrow it
                    if self.error != None: raise self.error

                    # Upload the piece of work 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 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.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 a long poll comes in, 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.miner.log(self.name + ": %s\n" % e, "rB")
                # Make sure that the listener thread realizes that something went wrong
                self.error = e
                # We're not doing productive work any more, update stats
                self.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
                # Wait for the listener thread to terminate.
                # If it doens't within 10 seconds, continue anyway. We can't do much about that.
                try:
                    self.listenerthread.join(10)
                except:
                    pass
                # Set MH/s to zero again, the listener thread might have overwritten that.
                self.mhps = 0
                # Make sure that the RS232 interface handle is closed,
                # otherwise we can't reopen it after restarting.
                try:
                    self.handle.close()
                except:
                    pass
                # Wait for a second to avoid 100% CPU load if something fails reproducibly
                time.sleep(1)
예제 #4
0
    def main(self):

        # Make sure the FPGA is put to sleep when MPBM exits
        #atexit.register(self.fpga.sleep)

        # Loop forever. If anything fails, restart.
        while True:
            try:

                # 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.mhps = 0

                # Job that the device is currently working on (found nonces are coming from this one).
                self.job = None

                # Job that is currently being uploaded to the device but not yet being processed.
                self.nextjob = 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
                # Set validation job second iteration flag to false
                self.seconditeration = False
                # Initialize job cancellation (long poll) flag to false
                self.canceled = False

                # Initialize hash rate tracking data
                self.lasttime = None
                self.lastnonce = None

                if self.firmware_rev > 0:
                    self.miner.log(
                        self.name + ": Setting clock speed to %d MHz...\n" %
                        self.clockspeed, "B")
                    self.fpga.setClockSpeed(self.clockspeed)
                    if self.fpga.readClockSpeed() != self.clockspeed:
                        self.miner.log(
                            self.name +
                            ": ERROR: Setting clock speed failed!\n", "rB")
                        # TODO: Raise an exception and shutdown the FPGA
                    self.mhps = self.clockspeed * 1  # this coefficient is the hashes per clock, change this when that increases :)

                # Clear FPGA's nonce queue
                self.fpga.clearQueue()

                # Start device response listener thread
                self.listenerthread = threading.Thread(None, self.listener,
                                                       self.name + "_listener")
                self.listenerthread.daemon = True
                self.listenerthread.start()

                # Send validation job to device
                self.miner.log(
                    self.name + ": Verifying correct operation...\n", "B")
                job = common.Job( \
                  miner = self.miner, \
                  pool = None, \
                  longpollepoch = None, \
                  state = binascii.unhexlify(b"5517a3f06a2469f73025b60444e018e61ff2c557ea403ccf3b9c5445dd353710"), \
                  data = b"\0" * 64 + binascii.unhexlify(b"42490d634f2c87761a0cd43f"), \
                  target = None, \
                  check = binascii.unhexlify(b"8fa95303") \
                )
                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. 180 seconds should be sufficient for devices
                # down to about 50MH/s, for slower devices this timeout will need to be increased.
                if self.firmware_rev > 0:
                    interval = (2**32 / 1000000. / self.mhps) * 1.1
                    self.wakeup.wait(interval)
                else:
                    self.wakeup.wait(180)
                # If an exception occurred in the listener thread, rethrow it
                if self.error != None: raise self.error
                # 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.mhps has now been populated by the listener thread
                self.miner.log(
                    self.name + ": Running at %f MH/s\n" % self.mhps, "B")
                # Calculate the time that the device will need to process 2**32 nonces.
                # This is limited at 30 seconds so that new transactions can be included into the block
                # by the work source. (Requirement of the bitcoin protocol and enforced by most pools.)
                interval = min(30, 2**32 / 1000000. / self.mhps)
                # Add some safety margin and take user's interval setting (if present) into account.
                self.jobinterval = min(self.jobinterval,
                                       max(0.5, interval * 0.8 - 1))
                self.miner.log(
                    self.name +
                    ": Job interval: %f seconds\n" % self.jobinterval, "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.miner.updatehashrate(self)

                # Main loop, continues until something goes wrong.
                while True:

                    # Fetch a job. Blocks until one is available. Because of this we need to release the
                    # wake lock temporarily in order to avoid possible deadlocks.
                    self.canceled = False
                    self.wakeup.release()
                    job = self.miner.getjob(self)
                    # Doesn't need acquisition of the statlock because we're the only one who modifies this.
                    self.jobsaccepted = self.jobsaccepted + 1
                    self.wakeup.acquire()

                    # If a new block was found while we were fetching that job,
                    # check the long poll epoch to verify that the work that we got isn't stale.
                    # If it is, just discard it and get a new one.
                    if self.canceled == True:
                        if job.longpollepoch != job.pool.blockchain.longpollepoch:
                            continue
                    self.canceled = False

                    # If an exception occurred in the listener thread, rethrow it
                    if self.error != None: raise self.error

                    # Upload the piece of work to the device
                    self.sendjob(job)

                    # Go through the safety checks and reduce the clock if necessary
                    self.safetycheck()

                    # 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.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 a long poll comes in, 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.miner.log(self.name + ": %s\n" % e, "rB")
                # Make sure that the listener thread realizes that something went wrong
                self.error = e
                # We're not doing productive work any more, update stats
                self.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
                if self.parent.hotplug:
                    for child in self.parent.children:
                        child.error = Exception(
                            "Sibling FPGA worker died, restarting board")
                    try:
                        self.parent.device.close()
                    except:
                        pass
                # Wait for the listener thread to terminate.
                # If it doens't within 10 seconds, continue anyway. We can't do much about that.
                try:
                    self.listenerthread.join(10)
                except:
                    pass
                # Set MH/s to zero again, the listener thread might have overwritten that.
                self.mhps = 0
                # Notify the hotplug manager about our death, so that it can respawn as neccessary
                if self.parent.hotplug:
                    self.parent.dead = True
                    return
                # Wait for a second to avoid 100% CPU load if something fails reproducibly
                time.sleep(1)