From: Forrest Voight Date: Fri, 28 Jun 2013 17:18:33 +0000 (-0400) Subject: modulate share difficulty to prevent any node from producing more than 5% of shares X-Git-Tag: 13.0~9 X-Git-Url: https://git.novaco.in/?p=p2pool.git;a=commitdiff_plain;h=819f0e3e3ab9460fe60606c3f1e9c562d40361c7 modulate share difficulty to prevent any node from producing more than 5% of shares --- diff --git a/p2pool/bitcoin/data.py b/p2pool/bitcoin/data.py index 8e4fa52..88e1730 100644 --- a/p2pool/bitcoin/data.py +++ b/p2pool/bitcoin/data.py @@ -219,6 +219,10 @@ def target_to_average_attempts(target): if target >= 2**256: warnings.warn('target >= 2**256!') return 2**256//(target + 1) +def average_attempts_to_target(average_attempts): + assert average_attempts > 0 + return min(int(2**256/average_attempts - 1 + 0.5), 2**256-1) + def target_to_difficulty(target): assert 0 <= target and isinstance(target, (int, long)), target if target >= 2**256: warnings.warn('target >= 2**256!') @@ -226,6 +230,7 @@ def target_to_difficulty(target): def difficulty_to_target(difficulty): assert difficulty >= 0 + if difficulty == 0: return 2**256-1 return min(int((0xffff0000 * 2**(256-64) + 1)/difficulty - 1 + 0.5), 2**256-1) # human addresses diff --git a/p2pool/test/test_node.py b/p2pool/test/test_node.py index f1f9bea..d1698bc 100644 --- a/p2pool/test/test_node.py +++ b/p2pool/test/test_node.py @@ -1,5 +1,6 @@ from __future__ import division +import base64 import random import tempfile @@ -185,7 +186,8 @@ class Test(unittest.TestCase): worker_interface.WorkerInterface(wb).attach_to(web_root) port = reactor.listenTCP(0, server.Site(web_root)) - proxy = jsonrpc.HTTPProxy('http://127.0.0.1:' + str(port.getHost().port)) + proxy = jsonrpc.HTTPProxy('http://127.0.0.1:' + str(port.getHost().port), + headers=dict(Authorization='Basic ' + base64.b64encode('user/0:password'))) yield deferral.sleep(3) @@ -227,7 +229,8 @@ class Test(unittest.TestCase): yield deferral.sleep(3) for i in xrange(SHARES): - proxy = jsonrpc.HTTPProxy('http://127.0.0.1:' + str(random.choice(nodes).web_port.getHost().port)) + proxy = jsonrpc.HTTPProxy('http://127.0.0.1:' + str(random.choice(nodes).web_port.getHost().port), + headers=dict(Authorization='Basic ' + base64.b64encode('user/0:password'))) blah = yield proxy.rpc_getwork() yield proxy.rpc_getwork(blah['data']) yield deferral.sleep(.05) diff --git a/p2pool/work.py b/p2pool/work.py index 40a1a30..346db56 100644 --- a/p2pool/work.py +++ b/p2pool/work.py @@ -142,18 +142,20 @@ class WorkerBridge(worker_interface.WorkerBridge): user, contents2 = contents[0], contents[1:] desired_pseudoshare_target = None - desired_share_target = 2**256 - 1 + desired_share_target = None for symbol, parameter in zip(contents2[::2], contents2[1::2]): if symbol == '+': try: desired_pseudoshare_target = bitcoin_data.difficulty_to_target(float(parameter)) except: - pass + if p2pool.DEBUG: + log.err() elif symbol == '/': try: desired_share_target = bitcoin_data.difficulty_to_target(float(parameter)) except: - pass + if p2pool.DEBUG: + log.err() if random.uniform(0, 100) < self.worker_fee: pubkey_hash = self.my_pubkey_hash @@ -169,6 +171,13 @@ class WorkerBridge(worker_interface.WorkerBridge): user, pubkey_hash, desired_share_target, desired_pseudoshare_target = self.get_user_details(user) return pubkey_hash, desired_share_target, desired_pseudoshare_target + def _estimate_local_hash_rate(self): + if len(self.recent_shares_ts_work) == 50: + hash_rate = sum(work for ts, work in self.recent_shares_ts_work[1:])//(self.recent_shares_ts_work[-1][0] - self.recent_shares_ts_work[0][0]) + if hash_rate: + return hash_rate + return None + def get_work(self, pubkey_hash, desired_share_target, desired_pseudoshare_target): if (self.node.p2p_node is None or len(self.node.p2p_node.peers) == 0) and self.node.net.PERSIST: raise jsonrpc.Error_for_code(-12345)(u'p2pool is not connected to any peers') @@ -212,6 +221,13 @@ class WorkerBridge(worker_interface.WorkerBridge): else: share_type = previous_share_type + if desired_share_target is None: + desired_share_target = 2**256-1 + local_hash_rate = self._estimate_local_hash_rate() + if local_hash_rate is not None: + desired_share_target = min(desired_share_target, + bitcoin_data.average_attempts_to_target(local_hash_rate * self.node.net.SHARE_PERIOD / 0.05)) # limit to 5% of pool shares by modulating share difficulty + if True: share_info, gentx, other_transaction_hashes, get_share = share_type.generate_transaction( tracker=self.node.tracker, @@ -249,10 +265,10 @@ class WorkerBridge(worker_interface.WorkerBridge): if desired_pseudoshare_target is None: target = 2**256-1 - if len(self.recent_shares_ts_work) == 50: - hash_rate = sum(work for ts, work in self.recent_shares_ts_work[1:])//(self.recent_shares_ts_work[-1][0] - self.recent_shares_ts_work[0][0]) - if hash_rate: - target = min(target, int(2**256/hash_rate)) + local_hash_rate = self._estimate_local_hash_rate() + if local_hash_rate is not None: + target = min(target, + bitcoin_data.average_attempts_to_target(local_hash_rate * 1)) # limit to 1 share response every second by modulating pseudoshare difficulty else: target = desired_pseudoshare_target target = max(target, share_info['bits'].target)