Skip to content
This repository has been archived by the owner on May 13, 2022. It is now read-only.

Commit

Permalink
Merge pull request #173 from adlai/mergy-police
Browse files Browse the repository at this point in the history
combat dust thru utxo merge policies
  • Loading branch information
chris-belcher committed Sep 5, 2015
2 parents ec35fc0 + e12a70e commit 6f3a98c
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 7 deletions.
71 changes: 68 additions & 3 deletions lib/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import sys, datetime, json, time, pprint, threading, getpass
import random
import blockchaininterface, slowaes
from ConfigParser import SafeConfigParser
from ConfigParser import SafeConfigParser, NoSectionError
import os, io, itertools

JM_VERSION = 2
Expand Down Expand Up @@ -50,6 +50,10 @@
#port = 6697
#usessl = true
#socks5 = true
[POLICY]
#for dust sweeping, try merge_algorithm = gradual
merge_algorithm = default
"""

def load_program_config():
Expand Down Expand Up @@ -163,13 +167,74 @@ def debug_dump_object(obj, skip_fields=[]):
else:
debug(str(v))

def select_gradual(unspent, value):
'''
UTXO selection algorithm for gradual dust reduction
If possible, combines outputs, picking as few as possible of the largest
utxos less than the target value; if the target value is larger than the
sum of all smaller utxos, uses the smallest utxo larger than the value.
'''
value, key = int(value), lambda u: u["value"]
high = sorted([u for u in unspent if key(u) >= value], key=key)
low = sorted([u for u in unspent if key(u) < value], key=key)
lowsum=reduce(lambda x,y:x+y,map(key,low),0)
if value > lowsum:
if len(high)==0:
raise Exception('Not enough funds')
else:
return [high[0]]
else:
start, end, total = 0, 0, 0
while total < value:
total += low[end]['value']
end += 1
while total >= value + low[start]['value']:
total -= low[start]['value']
start += 1
return low[start:end]

def select_greedy(unspent, value):
'''
UTXO selection algorithm for rapid dust reduction
Combines the shortest run of utxos (sorted by size, from smallest) which
exceeds the target value; if the target value is larger than the sum of
all smaller utxos, uses the smallest utxo larger than the target value.
'''
value, key = int(value), lambda u: u["value"]
high = sorted([u for u in unspent if key(u) >= value], key=key)
low = sorted([u for u in unspent if key(u) < value], key=key)
lowsum=reduce(lambda x,y:x+y,map(key,low),0)
print((high, low, lowsum))
if value > lowsum:
if len(high)==0:
raise Exception('Not enough funds')
else:
return [high[0]]
else:
end, total = 0, 0
while total < value:
total += low[end]['value']
end += 1
return low[0:end]

class AbstractWallet(object):
'''
Abstract wallet for use with JoinMarket
Mostly written with Wallet in mind, the default JoinMarket HD wallet
'''
def __init__(self):
pass
self.utxo_selector = btc.select # default fallback: upstream
try:
if config.get("POLICY", "merge_algorithm") == "gradual":
self.utxo_selector = select_gradual
elif config.get("POLICY", "merge_algorithm") == "greedy":
self.utxo_selector = select_greedy
elif config.get("POLICY", "merge_algorithm") != "default":
raise Exception("Unknown merge algorithm")
except NoSectionError:
debug("Please add the new [POLICY] section to your config")
debug("Set therein thine merge_algorithm as default or gradual")

def get_key_from_addr(self, addr):
return None
def get_utxos_by_mixdepth(self):
Expand All @@ -187,7 +252,7 @@ def select_utxos(self, mixdepth, amount):
utxo_list = self.get_utxos_by_mixdepth()[mixdepth]
unspent = [{'utxo': utxo, 'value': addrval['value']}
for utxo, addrval in utxo_list.iteritems()]
inputs = btc.select(unspent, amount)
inputs = self.utxo_selector(unspent, amount)
debug('for mixdepth=' + str(mixdepth) + ' amount=' + str(amount) + ' selected:')
debug(pprint.pformat(inputs))
return dict([(i['utxo'], {'value': i['value'], 'address':
Expand Down
5 changes: 1 addition & 4 deletions lib/socks.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,7 @@ def __negotiatesocks5(self,destaddr,destport):
elif resp[1] != "\x00":
# Connection failed
self.close()
if ord(resp[1])<=8:
raise Socks5Error(ord(resp[1]),_generalerrors[ord(resp[1])])
else:
raise Socks5Error(9,_generalerrors[9])
raise Socks5Error(_socks5errors[min(9,ord(resp[1]))])
# Get the bound address/port
elif resp[3] == "\x01":
boundaddr = self.__recvall(4)
Expand Down

0 comments on commit 6f3a98c

Please sign in to comment.