def test_cache(self): sleep(0.2) start_time = time() set_rate_cache_time(0) currency_to_satoshi_cached(1, 'usd') initial_time = time() - start_time start_time = time() set_rate_cache_time(60) currency_to_satoshi_cached(1, 'usd') cached_time = time() - start_time assert initial_time > cached_time
def sanitize_tx_data(unspents, outputs, fee, leftover, combine=True, message=None, compressed=True, min_change=0, version='main'): """ sanitize_tx_data() """ outputs = outputs.copy() for i, output in enumerate(outputs): dest, amount, currency = output outputs[i] = (dest, currency_to_satoshi_cached(amount, currency)) if not unspents: raise ValueError('Transactions must have at least one unspent.') # Temporary storage so all outputs precede messages. messages = [] if message: message_chunks = chunk_data(message.encode('utf-8'), MESSAGE_LIMIT) for message in message_chunks: messages.append((message, 0)) # Include return address in output count. # Calculate output size as a list (including return address). output_size = [len(address_to_scriptpubkey(o[0])) + 9 for o in outputs] output_size.append(len(messages) * (MESSAGE_LIMIT + 9)) output_size.append(len(address_to_scriptpubkey(leftover)) + 9) sum_outputs = sum(out[1] for out in outputs) # Use Branch-and-Bound for coin selection: unspents[:], remaining = select_coins(sum_outputs, fee, output_size, min_change=min_change, consolidate=combine, unspents=unspents) if remaining > 0: outputs.append((leftover, remaining)) # Sanity check: If spending from main-/testnet, then all output addresses must also be for main-/testnet. for output in outputs: dest, amount = output vs = get_version(dest) if vs and vs != version: raise ValueError('Cannot send to ' + vs + 'net address when ' 'spending from a ' + version + 'net address.') outputs.extend(messages) return unspents, outputs
def test_expires(self): sleep(0.2) set_rate_cache_time(0) currency_to_satoshi_cached(1, 'usd') start_time = time() set_rate_cache_time(60) currency_to_satoshi_cached(1, 'usd') cached_time = time() - start_time sleep(0.2) start_time = time() set_rate_cache_time(0.1) currency_to_satoshi_cached(1, 'usd') update_time = time() - start_time assert update_time > cached_time
def sanitize_tx_data(unspents, outputs, fee, leftover, combine=True, message=None, compressed=True): outputs = outputs.copy() for i, output in enumerate(outputs): dest, amount, currency = output outputs[i] = (dest, currency_to_satoshi_cached(amount, currency)) if not unspents: raise ValueError('Transactions must have at least one unspent.') # Temporary storage so all outputs precede messages. messages = [] if message: message_chunks = chunk_data(message.encode('utf-8'), MESSAGE_LIMIT) for message in message_chunks: messages.append((message, 0)) # Include return address in fee estimate. fee = estimate_tx_fee(len(unspents), len(outputs) + len(messages) + 1, fee, compressed) total_out = sum(out[1] for out in outputs) + fee total_in = 0 if combine: unspents = unspents.copy() total_in += sum(unspent.amount for unspent in unspents) else: unspents = sorted(unspents, key=lambda x: x.amount) index = 0 for index, unspent in enumerate(unspents): total_in += unspent.amount if total_in >= total_out: break unspents[:] = unspents[:index + 1] remaining = total_in - total_out if remaining > 0: outputs.append((leftover, remaining)) elif remaining < 0: raise InsufficientFunds('Balance {} is less than {} (including ' 'fee).'.format(total_in, total_out)) outputs.extend(messages) return unspents, outputs
def sanitize_tx_data(unspents, outputs, fee, leftover, combine=True, message=None, compressed=True, version='main'): """ sanitize_tx_data() fee is in satoshis per byte. """ outputs = outputs.copy() for i, output in enumerate(outputs): dest, amount, currency = output # Sanity check: If spending from main-/testnet, then all output addresses must also be for main-/testnet. if amount: # ``dest`` could be a text to be stored in the blockchain; but only if ``amount`` is exactly zero. vs = get_version(dest) if vs and vs != version: raise ValueError('Cannot send to ' + vs + 'net address when spending from a ' + version + 'net address.') outputs[i] = (dest, currency_to_satoshi_cached(amount, currency)) if not unspents: raise ValueError('Transactions must have at least one unspent.') # Temporary storage so all outputs precede messages. messages = [] if message: message_chunks = chunk_data(message.encode('utf-8'), MESSAGE_LIMIT) for message in message_chunks: messages.append((message, 0)) # Include return address in fee estimate. total_in = 0 num_outputs = len(outputs) + len(messages) + 1 sum_outputs = sum(out[1] for out in outputs) if combine: # calculated_fee is in total satoshis. calculated_fee = estimate_tx_fee(len(unspents), num_outputs, fee, compressed) total_out = sum_outputs + calculated_fee unspents = unspents.copy() total_in += sum(unspent.amount for unspent in unspents) else: unspents = sorted(unspents, key=lambda x: x.amount) index = 0 for index, unspent in enumerate(unspents): total_in += unspent.amount calculated_fee = estimate_tx_fee(len(unspents[:index + 1]), num_outputs, fee, compressed) total_out = sum_outputs + calculated_fee if total_in >= total_out: break unspents[:] = unspents[:index + 1] remaining = total_in - total_out if remaining > 0: outputs.append((leftover, remaining)) elif remaining < 0: raise InsufficientFunds('Balance {} is less than {} (including ' 'fee).'.format(total_in, total_out)) outputs.extend(messages) return unspents, outputs
def sanitize_tx_data(unspents, outputs, fee, leftover, combine=True, message=None, compressed=True): """ sanitize_tx_data() fee is in satoshis per byte. """ outputs = outputs.copy() for i, output in enumerate(outputs): dest, amount, currency = output outputs[i] = (dest, currency_to_satoshi_cached(amount, currency)) if not unspents: raise ValueError('Transactions must have at least one unspent.') messages = [] if message: if type(message) == int: messages.append((int_to_unknown_bytes(message), 0)) else: messages.append((hex_to_bytes(message), 0)) # Include return address in output count. num_outputs = len(outputs) + len(messages) + 1 sum_outputs = sum(out[1] for out in outputs) total_in = 0 if combine: # calculated_fee is in total satoshis. calculated_fee = estimate_tx_fee(len(unspents), num_outputs, fee, compressed) total_out = sum_outputs + calculated_fee unspents = unspents.copy() total_in += sum(unspent.amount for unspent in unspents) else: unspents = sorted(unspents, key=lambda x: x.amount) index = 0 for index, unspent in enumerate(unspents): total_in += unspent.amount calculated_fee = estimate_tx_fee(len(unspents[:index + 1]), num_outputs, fee, compressed) total_out = sum_outputs + calculated_fee if total_in >= total_out: break unspents[:] = unspents[:index + 1] remaining = total_in - total_out if remaining > 0: outputs.append((leftover, remaining)) elif remaining < 0: raise InsufficientFunds('Balance {} is less than {} (including ' 'fee).'.format(total_in, total_out)) outputs.extend(messages) return unspents, outputs