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
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]
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')
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")
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
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)
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
def redeem_script(self, for_change, n): pubkeys = self.get_pubkeys(for_change, n) return Transaction.multisig_script(sorted(pubkeys), self.m)