def test_build_spends(self): # first, here is the tx database TX_DB = {} def tx_out_for_hash_index_f(tx_hash, tx_out_idx): tx = TX_DB.get(tx_hash) return tx.txs_out[tx_out_idx] # create a coinbase Tx where we know the public & private key exponent = wif_to_secret_exponent("5JMys7YfK72cRVTrbwkq5paxU7vgkMypB55KyXEtN5uSnjV7K8Y") compressed = False public_key_sec = public_pair_to_sec(ecdsa.public_pair_for_secret_exponent(ecdsa.generator_secp256k1, exponent), compressed=compressed) the_coinbase_tx = Tx.coinbase_tx(public_key_sec, int(50 * 1e8), COINBASE_BYTES_FROM_80971) TX_DB[the_coinbase_tx.hash()] = the_coinbase_tx # now create a Tx that spends the coinbase compressed = False exponent_2 = int("137f3276686959c82b454eea6eefc9ab1b9e45bd4636fb9320262e114e321da1", 16) bitcoin_address_2 = public_pair_to_bitcoin_address( ecdsa.public_pair_for_secret_exponent(ecdsa.generator_secp256k1, exponent_2), compressed=compressed) self.assertEqual("12WivmEn8AUth6x6U8HuJuXHaJzDw3gHNZ", bitcoin_address_2) coins_from = [(the_coinbase_tx.hash(), 0, the_coinbase_tx.txs_out[0])] coins_to = [(int(50 * 1e8), bitcoin_address_2)] unsigned_coinbase_spend_tx = UnsignedTx.standard_tx(coins_from, coins_to) solver = SecretExponentSolver([exponent]) coinbase_spend_tx = unsigned_coinbase_spend_tx.sign(solver) # now check that it validates coinbase_spend_tx.validate(tx_out_for_hash_index_f) TX_DB[coinbase_spend_tx.hash()] = coinbase_spend_tx ## now try to respend from priv_key_2 to priv_key_3 compressed = True exponent_3 = int("f8d39b8ecd0e1b6fee5a340519f239097569d7a403a50bb14fb2f04eff8db0ff", 16) bitcoin_address_3 = public_pair_to_bitcoin_address( ecdsa.public_pair_for_secret_exponent(ecdsa.generator_secp256k1, exponent_3), compressed=compressed) self.assertEqual("13zzEHPCH2WUZJzANymow3ZrxcZ8iFBrY5", bitcoin_address_3) unsigned_spend_tx = UnsignedTx.standard_tx([(coinbase_spend_tx.hash(), 0, coinbase_spend_tx.txs_out[0])], [(int(50 * 1e8), bitcoin_address_3)]) solver.add_secret_exponents([exponent_2]) spend_tx = unsigned_spend_tx.sign(solver) # now check that it validates spend_tx.validate(tx_out_for_hash_index_f)
def send(self, ddestination_address, dcolourid=None): self.colordata.update() coins_to = [] total_spent = 0 for daa in [ddestination_address]: address, amount = daa[0], daa[1] amount = btc_to_satoshi(amount) total_spent += amount coins_to.append((amount, address)) selected_utxos, total_value = self.selectUTXOs(self.getAllUTXOs(), dcolourid, total_spent) change = (total_value - total_spent) - 10000 if change >= 1: coins_to.append((change, self.addresses[0].pubkey)) coins_from = [utxo.get_pycoin_coin_source() for utxo in selected_utxos] secret_exponents = [encoding.wif_to_secret_exponent(address.privkey) for address in self.addresses] unsigned_tx = UnsignedTx.standard_tx(coins_from, coins_to) solver = SecretExponentSolver(secret_exponents) new_tx = unsigned_tx.sign(solver) s = io.BytesIO() new_tx.stream(s) tx_bytes = s.getvalue() tx_hex = binascii.hexlify(tx_bytes).decode("utf8") recommended_tx_fee = tx_fee.recommended_fee_for_tx(new_tx) print tx_hex URL = "http://blockchain.info/pushtx" urllib2.urlopen(URL, data=tx_hex)
def bitcoin(public, private, address, amount): coins_from = [] coins_sources = blockchain_info.coin_sources_for_address(public) coins_from.extend(coins_sources) value = sum(cs[-1].coin_value for cs in coins_sources) secret_exponents = [encoding.wif_to_secret_exponent(private)] amount = btc_to_satoshi(amount) coins_to = [] coins_to.append((amount, address)) actual_tx_fee = value - amount if actual_tx_fee < 0: print( "not enough source coins (%s BTC) for destination (%s BTC). Short %s BTC" % (satoshi_to_btc(total_value), satoshi_to_btc(total_spent), satoshi_to_btc(-actual_tx_fee))) return None if actual_tx_fee > 0: coins_to.append((actual_tx_fee, public)) unsigned_tx = UnsignedTx.standard_tx(coins_from, coins_to) solver = SecretExponentSolver(secret_exponents) new_tx = unsigned_tx.sign(solver) s = io.BytesIO() new_tx.stream(s) tx_bytes = s.getvalue() tx_hex = binascii.hexlify(tx_bytes).decode("utf8") return tx_bytes
def bitcoin(public, private, address, amount): coins_from = [] coins_sources = blockchain_info.coin_sources_for_address(public) coins_from.extend(coins_sources) value = sum(cs[-1].coin_value for cs in coins_sources) secret_exponents = [encoding.wif_to_secret_exponent(private)] amount = btc_to_satoshi(amount) coins_to = [] coins_to.append((amount, address)) actual_tx_fee = value - amount if actual_tx_fee < 0: print("not enough source coins (%s BTC) for destination (%s BTC). Short %s BTC" % (satoshi_to_btc(total_value), satoshi_to_btc(total_spent), satoshi_to_btc(-actual_tx_fee))) return None; if actual_tx_fee > 0: coins_to.append((actual_tx_fee, public)) unsigned_tx = UnsignedTx.standard_tx(coins_from, coins_to) solver = SecretExponentSolver(secret_exponents) new_tx = unsigned_tx.sign(solver) s = io.BytesIO() new_tx.stream(s) tx_bytes = s.getvalue() tx_hex = binascii.hexlify(tx_bytes).decode("utf8") return tx_bytes
def test_standard_tx_out(self): coin_value = 10 recipient_bc_address = '1BcJRKjiwYQ3f37FQSpTYM7AfnXurMjezu' tx_out = UnsignedTx.standard_tx( [], [(coin_value, recipient_bc_address)]).new_txs_out[0] s = str(tx_out) self.assertEqual( 'TxOut<1E-7 "OP_DUP OP_HASH160 745e5b81fd30ca1e90311b012badabaa4411ae1a OP_EQUALVERIFY OP_CHECKSIG">', s)
def get_unsigned_tx(parser): args = parser.parse_args() # if there is only one item passed, it's assumed to be hex if len(args.txinfo) == 1: try: s = io.BytesIO(h2b(args.txinfo[0])) return UnsignedTx.parse(s) except Exception: parser.error("can't parse %s as hex\n" % args.txinfo[0]) coins_from = [] coins_to = [] for txinfo in args.txinfo: if '/' in txinfo: parts = txinfo.split("/") if len(parts) == 2: # we assume it's an output address, amount = parts amount = btc_to_satoshi(amount) coins_to.append((amount, address)) else: try: # we assume it's an input of the form # tx_hash_hex/tx_output_index_decimal/tx_out_val/tx_out_script_hex tx_hash_hex, tx_output_index_decimal, tx_out_val, tx_out_script_hex = parts tx_hash = h2b(tx_hash_hex) tx_output_index = int(tx_output_index_decimal) tx_out_val = btc_to_satoshi(decimal.Decimal(tx_out_val)) tx_out_script = h2b(tx_out_script_hex) tx_out = TxOut(tx_out_val, tx_out_script) coins_source = (tx_hash, tx_output_index, tx_out) coins_from.append(coins_source) except Exception: parser.error("can't parse %s\n" % txinfo) else: print("looking up funds for %s from blockchain.info" % txinfo) coins_sources = blockchain_info.unspent_tx_outs_info_for_address(txinfo) coins_from.extend(coins_sources) unsigned_tx = UnsignedTx.standard_tx(coins_from, coins_to) return unsigned_tx
def get_unsigned_tx(parser): args = parser.parse_args() # if there is only one item passed, it's assumed to be hex if len(args.txinfo) == 1: try: s = io.BytesIO(binascii.unhexlify(args.txinfo[0].decode("utf8"))) return UnsignedTx.parse(s) except Exception: parser.error("can't parse %s as hex\n" % args.txinfo[0]) coins_from = [] coins_to = [] for txinfo in args.txinfo: if '/' in txinfo: parts = txinfo.split("/") if len(parts) == 2: # we assume it's an output address, amount = parts amount = btc_to_satoshi(amount) coins_to.append((amount, address)) else: try: # we assume it's an input of the form # tx_hash_hex/tx_output_index_decimal/tx_out_val/tx_out_script_hex tx_hash_hex, tx_output_index_decimal, tx_out_val, tx_out_script_hex = parts tx_hash = binascii.unhexlify(tx_hash_hex) tx_output_index = int(tx_output_index_decimal) tx_out_val = btc_to_satoshi(decimal.Decimal(tx_out_val)) tx_out_script = binascii.unhexlify(tx_out_script_hex) tx_out = TxOut(tx_out_val, tx_out_script) coins_source = (tx_hash, tx_output_index, tx_out) coins_from.append(coins_source) except Exception: parser.error("can't parse %s\n" % txinfo) else: print("looking up funds for %s from blockchain.info" % txinfo) coins_sources = blockchain_info.unspent_tx_outs_info_for_address(txinfo) coins_from.extend(coins_sources) unsigned_tx = UnsignedTx.standard_tx(coins_from, coins_to) return unsigned_tx
def pycoin_construct_tx(input_utxos, outputs): from pycoin import encoding from pycoin.tx import UnsignedTx, SecretExponentSolver import io inputs = [utxo.get_pycoin_coin_source() for utxo in input_utxos] secret_exponents = [encoding.wif_to_secret_exponent(utxo.address.meat.privkey) for utxo in input_utxos] unsigned_tx = UnsignedTx.standard_tx(inputs, outputs) solver = SecretExponentSolver(secret_exponents) new_tx = unsigned_tx.sign(solver) s = io.BytesIO() new_tx.stream(s) return s.getvalue()
def main(): parser = argparse.ArgumentParser(description="Create a Bitcoin transaction.") parser.add_argument('-s', "--source-address", help='source Bitcoin address', required=True, nargs="+", metavar='source_address') parser.add_argument('-d', "--destination-address", help='destination Bitcoin address/amount', required=True, metavar='dest_address/amount_in_btc', nargs="+") parser.add_argument('-f', "--wif-file", help='WIF items for source Bitcoin addresses', required=True, metavar="path-to-WIF-values", type=argparse.FileType('r')) args = parser.parse_args() total_value = 0 coins_from = [] for bca in args.source_address: coins_sources = blockchain_info.coin_sources_for_address(bca) coins_from.extend(coins_sources) total_value += sum(cs[-1].coin_value for cs in coins_sources) secret_exponents = [] for l in args.wif_file: print l secret_exponents.append(encoding.wif_to_secret_exponent(l[:-1])) coins_to = [] total_spent = 0 for daa in args.destination_address: address, amount = daa.split("/") amount = btc_to_satoshi(amount) total_spent += amount coins_to.append((amount, address)) actual_tx_fee = total_value - total_spent if actual_tx_fee < 0: print("not enough source coins (%s BTC) for destination (%s BTC). Short %s BTC" % (satoshi_to_btc(total_value), satoshi_to_btc(total_spent), satoshi_to_btc(-actual_tx_fee))) sys.exit(1) print("transaction fee: %s BTC" % satoshi_to_btc(actual_tx_fee)) unsigned_tx = UnsignedTx.standard_tx(coins_from, coins_to) solver = SecretExponentSolver(secret_exponents) new_tx = unsigned_tx.sign(solver) s = io.BytesIO() new_tx.stream(s) tx_bytes = s.getvalue() tx_hex = binascii.hexlify(tx_bytes).decode("utf8") recommended_tx_fee = tx_fee.recommended_fee_for_tx(new_tx) if actual_tx_fee > recommended_tx_fee: print("warning: transaction fee of exceeds expected value of %s BTC" % satoshi_to_btc(recommended_tx_fee)) elif actual_tx_fee < recommended_tx_fee: print("warning: transaction fee lower than (casually calculated) expected value of %s BTC, transaction might not propogate" % satoshi_to_btc(recommended_tx_fee)) print("copy the following hex to http://blockchain.info/pushtx to put the transaction on the network:\n") print(tx_hex)
def pycoin_construct_tx(input_utxos, outputs, testnet): from pycoin import encoding from pycoin.tx import UnsignedTx, SecretExponentSolver import io inputs = [utxo.get_pycoin_coin_source() for utxo in input_utxos] secret_exponents = [ encoding.wif_to_tuple_of_secret_exponent_compressed( utxo.address_rec.meat.privkey, is_test=testnet)[0] for utxo in input_utxos ] unsigned_tx = UnsignedTx.standard_tx(inputs, outputs, is_test=testnet) solver = SecretExponentSolver(secret_exponents) new_tx = unsigned_tx.sign(solver) s = io.BytesIO() new_tx.stream(s) return s.getvalue()
def construct_data_tx(data, _from): # inputs coins_from = blockchain_info.coin_sources_for_address(_from) if len(coins_from) < 1: return "No free outputs to spend" max_coin_value, _, max_idx, max_h, max_script = max( (tx_out.coin_value, random(), idx, h, tx_out.script) for h, idx, tx_out in coins_from) unsigned_txs_out = [ UnsignedTxOut(max_h, max_idx, max_coin_value, max_script) ] # outputs if max_coin_value > TX_FEES * 2: return 'max output greater than twice the threshold, too big.' if max_coin_value < TX_FEES: return 'max output smaller than threshold, too small.' script_text = 'OP_RETURN %s' % data.encode('hex') script_bin = tools.compile(script_text) new_txs_out = [TxOut(0, script_bin)] version = 1 lock_time = 0 unsigned_tx = UnsignedTx(version, unsigned_txs_out, new_txs_out, lock_time) return unsigned_tx
def send(self, ddestination_address, dcolourid=None): self.colordata.update() coins_to = [] total_spent = 0 for daa in [ddestination_address]: address, amount = daa[0], daa[1] amount = btc_to_satoshi(amount) total_spent += amount coins_to.append((amount, address)) selected_utxos, total_value = self.selectUTXOs(self.getAllUTXOs(), dcolourid, total_spent) change = (total_value - total_spent) - 10000 if change >= 1: coins_to.append((change, self.addresses[0].pubkey)) coins_from = [utxo.get_pycoin_coin_source() for utxo in selected_utxos] secret_exponents = [ encoding.wif_to_secret_exponent(address.privkey) for address in self.addresses ] unsigned_tx = UnsignedTx.standard_tx(coins_from, coins_to) solver = SecretExponentSolver(secret_exponents) new_tx = unsigned_tx.sign(solver) s = io.BytesIO() new_tx.stream(s) tx_bytes = s.getvalue() tx_hex = binascii.hexlify(tx_bytes).decode("utf8") recommended_tx_fee = tx_fee.recommended_fee_for_tx(new_tx) print tx_hex URL = "http://blockchain.info/pushtx" urllib2.urlopen(URL, data=tx_hex)
def test_standard_tx_out(self): coin_value = 10 recipient_bc_address = '1BcJRKjiwYQ3f37FQSpTYM7AfnXurMjezu' tx_out = UnsignedTx.standard_tx([], [(coin_value, recipient_bc_address)]).new_txs_out[0] s = str(tx_out) self.assertEqual('TxOut<1E-7 "OP_DUP OP_HASH160 745e5b81fd30ca1e90311b012badabaa4411ae1a OP_EQUALVERIFY OP_CHECKSIG">', s)
unspent = satoshis - total_s change = unspent - fee if change < 0: raise Exception("wtf happened? can't have negative change!") if change > 0: print "Adding change of %s back to source address %s (NOTE: THIS TX WILL HAVE %s FEE!)" % (change, bitcoin_address_compressed, fee) coins_to.append((change, bitcoin_address_compressed)) #print "Here with tmpl_vars %s" % tmpl_vars html = tmpl.render(**tmpl_vars) f = open(savepath+'/qrlayout.html', "w") f.write(html) f.close() #prepare the transaction to fund these addresses. (code below essentially lifted from the bottom of pycoin's spend.py). Note that code does multiple input addresses. this is just cheesed down to a single. unsigned_tx = UnsignedTx.standard_tx(coin_sources, coins_to) solver = SecretExponentSolver([secret_exponent]) new_tx = unsigned_tx.sign(solver) print "Created tx like %s" % (repr(new_tx)) s = io.BytesIO() new_tx.stream(s) tx_bytes = s.getvalue() tx_hex = binascii.hexlify(tx_bytes).decode("utf8") #write the tx to a tx file. tx_f = open(savepath+'/pushtx.txt', "w") tx_f.write(tx_hex) tx_f.close() print "Job Complete"