Esempio n. 1
0
    def make_tx(self,
                coins,
                outputs,
                change_addrs,
                fee_estimator,
                dust_threshold,
                abandon_txid=None):
        '''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.'''

        # Deterministic randomness from coins
        utxos = [c['prevout_hash'] + str(c['prevout_n']) for c in coins]
        self.p = PRNG(''.join(sorted(utxos)))

        # Copy the ouputs so when adding change we don't modify "outputs"
        tx = Transaction.from_io([], outputs[:])
        # Size of the transaction with no inputs and no change
        base_size = tx.estimated_size()
        spent_amount = tx.output_value()

        claim_coin = None
        if abandon_txid is not None:
            claim_coins = [coin for coin in coins if coin['is_claim']]
            assert len(claim_coins) >= 1
            claim_coin = claim_coins[0]
            spent_amount -= claim_coin['value']
            coins = [coin for coin in coins if not coin['is_claim']]

        def sufficient_funds(buckets):
            '''Given a list of buckets, return True if it has enough
            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)

        # Collect the coins into buckets, choose a subset of the buckets
        buckets = self.bucketize_coins(coins)
        buckets = self.choose_buckets(buckets, sufficient_funds,
                                      self.penalty_func(tx))

        if claim_coin is not None:
            tx.add_inputs([claim_coin])
        tx.add_inputs([coin for b in buckets for coin in b.coins])
        tx_size = base_size + sum(bucket.size for bucket in buckets)

        # This takes a count of change outputs and returns a tx fee;
        # each pay-to-bitcoin-address output serializes as 34 bytes
        def fee(count):
            return fee_estimator(tx_size + count * 34)

        change = self.change_outputs(tx, change_addrs, fee, dust_threshold)
        tx.add_outputs(change)

        log.debug("using %i inputs", len(tx.inputs()))
        log.info("using buckets: %s", [bucket.desc for bucket in buckets])

        return tx
Esempio n. 2
0
    def load_transactions(self):
        self.tx_transactions = {}
        for tx_hash, raw in self.transactions.items():
            tx = Transaction(raw)
            self.tx_transactions[tx_hash] = tx
            if not self.txi.get(tx_hash) and not self.txo.get(tx_hash) and \
                    (tx_hash not in self.pruned_txo.values()):
                log.info("removing unreferenced tx: %s", tx_hash)
                self.tx_transactions.pop(tx_hash)
                self.transactions.pop(tx_hash)

            # add to claimtrie transactions if its a claimtrie transaction
            tx.deserialize()
            for n, txout in enumerate(tx.outputs()):
                if txout[0] & (TYPE_CLAIM | TYPE_UPDATE | TYPE_SUPPORT):
                    key = tx_hash + ':' + str(n)
                    self.claimtrie_transactions[key] = txout[0]
Esempio n. 3
0
 def tx_response(self, response):
     params, result = self.parse_response(response)
     if not params:
         return
     tx_hash, tx_height = params
     assert tx_hash == hash_encode(Hash(result.decode('hex')))
     tx = Transaction(result)
     try:
         tx.deserialize()
     except Exception:
         log.info("cannot deserialize transaction, skipping: %s", tx_hash)
         return
     self.wallet.receive_tx_callback(tx_hash, tx, tx_height)
     self.requested_tx.remove((tx_hash, tx_height))
     log.info("received tx %s height: %d bytes: %d", tx_hash, tx_height, len(tx.raw))
     # callbacks
     self.network.trigger_callback('new_transaction', tx)
     if not self.requested_tx:
         self.network.trigger_callback('updated')
Esempio n. 4
0
 def on_qr(self, data):
     from uwallet.bitcoin import base_decode, is_address
     data = data.strip()
     if is_address(data):
         self.set_URI(data)
         return
     if data.startswith('bitcoin:'):
         self.set_URI(data)
         return
     # try to decode transaction
     from uwallet.transaction import Transaction
     try:
         text = base_decode(data, None, base=43).encode('hex')
         tx = Transaction(text)
         tx.deserialize()
     except:
         tx = None
     if tx:
         self.tx_dialog(tx)
         return
     # show error
     self.show_error("Unable to decode QR data")
Esempio n. 5
0
 def get_max_amount(self, config, inputs, recipient, fee):
     from uwallet.transaction import Transaction
     sendable = sum(map(lambda x: x['value'], inputs))
     for i in inputs:
         self.add_input_info(i)
     xf = self.extra_fee()
     _type, addr = recipient
     if xf and sendable >= xf:
         billing_address = self.billing_info['billing_address']
         sendable -= xf
         outputs = [(_type, addr, sendable),
                    (TYPE_ADDRESS, billing_address, xf)]
     else:
         outputs = [(_type, addr, sendable)]
     dummy_tx = Transaction.from_io(inputs, outputs)
     if fee is None:
         fee = self.estimate_fee(config, dummy_tx.estimated_size())
     amount = max(0, sendable - fee)
     return amount, fee
Esempio n. 6
0
 def make_Bucket(desc, coins):
     size = sum(
         Transaction.estimated_input_size(coin) for coin in coins)
     value = sum(coin['value'] for coin in coins)
     return Bucket(desc, size, value, coins)
Esempio n. 7
0
 def pubkeys_to_address(self, pubkeys):
     redeem_script = Transaction.multisig_script(sorted(pubkeys), self.m)
     address = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')), 5)
     return address
Esempio n. 8
0
 def redeem_script(self, for_change, n):
     pubkeys = self.get_pubkeys(for_change, n)
     return Transaction.multisig_script(sorted(pubkeys), self.m)