'Select unspent coins to spend to pay outputs.  If the change is
greater than dust_threshold (after adding the change output to
the transaction) it is kept, otherwise none is sent and it is
added to the transaction fee.'

def make_tx(self, coins, outputs, change_addrs, fee_estimator, dust_threshold):

    utxos = [(c['prevout_hash'] + str(c['prevout_n'])) for c in coins]
    self.p = PRNG(''.join(sorted(utxos)))
    tx = Transaction.from_io([], outputs[:])
    base_size = tx.estimated_size()
    spent_amount = tx.output_value()
    def sufficient_funds(buckets):
        'Given    a    list    of    buckets,    return    True    if    it    has    enough\n                                                value    to    pay    for    the    transaction'
        total_input = sum((bucket.value for bucket in buckets))
        total_size = (sum((bucket.size for bucket in buckets)) + base_size)
        return (total_input >= (spent_amount + fee_estimator(total_size)))
    buckets = self.bucketize_coins(coins)
    buckets = self.choose_buckets(buckets, sufficient_funds, self.penalty_func(tx))
    tx.add_inputs([coin for b in buckets for coin in b.coins])
    tx_size = (base_size + sum((bucket.size for bucket in buckets)))
    fee = (lambda count: fee_estimator((tx_size + (count * 34))))
    change = self.change_outputs(tx, change_addrs, fee, dust_threshold)
    tx.add_outputs(change)
    self.print_error(('using    %d    inputs' % len(tx.inputs())))
    self.print_error('using    buckets:', [bucket.desc for bucket in buckets])
    return tx
