From 464a86a7c63bce661d8f63573e57368a14f602d3 Mon Sep 17 00:00:00 2001 From: Forrest Voight Date: Thu, 15 Dec 2011 08:25:59 -0500 Subject: [PATCH] made FloatingInteger usage explicit --- p2pool/bitcoin/data.py | 71 ++++++++++++-------------------------- p2pool/bitcoin/getwork.py | 10 +++--- p2pool/data.py | 26 +++++++------- p2pool/main.py | 21 +++++------ p2pool/test/bitcoin/test_data.py | 2 +- 5 files changed, 51 insertions(+), 79 deletions(-) diff --git a/p2pool/bitcoin/data.py b/p2pool/bitcoin/data.py index c8d9743..2c2b629 100644 --- a/p2pool/bitcoin/data.py +++ b/p2pool/bitcoin/data.py @@ -322,7 +322,7 @@ class ChecksummedType(Type): return (file, data), hashlib.sha256(hashlib.sha256(data).digest()).digest()[:4] class FloatingInteger(object): - __slots__ = ['_bits'] + __slots__ = ['bits', '_target'] @classmethod def from_target_upper_bound(cls, target): @@ -333,60 +333,33 @@ class FloatingInteger(object): bits = struct.unpack('> 24) - 3)) + def target(self): + res = self._target + if res is None: + res = self._target = math.shift_left(self.bits & 0x00ffffff, 8 * ((self.bits >> 24) - 3)) + return res def __hash__(self): - return hash(self._value) + return hash(self.bits) - def __cmp__(self, other): - if isinstance(other, FloatingInteger): - return cmp(self._value, other._value) - elif isinstance(other, (int, long)): - return cmp(self._value, other) - else: - raise NotImplementedError(other) + def __eq__(self, other): + return self.bits == other.bits - def __int__(self): - return self._value + def __ne__(self, other): + return not (self == other) + + def __cmp__(self, other): + assert False def __repr__(self): - return 'FloatingInteger(bits=%s, value=%s)' % (hex(self._bits), hex(self._value)) - - def __add__(self, other): - if isinstance(other, (int, long)): - return self._value + other - raise NotImplementedError() - __radd__ = __add__ - def __mul__(self, other): - if isinstance(other, (int, long)): - return self._value * other - raise NotImplementedError() - __rmul__ = __mul__ - def __truediv__(self, other): - if isinstance(other, (int, long)): - return self._value / other - raise NotImplementedError() - def __floordiv__(self, other): - if isinstance(other, (int, long)): - return self._value // other - raise NotImplementedError() - __div__ = __truediv__ - def __rtruediv__(self, other): - if isinstance(other, (int, long)): - return other / self._value - raise NotImplementedError() - def __rfloordiv__(self, other): - if isinstance(other, (int, long)): - return other // self._value - raise NotImplementedError() - __rdiv__ = __rtruediv__ + return 'FloatingInteger(bits=%s, target=%s)' % (hex(self.bits), hex(self.target)) class FloatingIntegerType(Type): _inner = StructType(' res.header['target']): + if not (res.pow_hash > res.header['bits'].target): raise ValueError('invalid share type') return res elif share['type'] == 1: res = cls.from_share1b(share1b_type.unpack(share['contents']), net) - if not (res.pow_hash <= res.header['target']): + if not (res.pow_hash <= res.header['bits'].target): raise ValueError('invalid share type') return res else: @@ -96,7 +96,7 @@ class Share(object): self.merkle_branch = merkle_branch self.share_data = self.share_info['share_data'] - self.target = self.share_info['target'] + self.target = self.share_info['bits'].target self.timestamp = self.share_info['timestamp'] self.new_script = self.share_data['new_script'] @@ -127,7 +127,7 @@ class Share(object): self.stale_frac = self.share_data['stale_frac']/254 if self.share_data['stale_frac'] != 255 else None - self.other_txs = other_txs if self.pow_hash <= self.header['target'] else None + self.other_txs = other_txs if self.pow_hash <= self.header['bits'].target else None # XXX eww self.time_seen = time.time() @@ -140,7 +140,7 @@ class Share(object): if script.get_sigop_count(self.new_script) > 1: raise ValueError('too many sigops!') - share_info, gentx = generate_transaction(tracker, self.share_info['share_data'], self.header['target'], self.share_info['timestamp'], self.net) + share_info, gentx = generate_transaction(tracker, self.share_info['share_data'], self.header['bits'].target, self.share_info['timestamp'], self.net) if share_info != self.share_info: raise ValueError('share difficulty invalid') @@ -148,9 +148,9 @@ class Share(object): raise ValueError('''gentx doesn't match header via merkle_branch''') def as_share(self): - if self.pow_hash > self.header['target']: # share1a + if self.pow_hash > self.header['bits'].target: # share1a return dict(type=0, contents=share1a_type.pack(self.as_share1a())) - elif self.pow_hash <= self.header['target']: # share1b + elif self.pow_hash <= self.header['bits'].target: # share1b return dict(type=1, contents=share1b_type.pack(self.as_share1b())) else: raise AssertionError() @@ -168,7 +168,7 @@ class Share(object): if self.other_txs is None: raise ValueError('share does not contain all txs') - share_info, gentx = generate_transaction(tracker, self.share_info['share_data'], self.header['target'], self.share_info['timestamp'], self.net) + share_info, gentx = generate_transaction(tracker, self.share_info['share_data'], self.header['bits'].target, self.share_info['timestamp'], self.net) assert share_info == self.share_info return dict(header=self.header, txs=[gentx] + self.other_txs) @@ -199,18 +199,18 @@ def generate_transaction(tracker, share_data, block_target, desired_timestamp, n height, last = tracker.get_height_and_last(previous_share_hash) assert height >= chain_length or last is None if height < net.TARGET_LOOKBEHIND: - target = bitcoin_data.FloatingInteger.from_target_upper_bound(net.MAX_TARGET) + bits = bitcoin_data.FloatingInteger.from_target_upper_bound(net.MAX_TARGET) else: attempts_per_second = get_pool_attempts_per_second(tracker, previous_share_hash, net.TARGET_LOOKBEHIND) pre_target = 2**256//(net.SHARE_PERIOD*attempts_per_second) - 1 pre_target2 = math.clip(pre_target, (previous_share.target*9//10, previous_share.target*11//10)) pre_target3 = math.clip(pre_target2, (0, net.MAX_TARGET)) - target = bitcoin_data.FloatingInteger.from_target_upper_bound(pre_target3) + bits = bitcoin_data.FloatingInteger.from_target_upper_bound(pre_target3) attempts_to_block = bitcoin_data.target_to_average_attempts(block_target) max_att = net.SPREAD * attempts_to_block - this_att = min(bitcoin_data.target_to_average_attempts(target), max_att) + this_att = min(bitcoin_data.target_to_average_attempts(bits.target), max_att) other_weights, other_total_weight, other_donation_weight = tracker.get_cumulative_weights(previous_share_hash, min(height, chain_length), 65535*max(0, max_att - this_att)) assert other_total_weight == sum(other_weights.itervalues()) + other_donation_weight, (other_total_weight, sum(other_weights.itervalues()) + other_donation_weight) weights, total_weight, donation_weight = math.add_dicts({new_script: this_att*(65535-donation)}, other_weights), this_att*65535 + other_total_weight, this_att*donation + other_donation_weight @@ -234,7 +234,7 @@ def generate_transaction(tracker, share_data, block_target, desired_timestamp, n share_info = dict( share_data=share_data, - target=target, + bits=bits, timestamp=math.clip(desired_timestamp, (previous_share.timestamp - 60, previous_share.timestamp + 60)) if previous_share is not None else desired_timestamp, ) diff --git a/p2pool/main.py b/p2pool/main.py index db8fde7..75c1896 100644 --- a/p2pool/main.py +++ b/p2pool/main.py @@ -36,7 +36,7 @@ def getwork(bitcoind): transactions=[bitcoin_data.tx_type.unpack(x.decode('hex')) for x in work['transactions']], subsidy=work['coinbasevalue'], time=work['time'], - target=bitcoin_data.FloatingIntegerType().unpack(work['bits'].decode('hex')[::-1]) if isinstance(work['bits'], (str, unicode)) else bitcoin_data.FloatingInteger(work['bits']), + bits=bitcoin_data.FloatingIntegerType().unpack(work['bits'].decode('hex')[::-1]) if isinstance(work['bits'], (str, unicode)) else bitcoin_data.FloatingInteger(work['bits']), )) @deferral.retry('Error creating payout script:', 10) @@ -152,7 +152,7 @@ def main(args, net, datadir_path): pre_current_work.set(dict( version=work['version'], previous_block=work['previous_block_hash'], - target=work['target'], + bits=work['bits'], )) def set_real_work2(): @@ -247,7 +247,7 @@ def main(args, net, datadir_path): @tracker.verified.added.watch def _(share): - if share.pow_hash <= share.header['target']: + if share.pow_hash <= share.header['bits'].target: if factory.conn.value is not None: factory.conn.value.send_block(block=share.as_block(tracker)) else: @@ -442,14 +442,14 @@ def main(args, net, datadir_path): 255 if shares == 0 else math.perfect_round(254*stales/shares) )(*get_share_counts()), ), - block_target=state['target'], + block_target=state['bits'].target, desired_timestamp=int(time.time() - current_work2.value['clock_offset']), net=net, ) print 'New work for worker %s! Difficulty: %.06f Payout if block: %.6f %s Total block value: %.6f %s including %i transactions' % ( user, - bitcoin_data.target_to_difficulty(share_info['target']), + bitcoin_data.target_to_difficulty(share_info['bits'].target), (sum(t['value'] for t in generate_tx['tx_outs'] if t['script'] == payout_script) - subsidy//200)*1e-8, net.BITCOIN_SYMBOL, subsidy*1e-8, net.BITCOIN_SYMBOL, len(current_work2.value['transactions']), @@ -459,7 +459,7 @@ def main(args, net, datadir_path): merkle_root = bitcoin_data.merkle_hash(map(bitcoin_data.tx_type.hash256, transactions)) merkle_root_to_transactions[merkle_root] = share_info, transactions, time.time() - return bitcoin_getwork.BlockAttempt(state['version'], state['previous_block'], merkle_root, current_work2.value['time'], state['target'], share_info['target']), state['best_share_hash'] + return bitcoin_getwork.BlockAttempt(state['version'], state['previous_block'], merkle_root, current_work2.value['time'], state['bits'], share_info['bits'].target), state['best_share_hash'] my_shares = set() doa_shares = set() @@ -478,12 +478,12 @@ def main(args, net, datadir_path): pow_hash = net.BITCOIN_POW_FUNC(header) - if pow_hash <= header['target'] or p2pool.DEBUG: + if pow_hash <= header['bits'].target or p2pool.DEBUG: if factory.conn.value is not None: factory.conn.value.send_block(block=dict(header=header, txs=transactions)) else: print 'No bitcoind connection! Erp!' - if pow_hash <= header['target']: + if pow_hash <= header['bits'].target: print print 'GOT BLOCK! Passing to bitcoind! bitcoin: %x' % (hash_,) print @@ -511,9 +511,8 @@ def main(args, net, datadir_path): except: log.err(None, 'Error while processing merged mining POW:') - target = share_info['target'] - if pow_hash > target: - print 'Worker submitted share with hash > target:\nhash : %x\ntarget: %x' % (pow_hash, target) + if pow_hash > share_info['bits'].target: + print 'Worker submitted share with hash > target:\nhash : %x\ntarget: %x' % (pow_hash, share_info['bits'].target) return False share = p2pool_data.Share(net, header, share_info, other_txs=transactions[1:]) my_shares.add(share.hash) diff --git a/p2pool/test/bitcoin/test_data.py b/p2pool/test/bitcoin/test_data.py index a005518..a29c965 100644 --- a/p2pool/test/bitcoin/test_data.py +++ b/p2pool/test/bitcoin/test_data.py @@ -10,7 +10,7 @@ class Test(unittest.TestCase): previous_block=0x000000000000038a2a86b72387f93c51298298a732079b3b686df3603d2f6282, merkle_root=0x37a43a3b812e4eb665975f46393b4360008824aab180f27d642de8c28073bc44, timestamp=1323752685, - target=data.FloatingInteger(437159528), + bits=data.FloatingInteger(437159528), nonce=3658685446, )) == 0x000000000000003aaaf7638f9f9c0d0c60e8b0eb817dcdb55fd2b1964efc5175 -- 1.7.1