def _pack_linked_txos(self, linked_txos): ''' Packs input txos which are known as being controlled by a same entity Parameters: linked_txos = list of sets storing linked input txos. Each txo is identified by its "id" ''' idx = len(self._packs) # Merges packs sharing common elements packs = merge_sets(linked_txos) for pack in packs: ins = [] val_ins = 0 for i in self.inputs: if i[0] in pack: ins.append(i) val_ins += i[1] idx += 1 if len(ins) > 0: lbl = '%s_I%i' % (self.PACK, idx) inp = (lbl, val_ins) self.inputs.append(inp) in_pack = (lbl, val_ins, 'INPUTS', ins, []) self._packs.append(in_pack) [self.inputs.remove(v) for v in ins]
def process_tx(tx, options, max_duration, max_txos, max_cj_intrafees_ratio=0): ''' Processes a transaction Parameters: tx = Transaction to be processed (@see boltzmann.utils.transaction.Transaction) options = options to be applied during processing max_duration = max duration allocated to processing of a single tx (in seconds) max_txos = max number of txos. Txs with more than max_txos inputs or outputs are not processed. max_cj_intrafees_ratio = max intrafees paid by the taker of a coinjoined transaction. Expressed as a percentage of the coinjoined amount. ''' t1 = datetime.now() # Builds lists of filtered input/output txos (with generated ids) filtered_ins, map_ins = filter_txos(tx.inputs, 'I') filtered_outs, map_outs = filter_txos(tx.outputs, 'O') # Computes total input & output amounts + fees sum_inputs = sum([v[1] for v in filtered_ins]) sum_outputs = sum([v[1] for v in filtered_outs]) fees = sum_inputs - sum_outputs # Sets default intrafees paid by participants (fee_received_by_maker, fees_paid_by_taker) intrafees = (0, 0) # Processes the transaction if (len(filtered_ins) <= 1) or (len(filtered_outs) == 1): # Txs having no input (coinbase) or only 1 input/output (null entropy) # When entropy = 0, all inputs and outputs are linked and matrix is filled with 1. # No need to build this matrix. Every caller should be able to manage that. mat_lnk = None nb_cmbn = 1 txo_ins = filtered_ins txo_outs = filtered_outs else: # Initializes the TxosLinker for this tx linker = TxosLinker(filtered_ins, filtered_outs, fees, max_duration, max_txos) # Computes a list of sets of inputs controlled by a same address linked_ins = get_linked_txos( filtered_ins, map_ins) if ('MERGE_INPUTS' in options) else [] # Computes a list of sets of outputs controlled by a same address (not recommended) linked_outs = get_linked_txos( filtered_outs, map_outs) if ('MERGE_OUTPUTS' in options) else [] # Computes intrafees to be used during processing if max_cj_intrafees_ratio > 0: # Computes a theoretic max number of participants ls_filtered_ins = [set([i[0]]) for i in filtered_ins] max_nb_ptcpts = len(merge_sets(linked_ins + ls_filtered_ins)) # Checks if tx has a coinjoin pattern + gets estimated number of participants and coinjoined amount is_cj, nb_ptcpts, cj_amount = check_coinjoin_pattern( filtered_ins, filtered_outs, max_nb_ptcpts) # If coinjoin pattern detected, computes theoretic max intrafees if is_cj: intrafees = compute_coinjoin_intrafees(nb_ptcpts, cj_amount, max_cj_intrafees_ratio) # Computes entropy of the tx and txos linkability matrix (mat_lnk, nb_cmbn, txo_ins, txo_outs) = linker.process(linked_ins + linked_outs, options, intrafees) # Post processes results (replaces txo ids by bitcoin addresses) txo_ins = post_process_txos(txo_ins, map_ins) txo_outs = post_process_txos(txo_outs, map_outs) print('Duration = %s' % str((datetime.now() - t1).total_seconds())) return mat_lnk, nb_cmbn, txo_ins, txo_outs, fees, intrafees