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 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 test_sign_bitcoind_partially_signed_2_of_2(self): # Finish signing a 2 of 2 transaction, that already has one signature signed by bitcoind # This tx can be found on testnet3 blockchain # txid: 9618820d7037d2f32db798c92665231cd4599326f5bd99cb59d0b723be2a13a2 raw_script = ( "522103e33b41f5ed67a77d4c4c54b3e946bd30d15b8f66e42cb29fde059c168851165521" "02b92cb20a9fb1eb9656a74eeb7387636cf64cdf502ff50511830328c1b479986452ae" ) p2sh_lookup = build_p2sh_lookup([h2b(raw_script)]) partially_signed_raw_tx = ( "010000000196238f11a5fd3ceef4efd5a186a7e6b9217d900418e72aca917cd6a6e634" "e74100000000910047304402201b41b471d9dd93cf97eed7cfc39a5767a546f6bfbf3e" "0c91ff9ad23ab9770f1f02205ce565666271d055be1f25a7e52e34cbf659f6c70770ff" "59bd783a6fcd1be3dd0147522103e33b41f5ed67a77d4c4c54b3e946bd30d15b8f66e4" "2cb29fde059c16885116552102b92cb20a9fb1eb9656a74eeb7387636cf64cdf502ff5" "0511830328c1b479986452aeffffffff01a0bb0d00000000001976a9143b3beefd6f78" "02fa8706983a76a51467bfa36f8b88ac00000000") tx = Tx.from_hex(partially_signed_raw_tx) tx_out = TxOut(1000000, h2b("a914a10dfa21ee8c33b028b92562f6fe04e60563d3c087")) tx.set_unspents([tx_out]) key = Key.from_text( "cThRBRu2jAeshWL3sH3qbqdq9f4jDiDbd1SVz4qjTZD2xL1pdbsx") hash160_lookup = build_hash160_lookup([key.secret_exponent()]) self.assertEqual(tx.bad_signature_count(), 1) tx.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup) self.assertEqual(tx.bad_signature_count(), 0) self.assertEqual( tx.id(), "9618820d7037d2f32db798c92665231cd4599326f5bd99cb59d0b723be2a13a2")
def test_sign(self): sv = 33143560198659167577410026742586567991638126035902913554051654024377193788946 tx_out_script = b'v\xa9\x14\x91\xb2K\xf9\xf5(\x852\x96\n\xc6\x87\xab\xb05\x12{\x1d(\xa5\x88\xac' st = script_obj_from_script(tx_out_script) hl = build_hash160_lookup([1]) solution = st.solve(hash160_lookup=hl, sign_value=sv, signature_type=SIGHASH_ALL) self.assertEqual(solution, b'G0D\x02 ^=\xf5\xb5[\xe6!@\x04,"\x0b\x1f\xdf\x10\\\xc8Q\x13\xafV*!\\\x1f\xc5\xb5\xc5"\xd1\xb3\xd3\x02 8\xc9YK\x15o\xae\xd7\xf3|0\x07z\xff\xbfj\xcfB\xbf\x17\xb1\xe69\xa1\xfc\xc6\xc5\x1ag\xab\xa2\x16\x01A\x04y\xbef~\xf9\xdc\xbb\xacU\xa0b\x95\xce\x87\x0b\x07\x02\x9b\xfc\xdb-\xce(\xd9Y\xf2\x81[\x16\xf8\x17\x98H:\xdaw&\xa3\xc4e]\xa4\xfb\xfc\x0e\x11\x08\xa8\xfd\x17\xb4H\xa6\x85T\x19\x9cG\xd0\x8f\xfb\x10\xd4\xb8')
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 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 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 sign_transaction(self, wif, transaction_to_sign): secret_exponent = wif_to_secret_exponent(wif, self.allowable_wif_prefixes) lookup = build_hash160_lookup([secret_exponent]) signed_transaction = transaction_to_sign.sign(lookup) # Because signing failures silently continue, first check that the inputs are signed for input in signed_transaction.txs_in: if len(input.script) == 0: logging.error('Unable to sign transaction. hextx=%s', signed_transaction.as_hex()) raise UnableToSignTxError('Unable to sign transaction') return signed_transaction
def sign_tx(service, testnet, tx, keys): netcode = 'XTN' if testnet else 'BTC' secretexponents = list(map(lambda key: key.secret_exponent(), keys)) lookup = build_hash160_lookup(secretexponents) for txin_idx in range(len(tx.txs_in)): txin = tx.txs_in[txin_idx] utxo_tx = service.get_tx(txin.previous_hash) script = utxo_tx.txs_out[txin.previous_index].script tx.sign_tx_in(lookup, txin_idx, script, SIGHASH_ALL, netcode=netcode) return tx
def get(self, v): if v in self.secret_exponent_db_cache: return self.secret_exponent_db_cache[v] for wif in self.wif_iterable: secret_exponent = wif_to_secret_exponent(wif, self.wif_prefix) d = build_hash160_lookup([secret_exponent]) self.secret_exponent_db_cache.update(d) if v in self.secret_exponent_db_cache: return self.secret_exponent_db_cache[v] self.wif_iterable = [] return None
def test_sign(self): sv = 33143560198659167577410026742586567991638126035902913554051654024377193788946 tx_out_script = b'v\xa9\x14\x91\xb2K\xf9\xf5(\x852\x96\n\xc6\x87\xab\xb05\x12{\x1d(\xa5\x88\xac' st = script_obj_from_script(tx_out_script) hl = build_hash160_lookup([1]) solution = st.solve(hash160_lookup=hl, signature_for_hash_type_f=const_f(sv), signature_type=SIGHASH_ALL) self.assertEqual( solution, h2b( "47304402205e3df5b55be62140042c220b1fdf105cc85113af562a215c1fc5b5c522d1" "b3d3022038c9594b156faed7f37c30077affbf6acf42bf17b1e639a1fcc6c51a67aba2" "1601410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817" "98483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"))
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 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 test_solve_pay_to_public_pair(self): for se in range(1, 10): key = Key(secret_exponent=se) for b in [True, False]: addr = key.address(use_uncompressed=b) st = ScriptPayToPublicKey.from_key(key, use_uncompressed=b) self.assertEqual(st.address(), addr) hl = build_hash160_lookup([se]) sv = 100 solution = st.solve(hash160_lookup=hl, sign_value=sv, signature_type=SIGHASH_ALL) sc = st.script() st = script_obj_from_script(sc) self.assertEqual(st.address(), addr)
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_solve_pay_to_address(self): for se in range(1, 10): key = Key(secret_exponent=se) for b in [True, False]: addr = key.address(use_uncompressed=b) st = script_obj_from_address(addr) self.assertEqual(st.address(), addr) hl = build_hash160_lookup([se]) sv = 100 solution = st.solve(hash160_lookup=hl, signature_for_hash_type_f=const_f(sv), signature_type=SIGHASH_ALL) sc = st.script() st = script_obj_from_script(sc) self.assertEqual(st.address(), addr)
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(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]) for partial_key_list in itertools.permutations(keys[:N], M): tx2 = 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): 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 sign_tx(hex_tx, tx_input): """ Sign the transaction with private key :param hex_tx: :param tx_input: :return: """ logging.info('Signing tx with private key') transaction = Tx.from_hex(hex_tx) wif = wif_to_secret_exponent(helpers.import_key(), ALLOWABLE_WIF_PREFIXES) lookup = build_hash160_lookup([wif]) transaction.set_unspents([TxOut(coin_value=tx_input.coin_value, script=tx_input.script)]) signed_tx = transaction.sign(lookup) logging.info('Finished signing transaction') return signed_tx
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 test_sign_bitcoind_partially_signed_2_of_2(self): # Finish signing a 2 of 2 transaction, that already has one signature signed by bitcoind # This tx can be found on testnet3 blockchain, txid: 9618820d7037d2f32db798c92665231cd4599326f5bd99cb59d0b723be2a13a2 raw_script = "522103e33b41f5ed67a77d4c4c54b3e946bd30d15b8f66e42cb29fde059c16885116552102b92cb20a9fb1eb9656a74eeb7387636cf64cdf502ff50511830328c1b479986452ae" p2sh_lookup = build_p2sh_lookup([h2b(raw_script)]) partially_signed_raw_tx = "010000000196238f11a5fd3ceef4efd5a186a7e6b9217d900418e72aca917cd6a6e634e74100000000910047304402201b41b471d9dd93cf97eed7cfc39a5767a546f6bfbf3e0c91ff9ad23ab9770f1f02205ce565666271d055be1f25a7e52e34cbf659f6c70770ff59bd783a6fcd1be3dd0147522103e33b41f5ed67a77d4c4c54b3e946bd30d15b8f66e42cb29fde059c16885116552102b92cb20a9fb1eb9656a74eeb7387636cf64cdf502ff50511830328c1b479986452aeffffffff01a0bb0d00000000001976a9143b3beefd6f7802fa8706983a76a51467bfa36f8b88ac00000000" tx = Tx.from_hex(partially_signed_raw_tx) tx_out = TxOut(1000000, h2b("a914a10dfa21ee8c33b028b92562f6fe04e60563d3c087")) tx.set_unspents([tx_out]) key = Key.from_text("cThRBRu2jAeshWL3sH3qbqdq9f4jDiDbd1SVz4qjTZD2xL1pdbsx") hash160_lookup = build_hash160_lookup([key.secret_exponent()]) self.assertEqual(tx.bad_signature_count(), 1) tx.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup) self.assertEqual(tx.bad_signature_count(), 0) self.assertEqual(tx.id(), "9618820d7037d2f32db798c92665231cd4599326f5bd99cb59d0b723be2a13a2")
def test_sign(self): sv = 33143560198659167577410026742586567991638126035902913554051654024377193788946 tx_out_script = b'v\xa9\x14\x91\xb2K\xf9\xf5(\x852\x96\n\xc6\x87\xab\xb05\x12{\x1d(\xa5\x88\xac' st = script_obj_from_script(tx_out_script) hl = build_hash160_lookup([1]) solution = st.solve(hash160_lookup=hl, signature_for_hash_type_f=const_f(sv), signature_type=SIGHASH_ALL) self.assertEqual( solution, h2b("47304402205e3df5b55be62140042c220b1fdf105cc85113af562a215c1fc5b5c522d1" "b3d3022038c9594b156faed7f37c30077affbf6acf42bf17b1e639a1fcc6c51a67aba2" "1601410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817" "98483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8" ))
def post(self): logging.info("transaction coming in") hextx = self.get_argument('hextx', None) subkeys = self.get_argument('subkeys', None) payoutaddress = self.get_argument('payoutaddress', None) fees = self.get_argument('fees', None) print subkeys if not hextx or not subkeys or not payoutaddress or not fees: logging.error("Did not receive trans or tree argument") return fees = tornado.escape.json_decode(fees) subkeys = tornado.escape.json_decode(subkeys) seed = mnemonic.Mnemonic.to_seed(PHRASE) wallet = BIP32Node.from_master_secret(seed) wifs = [] keys = [] for subkey in subkeys: key = wallet.subkey_for_path(subkey) keys.append(key) wifs.append(key.wif()) underlying_script = ScriptMultisig( n=N, sec_keys=[key.sec() for key in keys[:M]]).script() address = address_for_pay_to_script(underlying_script) tx2 = Tx.tx_from_hex(hextx) # first tx out, need another for the 1% to our wallet script = standard_tx_out_script(payoutaddress) tx_out = TxOut(fees['seller'], script) # TODO: figure out final wallet. This is sending to my phone script = standard_tx_out_script("1LhkvTTxFXam672vjwbABtkp9td7dxCwyB") tx2_out = TxOut(fees['bestcrow'], script) txs_out = [tx_out, tx2_out] tx2.txs_out = txs_out hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys) p2sh_lookup = build_p2sh_lookup([underlying_script]) tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup) print tx2.as_hex() self.write(tx2.as_hex())
def sign_deposit(get_txs_func, payer_wif, rawtx): """ Sign deposit transaction. Args: get_txs_func (function): txid list -> matching raw transactions. payer_wif (str): Payer wif used for signing. rawtx (str): Deposit raw transaction to be signed. Return: Signed deposit raw transaction. """ tx = load_tx(get_txs_func, rawtx) key = Key.from_text(payer_wif) with xxx_capture_out(): tx.sign(build_hash160_lookup([key.secret_exponent()])) return tx.as_hex()
def sign_tx(tx, utxo_list, is_test): secret_exponents = [utxo.address_rec.rawPrivKey for utxo in utxo_list if utxo.address_rec] hash160_lookup = build_hash160_lookup(secret_exponents) txins = tx.txs_in[:] for txin_idx in xrange(len(txins)): blank_txin = txins[txin_idx] utxo = None for utxo_candidate in utxo_list: if utxo_candidate.get_txhash() == blank_txin.previous_hash \ and utxo_candidate.outindex == blank_txin.previous_index: utxo = utxo_candidate break if not (utxo and utxo.address_rec): continue txout_script = utxo.script.decode('hex') tx.sign_tx_in(hash160_lookup, txin_idx, txout_script, SIGHASH_ALL)
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 sign_tx(tx, utxo_list, is_test): secret_exponents = [ utxo.address_rec.rawPrivKey for utxo in utxo_list if utxo.address_rec ] hash160_lookup = build_hash160_lookup(secret_exponents) txins = tx.txs_in[:] for txin_idx in xrange(len(txins)): blank_txin = txins[txin_idx] utxo = None for utxo_candidate in utxo_list: if utxo_candidate.get_txhash() == blank_txin.previous_hash \ and utxo_candidate.outindex == blank_txin.previous_index: utxo = utxo_candidate break if not (utxo and utxo.address_rec): continue txout_script = utxo.script.decode('hex') tx.sign_tx_in(hash160_lookup, txin_idx, txout_script, SIGHASH_ALL)
def signTxSegwit(txHex, wif_key): tx = Tx.from_hex(txHex) my_key = Key.from_text(wif_key) script = ScriptPayToAddressWit(b'\0', my_key.hash160()).script() redeem = binascii.hexlify(script).decode() in_keys = [wif_key] hash160_lookup = build_hash160_lookup( [Key.from_text(wif).secret_exponent() for wif in in_keys]) for i in range(0, len(tx.txs_in)): p2sh_lookup = build_p2sh_lookup([binascii.unhexlify(redeem)]) tx.sign_tx_in(hash160_lookup, i, tx.unspents[i].script, hash_type=SIGHASH_ALL, p2sh_lookup=p2sh_lookup) return tx.as_hex()
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 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 createTransaction (self, outs, fee): # Create the signed transaction spendables = self._spendables (int (fee)) #print (spendables) if len (spendables) == 0: logger.error ('No spendables available') return None t = create_tx(spendables, [self.address], fee=int (fee)) for o in outs: t.txs_out.append (TxOut (0.0, tools.compile (o))) secret_exponent = wif_to_secret_exponent(self.wif, allowable_wif_prefixes=[wif_prefix_for_netcode (self.chain)]) d = {} d.update (build_hash160_lookup([secret_exponent])) t.sign (d) txhash = (t.as_hex ()) return txhash
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 sign_tx(self, hex_tx, tx_input, netcode): """ Sign the transaction with private key :param hex_tx: :param tx_input: :param netcode: :return: """ logging.info('Signing tx with private key') self.secret_manager.start() wif = self.secret_manager.get_wif() transaction = Tx.from_hex(hex_tx) allowable_wif_prefixes = wif_prefix_for_netcode(netcode) se = wif_to_secret_exponent(wif, allowable_wif_prefixes) lookup = build_hash160_lookup([se]) transaction.set_unspents([TxOut(coin_value=tx_input.coin_value, script=tx_input.script)]) signed_tx = transaction.sign(lookup) self.secret_manager.stop() logging.info('Finished signing transaction') return signed_tx
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 publish_data(data, unused_utxo): data = POE_MARKER_BYTES + data if len(data) > OP_RETURN_MAX_DATA: msg = 'data too long for OP_RETURN: %s' % (data.encode('hex')) ErrorNotification.new(msg) return None, msg _from = unused_utxo.address _private_key = PAYMENT_OBJ[_from][0] secret_exponent = wif_to_secret_exponent(_private_key) #mainnet unsigned_tx = construct_data_tx(data, _from, unused_utxo) if type(unsigned_tx) == str: # error msg = 'ERROR: type(unsigned_tx) == str' ErrorNotification.new(msg) return (None, unsigned_tx) solver = build_hash160_lookup([secret_exponent]) signed_tx = unsigned_tx.sign(solver) raw_tx = tx2hex(signed_tx) txid, message = pushtxn(raw_tx) return txid, message
def publish_data(data, unused_utxo): data = POE_MARKER_BYTES + data if len(data) > OP_RETURN_MAX_DATA: msg='data too long for OP_RETURN: %s' % (data.encode('hex')) ErrorNotification.new(msg) return None, msg _from = unused_utxo.address _private_key=PAYMENT_OBJ[_from][0] secret_exponent = wif_to_secret_exponent(_private_key) #mainnet unsigned_tx = construct_data_tx(data, _from, unused_utxo) if type(unsigned_tx) == str: # error msg='ERROR: type(unsigned_tx) == str' ErrorNotification.new(msg) return (None, unsigned_tx) solver = build_hash160_lookup([secret_exponent]) signed_tx = unsigned_tx.sign(solver) raw_tx = tx2hex(signed_tx) txid, message = pushtxn(raw_tx) return txid, message
for i in subBip32PrivateNodes: print(i) print("") """ # beginning part totally signed hash160_lookup = build_hash160_lookup([subBip32PrivateNodes[i].secret_exponent() for i in range(len(subBip32PrivateNodes))]) # >>> [subBip32PrivateNodes[i].secret_exponent() for i in range(len(subBip32PrivateNodes))] # [110380562092968897127842430006032843930864261596730345665503170493711194530512, 73231854494958203118397405284330291107828238186602400029170683163884922382627] p2sh_lookup = build_p2sh_lookup([script_encoded]) p2sh_lookup = build_p2sh_lookup([script_encoded]) tx.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup) tx.bad_signature_count() # checking if the signature process has worked tx.as_hex() # is the raw hex correctly signed transaction # 01000000020076ae0b7d8b4b7b44ac0b2fe2d5dc67aabbf0898291f190c7f9004f3923744301000000fc0047304402206fa07cce3d3c76dfb837c06bea796cb5b15e9075be6f20c708175662b3439c840220110fdc96c589ccaaf019e0678efd9aa2770661fb9f61227fb34b283a433b29110147304402207fb7f368d9458dd4d5afdf2ba89f42e5420634418759cdc8438f6ece60494b9d02203efe6428ec53bd08665300470f5e21f80f37fdb131281810f3b539d8268371e7014c695221033cb2f8b318f4c14e42cbe20cb365b2017d28bc557b0dde9eca2fbe8d3c9ed1982102e680e729a24923c09db6f958363b0416bc13970008ab7b925b2f2aa410e6b0a72102208fa0a00d6b9ae56f7cc137a021d03ae294d39242d64322f69bdc785853ba6453aeffffffffbbedb48aacb4dcea45687631cf592035843e754f603f7615b590d2b2f12e858d00000000fdfe0000483045022100f3a6e2cac3ffd51c85bfa0162d60ab125d669bb31b735563b8b4f47cf9fd7495022019f9a668d4c984e1da7f9ff16321bed57df66f7a80a953cc798682204b91e4f301483045022100c6d9226dccee03fcd9539db6780e0c9af1e096b260e4b60852c4ba1c2d1c9810022061bfa26cb8984aac054d6525cb7aeb9ce2d77021233e15928c2668de60848704014c695221033cb2f8b318f4c14e42cbe20cb365b2017d28bc557b0dde9eca2fbe8d3c9ed1982102e680e729a24923c09db6f958363b0416bc13970008ab7b925b2f2aa410e6b0a72102208fa0a00d6b9ae56f7cc137a021d03ae294d39242d64322f69bdc785853ba6453aeffffffff01803801000000000017a914b2f5e0dfcfa103a0fb4208c3393c30ff3204b5d78700000000 # end part totally signed """ # To sign the transaction for cryptocorp I will sign with just one of the two private keys required let's choose the first. hash160_lookup = build_hash160_lookup([subBip32PrivateNodes[0].secret_exponent()]) p2sh_lookup = build_p2sh_lookup([script_encoded]) tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup) tx2.bad_signature_count() tx2.as_hex() # is the raw hex of the totally signed transaction print(tx.as_hex()) print("") print("N. bad signatures: %s" % tx.bad_signature_count() )
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)
print("script:") print(b2h(script)) address = address_for_pay_to_script(script) print(address) # Everything's ok until here """ tx_in = TxIn.coinbase_tx_in(script=b'') tx_out = TxOut(10000, script) # 0.1 mBits tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) """ spendables = blockr_io.spendables_for_address(address) #grab the spendables from an address tx = tx_utils.create_tx(spendables, [spk1.address()], fee="standard") # tx with the amount to the destination address. I take one key of which I have the secret key. hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys[0:2]) # only the first two are private keys # build_hash160_lookup(key.secret_exponent() for key in keys[0:1]) # I sign only with the first one. # also build_hash160_lookup(Key.secret_exponent(keys[0])) tx2.sign(hash160_lookup=hash160_lookup) tx2.as_hex() #to be tested """ tx = create_tx( spendables_for_address("1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH"), [("1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP", 100)], fee=0) tx.sign_tx(wifs=["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"]) oppure tuuto d'un colpo: tx = create_signed_tx( spendables_for_address("1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH"),
def sign_transaction(self, transaction_to_sign): secret_exponent = wif_to_secret_exponent(self.wif, self.allowable_wif_prefixes) lookup = build_hash160_lookup([secret_exponent]) signed_transaction = transaction_to_sign.sign(lookup) return signed_transaction
def _make_lookups(wif, script_hex): script_bin = h2b(script_hex) key = Key.from_text(wif) hash160_lookup = build_hash160_lookup([key.secret_exponent()]) p2sh_lookup = build_p2sh_lookup([script_bin]) return hash160_lookup, p2sh_lookup
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()
def send(self, wallet_id, passcode, address, amount, message='', fee=None, fan_unspend=10): """ Send bitcoins to address :param wallet_id: bitgo wallet id :param address: bitcoin address :param amount: btc amount in satoshis :param split: create new outputs if needed :return: boolean """ MINIMAL_FEE = 20000 MINIMAL_SPLIT = 10000000 MIN_UNSPENTS_FAN = 5 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)['unspents'] order_unspents = sorted(unspents, key=lambda k: k['confirmations'], reverse=True) total_value = 0 for d in order_unspents: 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 # make many outputs? if len(order_unspents) < MIN_UNSPENTS_FAN and (total_value > (amount + MINIMAL_SPLIT)) and fan_unspend > 0: fee = self.calculate_fee(len(spendables), fan_unspend) value = (total_value - amount - fee) / fan_unspend for i in range(fan_unspend): payables.append((change_address, value)) elif total_value > (amount + MINIMAL_FEE): # add a change address if fee is None: fee = self.calculate_fee(len(spendables), 2) value = total_value - amount - fee if value > 10000: #avoid dust payables.append((change_address, value)) 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()
def test_bip143_txs(self): # these five examples are from BIP 143 at # https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki tx_u1, tx_s1 = self.check_bip143_tx( '0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000', '01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000', [(6.25, "2103c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432ac" ), (6, "00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1")], 2, 2, 1, 17) self.assertEqual( b2h(tx_s1.hash_prevouts(SIGHASH_ALL)), "96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37") self.assertEqual( b2h(tx_s1.hash_sequence(SIGHASH_ALL)), "52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b") self.assertEqual( b2h(tx_s1.hash_outputs(SIGHASH_ALL, 0)), "863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5") script = tools.compile( "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % b2h(tx_s1.unspents[1].script[2:])) self.assertEqual( b2h( tx_s1.segwit_signature_preimage(script=script, tx_in_idx=1, hash_type=SIGHASH_ALL)), "0100000096b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd3752b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3bef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a010000001976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac0046c32300000000ffffffff863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e51100000001000000" ) self.assertEqual( b2h(to_bytes_32(tx_s1.signature_for_hash_type_segwit(script, 1, 1))), "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670") self.check_tx_can_be_signed(tx_u1, tx_s1, [ 0xbbc27228ddcb9209d7fd6f36b02f7dfa6252af40bb2f1cbc7a557da8027ff866, 0x619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9 ]) tx_u2, tx_s2 = self.check_bip143_tx( "0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000", "01000000000101db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477010000001716001479091972186c449eb1ded22b78e40d009bdf0089feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac02473044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb012103ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a2687392040000", [(10, "a9144733f37cf4db86fbc2efed2500b4f4e49f31202387")], 1, 2, 1, 1170) self.check_tx_can_be_signed(tx_u2, tx_s2, [ 0xeb696a065ef48a2192da5b28b694f87544b30fae8327c4510137a922f32c6dcf ], ["001479091972186c449eb1ded22b78e40d009bdf0089"]) tx_u3, tx_s3 = self.check_bip143_tx( "0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac00000000", "01000000000102fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e000000004847304402200af4e47c9b9629dbecc21f73af989bdaa911f7e6f6c2e9394588a3aa68f81e9902204f3fcf6ade7e5abb1295b6774c8e0abd94ae62217367096bc02ee5e435b67da201ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac000347304402200de66acf4527789bfda55fc5459e214fa6083f936b430a762c629656216805ac0220396f550692cd347171cbc1ef1f51e15282e837bb2b30860dc77c8f78bc8501e503473044022027dc95ad6b740fe5129e7e62a75dd00f291a2aeb1200b84b09d9e3789406b6c002201a9ecd315dd6a0e632ab20bbb98948bc0c6fb204f2c286963bb48517a7058e27034721026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac00000000", [(1.5625, "21036d5c20fa14fb2f635474c1dc4ef5909d4568e5569b79fc94d3448486e14685f8ac" ), (49, "00205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a0" )], 2, 1, 1, 0) tx_u4, tx_s4 = self.check_bip143_tx( "0100000002e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac00000000", "01000000000102e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000", [ (0.16777215, "0020ba468eea561b26301e4cf69fa34bde4ad60c81e70f059f045ca9a79931004a4d" ), (0.16777215, "0020d9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537" ), ], 2, 2, 1, 0) tx_u5, tx_s5 = self.check_bip143_tx( "010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000", "0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000", [(9.87654321, "a9149993a429037b5d912407a71c252019287b8d27a587")], 1, 2, 1, 0) tx_u5prime = self.unsigned_copy(tx_s5) tx_s_hex = tx_s5.as_hex() tx_u5prime.set_unspents(tx_s5.unspents) ss = [ "56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae", "0020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54" ] p2sh_lookup = build_p2sh_lookup([h2b(x) for x in ss]) for se, sighash_type in [ (0x730fff80e1413068a05b57d6a58261f07551163369787f349438ea38ca80fac6, SIGHASH_ALL), (0x11fa3d25a17cbc22b29c44a484ba552b5a53149d106d3d853e22fdd05a2d8bb3, SIGHASH_NONE), (0x77bf4141a87d55bdd7f3cd0bdccf6e9e642935fec45f2f30047be7b799120661, SIGHASH_SINGLE), (0x14af36970f5025ea3e8b5542c0f8ebe7763e674838d08808896b63c3351ffe49, SIGHASH_ANYONECANPAY | SIGHASH_ALL), (0xfe9a95c19eef81dde2b95c1284ef39be497d128e2aa46916fb02d552485e0323, SIGHASH_ANYONECANPAY | SIGHASH_NONE), (0x428a7aee9f0c2af0cd19af3cf1c78149951ea528726989b2e83e4778d2c3f890, SIGHASH_ANYONECANPAY | SIGHASH_SINGLE), ]: tx_u5prime.sign(hash_type=sighash_type, hash160_lookup=build_hash160_lookup([se]), p2sh_lookup=p2sh_lookup) self.check_signed(tx_u5prime) tx_hex = tx_u5prime.as_hex() self.assertEqual(tx_hex, tx_s_hex) self.assertEqual( b2h(tx_s5.hash_prevouts(SIGHASH_ALL)), "74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0") self.assertEqual( b2h(tx_s5.hash_sequence(SIGHASH_ALL)), "3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044") self.assertEqual( b2h(tx_s5.hash_outputs(SIGHASH_ALL, 0)), "bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc") self.assertEqual( b2h(tx_s5.hash_outputs(SIGHASH_SINGLE, 0)), "9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f708") script = tx_s5.txs_in[0].witness[-1] self.assertEqual( b2h( tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_ALL)), "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa03bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504436641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffffbc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc0000000001000000" ) self.assertEqual( b2h( tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_NONE)), "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000002000000" ) self.assertEqual( b2h( tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_SINGLE)), "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000003000000" ) self.assertEqual( b2h( tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_ALL | SIGHASH_ANYONECANPAY)), "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffffbc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc0000000081000000" ) self.assertEqual( b2h( tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_NONE | SIGHASH_ANYONECANPAY)), "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000082000000" ) self.assertEqual( b2h( tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_SINGLE | SIGHASH_ANYONECANPAY)), "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000083000000" ) tx = Tx.from_hex( "010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff0101000000000000000000000000" ) tx.set_witness(0, [ h2b(x) for x in [ "30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01", "02a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c", "ad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01" ] ]) tx = Tx.from_hex( "0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000" ) tx_hex = tx.as_hex() print(tx) print(tx_hex) tx = Tx.from_hex( "010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff0101000000000000000000000000" ) self.assertEqual( tx_hex, "0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000" ) tx_u6, tx_s6 = self.check_bip143_tx( "010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff0101000000000000000000000000", "0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000", [(0.002, "00209e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19" )], 1, 1, 1, 0) tx_u7, tx_s7 = self.check_bip143_tx( "01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000000000000", "010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960101022102966f109c54e85d3aee8321301136cedeb9fc710fdef58a9de8a73942f8e567c021034ffc99dd9a79dd3cb31e2ab3e0b09e0e67db41ac068c625cd1f491576016c84e9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000", [(0.002, "00209b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52" )], 1, 1, 1, 0) print(tx_s7.txs_in[0])
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()
def test_bip143_txs(self): # these five examples are from BIP 143 at # https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki tx_u1, tx_s1 = self.check_bip143_tx( '0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000', '01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000', [ (6.25, "2103c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432ac"), (6, "00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1") ], 2, 2, 1, 17 ) self.assertEqual(b2h(tx_s1.hash_prevouts(SIGHASH_ALL)), "96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37") self.assertEqual(b2h(tx_s1.hash_sequence(SIGHASH_ALL)), "52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b") self.assertEqual(b2h(tx_s1.hash_outputs(SIGHASH_ALL, 0)), "863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5") script = tools.compile("OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % b2h(tx_s1.unspents[1].script[2:])) self.assertEqual(b2h(tx_s1.segwit_signature_preimage(script=script, tx_in_idx=1, hash_type=SIGHASH_ALL)), "0100000096b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd3752b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3bef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a010000001976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac0046c32300000000ffffffff863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e51100000001000000") self.assertEqual(b2h(to_bytes_32(tx_s1.signature_for_hash_type_segwit(script, 1, 1))), "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670") self.check_tx_can_be_signed(tx_u1, tx_s1, [ 0xbbc27228ddcb9209d7fd6f36b02f7dfa6252af40bb2f1cbc7a557da8027ff866, 0x619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9 ]) tx_u2, tx_s2 = self.check_bip143_tx( "0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000", "01000000000101db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477010000001716001479091972186c449eb1ded22b78e40d009bdf0089feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac02473044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb012103ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a2687392040000", [(10, "a9144733f37cf4db86fbc2efed2500b4f4e49f31202387")], 1, 2, 1, 1170 ) self.check_tx_can_be_signed( tx_u2, tx_s2, [0xeb696a065ef48a2192da5b28b694f87544b30fae8327c4510137a922f32c6dcf], ["001479091972186c449eb1ded22b78e40d009bdf0089"]) tx_u3, tx_s3 = self.check_bip143_tx( "0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac00000000", "01000000000102fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e000000004847304402200af4e47c9b9629dbecc21f73af989bdaa911f7e6f6c2e9394588a3aa68f81e9902204f3fcf6ade7e5abb1295b6774c8e0abd94ae62217367096bc02ee5e435b67da201ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac000347304402200de66acf4527789bfda55fc5459e214fa6083f936b430a762c629656216805ac0220396f550692cd347171cbc1ef1f51e15282e837bb2b30860dc77c8f78bc8501e503473044022027dc95ad6b740fe5129e7e62a75dd00f291a2aeb1200b84b09d9e3789406b6c002201a9ecd315dd6a0e632ab20bbb98948bc0c6fb204f2c286963bb48517a7058e27034721026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac00000000", [ (1.5625, "21036d5c20fa14fb2f635474c1dc4ef5909d4568e5569b79fc94d3448486e14685f8ac"), (49, "00205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a0") ], 2, 1, 1, 0 ) tx_u4, tx_s4 = self.check_bip143_tx( "0100000002e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac00000000", "01000000000102e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000", [ (0.16777215, "0020ba468eea561b26301e4cf69fa34bde4ad60c81e70f059f045ca9a79931004a4d"), (0.16777215, "0020d9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537"), ], 2, 2, 1, 0 ) tx_u5, tx_s5 = self.check_bip143_tx( "010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000", "0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000", [(9.87654321, "a9149993a429037b5d912407a71c252019287b8d27a587")], 1, 2, 1, 0 ) tx_u5prime = self.unsigned_copy(tx_s5) tx_s_hex = tx_s5.as_hex() tx_u5prime.set_unspents(tx_s5.unspents) ss = ["56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae", "0020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54"] p2sh_lookup = build_p2sh_lookup([h2b(x) for x in ss]) for se, sighash_type in [ (0x730fff80e1413068a05b57d6a58261f07551163369787f349438ea38ca80fac6, SIGHASH_ALL), (0x11fa3d25a17cbc22b29c44a484ba552b5a53149d106d3d853e22fdd05a2d8bb3, SIGHASH_NONE), (0x77bf4141a87d55bdd7f3cd0bdccf6e9e642935fec45f2f30047be7b799120661, SIGHASH_SINGLE), (0x14af36970f5025ea3e8b5542c0f8ebe7763e674838d08808896b63c3351ffe49, SIGHASH_ANYONECANPAY|SIGHASH_ALL), (0xfe9a95c19eef81dde2b95c1284ef39be497d128e2aa46916fb02d552485e0323, SIGHASH_ANYONECANPAY|SIGHASH_NONE), (0x428a7aee9f0c2af0cd19af3cf1c78149951ea528726989b2e83e4778d2c3f890, SIGHASH_ANYONECANPAY|SIGHASH_SINGLE), ]: tx_u5prime.sign(hash_type=sighash_type, hash160_lookup=build_hash160_lookup([se]), p2sh_lookup=p2sh_lookup) self.check_signed(tx_u5prime) tx_hex = tx_u5prime.as_hex() self.assertEqual(tx_hex, tx_s_hex) self.assertEqual(b2h(tx_s5.hash_prevouts(SIGHASH_ALL)), "74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0") self.assertEqual(b2h(tx_s5.hash_sequence(SIGHASH_ALL)), "3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044") self.assertEqual(b2h(tx_s5.hash_outputs(SIGHASH_ALL, 0)), "bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc") self.assertEqual(b2h(tx_s5.hash_outputs(SIGHASH_SINGLE, 0)), "9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f708") script = tx_s5.txs_in[0].witness[-1] self.assertEqual(b2h(tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_ALL)), "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa03bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504436641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffffbc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc0000000001000000") self.assertEqual(b2h(tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_NONE)), "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000002000000") self.assertEqual(b2h(tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_SINGLE)), "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000003000000") self.assertEqual(b2h(tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_ALL | SIGHASH_ANYONECANPAY)), "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffffbc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc0000000081000000") self.assertEqual(b2h(tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_NONE | SIGHASH_ANYONECANPAY)), "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000082000000") self.assertEqual(b2h(tx_s5.segwit_signature_preimage(script=script, tx_in_idx=0, hash_type=SIGHASH_SINGLE | SIGHASH_ANYONECANPAY)), "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000083000000") tx = Tx.from_hex("010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff0101000000000000000000000000") tx.set_witness(0, [h2b(x) for x in [ "30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01", "02a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c", "ad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01" ]]) tx = Tx.from_hex("0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000") tx_hex = tx.as_hex() print(tx) print(tx_hex) tx = Tx.from_hex("010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff0101000000000000000000000000") self.assertEqual(tx_hex, "0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000") tx_u6, tx_s6 = self.check_bip143_tx( "010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff0101000000000000000000000000", "0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000", [(0.002, "00209e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19")], 1, 1, 1, 0 ) tx_u7, tx_s7 = self.check_bip143_tx( "01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000000000000", "010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960101022102966f109c54e85d3aee8321301136cedeb9fc710fdef58a9de8a73942f8e567c021034ffc99dd9a79dd3cb31e2ab3e0b09e0e67db41ac068c625cd1f491576016c84e9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000", [(0.002, "00209b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52")], 1, 1, 1, 0 ) print(tx_s7.txs_in[0])
# Very important part. When you move funds to a p2sh address you write a special scriptPubKey: # Instead of: OP_DUP OP_HASH160 <PubkeyHash> OP_EQUALVERIFY OP_CHECKSIG # your p2sh scriptPubKey will be: # OP_HASH160 <hash(redeemScript)> OP_EQUAL # standard_tx_out_script(address) gives the scriptPubKey for a given multisig address script = standard_tx_out_script(address) # Fake coinbase transaction to fill our p2sh address # It it is a coinbase transaction we put in a newly constructed block. tx_in = TxIn.coinbase_tx_in(script=b'') print("TxIn: %s" % tx_in.__str__()) tx_out = TxOut(1000000, script) print("TxOut: %s" % tx_out.__str__()) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) tx1.as_hex() # we now have an UTXO redeemable by supplying the script and the required sigs. # tx_utils.create_tx() allows to spend all the UTXO from the preavious tx to an arbitrary address. tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()]) # to split the input in each of the generated addresses # tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[i].address() for i in range(len(keys))]) print("unsigned transaction:") print("bad signatures: %s" % tx2.bad_signature_count()) print(tx2.as_hex()) for i in range(1, N+1): print("signining with key number: %s" % i) hash160_lookup = build_hash160_lookup([keys[i].secret_exponent()]) p2sh_lookup = build_p2sh_lookup([underlying_script]) tx2.sign(hash160_lookup=hash160_lookup,p2sh_lookup=p2sh_lookup) print(tx2.as_hex()) print("This transactions have now : %s signature of %t necessary" % (i, N)) print("bad signatures: %s" % tx2.bad_signature_count())