def test_build_spends(self): # first, here is the tx database TX_DB = {} # 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 = standard_tx(coins_from, coins_to) solver = build_hash160_lookup([exponent]) coinbase_spend_tx = unsigned_coinbase_spend_tx.sign(solver) # now check that it validates self.assertEqual(coinbase_spend_tx.bad_signature_count(), 0) 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) coins_from = [(coinbase_spend_tx.hash(), 0, coinbase_spend_tx.txs_out[0])] unsigned_spend_tx = standard_tx(coins_from, [(int(50 * 1e8), bitcoin_address_3)]) solver.update(build_hash160_lookup([exponent_2])) spend_tx = unsigned_spend_tx.sign(solver) # now check that it validates self.assertEqual(spend_tx.bad_signature_count(), 0)
def tx_from_json_dict(r): version = r.get("version") lock_time = r.get("locktime") txs_in = [] for vin in r.get("vin"): if "coinbase" in vin: previous_hash = b'\0' * 32 script = h2b(vin.get("coinbase")) previous_index = 4294967295 else: previous_hash = h2b_rev(vin.get("txid")) scriptSig = vin.get("scriptSig") if "hex" in scriptSig: script = h2b(scriptSig.get("hex")) else: script = tools.compile(scriptSig.get("asm")) previous_index = vin.get("vout") sequence = vin.get("sequence") txs_in.append(TxIn(previous_hash, previous_index, script, sequence)) txs_out = [] for vout in r.get("vout"): coin_value = btc_to_satoshi(decimal.Decimal(vout.get("value"))) script = tools.compile(vout.get("scriptPubKey").get("asm")) txs_out.append(TxOut(coin_value, script)) tx = Tx(version, txs_in, txs_out, lock_time) bh = r.get("blockhash") if bh: bh = h2b_rev(bh) tx.confirmation_block_hash = bh return tx
def process_tx_initial(tx_obj: Tx): found_relevant_address = False for out in tx_obj.txs_out: address = out.bitcoin_address() if address in all_addresses: found_relevant_address = True break if not found_relevant_address: logging.info('Found irrelevant tx %s' % hash_to_hex(tx_obj.hash())) return tx_hash = tx_obj.hash() txid = hash_to_hex(tx_hash).decode() if tx_hash in known_txs: return known_txs.add(tx_hash) txs[tx_hash] = tx_obj.as_hex() for out in tx_obj.txs_out: address = out.bitcoin_address() if address in all_addresses and address is not None: unprocessed_txs.add(tx_hash) uid = addr_to_uid[address] account = Account(uid) account.txs.add(tx_hash) account.unconf_minutes.incr(calc_node_minutes(satoshi_amount=out.coin_value, exchange_rate=exchange_rate.get())) account.add_msg('Found tx for %.08f, %s' % (out.coin_value / COIN, txid)) nodes_recently_updated.append(account.uid)
def test_multisig_one_at_a_time(self): N = 3 M = 3 keys = [Key(secret_exponent=i) for i in range(1, M + 2)] tx_in = TxIn.coinbase_tx_in(script=b'') script = ScriptMultisig(n=N, sec_keys=[key.sec() for key in keys[:M]]).script() tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()]) ids = [ "403e5bfc59e097bb197bf77a692d158dd3a4f7affb4a1fa41072dafe7bec7058", "5931d9995e83721243dca24772d7012afcd4378996a8b953c458175f15a544db", "9bb4421088190bbbb5b42a9eaa9baed7ec7574a407c25f71992ba56ca43d9c44", "03a1dc2a63f93a5cf5a7cb668658eb3fc2eda88c06dc287b85ba3e6aff751771" ] for i in range(1, M + 1): self.assertEqual(tx2.bad_signature_count(), 1) self.assertEqual(tx2.id(), ids[i - 1]) hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys[i - 1:i]) tx2.sign(hash160_lookup=hash160_lookup) self.assertEqual(tx2.id(), ids[i]) self.assertEqual(tx2.bad_signature_count(), 0)
def dummy_op_return_tx(key, message, spendables, fee=10000): address = key.address() if len(message) > 80: raise ValueError("message must not be longer than 80 bytes") message = hexlify(message).decode() bitcoin_sum = sum(spendable.coin_value for spendable in spendables) if bitcoin_sum < fee: raise Exception("not enough bitcoin to cover fee") inputs = [spendable.tx_in() for spendable in spendables] outputs = [] if bitcoin_sum > fee: change_output_script = standard_tx_out_script(address) outputs.append(TxOut(bitcoin_sum - fee, change_output_script)) op_return_output_script = script.tools.compile('OP_RETURN %s' % message) outputs.append(TxOut(0, op_return_output_script)) tx = Tx(version=1, txs_in=inputs, txs_out=outputs) tx.set_unspents(spendables) sign_tx(tx, wifs=[key.wif()]) return tx
def test_build_spends(self): # 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) # 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) TX_DB = dict((tx.hash(), tx) for tx in [the_coinbase_tx]) coins_from = [(the_coinbase_tx.hash(), 0)] coins_to = [(int(50 * 1e8), bitcoin_address_2)] coinbase_spend_tx = Tx.standard_tx(coins_from, coins_to, TX_DB, [exponent]) coinbase_spend_tx.validate(TX_DB) ## 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) TX_DB = dict((tx.hash(), tx) for tx in [coinbase_spend_tx]) spend_tx = Tx.standard_tx([(coinbase_spend_tx.hash(), 0)], [(int(50 * 1e8), bitcoin_address_3)], TX_DB, [exponent_2]) spend_tx.validate(TX_DB)
def create_raw_transaction(self, escrow, fees): logging.info('starting raw transaction to payout address %s' % escrow['sellerpayoutaddress']) # convenience method provided by pycoin to get spendables from insight server insight = InsightService(INSIGHT) spendables = insight.spendables_for_address(escrow['multisigaddress']) # create the tx_in txs_in = [] for s in spendables: txs_in.append(s.tx_in()) script = standard_tx_out_script(escrow['multisigaddress']) tx_out = TxOut(fees['seller'], script) txs_out = [tx_out] tx1 = Tx(version=1, txs_in=txs_in, txs_out=txs_out) tx1.set_unspents(txs_out) # this will be the hex of the tx we're going to send in the POST request hex_tx = tx1.as_hex(include_unspents=True) return hex_tx
def multisig_N_of_M(self, N, M, unsigned_id, signed_id): keys = [Key(secret_exponent=i) for i in range(1, M+2)] tx_in = TxIn.coinbase_tx_in(script=b'') script = ScriptMultisig(n=N, sec_keys=[key.sec() for key in keys[:M]]).script() tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()]) self.assertEqual(tx2.id(), unsigned_id) self.assertEqual(tx2.bad_signature_count(), 1) hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys) tx2.sign(hash160_lookup=hash160_lookup) self.assertEqual(tx2.id(), signed_id) self.assertEqual(tx2.bad_signature_count(), 0)
def multisig_M_of_N(self, M, N, unsigned_id, signed_id): keys = [Key(secret_exponent=i) for i in range(1, N+2)] tx_in = TxIn.coinbase_tx_in(script=b'') script = ScriptMultisig(m=M, sec_keys=[key.sec() for key in keys[:N]]).script() tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()]) self.assertEqual(tx2.id(), unsigned_id) self.assertEqual(tx2.bad_signature_count(), 1) hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys) tx2.sign(hash160_lookup=hash160_lookup) self.assertEqual(tx2.id(), signed_id) self.assertEqual(tx2.bad_signature_count(), 0)
def multisig_M_of_N_individually(self, M, N): keys = [Key(secret_exponent=i) for i in range(1, N+2)] tx_in = TxIn.coinbase_tx_in(script=b'') script = ScriptMultisig(n=M, sec_keys=[key.sec() for key in keys[:N]]).script() tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) for partial_key_list in itertools.permutations(keys[:N], M): tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()]) for key in partial_key_list: self.assertEqual(tx2.bad_signature_count(), 1) hash160_lookup = build_hash160_lookup([key.secret_exponent()]) tx2.sign(hash160_lookup=hash160_lookup) self.assertEqual(tx2.bad_signature_count(), 0)
def load_tx(get_txs_func, rawtx): Tx.ALLOW_SEGWIT = False # FIXME remove on next pycoin version tx = Tx.from_hex(rawtx) unspent_info = {} # txid -> index for txin in tx.txs_in: unspent_info[b2h_rev(txin.previous_hash)] = txin.previous_index utxo_rawtxs = get_txs_func(list(unspent_info.keys())) for utxo_txid, utxo_rawtx in utxo_rawtxs.items(): utxo_tx = Tx.from_hex(utxo_rawtx) prev_index = unspent_info[utxo_txid] tx.unspents.append(utxo_tx.txs_out[prev_index]) return tx
def main(): if len(sys.argv) != 2: print("usage: %s address" % sys.argv[0]) sys.exit(-1) # validate the address address = sys.argv[1] assert is_address_valid(address) print("creating coinbase transaction to %s" % address) tx_in = TxIn.coinbase_tx_in(script=b'') tx_out = TxOut(50*1e8, standard_tx_out_script(address)) tx = Tx(1, [tx_in], [tx_out]) print("Here is the tx as hex:\n%s" % tx.as_hex())
def test_sign_pay_to_script_multisig(self): M, N = 3, 3 keys = [Key(secret_exponent=i) for i in range(1, N+2)] tx_in = TxIn.coinbase_tx_in(script=b'') underlying_script = ScriptMultisig(m=M, sec_keys=[key.sec() for key in keys[:N]]).script() address = address_for_pay_to_script(underlying_script) self.assertEqual(address, "39qEwuwyb2cAX38MFtrNzvq3KV9hSNov3q") script = standard_tx_out_script(address) tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [address]) hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys[:N]) p2sh_lookup = build_p2sh_lookup([underlying_script]) tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup) self.assertEqual(tx2.bad_signature_count(), 0)
def multisig_M_of_N_individually(self, M, N): keys = [Key(secret_exponent=i) for i in range(1, N + 2)] tx_in = TxIn.coinbase_tx_in(script=b'') script = ScriptMultisig(n=M, sec_keys=[key.sec() for key in keys[:N]]).script() tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) for partial_key_list in itertools.permutations(keys[:N], M): tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()]) for key in partial_key_list: self.assertEqual(tx2.bad_signature_count(), 1) hash160_lookup = build_hash160_lookup([key.secret_exponent()]) tx2.sign(hash160_lookup=hash160_lookup) self.assertEqual(tx2.bad_signature_count(), 0)
def test_sign_pay_to_script_multisig(self): N, M = 3, 3 keys = [Key(secret_exponent=i) for i in range(1, M+2)] tx_in = TxIn.coinbase_tx_in(script=b'') underlying_script = ScriptMultisig(n=N, sec_keys=[key.sec() for key in keys[:M]]).script() address = address_for_pay_to_script(underlying_script) self.assertEqual(address, "39qEwuwyb2cAX38MFtrNzvq3KV9hSNov3q") script = standard_tx_out_script(address) tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [address]) hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys[:M]) p2sh_lookup = build_p2sh_lookup([underlying_script]) tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup) self.assertEqual(tx2.bad_signature_count(), 0)
def main(): if len(sys.argv) != 2: print("usage: %s address" % sys.argv[0]) sys.exit(-1) # validate the address address = sys.argv[1] assert is_address_valid(address) print("creating coinbase transaction to %s" % address) tx_in = TxIn.coinbase_tx_in(script=b'') tx_out = TxOut(50 * 1e8, standard_tx_out_script(address)) tx = Tx(1, [tx_in], [tx_out]) print("Here is the tx as hex:\n%s" % tx.as_hex())
def standard_tx(coins_from, coins_to): txs_in = [] unspents = [] for h, idx, tx_out in coins_from: txs_in.append(TxIn(h, idx)) unspents.append(tx_out) txs_out = [] for coin_value, bitcoin_address in coins_to: txs_out.append(TxOut(coin_value, standard_tx_out_script(bitcoin_address))) version, lock_time = 1, 0 tx = Tx(version, txs_in, txs_out, lock_time) tx.set_unspents(unspents) return tx
def sign_tx(certificate_metadata, last_input, allowable_wif_prefixes=None): """sign the transaction with private key""" with open(certificate_metadata.unsigned_tx_file_name, 'rb') as in_file: hextx = str(in_file.read(), 'utf-8') logging.info( 'Signing tx with private key for recipient id: %s ...', certificate_metadata.uid) tx = Tx.from_hex(hextx) if allowable_wif_prefixes: wif = wif_to_secret_exponent( helpers.import_key(), allowable_wif_prefixes) else: wif = wif_to_secret_exponent(helpers.import_key()) lookup = build_hash160_lookup([wif]) tx.set_unspents( [TxOut(coin_value=last_input.amount, script=last_input.script_pub_key)]) signed_tx = tx.sign(lookup) signed_hextx = signed_tx.as_hex() with open(certificate_metadata.unsent_tx_file_name, 'wb') as out_file: out_file.write(bytes(signed_hextx, 'utf-8')) logging.info('Finished signing transaction for certificate uid=%s', certificate_metadata.uid)
def main(): parser = argparse.ArgumentParser( description="Add a transaction to tx cache.") parser.add_argument( "tx_id_or_path", nargs="+", help= 'The id of the transaction to fetch from web services or the path to it.' ) args = parser.parse_args() TX_RE = re.compile(r"^[0-9a-fA-F]{64}$") tx_db = get_tx_db("BTC") for p in args.tx_id_or_path: if TX_RE.match(p): tx = tx_db.get(h2b_rev(p)) if not tx: parser.error("can't find Tx with id %s" % p) else: f = open(p, "rb") try: if f.name.endswith("hex"): f = io.BytesIO(codecs.getreader("hex_codec")(f).read()) tx = Tx.parse(f) except Exception: parser.error("can't parse %s" % f.name) tx_db[tx.hash()] = tx print("cached %s" % tx.id())
def get_tx(self, tx_hash): URL = "%s/api/rawtx/%s" % (self.base_url, b2h_rev(tx_hash)) r = json.loads(urlopen(URL).read().decode("utf8")) tx = Tx.tx_from_hex(r['rawtx']) if tx.hash() == tx_hash: return tx return None
def broadcastTransaction(self, transaction): print(transaction) t = Tx.tx_from_hex(transaction) deserializer = serializers.TxSerializer() tx = deserializer.deserialize(BytesIO(bytearray.fromhex(transaction))) h = t.id() print('BROADCAST:', str(tx.calculate_hash())[2:-1], h) #try: # t = Tx.tx_from_hex (transaction) # print ('OMG',t.id ()) #except Exception as e: # print (e) if not h in self.db['mempool']: mp = self.db['mempool'] mp[h] = tx self.db['mempool'] = mp self.db.sync() self.mempooltimer = Timer(1.0, self.announceTransactions) self.mempooltimer.start() return h
def get_tx(self, tx_hash): URL = "%s/api/rawtx/%s" % (self.base_url, b2h_rev(tx_hash)) r = json.loads(urlopen(URL).read().decode("utf8")) tx = Tx.from_hex(r['rawtx']) if tx.hash() == tx_hash: return tx return None
def sign_tx(hextx, tx_input, allowable_wif_prefixes=None): """ Sign the transaction with private key :param hextx: :param tx_input: :param allowable_wif_prefixes: :return: """ logging.info('Signing tx with private key') tx = Tx.from_hex(hextx) if allowable_wif_prefixes: wif = wif_to_secret_exponent( helpers.import_key(), allowable_wif_prefixes) else: wif = wif_to_secret_exponent(helpers.import_key()) lookup = build_hash160_lookup([wif]) tx.set_unspents( [TxOut(coin_value=tx_input.amount, script=tx_input.script_pub_key)]) signed_tx = tx.sign(lookup) signed_hextx = signed_tx.as_hex() logging.info('Finished signing transaction') return signed_hextx
def test_signature_hash(self): 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) exponent = wif_to_secret_exponent( "5JMys7YfK72cRVTrbwkq5paxU7vgkMypB55KyXEtN5uSnjV7K8Y") 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) 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 = standard_tx(coins_from, coins_to) tx_out_script_to_check = the_coinbase_tx.txs_out[0].script idx = 0 actual_hash = unsigned_coinbase_spend_tx.signature_hash( tx_out_script_to_check, idx, hash_type=SIGHASH_ALL) self.assertEqual( actual_hash, 29819170155392455064899446505816569230970401928540834591675173488544269166940 )
def standard_tx(coins_from, coins_to): txs_in = [] unspents = [] for h, idx, tx_out in coins_from: txs_in.append(TxIn(h, idx)) unspents.append(tx_out) txs_out = [] for coin_value, bitcoin_address in coins_to: txs_out.append( TxOut(coin_value, standard_tx_out_script(bitcoin_address))) version, lock_time = 1, 0 tx = Tx(version, txs_in, txs_out, lock_time) tx.set_unspents(unspents) return tx
def get_tx(self, tx_hash): url = "%s/rawtx/%s" % (self.base_url, b2h_rev(tx_hash)) result = json.loads(urlopen(url).read().decode("utf8")) tx = Tx.from_hex(result["rawtx"]) if tx.hash() == tx_hash: return tx return None
def sign_tx(certificate_metadata, last_input, allowable_wif_prefixes=None): """sign the transaction with private key""" with open(certificate_metadata.unsigned_tx_file_name, 'rb') as in_file: hextx = str(in_file.read(), 'utf-8') logging.info('Signing tx with private key for recipient id: %s ...', certificate_metadata.uid) tx = Tx.from_hex(hextx) if allowable_wif_prefixes: wif = wif_to_secret_exponent(helpers.import_key(), allowable_wif_prefixes) else: wif = wif_to_secret_exponent(helpers.import_key()) lookup = build_hash160_lookup([wif]) tx.set_unspents([ TxOut(coin_value=last_input.amount, script=last_input.script_pub_key) ]) signed_tx = tx.sign(lookup) signed_hextx = signed_tx.as_hex() with open(certificate_metadata.unsent_tx_file_name, 'wb') as out_file: out_file.write(bytes(signed_hextx, 'utf-8')) logging.info('Finished signing transaction for certificate uid=%s', certificate_metadata.uid)
def check_unprocessed(top_height): for tx_hash in unprocessed_txs.members(): txid = hash_to_hex(tx_hash).decode() tx = Tx.tx_from_hex(txs[tx_hash].decode()) tx_blockchain = get_tx(txid) logging.info('Checking %s' % txid) if tx_blockchain.block_height == -1: continue if top_height - tx_blockchain.block_height + 1 >= REQUIRED_CONFIRMATIONS: # off by one error - if tx in top block that is 1 conf unprocessed_txs.remove(tx_hash) for out in tx.txs_out: address = out.bitcoin_address() if address not in all_addresses: continue account = Account(addr_to_uid[address]) satoshis = out.coin_value satoshis = int(satoshis / (1 + account.tip.get())) # scale for tip account.total_coins.incr(satoshis) node_minutes_d = calc_node_minutes(satoshis, exchange_rate=exchange_rate.get()) account.total_minutes.incr(node_minutes_d) total_nodeminutes.incr(node_minutes_d) nodes_recently_updated.append(account.uid) account.add_msg('Detected payment via txid: %s' % (txid,)) account.add_msg('Increased total paid by %.8f to %.8f (considering tip of %d %%)' % (satoshis / COIN, account.total_coins.get() / COIN, account.tip.get() * 100)) account.add_msg('Increased node life by %d minutes; expiring around %s' % (node_minutes_d, account.get_expiry().isoformat()))
def broadcastTransaction (self, transaction): print (transaction) t = Tx.tx_from_hex (transaction) deserializer = serializers.TxSerializer () tx = deserializer.deserialize (BytesIO (bytearray.fromhex(transaction))) h = t.id () print ('BROADCAST:', str (tx.calculate_hash ())[2:-1], h) #try: # t = Tx.tx_from_hex (transaction) # print ('OMG',t.id ()) #except Exception as e: # print (e) if not h in self.db['mempool']: mp = self.db['mempool'] mp[h] = tx self.db['mempool'] = mp self.db.sync () self.mempooltimer = Timer (1.0, self.announceTransactions) self.mempooltimer.start () return h
def main(): parser = argparse.ArgumentParser(description="Add a transaction to tx cache.") parser.add_argument("tx_id_or_path", nargs="+", help='The id of the transaction to fetch from web services or the path to it.') args = parser.parse_args() TX_RE = re.compile(r"^[0-9a-fA-F]{64}$") tx_db = get_tx_db() for p in args.tx_id_or_path: if TX_RE.match(p): tx = tx_db.get(h2b_rev(p)) if not tx: parser.error("can't find Tx with id %s" % p) else: f = open(p, "rb") try: if f.name.endswith("hex"): f = io.BytesIO(codecs.getreader("hex_codec")(f).read()) tx = Tx.parse(f) except Exception: parser.error("can't parse %s" % f.name) tx_db[tx.hash()] = tx print("cached %s" % tx.id())
def make_bare_tx(candidate, change_address, rs_asm, version=1): # <Tx> components spendables = [] ins = [] outs = [] # estimate the final (signed) bytesize per input based on the redeemscript redeem_script = tools.compile(rs_asm) in_size = estimate_input_size(redeem_script) # initialize size and amount counters in_amount = Decimal(0) est_size = TX_COMPONENTS.version + TX_COMPONENTS.out_count + TX_COMPONENTS.in_count # add output size est_size += OUTSIZE * 2 # iterate over unspents for utxo in candidate.utxos: value = Decimal(utxo.amount) * COIN in_amount += value script = h2b(utxo.script) # for now: test if the in_script we figured we would need, actually matches the in script :D # reverse that tx hash prevtx = h2b_rev(utxo.hash) # output index outnum = utxo.outpoint # create "spendable" spdbl = Spendable(value, script, prevtx, outnum) spendables.append(spdbl) # also create this as input as_input = spdbl.tx_in() as_input.sigs = [] ins.append(as_input) # add the estimated size per input est_size += in_size # calc fee and out amount fee = (Decimal(math.ceil(est_size / 1000)) * COIN * NETWORK_FEE) + FEE_MARGIN change_amount = Decimal( math.floor(in_amount - (candidate.amount * COIN) - fee)) # create outputs outs.append( TxOut(int(candidate.amount * COIN), make_payto(candidate.address))) outs.append(TxOut(int(change_amount), make_payto_script(change_address))) # create bare tx without sigs tx = Tx(version, ins, outs, 0, spendables) return tx
def test_validate_multisig(self): # this is a transaction in the block chain # the unspents are included too, so it can be validated f = io.BytesIO(h2b("01000000025718fb915fb8b3a802bb699ddf04dd91261ef6715f5f2820a2b1b9b7e38b4f27000000004a004830450221008c2107ed4e026ab4319a591e8d9ec37719cdea053951c660566e3a3399428af502202ecd823d5f74a77cc2159d8af2d3ea5d36a702fef9a7edaaf562aef22ac35da401ffffffff038f52231b994efb980382e4d804efeadaee13cfe01abe0d969038ccb45ec17000000000490047304402200487cd787fde9b337ab87f9fe54b9fd46d5d1692aa58e97147a4fe757f6f944202203cbcfb9c0fc4e3c453938bbea9e5ae64030cf7a97fafaf460ea2cb54ed5651b501ffffffff0100093d00000000001976a9144dc39248253538b93d3a0eb122d16882b998145888ac0000000002000000000000004751210351efb6e91a31221652105d032a2508275f374cea63939ad72f1b1e02f477da782100f2b7816db49d55d24df7bdffdbc1e203b424e8cd39f5651ab938e5e4a193569e52ae404b4c00000000004751210351efb6e91a31221652105d032a2508275f374cea63939ad72f1b1e02f477da7821004f0331742bbc917ba2056a3b8a857ea47ec088dd10475ea311302112c9d24a7152ae")) tx = Tx.parse(f) tx.parse_unspents(f) self.assertEqual(tx.id(), "70c4e749f2b8b907875d1483ae43e8a6790b0c8397bbb33682e3602617f9a77a") self.assertEqual(tx.bad_signature_count(), 0)
def get_tx(tx_hash): """ Get a Tx by its hash. """ URL = "http://btc.blockr.io/api/v1/tx/raw/%s" % b2h_rev(tx_hash) r = json.loads(urlopen(URL).read().decode("utf8")) tx = Tx.parse(io.BytesIO(h2b(r.get("data").get("tx").get("hex")))) return tx
def main(): tx = Tx.tx_from_hex(sys.argv[1]) print('Input Scripts:') for inp in tx.txs_in: print(' - ' + disassemble(inp.script)) print('Output Scripts:') for out in tx.txs_out: print(' - ' + disassemble(out.script))
def get_tx(tx_hash): """ Get a Tx by its hash. """ URL = "%s/tx/raw/%s" % (blockrendpoint.url, b2h_rev(tx_hash)) r = json.loads(urlopen(URL).read().decode("utf8")) tx = Tx.parse(io.BytesIO(h2b(r.get("data").get("tx").get("hex")))) return tx
def build_spending_tx(script_in_bin, credit_tx): txs_in = [TxIn(credit_tx.hash(), 0, script_in_bin, sequence=4294967295)] txs_out = [TxOut(credit_tx.txs_out[0].coin_value, b'')] spend_tx = Tx(1, txs_in, txs_out, unspents=credit_tx.tx_outs_as_spendable()) return spend_tx
def write_opreturn(bitcoin_address, bitcoin_private_key, raw_message, fee=5000, push=False): message = hexlify(raw_message.encode()).decode('utf8') spendables = spendables_for_address(bitcoin_address) spendables = [s for s in spendables] bitcoin_sum = sum([spendable.coin_value for spendable in spendables]) inputs = [spendable.tx_in() for spendable in spendables] outputs = [] if (bitcoin_sum > fee): change_output_script = standard_tx_out_script(bitcoin_address) print change_output_script outputs.append(TxOut(bitcoin_sum - fee, change_output_script)) ## Build the OP_RETURN output with our message op_return_output_script = script.tools.compile("OP_RETURN %s" % message) outputs.append(TxOut(0, op_return_output_script)) ## Create the transaction and sign it with the private key tx = Tx(version=1, txs_in=inputs, txs_out=outputs) tx.set_unspents(spendables) sign_tx(tx, wifs=[bitcoin_private_key]) print tx.as_hex() if not push: return tx.as_hex() else: pushtx(tx.as_hex()) else: print "INADEQUATE FUNDS"
def get_tx(self, tx_hash): """ Get a Tx by its hash. """ url_append = "tx/raw/%s" %(tx_hash) URL = self.base_url("%s" %url_append) r = json.loads(urlopen(URL).read().decode("utf8")) tx = Tx.parse(io.BytesIO(h2b(r.get("data").get("tx").get("hex")))) return tx
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 test_standard_tx_out(self): coin_value = 10 recipient_bc_address = '1BcJRKjiwYQ3f37FQSpTYM7AfnXurMjezu' tx_out = Tx.standard_tx( [], [(coin_value, recipient_bc_address)]).txs_out[0] s = str(tx_out) self.assertEqual( 'TxOut<1E-7 "OP_DUP OP_HASH160 745e5b81fd30ca1e90311b012badabaa4411ae1a OP_EQUALVERIFY OP_CHECKSIG">', s)
def test_recognize_multisig(self): h = '010000000139c92b102879eb95f14e7344e4dd7d481e1238b1bfb1fa0f735068d2927b231400000000910047304402208fc06d216ebb4b6a3a3e0f906e1512c372fa8a9c2a92505d04e9b451ea7acd0c0220764303bb7e514ddd77855949d941c934e9cbda8e3c3827bfdb5777477e73885b014730440220569ec6d2e81625dd18c73920e0079cdb4c1d67d3d7616759eb0c18cf566b3d3402201c60318f0a62e3ba85ca0f158d4dfe63c0779269eb6765b6fc939fc51e7a8ea901ffffffff0140787d01000000001976a914641ad5051edd97029a003fe9efb29359fcee409d88ac0000000040787d0100000000c952410496ec45f878b62c46c4be8e336dff7cc58df9b502178cc240eb3d31b1266f69f5767071aa3e017d1b82a0bb28dab5e27d4d8e9725b3e68ed5f8a2d45c730621e34104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af53ae' f = io.BytesIO(h2b(h)) tx = Tx.parse(f) tx.parse_unspents(f) self.assertEqual(tx.id(), "10c61e258e0a2b19b245a96a2d0a1538fe81cd4ecd547e0a3df7ed6fd3761ada") the_script = tx.unspents[0].script s = script_obj_from_script(tx.unspents[0].script) self.assertEqual(s.script(), the_script)
def prepare_tx_for_signing(hex_tx, tx_inputs): logging.info('Preparing tx for signing') transaction = Tx.from_hex(hex_tx) unspents = [ TxOut(coin_value=tx_input.coin_value, script=tx_input.script) for tx_input in tx_inputs ] transaction.set_unspents(unspents) return transaction
def test_build_spends(self): # 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) # 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) TX_DB = dict((tx.hash(), tx) for tx in [the_coinbase_tx]) coins_from = [(the_coinbase_tx.hash(), 0)] coins_to = [(int(50 * 1e8), bitcoin_address_2)] coinbase_spend_tx = Tx.standard_tx(coins_from, coins_to, TX_DB, [exponent]) coinbase_spend_tx.validate(TX_DB) ## 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) TX_DB = dict((tx.hash(), tx) for tx in [coinbase_spend_tx]) spend_tx = Tx.standard_tx([(coinbase_spend_tx.hash(), 0)], [(int(50 * 1e8), bitcoin_address_3)], TX_DB, [exponent_2]) spend_tx.validate(TX_DB)
def sign_with_paths(self, tx, input_chain_paths, output_chain_paths, spend_id=None, verifications=None, callback=None): """ Have the Oracle sign the transaction :param tx: the transaction to be signed :type tx: Tx :param input_chain_paths: the derivation path for each input, or None if the input does not need to be signed :type input_chain_paths: list[str or None] :param output_chain_paths: the derivation path for each change output, or None if the output is not change :type output_chain_paths: list[str or None] :param spend_id: an additional hex ID to disambiguate sends to the same outputs :type spend_id: str :param verifications: an optional dictionary with authorization code for each verification type. Keys include "otp" and "code" (for SMS). :type verifications: dict of [str, str] :return: a dictionary with the transaction in 'transaction' if successful :rtype: dict """ req = self._create_oracle_request(input_chain_paths, output_chain_paths, spend_id, tx, verifications, callback=callback) body = json.dumps(req) url = self._url() + "/transactions" if self.verbose > 0: print(body) self._request_logger.before('post', url, self._default_headers, body) response = requests.post(url, body, headers=self._default_headers) self._request_logger.after('post', url, response) if response.status_code >= 500: raise OracleInternalError(response.content) result = response.json() if response.status_code == 200 and result.get('result', None) == 'success': tx = None if 'transaction' in result: tx = Tx.tx_from_hex(result['transaction']['bytes']) return SignatureResult({ 'transaction': tx, 'now': result['now'], 'spend_id': result['spendId'], 'deferral': result.get('deferral') }) if result.get('result') == 'deferred': deferral = result['deferral'] until = None if deferral and deferral['reason'] == 'delay': tzlocal = dateutil.tz.tzlocal() until = dateutil.parser.parse(deferral['until']).astimezone(tzlocal) #remain = int((until - datetime.datetime.now(tzlocal)).total_seconds()) raise OracleDeferralException(deferral.get('verifications'), until, result['spendId']) elif result.get('result') == 'rejected': raise OracleRejectionException() elif result.get('result') == 'locked': raise OracleLockoutException() elif result.get('error') == 'Platform velocity hard-limit exceeded': raise OraclePlatformVelocityHardLimitException('Platform velocity hard-limit exceeded') elif response.status_code == 200 or response.status_code == 400: raise OracleError(response.content) else: raise IOError("Unknown response %d" % (response.status_code,))
def test_coinbase_tx(self): coinbase_bytes = h2b("04ed66471b02c301") tx = Tx.coinbase_tx(COINBASE_PUB_KEY_FROM_80971, int(50 * 1e8), COINBASE_BYTES_FROM_80971) s = io.BytesIO() tx.stream(s) tx1 = s.getvalue() s = io.BytesIO() block_80971.txs[0].stream(s) tx2 = s.getvalue() self.assertEqual(tx1, tx2)
def test_multisig_one_at_a_time(self): N = 3 M = 3 keys = [Key(secret_exponent=i) for i in range(1, M+2)] tx_in = TxIn.coinbase_tx_in(script=b'') script = ScriptMultisig(n=N, sec_keys=[key.sec() for key in keys[:M]]).script() tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()]) ids = ["403e5bfc59e097bb197bf77a692d158dd3a4f7affb4a1fa41072dafe7bec7058", "5931d9995e83721243dca24772d7012afcd4378996a8b953c458175f15a544db", "9bb4421088190bbbb5b42a9eaa9baed7ec7574a407c25f71992ba56ca43d9c44", "03a1dc2a63f93a5cf5a7cb668658eb3fc2eda88c06dc287b85ba3e6aff751771"] for i in range(1, M+1): self.assertEqual(tx2.bad_signature_count(), 1) self.assertEqual(tx2.id(), ids[i-1]) hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys[i-1:i]) tx2.sign(hash160_lookup=hash160_lookup) self.assertEqual(tx2.id(), ids[i]) self.assertEqual(tx2.bad_signature_count(), 0)
def tx_for_tx_hash(self, tx_hash): """ returns the pycoin.tx object for tx_hash """ try: url_append = "?token=%s&includeHex=true" % self.api_key url = self.base_url("txs/%s%s" % (b2h_rev(tx_hash), url_append)) result = json.loads(urlopen(url).read().decode("utf8")) tx = Tx.parse(io.BytesIO(h2b(result.get("hex")))) return tx except: raise Exception
def test_nulldata(self): # note that because chr() is used samples with length > 255 will not work for sample in [b'test', b'me', b'a', b'39qEwuwyb2cAX38MFtrNzvq3KV9hSNov3q']: sample_script = b'\x6a' + chr(len(sample)).encode() + sample nd = ScriptNulldata(sample) self.assertEqual(nd.nulldata, sample) self.assertEqual(nd.script(), sample_script) nd2 = ScriptNulldata.from_script(sample_script) self.assertEqual(nd.nulldata, nd2.nulldata) out = TxOut(1, nd.script()) tx = Tx(0, [], [out]) # ensure we can create a tx self.assertEqual(nd.script(), tools.compile(tools.disassemble(nd.script()))) # convert between asm and back to ensure no bugs with compilation
def write_transfer(sender, sender_priv, recipient, message, fee=m.default_fee, avoid_inputs=[]): message = hexlify(message.encode()).decode('utf8') spendables = spendables_for_address(sender) spendables = [s for s in spendables if not spendable_to_legible(s.tx_in()) in avoid_inputs] bitcoin_sum = sum([spendable.coin_value for spendable in spendables]) inputs = [spendable.tx_in() for spendable in spendables] outputs = [] if bitcoin_sum > fee + m.dust*2: remaining = bitcoin_sum - fee - m.dust*2 dest_output_script = standard_tx_out_script(recipient) change_output_script = standard_tx_out_script(sender) btc_change_output_script = standard_tx_out_script(sender) op_return_output_script = script.tools.compile("OP_RETURN %s" % message) outputs.append(TxOut(m.dust, dest_output_script)) outputs.append(TxOut(m.dust, change_output_script)) outputs.append(TxOut(remaining, btc_change_output_script)) outputs.append(TxOut(0, op_return_output_script)) tx = Tx(version=1, txs_in=inputs, txs_out=outputs) tx.set_unspents(spendables) sign_tx(tx, wifs=[sender_priv]) print tx.as_hex() return tx.as_hex() else: print "INADEQUATE FUNDS"
def test_broadcast_tx_mainnet(self): """ Broadcasting tests fail because the transaction has already been pushed. So we're looking for a 'transaction already in blockchain' error """ try: tx = Tx.from_hex(MAINNET_TX) broadcast_tx(tx) self.assertTrue(False) except Exception as e: self.assertTrue('already in block chain', str(e.args[0])) return self.assertTrue(False)
def create_coinbase_tx(parser): args = parser.parse_args() try: if len(args.txinfo) != 1: parser.error("coinbase transactions need exactly one output parameter (wif/BTC count)") wif, btc_amount = args.txinfo[0].split("/") satoshi_amount = btc_to_satoshi(btc_amount) secret_exponent, compressed = encoding.wif_to_tuple_of_secret_exponent_compressed(wif) public_pair = ecdsa.public_pair_for_secret_exponent(ecdsa.secp256k1.generator_secp256k1, secret_exponent) public_key_sec = encoding.public_pair_to_sec(public_pair, compressed=compressed) coinbase_tx = Tx.coinbase_tx(public_key_sec, satoshi_amount) return coinbase_tx except Exception: parser.error("coinbase transactions need exactly one output parameter (wif/BTC count)")
def broadcastTransaction (self, transaction): t = Tx.from_hex (transaction) h = t.id () if not h in self.db['mempool']: mp = self.db['mempool'] mp[h] = t self.db['mempool'] = mp self.db.sync () self.mempooltimer = Timer (1.0, self.announceTransactions) self.mempooltimer.start () return h