def generate_tumbler_tx(destaddrs, options): # sends the coins up through a few mixing depths # send to the destination addresses from different mixing depths # simple algo, move coins completely from one mixing depth to the next # until you get to the end, then send to destaddrs # txcounts for going completely from one mixdepth to the next # follows a normal distribution txcounts = rand_norm_array(options.txcountparams[0], options.txcountparams[1], options.mixdepthcount) txcounts = lower_bounded_int(txcounts, options.mintxcount) tx_list = [] for m, txcount in enumerate(txcounts): # assume that the sizes of outputs will follow a power law amount_fractions = rand_pow_array(options.amountpower, txcount) amount_fractions = [1.0 - x for x in amount_fractions] amount_fractions = [x / sum(amount_fractions) for x in amount_fractions] # transaction times are uncorrelated # time between events in a poisson process followed exp waits = rand_exp_array(options.timelambda, txcount) # number of makers to use follows a normal distribution makercounts = rand_norm_array(options.makercountrange[0], options.makercountrange[1], txcount) makercounts = lower_bounded_int(makercounts, options.minmakercount) if m == options.mixdepthcount - options.addrcount and options.donateamount: tx_list.append({'amount_fraction': 0, 'wait': round(waits[0], 2), 'srcmixdepth': m + options.mixdepthsrc, 'makercount': makercounts[0], 'destination': 'internal'}) for amount_fraction, wait, makercount in zip(amount_fractions, waits, makercounts): tx = {'amount_fraction': amount_fraction, 'wait': round(wait, 2), 'srcmixdepth': m + options.mixdepthsrc, 'makercount': makercount, 'destination': 'internal'} tx_list.append(tx) addrask = options.addrcount - len(destaddrs) external_dest_addrs = ['addrask'] * addrask + destaddrs for mix_offset in range(options.addrcount): srcmix = options.mixdepthsrc + options.mixdepthcount - mix_offset - 1 for tx in reversed(tx_list): if tx['srcmixdepth'] == srcmix: tx['destination'] = external_dest_addrs[mix_offset] break if mix_offset == 0: # setting last mixdepth to send all to dest tx_list_remove = [] for tx in tx_list: if tx['srcmixdepth'] == srcmix: if tx['destination'] == 'internal': tx_list_remove.append(tx) else: tx['amount_fraction'] = 1.0 [tx_list.remove(t) for t in tx_list_remove] return tx_list
def generate_tumbler_tx(destaddrs, options): # sends the coins up through a few mixing depths # send to the destination addresses from different mixing depths # simple algo, move coins completely from one mixing depth to the next # until you get to the end, then send to destaddrs # txcounts for going completely from one mixdepth to the next # follows a normal distribution txcounts = rand_norm_array(options.txcountparams[0], options.txcountparams[1], options.mixdepthcount) txcounts = lower_bounded_int(txcounts, options.mintxcount) tx_list = [] for m, txcount in enumerate(txcounts): if options.mixdepthcount - options.addrcount <= m and m < \ options.mixdepthcount - 1: #these mixdepths send to a destination address, so their # amount_fraction cant be 1.0, some coins must be left over if txcount == 1: txcount = 2 # assume that the sizes of outputs will follow a power law amount_fractions = rand_pow_array(options.amountpower, txcount) amount_fractions = [1.0 - x for x in amount_fractions] amount_fractions = [ x / sum(amount_fractions) for x in amount_fractions ] # transaction times are uncorrelated # time between events in a poisson process followed exp waits = rand_exp_array(options.timelambda, txcount) # number of makers to use follows a normal distribution makercounts = rand_norm_array(options.makercountrange[0], options.makercountrange[1], txcount) makercounts = lower_bounded_int(makercounts, options.minmakercount) if m == options.mixdepthcount - options.addrcount and options.donateamount: tx_list.append({ 'amount_fraction': 0, 'wait': round(waits[0], 2), 'srcmixdepth': m + options.mixdepthsrc, 'makercount': makercounts[0], 'destination': 'internal' }) for amount_fraction, wait, makercount in zip(amount_fractions, waits, makercounts): tx = { 'amount_fraction': amount_fraction, 'wait': round(wait, 2), 'srcmixdepth': m + options.mixdepthsrc, 'makercount': makercount, 'destination': 'internal' } tx_list.append(tx) addrask = options.addrcount - len(destaddrs) external_dest_addrs = ['addrask'] * addrask + destaddrs for mix_offset in range(options.addrcount): srcmix = options.mixdepthsrc + options.mixdepthcount - mix_offset - 1 for tx in reversed(tx_list): if tx['srcmixdepth'] == srcmix: tx['destination'] = external_dest_addrs[mix_offset] break if mix_offset == 0: # setting last mixdepth to send all to dest tx_list_remove = [] for tx in tx_list: if tx['srcmixdepth'] == srcmix: if tx['destination'] == 'internal': tx_list_remove.append(tx) else: tx['amount_fraction'] = 1.0 [tx_list.remove(t) for t in tx_list_remove] return tx_list