--- /dev/null
+from stratum import settings
+
+import stratum.logger
+log = stratum.logger.get_logger('BasicShareLimiter')
+
+import DBInterface
+dbi = DBInterface.DBInterface()
+dbi.clear_worker_diff()
+
+from twisted.internet import defer
+from mining.interfaces import Interfaces
+import time
+
+''' This is just a customized ring buffer '''
+class SpeedBuffer:
+ def __init__(self, size_max):
+ self.max = size_max
+ self.data = []
+ self.cur = 0
+ def append(self, x):
+ self.data.append(x)
+ self.cur += 1
+ if len(self.data) == self.max:
+ self.cur = 0
+ self.__class__ = SpeedBufferFull
+ def avg(self):
+ return sum(self.data) / self.cur
+ def pos(self):
+ return self.cur
+ def clear(self):
+ self.data = []
+ self.cur = 0
+ def size(self):
+ return self.cur
+
+class SpeedBufferFull:
+ def __init__(self, n):
+ raise "you should use SpeedBuffer"
+ def append(self, x):
+ self.data[self.cur] = x
+ self.cur = (self.cur + 1) % self.max
+ def avg(self):
+ return sum(self.data) / self.max
+ def pos(self):
+ return self.cur
+ def clear(self):
+ self.data = []
+ self.cur = 0
+ self.__class__ = SpeedBuffer
+ def size(self):
+ return self.max
+
+class BasicShareLimiter(object):
+ def __init__(self):
+ self.worker_stats = {}
+ self.target = settings.VDIFF_TARGET
+ self.retarget = settings.VDIFF_RETARGET
+ self.variance = self.target * (float(settings.VDIFF_VARIANCE_PERCENT) / float(100))
+ self.tmin = self.target - self.variance
+ self.tmax = self.target + self.variance
+ self.buffersize = self.retarget / self.target * 4
+ # TODO: trim the hash of inactive workers
+
+ def submit(self, connection_ref, job_id, current_difficulty, timestamp, worker_name):
+ ts = int(timestamp)
+ # Init the stats for this worker if it isn't set.
+ if worker_name not in self.worker_stats or self.worker_stats[worker_name]['last_ts'] < ts - settings.DB_USERCACHE_TIME :
+ self.worker_stats[worker_name] = {'last_rtc': (ts - self.retarget / 2), 'last_ts': ts, 'buffer': SpeedBuffer(self.buffersize) }
+ dbi.update_worker_diff(worker_name, settings.POOL_TARGET)
+ return
+
+ # Standard share update of data
+ self.worker_stats[worker_name]['buffer'].append(ts - self.worker_stats[worker_name]['last_ts'])
+ self.worker_stats[worker_name]['last_ts'] = ts
+ # Do We retarget? If not, we're done.
+ if ts - self.worker_stats[worker_name]['last_rtc'] < self.retarget and self.worker_stats[worker_name]['buffer'].size() > 0:
+ return
+
+ # Set up and log our check
+ self.worker_stats[worker_name]['last_rtc'] = ts
+ avg = self.worker_stats[worker_name]['buffer'].avg()
+ log.info("Checking Retarget for %s (%i) avg. %i target %i+-%i" % (worker_name, current_difficulty, avg,
+ self.target, self.variance))
+ if avg < 1:
+ log.info("Reseting avg = 1 since it's SOOO low")
+ avg = 1
+
+ # Figure out our Delta-Diff
+ ddiff = int((float(current_difficulty) * (float(self.target) / float(avg))) - current_difficulty)
+ if (avg > self.tmax and current_difficulty > settings.POOL_TARGET):
+ # For fractional -0.1 ddiff's just drop by 1
+ if ddiff > -1:
+ ddiff = -1
+ # Don't drop below POOL_TARGET
+ if (ddiff + current_difficulty) < settings.POOL_TARGET:
+ ddiff = settings.POOL_TARGET - current_difficulty
+ elif avg < self.tmin:
+ # For fractional 0.1 ddiff's just up by 1
+ if ddiff < 1:
+ ddiff = 1
+ # Don't go above BITCOIN_DIFF
+ # TODO
+ else: # If we are here, then we should not be retargeting.
+ return
+
+ # At this point we are retargeting this worker
+ new_diff = current_difficulty + ddiff
+ log.info("Retarget for %s %i old: %i new: %i" % (worker_name, ddiff, current_difficulty, new_diff))
+
+ self.worker_stats[worker_name]['buffer'].clear()
+ session = connection_ref().get_session()
+ session['prev_diff'] = session['difficulty']
+ session['prev_jobid'] = job_id
+ session['difficulty'] = new_diff
+ connection_ref().rpc('mining.set_difficulty', [new_diff, ], is_notification=True)
+ dbi.update_worker_diff(worker_name, new_diff)
+