def txs_from_json(path): """ Read tests from ./data/tx_??valid.json Format is an array of arrays Inner arrays are either [ "comment" ] or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...], serializedTransaction, verifyFlags] ... where all scripts are stringified scripts. verifyFlags is a comma separated list of script verification flags to apply, or "NONE" """ with open(path, 'r') as f: for tvec in json.load(f): if len(tvec) == 1: continue assert len(tvec) == 3 prevouts = tvec[0] for prevout in prevouts: assert len(prevout) == 3 tx_hex = tvec[1] flags = set() for flag in tvec[2].split(','): assert flag in FLAGS flags.add(flag) try: tx = Tx.from_hex(tx_hex) except: print("Cannot parse tx_hex: %s" % tx_hex) raise spendable_db = {} blank_spendable = Spendable(0, b'', b'\0' * 32, 0) for prevout in prevouts: spendable = Spendable(coin_value=1000000, script=compile_script(prevout[2]), tx_hash=h2b_rev(prevout[0]), tx_out_index=prevout[1]) spendable_db[(spendable.tx_hash, spendable.tx_out_index)] = spendable unspents = [ spendable_db.get((tx_in.previous_hash, tx_in.previous_index), blank_spendable) for tx_in in tx.txs_in ] tx.set_unspents(unspents) yield (tx, flags)
def createTX(payment): (content,(addrToSend,amountToSend)) = payment if content is None: pass # it should include a reason for the error.... # raise an exception return None # actually instead of returning it should raise an exception.... else: (utxos,retAddr) = content keys = [] spendings = [] for ((txid,index),amount,key) in utxos: keys += [key.wif()] spendings += [ Spendable( amount , ScriptPayToAddress( key.hash160()).script() , h2b_rev(txid) , index ) ] print "########################################################################################" print ('spendings :',spendings) print ('addr to send :',addrToSend) print ('amountToSend :',amountToSend) print ('retAddr :',retAddr) print ('wif list :',keys) print ('transaction :',create_signed_tx(spendings,[(addrToSend,amountToSend),retAddr],wifs=keys, fee="standard").as_hex()) print "########################################################################################"
def test_confirm_input(self): FEE = 10000 # create a fake Spendable COIN_VALUE = 100000000 spendables = [ Spendable(COIN_VALUE, standard_tx_out_script(BITCOIN_ADDRESSES[0]), FAKE_HASHES[1], 0) ] tx_1 = create_signed_tx(spendables, BITCOIN_ADDRESSES[1:2], wifs=WIFS[:1]) spendables = tx_1.tx_outs_as_spendable() tx_db = dict((tx.hash(), tx) for tx in [tx_1]) tx_2 = create_signed_tx(spendables, BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3]) tx_2.validate_unspents(tx_db) tx_2 = create_signed_tx([s.as_dict() for s in spendables], BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3]) tx_2.validate_unspents(tx_db) tx_2 = create_signed_tx([s.as_text() for s in spendables], BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3]) tx_2.validate_unspents(tx_db)
def test_simple_spend(self): FEE = 10000 # create a fake Spendable COIN_VALUE = 100000000 spendables = [Spendable(COIN_VALUE, standard_tx_out_script(BITCOIN_ADDRESSES[0]), FAKE_HASHES[1], 0)] EXPECTED_IDS = [ "d28bff6c4a8a0f9e7d5b7df0670d07b43c5613d8c9b14e84707b1e2c0154a978", "7afbe63b00171b18f806ebd48190ebc1c68cadf286a85489c06ebe43d146489e", "2b90c150ba1d080a0816952f5d9c2642d408989cbc4d4c540591c8c9241294bd", "17b0b5b22887081595c1a9ad153e903f63bb8682ae59d6082df018dc617e5e67", "dff1b34c243becb096ad2a2d6119973067a8137cc8bf95615e742bbf6f0944c1", "206bbfbb759a8f91901d86b62390d7587f6097a32994ece7752d143fc8a02cee", "7841412716ad35cbc9954e547ba85be89e5ed0b34ed5fb8d7594517318dc10d6", "8b7e643bf47db46ada7a75b8498990b111fe20917b5610ca6759b8b0078ccd5e", "5756f0a6d5a2bbb93a07f0729d3773aaafd21393ede3ec0e20b0b5219ca45548", "32dcbb34965ea72d2caa59eb1e907aa28bac2afea43214c1809f5d8ed360f30e", ] for count in range(1, 11): tx = create_signed_tx(spendables, BITCOIN_ADDRESSES[1:count+1], wifs=WIFS[:1]) self.assertEqual(tx.bad_signature_count(), 0) self.assertEqual(tx.fee(), FEE) self.assertEqual(tx.id(), EXPECTED_IDS[count-1]) # TODO: add check that s + s < generator for each signature for i in range(count): extra = (1 if i < ((COIN_VALUE - FEE) % count) else 0) self.assertEqual(tx.txs_out[i].coin_value, (COIN_VALUE - FEE)//count + extra)
def test_segwit_create_tx(self): from pycoin.tx.tx_utils import create_tx, sign_tx from pycoin.tx.Spendable import Spendable from pycoin.tx.pay_to.ScriptPayToAddress import ScriptPayToAddress from pycoin.tx.pay_to.ScriptPayToAddressWit import ScriptPayToAddressWit from pycoin.tx.pay_to.ScriptPayToScriptWit import ScriptPayToScriptWit from pycoin.ui import address_for_pay_to_script_wit, script_obj_from_address key1 = Key(1) coin_value = 5000000 script = ScriptPayToAddressWit(b'\0', key1.hash160()).script() tx_hash = b'\ee' * 32 tx_out_index = 0 spendable = Spendable(coin_value, script, tx_hash, tx_out_index) key2 = Key(2) tx = create_tx([spendable], [(key2.address(), coin_value)]) self.check_unsigned(tx) sign_tx(tx, [key1.wif()]) self.check_signed(tx) self.assertEqual(len(tx.txs_in[0].witness), 2) s1 = ScriptPayToAddress(key1.hash160()).script() address = address_for_pay_to_script_wit(s1) spendable.script = script_obj_from_address(address).script() tx = create_tx([spendable], [(key2.address(), coin_value)]) self.check_unsigned(tx) sign_tx(tx, [key1.wif()], p2sh_lookup=build_p2sh_lookup([s1])) self.check_signed(tx)
def test_create_trx(self): SelectParams('testnet') b = h2b('8443b07464c762d7fb404ea918a5ac9b3618d5cd6a0c5ea6e4dd5d7bbe28b154') tx_input = Spendable(200, b'18eKkAWyU9kvRNHPKxnZb6wwtPMrNmRRRA', b, 0) tx_outs = [tx_utils.create_transaction_output('mgAqW5ZCnEp7fjvpj8RUL3WxsBy8rcDcCi', 0.0000275)] tx = tx_utils.create_trx('TEST'.encode('utf-8'), 3, 'mgAqW5ZCnEp7fjvpj8RUL3WxsBy8rcDcCi', tx_outs, [tx_input]) hextx = b2h(tx.serialize()) self.assertEquals(hextx, '01000000018443b07464c762d7fb404ea918a5ac9b3618d5cd6a0c5ea6e4dd5d7bbe28b1540000000000ffffffff0300000000000000001976a914072a22e5913cd939904c46bbd0bc56755543384b88acc5000000000000001976a914072a22e5913cd939904c46bbd0bc56755543384b88ac0000000000000000066a045445535400000000')
async def get_spendable_list_for_addr(self, addr: str) -> List[Spendable]: unspent_list = await self.get_listunspent_for_addr(addr) return [ Spendable( unspent['amount'], bytes(unspent['scriptPubKey']), unspent['outpoint'].hash, unspent['outpoint'].n, ) for unspent in unspent_list ]
def test_verify_transaction(self): SelectParams('testnet') b = h2b('8443b07464c762d7fb404ea918a5ac9b3618d5cd6a0c5ea6e4dd5d7bbe28b154') tx_input = Spendable(200, b'18eKkAWyU9kvRNHPKxnZb6wwtPMrNmRRRA', b, 0) tx_outs = [tx_utils.create_transaction_output('mgAqW5ZCnEp7fjvpj8RUL3WxsBy8rcDcCi', 0.0000275)] op_return_val = h2b('e9cee71ab932fde863338d08be4de9dfe39ea049bdafb342ce659ec5450b69ae') tx = tx_utils.create_trx(op_return_val, 3, 'mgAqW5ZCnEp7fjvpj8RUL3WxsBy8rcDcCi', tx_outs, [tx_input]) hextx = b2h(tx.serialize()) tx_utils.verify_transaction(hextx, b2h(op_return_val))
def test_BloomFilter(self): bf = BloomFilter(20, hash_function_count=5, tweak=127) bf.add_hash160(h2b("751e76e8199196d454941c45d1b3a323f1433bd6")) tx_hash = h2b( "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798") spendable = Spendable(coin_value=1000, script=b'foo', tx_hash=tx_hash, tx_out_index=1) bf.add_spendable(spendable) self.assertEqual(bf.filter_bytes, h2b("0000400000000000090030400042100100000000"))
def spend_sh_fund(tx_ins, wif_keys, tx_outs): """ spend script hash fund the key point of an input comes from multisig address is that, its sign script is combined with several individual signs :param tx_ins: list with tuple(tx_id, idx, balance, address, redeem_script) :param wif_keys: private keys in wif format, technical should be the same order with the pubkey in redeem script, but pycoin has inner control, so here order is not mandatory :param tx_outs: balance, receiver_address :return: raw hex and tx id """ _txs_in = [] _un_spent = [] for tx_id, idx, balance, address, _ in tx_ins: # must h2b_rev NOT h2b tx_id_b = h2b_rev(tx_id) _txs_in.append(TxIn(tx_id_b, idx)) _un_spent.append( Spendable( balance, script_obj_from_address(address, netcodes=[NET_CODE]).script(), tx_id_b, idx)) _txs_out = [] for balance, receiver_address in tx_outs: _txs_out.append( TxOut( balance, script_obj_from_address(receiver_address, netcodes=[NET_CODE]).script())) version, lock_time = 1, 0 tx = Tx(version, _txs_in, _txs_out, lock_time) tx.set_unspents(_un_spent) # construct hash160_lookup[hash160] = (secret_exponent, public_pair, compressed) for each individual key hash160_lookup = build_hash160_lookup( [Key.from_text(wif_key).secret_exponent() for wif_key in wif_keys]) for i in range(0, len(tx_ins)): # you can add some conditions that if the input script is not p2sh type, not provide p2sh_lookup, # so that all kinds of inputs can work together p2sh_lookup = build_p2sh_lookup([binascii.unhexlify(tx_ins[i][-1])]) tx.sign_tx_in(hash160_lookup, i, tx.unspents[i].script, hash_type=SIGHASH_ALL, p2sh_lookup=p2sh_lookup) return tx.as_hex(), tx.id()
def test_confirm_input_raises(self): FEE = 10000 # create a fake Spendable COIN_VALUE = 100000000 spendables = [Spendable(COIN_VALUE, standard_tx_out_script(BITCOIN_ADDRESSES[0]), FAKE_HASHES[1], 0)] tx_1 = create_signed_tx(spendables, BITCOIN_ADDRESSES[1:2], wifs=WIFS[:1]) spendables = tx_1.tx_outs_as_spendable() spendables[0].coin_value += 100 tx_db = dict((tx.hash(), tx) for tx in [tx_1]) tx_2 = create_signed_tx(spendables, BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3]) self.assertRaises(BadSpendableError, tx_2.validate_unspents, tx_db)
def spendables_for_address(self, bitcoin_address): """ Return a list of Spendable objects for the given bitcoin address. """ URL = "https://blockchain.info/unspent?active=%s" % bitcoin_address r = json.loads(urlopen(URL).read().decode("utf8")) spendables = [] for u in r["unspent_outputs"]: coin_value = u["value"] script = h2b(u["script"]) previous_hash = h2b(u["tx_hash"]) previous_index = u["tx_output_n"] spendables.append( Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def createTransaction(self, address, amount, keychain, fee="standard", confirms=0): unspents_result = yield self.unspents() spendables = [] p2sh = [] chain_paths = [] # Strip leading / keychain_path = keychain['path'][1:] for unspent in unspents_result["unspents"]: if unspent["confirmations"] < confirms: continue p2sh.append(h2b(unspent["redeemScript"])) spendable = Spendable(unspent["value"], h2b(unspent["script"]), h2b_rev(unspent["tx_hash"]), unspent["tx_output_n"]) spendables.append(spendable) chain_paths.append(keychain_path + unspent['chainPath']) p2sh_lookup = build_p2sh_lookup(p2sh) address_result = yield self.createAddress(1) change = address_result["address"] tx = tx_utils.create_tx(spendables, [(address, amount), change], fee) # address_keys = [BIP32Node.from_hwif(keychain["xprv"]).subkey_for_path("0/0/0/0"), # BIP32Node.from_hwif(keychain["xprv"]).subkey_for_path(address_result['path'])] spendable_keys = [ BIP32Node.from_hwif(keychain["xprv"]).subkey_for_path(path) for path in chain_paths ] # all_keys = address_keys + spendable_keys hash160_lookup = build_hash160_lookup( [key.secret_exponent() for key in spendable_keys]) pprint(tx) tx.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup) pprint(tx) returnValue({'tx': tx.as_hex(), 'fee': tx.fee()})
def spendables_for_address(self, address): """ Return a list of Spendable objects for the given bitcoin address. """ logging.debug('spendables_for_address %s', address) spendables = [] url_append = "?unspentOnly=true&token=%s&includeScript=true" % self.api_token url = self.base_url + '/addrs/' + address + url_append result = json.loads(urlopen(url).read().decode("utf8")) for txn in result.get("txrefs", []): coin_value = txn.get("value") script = h2b(txn.get("script")) previous_hash = h2b_rev(txn.get("tx_hash")) previous_index = txn.get("tx_output_n") spendables.append( Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def spendables_for_address(self, address): """ Converts to pycoin Spendable type :param address: :return: list of Spendables """ unspent_outputs = bitcoin.rpc.Proxy().listunspent(addrs=[address]) logging.debug('spendables_for_address %s', address) spendables = [] for unspent in unspent_outputs: coin_value = unspent.get('amount', 0) outpoint = unspent.get('outpoint') script = unspent.get('scriptPubKey') previous_hash = outpoint.hash previous_index = outpoint.n spendables.append(Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def tether_tx(tx_ins, private_key, send_amount, receiver): """ simple usdt transaction here assume utxo comes from the sender and is used for mine fee bitcoin change will be sent back to sender address of course different address's utxo can be used for mine fee, but should be aware sender is determined by the first input in the tx bitcoin change can also be sent back to different address, but should be aware receiver is indicated by the last output address that is not the sender for full customization, use btc sample p2pkh_tx :param tx_ins: utxo from the sender :param private_key: private key of the same sender :param send_amount: (display amount) * (10 ** 8) :param receiver: address to receive usdt """ _txs_in = [] _un_spent = [] total_bal = 0 for tx_id, idx, balance, address in tx_ins: total_bal += balance # must h2b_rev NOT h2b tx_id_b = h2b_rev(tx_id) _txs_in.append(TxIn(tx_id_b, idx)) _un_spent.append(Spendable(balance, standard_tx_out_script(address), tx_id_b, idx)) txn_fee = estimate_p2pkh_tx_bytes(len(tx_ins), 3) * recommend_satoshi_per_byte() _txs_out = [TxOut(total_bal - txn_fee - 546, standard_tx_out_script(tx_ins[0][3])), TxOut(0, binascii.unhexlify(omni_tether_script(send_amount))), TxOut(546, standard_tx_out_script(receiver))] version, lock_time = 1, 0 tx = Tx(version, _txs_in, _txs_out, lock_time) tx.set_unspents(_un_spent) solver = build_hash160_lookup([int(private_key, 16)] * len(tx_ins)) signed_tx = tx.sign(solver, hash_type=SIGHASH_ALL) return signed_tx.as_hex(), signed_tx.id()
def spendables_for_address(self, address): """ Return a list of Spendable objects for the given bitcoin address. """ logging.info('trying to get spendables from blockcypher') spendables = [] url_append = '?unspentOnly=true&includeScript=true' if self.api_token: url_append += '&token=' + self.api_token url = self.base_url + '/addrs/' + address + url_append response = requests.get(url) if int(response.status_code) == 200: for txn in response.json().get('txrefs', []): coin_value = txn.get('value') script = h2b(txn.get('script')) previous_hash = h2b_rev(txn.get('tx_hash')) previous_index = txn.get('tx_output_n') spendables.append(Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def test_is_invalid(self): for (prevouts, tx_hex, flags) in txs_from_json(TX_INVALID_JSON): try: tx = Tx.from_hex(tx_hex) if not check_transaction(tx): continue unspents = [ Spendable(coin_value=1000000, script=compile_script(prevout[2]), tx_hash=prevout[0], tx_out_index=prevout[1]) for prevout in prevouts ] tx.set_unspents(unspents) bs = tx.bad_signature_count() self.assertEqual(bs, 0) except: continue self.fail("Invalid transaction: " + tx.id() + " appears to be valid.")
def test_is_valid(self): for (prevouts, tx_hex, flags) in txs_from_json(TX_VALID_JSON): try: tx = Tx.from_hex(tx_hex) except: self.fail("Cannot parse tx_hex: " + tx_hex) if not check_transaction(tx): self.fail("check_transaction(tx) = False for valid tx: " + tx_hex) unspents = [ Spendable(coin_value=1000000, script=compile_script(prevout[2]), tx_hash=prevout[0], tx_out_index=prevout[1]) for prevout in prevouts ] tx.set_unspents(unspents) bs = tx.bad_signature_count() if bs > 0: msg = str(tx_hex) + " bad_signature_count() = " + str(bs) self.fail(msg)
def spend_pkh_fund(tx_ins, in_keys, tx_outs): """ p2pkh address send to p2pkh p2sh transaction :param tx_ins: list with tuple(tx_id, idx, balance, address) :param in_keys: list of private keys in hex format corresponding to each input :param tx_outs: balance, receiver_address :return: raw hex and tx id """ _txs_in = [] _un_spent = [] for tx_id, idx, balance, address in tx_ins: # must h2b_rev NOT h2b tx_id_b = h2b_rev(tx_id) _txs_in.append(TxIn(tx_id_b, idx)) _un_spent.append( Spendable( balance, script_obj_from_address(address, netcodes=[NET_CODE]).script(), tx_id_b, idx)) _txs_out = [] for balance, receiver_address in tx_outs: _txs_out.append( TxOut( balance, script_obj_from_address(receiver_address, netcodes=[NET_CODE]).script())) version, lock_time = 1, 0 tx = Tx(version, _txs_in, _txs_out, lock_time) tx.set_unspents(_un_spent) solver = build_hash160_lookup([int(pri_hex, 16) for pri_hex in in_keys]) tx.sign(solver, hash_type=SIGHASH_ALL) return tx.as_hex(), tx.id()
def searchSpendById(id): c = CoinSqlite3()._exec_sql( 'Select * from TransactionInfoOut where id = ? ', id) tmp = c.fetchone() spend = Spendable(tmp[1], tmp[2], tmp[4], tmp[6]) return spend
def send(self, wallet_id, passcode, address, amount, message='', fee=10000): """ Send bitcoins to address :param wallet_id: bitgo wallet id :param address: bitcoin address :param amount: btc amount in satoshis :return: boolean """ wallet = self.get_wallet(wallet_id) if not wallet['spendingAccount']: raise NotSpendableWallet() if not wallet['isActive']: raise NotActiveWallet() if amount < 10000: raise Exception('amount to small') if wallet['confirmedBalance'] < amount: raise NotEnoughFunds('Not enough funds: balance %s amount %s' % (wallet['confirmedBalance'], amount)) change_address = self.create_address(wallet_id, chain=1) usableKeychain = False spendables = [] chain_paths = [] p2sh = [] payables = [(address, amount)] keychain_path = "" for keychain in wallet['private']['keychains']: keychain_path = keychain['path'][1:] keychain = self.get_keychain(keychain['xpub']) if 'encryptedXprv' not in keychain: continue usableKeychain = True break if not usableKeychain: raise BitGoError("didn't found a spendable keychain") data = json.loads(keychain['encryptedXprv']) #add base64 paddings for k in ['iv', 'salt', 'ct']: data[k] = data[k] + "==" cipher = sjcl.SJCL() xprv = cipher.decrypt(data, passcode) unspents = self.get_unspents(wallet_id) total_value = 0 for d in unspents['unspents'][::-1]: path = keychain_path + d['chainPath'] chain_paths.append(path) p2sh.append(h2b(d["redeemScript"])) spendables.append( Spendable(d["value"], h2b(d["script"]), h2b_rev(d["tx_hash"]), d["tx_output_n"])) total_value += d['value'] if total_value > amount: break if total_value > (amount + fee): #add a change address #TODO: create address payables.append(change_address) p2sh_lookup = build_p2sh_lookup(p2sh) spendable_keys = [] priv_key = BIP32Node.from_hwif(xprv) spendable_keys = [ priv_key.subkey_for_path(path) for path in chain_paths ] hash160_lookup = build_hash160_lookup( [key.secret_exponent() for key in spendable_keys]) tx = create_tx(spendables, payables) tx.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup) r = requests.post(self.url + '/tx/send', { 'tx': tx.as_hex(), 'message': message }, headers={ 'Authorization': 'Bearer %s' % self.access_token, }) return r.json()