cleaned up anti-bitdust patch
authorForrest Voight <forrest@forre.st>
Tue, 10 Jan 2012 00:48:54 +0000 (19:48 -0500)
committerForrest Voight <forrest@forre.st>
Tue, 10 Jan 2012 00:48:54 +0000 (19:48 -0500)
p2pool/main.py
p2pool/util/math.py

index 14b037b..8fa6d49 100644 (file)
@@ -585,58 +585,51 @@ def main(args, net, datadir_path):
                 res[bitcoin_data.script2_to_human(script, net.PARENT)] = weights[script]/total_weight
             return json.dumps(res)
         
-        def get_current_txouts(scale=1e8):
+        def get_current_txouts():
             wb = WorkerBridge()
             tmp_tag = str(random.randrange(2**64))
             outputs = wb.merkle_root_to_transactions[wb.get_work(tmp_tag).merkle_root][1][0]['tx_outs']
             total = sum(out['value'] for out in outputs)
             total_without_tag = sum(out['value'] for out in outputs if out['script'] != tmp_tag)
-            total_diff = total-total_without_tag
-            return dict((out['script'], (out['value']+math.perfect_round(out['value']*total_diff/total))/scale) for out in outputs if out['script'] != tmp_tag and out['value'])
+            total_diff = total - total_without_tag
+            return dict((out['script'], out['value'] + math.perfect_round(out['value']*total_diff/total)) for out in outputs if out['script'] != tmp_tag and out['value'])
         
-        def get_current_scaled_txouts(scale=1e8,trunc=0):
-            txouts = get_current_txouts(scale=1)
+        def get_current_scaled_txouts(scale, trunc=0):
+            txouts = get_current_txouts()
             total = sum(txouts.itervalues())
-            results = dict((script, int(scale*value/total)) for script, value in txouts.iteritems())
-            if trunc>0:
-                total_random=0
-                random_set=set()
+            results = dict((script, value*scale//total) for script, value in txouts.iteritems())
+            if trunc > 0:
+                total_random = 0
+                random_set = set()
                 for s in sorted(results, key=results.__getitem__):
-                    value=results[s]
-                    total_random += value
+                    total_random += results[s]
                     random_set.add(s)
-                    if total_random>=trunc and value>=trunc:
+                    if total_random >= trunc and results[s] >= trunc:
                         break
-                target = random.randrange(0,total_random)
-                for s in random_set:
-                    if target<results[s]:
-                        break
-                    target = target - results[s]
-                results = dict((script,value) for script, value in results.iteritems() if script not in random_set)
-                results[s]=total_random
-            total = sum(results.itervalues())
-            total_diff = int(scale)-total
-            if total_diff>0:
-                target = random.randrange(0,total)
-                for s in results.keys():
-                    if target<results[s]:
-                        break
-                    target = target - results[s]
-                results[s] += total_diff
+                winner = math.weighted_choice((script, results[script]) for script in random_set)
+                for script in random_set:
+                    del results[script]
+                results[winner] = total_random
+            if sum(results.itervalues()) < int(scale):
+                results[math.weighted_choice(results.iteritems())] += int(scale) - sum(results.itervalues())
             return results
 
         def get_current_payouts():
-            return json.dumps(dict((bitcoin_data.script2_to_human(script, net.PARENT), value) for script, value in get_current_txouts().iteritems()))
+            return json.dumps(dict((bitcoin_data.script2_to_human(script, net.PARENT), value/1e8) for script, value in get_current_txouts().iteritems()))
         
-        def get_patron_sendmany(this='1'):
+        def get_patron_sendmany(this):
             try:
                 if '/' in this:
-                    this,trunc = this.split('/',1)
+                    this, trunc = this.split('/', 1)
                 else:
-                    trunc = 0.01
-                return json.dumps(dict((bitcoin_data.script2_to_address(script, net.PARENT), value/1e8) for script, value in get_current_scaled_txouts(scale=int(float(this)*1e8),trunc=int(float(trunc)*1e8)).iteritems() if bitcoin_data.script2_to_address(script, net.PARENT) is not None))
+                    trunc = '0.01'
+                return json.dumps(dict(
+                    (bitcoin_data.script2_to_address(script, net.PARENT), value/1e8)
+                    for script, value in get_current_scaled_txouts(scale=int(float(this)*1e8), trunc=int(float(trunc)*1e8)).iteritems()
+                    if bitcoin_data.script2_to_address(script, net.PARENT) is not None
+                ))
             except:
-                return json.dumps(dict())
+                return json.dumps(None)
          
         def get_global_stats():
             # averaged over last hour
index 4940cc8..3600064 100644 (file)
@@ -143,6 +143,15 @@ def flatten_linked_list(x):
         x, cur = x
         yield cur
 
+def weighted_choice(choices):
+    choices = list((item, weight) for item, weight in choices)
+    target = random.randrange(sum(weight for item, weight in choices))
+    for item, weight in choices:
+        if weight > target:
+            return item
+        target -= weight
+    raise AssertionError()
+
 if __name__ == '__main__':
     import random
     a = 1