def script_obj_from_address(address, netcodes=None): netcode, key_type, data = netcode_and_type_for_text(address) if key_type == 'pay_to_script': return ScriptPayToScript(hash160=data) if key_type == 'address': return ScriptPayToAddress(hash160=data) raise ValueError("bad text")
def script_obj_from_address(address, netcodes=None): netcode, key_type, data = netcode_and_type_for_text(address) if key_type == 'pay_to_script': return ScriptPayToScript(hash160=data) if key_type == 'address': return ScriptPayToAddress(hash160=data) raise ValueError("bad text")
def script_obj_from_address(address, netcodes=None): netcode, key_type, data = netcode_and_type_for_text(address, netcodes) if key_type == 'pay_to_script': return ScriptPayToScript(hash160=data) if key_type == 'address': return ScriptPayToAddress(hash160=data) if key_type == 'address_wit': return ScriptPayToAddressWit(version=data[:1], hash160=data[2:]) if key_type == 'pay_to_script_wit': return ScriptPayToScriptWit(version=data[:1], hash256=data[2:]) raise ValueError("bad text")
def script_obj_from_address(address, netcodes=None): netcode, key_type, data = netcode_and_type_for_text(address, netcodes) if key_type == 'pay_to_script': return ScriptPayToScript(hash160=data) if key_type == 'address': return ScriptPayToAddress(hash160=data) if key_type == 'address_wit': return ScriptPayToAddressWit(version=data[:1], hash160=data[2:]) if key_type == 'pay_to_script_wit': return ScriptPayToScriptWit(version=data[:1], hash256=data[2:]) raise ValueError("bad text")
def create_change(self, address: str, existing_txouts, balance: int): new_txouts = [] change_size = 100 * 1000000 # 100 coins total_out = sum(txo.coin_value for txo in existing_txouts) balance = balance - total_out spendables = self.get_spendables(address, get_all=True) # Prune out spendables that we will spend. for spendable in spendables.copy(): if total_out == 0: continue if total_out < 0: raise Exception(f"total_out is negative. ({total_out})") if spendable.coin_value > total_out: spendables.remove(spendable) break elif total_out > spendable.coin_value: spendables.remove(spendable) total_out -= spendable.coin_value # XXX: Find a way to cleanly unify this. _, _, address_hash160 = netcode_and_type_for_text(address) # 15 TXs in our own wallet should be a good buffer to have. if len(spendables) >= 15: return [] # Create our payment to ourselves if we still have the coins. if (balance - (change_size * len(spendables))) < change_size: print("Warning: Low balance in address.") balance -= (change_size * len(spendables)) for x in range(len(spendables), 50): balance -= change_size if balance < 0: break script_pay = ScriptPayToAddress(hash160=address_hash160).script() new_txouts.append(TxOut(change_size, script_pay)) return new_txouts
def make_txs(self, address: str, chunker: Chunker, use_sends: bool = False) -> bool: # We'll do our own chunking if we have to send to address hashes. if use_sends: chunker.chunk_size = 1024 * 128 # Calculate hash160 for later. _, _, address_hash160 = netcode_and_type_for_text(address) # Calculate required TXes and their fees. total_fee_needed = self.fee(chunker.data_size) last_amount = float(self.get_balance(address)) # Pick the generation function appropiate for our coin. if use_sends: gen_function = self.generate_addr_txouts else: gen_function = self.generate_return_txouts print(f"{chunker.chunk_count} TXs will be made.") print(f"{total_fee_needed / 1000000} coins will be burnt.") if total_fee_needed / 1000000 >= last_amount: raise Exception( f"Not enough coins to cover insertions. ({total_fee_needed / 1000000} or greater needed.)" ) for nonce, payload in chunker.generate_return_payloads(): last_amount = float(self.get_balance(address)) * 1000000 fee_needed = self.fee(len(payload)) # txout generate stage 1 txs_out = [] txs_out.extend(gen_function(address_hash160, payload, fee_needed)) txs_out.extend(self.create_change(address, txs_out, last_amount)) # txin generate total_amount_txout = sum(txo.coin_value for txo in txs_out) remainder_txout = total_amount_txout + fee_needed total_amount_txin = 0 txs_in = [] # We sort by reverse if we want to devour the latest large TXIn chunk for making change addresses. # Sort by random if we have enough spare change. creates_change_addrs = ( total_amount_txout / 1000000 ) > 100 # XXX/HACK This is assuming spending is not above 100 coins. spendables = self.get_spendables(address, total_amount_txout) if creates_change_addrs: spendables.sort(key=lambda _: _.coin_value, reverse=creates_change_addrs) else: random.shuffle(spendables) for spendable in spendables: print( f"OUT {remainder_txout / 1000000}; CV {spendable.coin_value / 1000000}" ) if remainder_txout < 0: break txs_in.append(spendable.tx_in()) total_amount_txin += spendable.coin_value remainder_txout -= spendable.coin_value # We need to round the change. / txout generate stage 2 round_change_tx, round_change_amount = self.round_change( address_hash160, total_amount_txin, total_amount_txout, fee_needed) # XXX/HACK This fixes a bug where the round change somehow gets to negative values. # I don't even know how that even happens... yet. if round_change_tx.coin_value > 0: txs_out.append(round_change_tx) total_amount_txout += round_change_amount # tx sanity checks total_combined = total_amount_txin - total_amount_txout print(f"[tx#{nonce}] IN {total_amount_txin / 1000000}") print(f"[tx#{nonce}] OUT {total_amount_txout / 1000000}") print(f"[tx#{nonce}] FEE {total_combined / 1000000}") if total_combined < 0: print(total_amount_txin) print(total_amount_txout) raise Exception( f"[tx#{nonce}] negative transaction ({total_combined / 1000000})" ) elif total_combined > HIGHWAY_ROBBERY: print(total_amount_txin) print(total_amount_txout) raise Exception( f"[tx#{nonce}] overpaying fees ({total_combined / 1000000})" ) # tx generate new_tx = Tx(1, txs_in, txs_out) yield new_tx.as_hex(with_time=True)