X-Git-Url: https://git.novaco.in/?p=stratum-mining.git;a=blobdiff_plain;f=mining%2Fbasic_share_limiter.py;fp=mining%2Fbasic_share_limiter.py;h=6893a12309a977b0b378efe85a966edfbbee7336;hp=0000000000000000000000000000000000000000;hb=1e5ed48cb8611adccaf854c4ba2c83c51cde832c;hpb=f91c94efe54a29de9af37412349df5ec7415089c diff --git a/mining/basic_share_limiter.py b/mining/basic_share_limiter.py new file mode 100644 index 0000000..6893a12 --- /dev/null +++ b/mining/basic_share_limiter.py @@ -0,0 +1,117 @@ +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) +