mirror of
https://github.com/JoinMarket-Org/joinmarket-clientserver.git
synced 2026-08-13 12:33:40 +02:00
Remove amountpower and use uniform distn instead
Remove the power law generation for amount_fractions, instead use a uniform distribution This is part of the 2/2019 Plan to improve the privacy of JoinMarket's tumbler script: https://gist.github.com/chris-belcher/7e92810f07328fdfdef2ce444aad0968
This commit is contained in:
parent
f40ef2c795
commit
b79d34a348
4 changed files with 33 additions and 43 deletions
|
|
@ -7,7 +7,7 @@ import random
|
|||
import sys
|
||||
|
||||
from .configure import validate_address, jm_single
|
||||
from .support import rand_exp_array, rand_norm_array, rand_pow_array, rand_weighted_choice
|
||||
from .support import rand_exp_array, rand_norm_array, rand_weighted_choice
|
||||
"""Utility functions for dealing with Taker schedules.
|
||||
|
||||
- get_schedule(filename):
|
||||
|
|
@ -60,9 +60,8 @@ def get_schedule(filename):
|
|||
waittime, rounding, completed])
|
||||
return (True, schedule)
|
||||
|
||||
def get_amount_fractions(power, count):
|
||||
"""Get 'count' fractions following power law distn according to
|
||||
parameter 'power'
|
||||
def get_amount_fractions(count):
|
||||
"""Get 'count' fractions following uniform distn
|
||||
Note that this function is not entirely generic; it ensures that
|
||||
the final entry is larger than a certain fraction, for a reason
|
||||
specific to the way the tumbler algo works: the last entry
|
||||
|
|
@ -71,9 +70,16 @@ def get_amount_fractions(power, count):
|
|||
setting, so we make sure it's appreciable to begin with.
|
||||
"""
|
||||
while True:
|
||||
amount_fractions = rand_pow_array(power, count)
|
||||
amount_fractions = [1.0 - x for x in amount_fractions]
|
||||
y = [x / sum(amount_fractions) for x in amount_fractions]
|
||||
knives = [random.random() for i in range(count-1)]
|
||||
knives = sorted(knives)[::-1]
|
||||
y = []
|
||||
l = 1
|
||||
k = 1
|
||||
for k in knives:
|
||||
y.append( l - k )
|
||||
l = k
|
||||
y.append(k)
|
||||
|
||||
#Here we insist that the last entry in the list is more
|
||||
#than 5% of the total, to account for tweaks upwards
|
||||
#on previous joins.
|
||||
|
|
@ -134,7 +140,7 @@ def get_tumble_schedule(options, destaddrs, mixdepth_balance_dict):
|
|||
# amount_fraction cant be 1.0, some coins must be left over
|
||||
if txcount == 1:
|
||||
txcount = 2
|
||||
amount_fractions = get_amount_fractions(options['amountpower'], txcount)
|
||||
amount_fractions = get_amount_fractions(txcount)
|
||||
# transaction times are uncorrelated
|
||||
# time between events in a poisson process followed exp
|
||||
waits = rand_exp_array(options['timelambda'], txcount)
|
||||
|
|
@ -232,7 +238,7 @@ def tweak_tumble_schedule(options, schedule, last_completed, destaddrs=[]):
|
|||
alreadyspent = sum([x[1] for x in already_done])
|
||||
tobespent = 1.0 - alreadyspent
|
||||
#power law for what's left:
|
||||
new_fracs = get_amount_fractions(options['amountpower'], len(tobedone))
|
||||
new_fracs = get_amount_fractions(len(tobedone))
|
||||
#rescale; the sum must be 'tobespent':
|
||||
new_fracs = [x*tobespent for x in new_fracs]
|
||||
#starting from the known 'last_completed+1' index, apply these new
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ def get_options():
|
|||
options.txfee = 5000
|
||||
options.addrcount = 3
|
||||
options.mintxcount = 1
|
||||
options.amountpower = 100
|
||||
options.timelambda = 0.2
|
||||
options.waittime = 10
|
||||
options.stage1_timelambda_increase = 3
|
||||
|
|
|
|||
|
|
@ -310,13 +310,6 @@ def get_tumbler_parser():
|
|||
default=0,
|
||||
help=
|
||||
'percent of funds to donate to joinmarket development, or zero to opt out (default=0%)')
|
||||
parser.add_option(
|
||||
'--amountpower',
|
||||
type='float',
|
||||
dest='amountpower',
|
||||
default=100.0,
|
||||
help=
|
||||
'The output amounts follow a power law distribution, this is the power, default=100.0')
|
||||
parser.add_option(
|
||||
'-l',
|
||||
'--timelambda',
|
||||
|
|
|
|||
|
|
@ -626,7 +626,6 @@ class SchFinishPage(QWizardPage):
|
|||
results = []
|
||||
sN = ['Makercount sdev',
|
||||
'Tx count sdev',
|
||||
'Amount power',
|
||||
'Minimum maker count',
|
||||
'Minimum transaction count',
|
||||
'Min coinjoin amount',
|
||||
|
|
@ -640,7 +639,6 @@ class SchFinishPage(QWizardPage):
|
|||
"transaction.",
|
||||
"Standard deviation of the number of transactions to use in each "
|
||||
"mixdepth",
|
||||
"A parameter to control the random coinjoin sizes.",
|
||||
"The lowest allowed number of maker counterparties.",
|
||||
"The lowest allowed number of transactions in one mixdepth.",
|
||||
"The lowest allowed size of any coinjoin, in satoshis.",
|
||||
|
|
@ -652,12 +650,12 @@ class SchFinishPage(QWizardPage):
|
|||
"is the relative probability of rounding to " + w +
|
||||
" significant figures"]
|
||||
#types
|
||||
sT = [float, float, float, int, int, int, float, float, float] + [int]*5
|
||||
sT = [float, float, int, int, int, float, float, float] + [int]*5
|
||||
#constraints
|
||||
sMM = [(0.0, 10.0, 2), (0.0, 10.0, 2), (1.0, 10000.0, 1), (2,20),
|
||||
sMM = [(0.0, 10.0, 2), (0.0, 10.0, 2), (2,20),
|
||||
(1, 10), (100000, 100000000), (10.0, 500.0, 2), (0, 100, 1),
|
||||
(0.0, 1.0, 3)] + [(0, 10000)]*5
|
||||
sD = ['1.0', '1.0', '100.0', '2', '1', '1000000', '20', '3', '0.25'] +\
|
||||
sD = ['1.0', '1.0', '2', '1', '1000000', '20', '3', '0.25'] +\
|
||||
['55', '15', '25', '65', '40']
|
||||
for x in zip(sN, sH, sT, sD, sMM):
|
||||
ql = QLabel(x[0])
|
||||
|
|
@ -677,15 +675,14 @@ class SchFinishPage(QWizardPage):
|
|||
#fields not considered 'mandatory' as defaults are accepted
|
||||
self.registerField("makercountsdev", results[0][1])
|
||||
self.registerField("txcountsdev", results[1][1])
|
||||
self.registerField("amountpower", results[2][1])
|
||||
self.registerField("minmakercount", results[3][1])
|
||||
self.registerField("mintxcount", results[4][1])
|
||||
self.registerField("mincjamount", results[5][1])
|
||||
self.registerField("waittime", results[6][1])
|
||||
self.registerField("stage1_timelambda_increase", results[7][1])
|
||||
self.registerField("rounding_chance", results[8][1])
|
||||
self.registerField("minmakercount", results[2][1])
|
||||
self.registerField("mintxcount", results[3][1])
|
||||
self.registerField("mincjamount", results[4][1])
|
||||
self.registerField("waittime", results[5][1])
|
||||
self.registerField("stage1_timelambda_increase", results[6][1])
|
||||
self.registerField("rounding_chance", results[7][1])
|
||||
for i in range(5):
|
||||
self.registerField("rounding_sigfig_weight_" + str(i+1), results[9+i][1])
|
||||
self.registerField("rounding_sigfig_weight_" + str(i+1), results[8+i][1])
|
||||
|
||||
class SchIntroPage(QWizardPage):
|
||||
def __init__(self, parent):
|
||||
|
|
@ -753,7 +750,6 @@ class ScheduleWizard(QWizard):
|
|||
self.opts['txcountparams'] = (int(self.field("txcountparams")),
|
||||
float(self.field("txcountsdev")))
|
||||
self.opts['mintxcount'] = int(self.field("mintxcount"))
|
||||
self.opts['amountpower'] = float(self.field("amountpower"))
|
||||
self.opts['timelambda'] = float(self.field("timelambda"))
|
||||
self.opts['waittime'] = float(self.field("waittime"))
|
||||
self.opts["stage1_timelambda_increase"] = float(self.field("stage1_timelambda_increase"))
|
||||
|
|
@ -776,7 +772,6 @@ class TumbleRestartWizard(QWizard):
|
|||
|
||||
def getOptions(self):
|
||||
self.opts = {}
|
||||
self.opts['amountpower'] = float(self.field("amountpower"))
|
||||
self.opts['mincjamount'] = int(self.field("mincjamount"))
|
||||
relfeeval = float(self.field("maxrelfee"))
|
||||
absfeeval = int(self.field("maxabsfee"))
|
||||
|
|
@ -795,21 +790,19 @@ class RestartSettingsPage(QWizardPage):
|
|||
layout.setSpacing(4)
|
||||
|
||||
results = []
|
||||
sN = ['Amount power',
|
||||
'Min coinjoin amount',
|
||||
sN = ['Min coinjoin amount',
|
||||
'Max relative fee per counterparty (e.g. 0.005)',
|
||||
'Max fee per counterparty, satoshis (e.g. 10000)']
|
||||
#Tooltips
|
||||
sH = ["A parameter to control the random coinjoin sizes.",
|
||||
"The lowest allowed size of any coinjoin, in satoshis.",
|
||||
sH = ["The lowest allowed size of any coinjoin, in satoshis.",
|
||||
"A decimal fraction (e.g. 0.001 = 0.1%) (this AND next must be violated to reject",
|
||||
"Integer number of satoshis (this AND previous must be violated to reject)"]
|
||||
#types
|
||||
sT = [float, int, float, int]
|
||||
sT = [int, float, int]
|
||||
#constraints
|
||||
sMM = [(1.0, 10000.0, 1), (100000, 100000000), (0.000001, 0.25, 6),
|
||||
sMM = [(100000, 100000000), (0.000001, 0.25, 6),
|
||||
(0, 10000000)]
|
||||
sD = ['100.0', '1000000', '0.0005', '10000']
|
||||
sD = ['1000000', '0.0005', '10000']
|
||||
for x in zip(sN, sH, sT, sD, sMM):
|
||||
ql = QLabel(x[0])
|
||||
ql.setToolTip(x[1])
|
||||
|
|
@ -826,7 +819,6 @@ class RestartSettingsPage(QWizardPage):
|
|||
layout.addWidget(x[1], i + 1, 1, 1, 2)
|
||||
self.setLayout(layout)
|
||||
#fields not considered 'mandatory' as defaults are accepted
|
||||
self.registerField("amountpower", results[0][1])
|
||||
self.registerField("mincjamount", results[1][1])
|
||||
self.registerField("maxrelfee", results[2][1])
|
||||
self.registerField("maxabsfee", results[3][1])
|
||||
self.registerField("mincjamount", results[0][1])
|
||||
self.registerField("maxrelfee", results[1][1])
|
||||
self.registerField("maxabsfee", results[2][1])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue