def recv_txio(self, nick, utxo_list, cj_pub, change_addr): if nick not in self.nonrespondants: debug('nick(' + nick + ') not in nonrespondants ' + str(self.nonrespondants)) return self.utxos[nick] = utxo_list order = self.db.execute('SELECT ordertype, txfee, cjfee FROM ' 'orderbook WHERE oid=? AND counterparty=?', (self.active_orders[nick], nick)).fetchone() utxo_data = common.bc_interface.query_utxo_set(self.utxos[nick]) if None in utxo_data: common.debug('ERROR outputs unconfirmed or already spent. utxo_data=' + pprint.pformat(utxo_data)) raise RuntimeError('killing taker, TODO handle this error') total_input = sum([d['value'] for d in utxo_data]) real_cjfee = calc_cj_fee(order['ordertype'], order['cjfee'], self.cj_amount) self.outputs.append({'address': change_addr, 'value': total_input - self.cj_amount - order['txfee'] + real_cjfee}) print 'fee breakdown for %s totalin=%d cjamount=%d txfee=%d realcjfee=%d' % (nick, total_input, self.cj_amount, order['txfee'], real_cjfee) cj_addr = btc.pubtoaddr(cj_pub, get_addr_vbyte()) self.outputs.append({'address': cj_addr, 'value': self.cj_amount}) self.cjfee_total += real_cjfee self.nonrespondants.remove(nick) if len(self.nonrespondants) > 0: debug('nonrespondants = ' + str(self.nonrespondants)) return debug('got all parts, enough to build a tx cjfeetotal=' + str(self.cjfee_total)) my_total_in = 0 for u, va in self.input_utxos.iteritems(): my_total_in += va['value'] #my_total_in = sum([va['value'] for u, va in self.input_utxos.iteritems()]) my_change_value = my_total_in - self.cj_amount - self.cjfee_total - self.my_txfee print 'fee breakdown for me totalin=%d txfee=%d cjfee_total=%d => changevalue=%d' % (my_total_in, self.my_txfee, self.cjfee_total, my_change_value) if self.my_change_addr == None: if my_change_value != 0 and abs(my_change_value) != 1: #seems you wont always get exactly zero because of integer rounding # so 1 satoshi extra or fewer being spent as miner fees is acceptable print 'WARNING CHANGE NOT BEING USED\nCHANGEVALUE = ' + str(my_change_value) else: self.outputs.append({'address': self.my_change_addr, 'value': my_change_value}) utxo_tx = [dict([('output', u)]) for u in sum(self.utxos.values(), [])] random.shuffle(utxo_tx) random.shuffle(self.outputs) tx = btc.mktx(utxo_tx, self.outputs) debug('obtained tx\n' + pprint.pformat(btc.deserialize(tx))) self.msgchan.send_tx(self.active_orders.keys(), tx) #now sign it ourselves here for index, ins in enumerate(btc.deserialize(tx)['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) if utxo not in self.input_utxos.keys(): continue addr = self.input_utxos[utxo]['address'] tx = btc.sign(tx, index, self.wallet.get_key_from_addr(addr)) self.latest_tx = btc.deserialize(tx)
def recv_tx(self, nick, txhex): try: self.tx = btc.deserialize(txhex) except IndexError as e: self.maker.msgchan.send_error(nick, 'malformed txhex. ' + repr(e)) log.debug('obtained tx\n' + pprint.pformat(self.tx)) goodtx, errmsg = self.verify_unsigned_tx(self.tx) if not goodtx: log.debug('not a good tx, reason=' + errmsg) self.maker.msgchan.send_error(nick, errmsg) # TODO: the above 3 errors should be encrypted, but it's a bit messy. log.debug('goodtx') sigs = [] for index, ins in enumerate(self.tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str( ins['outpoint']['index']) if utxo not in self.utxos: continue addr = self.utxos[utxo]['address'] txs = btc.sign(txhex, index, self.maker.wallet.get_key_from_addr(addr)) sigs.append( base64.b64encode( btc.deserialize(txs)['ins'][index]['script'].decode( 'hex'))) # len(sigs) > 0 guarenteed since i did verify_unsigned_tx() jm_single().bc_interface.add_tx_notify(self.tx, self.unconfirm_callback, self.confirm_callback, self.cj_addr) log.debug('sending sigs ' + str(sigs)) self.maker.msgchan.send_sigs(nick, sigs) self.maker.active_orders[nick] = None
def make_sign_and_push( ins_full, wallet, amount, output_addr=None, change_addr=None, hashcode=btc.SIGHASH_ALL, estimate_fee=False ): """Utility function for easily building transactions from wallets """ total = sum(x["value"] for x in ins_full.values()) ins = ins_full.keys() # random output address and change addr output_addr = wallet.get_new_addr(1, 1) if not output_addr else output_addr change_addr = wallet.get_new_addr(1, 0) if not change_addr else change_addr fee_est = estimate_tx_fee(len(ins), 2) if estimate_fee else 10000 outs = [{"value": amount, "address": output_addr}, {"value": total - amount - fee_est, "address": change_addr}] tx = btc.mktx(ins, outs) de_tx = btc.deserialize(tx) for index, ins in enumerate(de_tx["ins"]): utxo = ins["outpoint"]["hash"] + ":" + str(ins["outpoint"]["index"]) addr = ins_full[utxo]["address"] priv = wallet.get_key_from_addr(addr) if index % 2: priv = binascii.unhexlify(priv) tx = btc.sign(tx, index, priv, hashcode=hashcode) # pushtx returns False on any error print btc.deserialize(tx) push_succeed = jm_single().bc_interface.pushtx(tx) if push_succeed: return btc.txhash(tx) else: return False
def make_sign_and_push(ins_full, wallet, amount, output_addr=None, change_addr=None, hashcode=btc.SIGHASH_ALL): total = sum(x['value'] for x in ins_full.values()) ins = ins_full.keys() #random output address and change addr output_addr = wallet.get_new_addr(1, 1) if not output_addr else output_addr change_addr = wallet.get_new_addr(1, 0) if not change_addr else change_addr outs = [{'value': amount, 'address': output_addr}, {'value': total - amount - 100000, 'address': change_addr}] tx = btc.mktx(ins, outs) de_tx = btc.deserialize(tx) for index, ins in enumerate(de_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) addr = ins_full[utxo]['address'] priv = wallet.get_key_from_addr(addr) if index % 2: priv = binascii.unhexlify(priv) tx = btc.sign(tx, index, priv, hashcode=hashcode) #pushtx returns False on any error print btc.deserialize(tx) push_succeed = jm_single().bc_interface.pushtx(tx) if push_succeed: return btc.txhash(tx) else: return False
def make_tx_add_notify(): wallet_dict = make_wallets(1, [[1, 0, 0, 0, 0]], mean_amt=4, sdev_amt=0)[0] amount = 250000000 txfee = 10000 wallet = wallet_dict['wallet'] sync_wallet(wallet) inputs = wallet.select_utxos(0, amount) ins = inputs.keys() input_value = sum([i['value'] for i in inputs.values()]) output_addr = wallet.get_new_addr(1, 0) change_addr = wallet.get_new_addr(0, 1) outs = [{ 'value': amount, 'address': output_addr }, { 'value': input_value - amount - txfee, 'address': change_addr }] tx = btc.mktx(ins, outs) de_tx = btc.deserialize(tx) for index, ins in enumerate(de_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) addr = inputs[utxo]['address'] priv = wallet.get_key_from_addr(addr) tx = btc.sign(tx, index, priv) unconfirm_called[0] = confirm_called[0] = False timeout_unconfirm_called[0] = timeout_confirm_called[0] = False jm_single().bc_interface.add_tx_notify(btc.deserialize(tx), unconfirm_callback, confirm_callback, output_addr, timeout_callback) return tx
def recv_tx(self, nick, txhex): try: self.tx = btc.deserialize(txhex) except IndexError as e: self.maker.msgchan.send_error(nick, 'malformed txhex. ' + repr(e)) log.info('obtained tx\n' + pprint.pformat(self.tx)) goodtx, errmsg = self.verify_unsigned_tx(self.tx) if not goodtx: log.info('not a good tx, reason=' + errmsg) self.maker.msgchan.send_error(nick, errmsg) # TODO: the above 3 errors should be encrypted, but it's a bit messy. log.info('goodtx') sigs = [] for index, ins in enumerate(self.tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) if utxo not in self.utxos: continue addr = self.utxos[utxo]['address'] txs = btc.sign(txhex, index, self.maker.wallet.get_key_from_addr(addr)) sigs.append(base64.b64encode(btc.deserialize(txs)['ins'][index][ 'script'].decode('hex'))) # len(sigs) > 0 guarenteed since i did verify_unsigned_tx() jm_single().bc_interface.add_tx_notify( self.tx, self.unconfirm_callback, self.confirm_callback, self.cj_addr) self.maker.msgchan.send_sigs(nick, sigs) self.maker.active_orders[nick] = None
def make_tx_add_notify(): wallet_dict = make_wallets(1, [[1, 0, 0, 0, 0]], mean_amt=4, sdev_amt=0)[0] amount = 250000000 txfee = 10000 wallet = wallet_dict['wallet'] sync_wallet(wallet) inputs = wallet.select_utxos(0, amount) ins = inputs.keys() input_value = sum([i['value'] for i in inputs.values()]) output_addr = wallet.get_new_addr(1, 0) change_addr = wallet.get_new_addr(0, 1) outs = [{'value': amount, 'address': output_addr}, {'value': input_value - amount - txfee, 'address': change_addr}] tx = btc.mktx(ins, outs) de_tx = btc.deserialize(tx) for index, ins in enumerate(de_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) addr = inputs[utxo]['address'] priv = wallet.get_key_from_addr(addr) tx = btc.sign(tx, index, priv) unconfirm_called[0] = confirm_called[0] = False timeout_unconfirm_called[0] = timeout_confirm_called[0] = False jm_single().bc_interface.add_tx_notify( btc.deserialize(tx), unconfirm_callback, confirm_callback, output_addr, timeout_callback) return tx
def direct_send(wallet, amount, mixdepth, destaddr, answeryes=False): """Send coins directly from one mixdepth to one destination address; does not need IRC. Sweep as for normal sendpayment (set amount=0). """ #Sanity checks; note destaddr format is carefully checked in startup assert isinstance(mixdepth, int) assert mixdepth >= 0 assert isinstance(amount, int) assert amount >= 0 and amount < 10000000000 assert isinstance(wallet, Wallet) import bitcoin as btc from pprint import pformat if amount == 0: utxos = wallet.get_utxos_by_mixdepth()[mixdepth] if utxos == {}: log.error("There are no utxos in mixdepth: " + str(mixdepth) + ", quitting.") return total_inputs_val = sum([va['value'] for u, va in utxos.iteritems()]) fee_est = estimate_tx_fee(len(utxos), 1) outs = [{"address": destaddr, "value": total_inputs_val - fee_est}] else: initial_fee_est = estimate_tx_fee(8, 2) #8 inputs to be conservative utxos = wallet.select_utxos(mixdepth, amount + initial_fee_est) if len(utxos) < 8: fee_est = estimate_tx_fee(len(utxos), 2) else: fee_est = initial_fee_est total_inputs_val = sum([va['value'] for u, va in utxos.iteritems()]) changeval = total_inputs_val - fee_est - amount outs = [{"value": amount, "address": destaddr}] change_addr = wallet.get_internal_addr(mixdepth) outs.append({"value": changeval, "address": change_addr}) #Now ready to construct transaction log.info("Using a fee of : " + str(fee_est) + " satoshis.") if amount != 0: log.info("Using a change value of: " + str(changeval) + " satoshis.") tx = btc.mktx(utxos.keys(), outs) stx = btc.deserialize(tx) for index, ins in enumerate(stx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) addr = utxos[utxo]['address'] tx = btc.sign(tx, index, wallet.get_key_from_addr(addr)) txsigned = btc.deserialize(tx) log.info("Got signed transaction:\n") log.info(tx + "\n") log.info(pformat(txsigned)) if not answeryes: if raw_input( 'Would you like to push to the network? (y/n):')[0] != 'y': log.info("You chose not to broadcast the transaction, quitting.") return jm_single().bc_interface.pushtx(tx) txid = btc.txhash(tx) log.info("Transaction sent: " + txid + ", shutting down")
def get_input_and_output_scriptpubkeys(rpc, txid): gettx = rpc.call("gettransaction", [txid]) txd = btc.deserialize(gettx["hex"]) output_scriptpubkeys = [sc['script'] for sc in txd['outs']] input_scriptpubkeys = [] for ins in txd["ins"]: try: wallet_tx = rpc.call("gettransaction", [ins["outpoint"]["hash"]]) except JsonRpcError: #wallet doesnt know about this tx, so the input isnt ours continue script = btc.deserialize(str( wallet_tx["hex"]))["outs"][ins["outpoint"]["index"]]["script"] input_scriptpubkeys.append(script) return output_scriptpubkeys, input_scriptpubkeys, txd
def test_decode_nonstandard_transaction_1(self): """ txid: e411dbebd2f7d64dafeef9b14b5c59ec60c36779d43f850e5e347abee1e1a455 """ rawtransaction = ( "010000000127d57276f1026a95b4af3b03b6aba859a001861682342af19825e8a2408ae008010000008c49304" "6022100cd92b992d4bde3b44471677081c5ece6735d6936480ff74659ac1824d8a1958e022100b08839f16753" "2aea10acecc9d5f7044ddd9793ef2989d090127a6e626dc7c9ce014104cac6999d6c3feaba7cdd6c62bce1743" "39190435cffd15af7cb70c33b82027deba06e6d5441eb401c0f8f92d4ffe6038d283d2b2dd59c4384b66b7b8f" "038a7cf5ffffffff0200093d0000000000434104636d69f81d685f6f58054e17ac34d16db869bba8b3562aabc" "38c35b065158d360f087ef7bd8b0bcbd1be9a846a8ed339bf0131cdb354074244b0a9736beeb2b9ac40420f00" "00000000fdba0f76a9144838a081d73cf134e8ff9cfd4015406c73beceb388" + ("ac" * 4002) + "00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 0.01000000, "n": 1, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 4838a081d73cf134e8ff9cfd4015406c73beceb3 OP_EQUALVERIFY" + (" OP_CHECKSIG" * 4002), "hex": "76a9144838a081d73cf134e8ff9cfd4015406c73beceb388" + ("ac" * 4002), "type": "nonstandard", }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][1], 1, "main") vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(sut, vout)
def test_decode_nonstandard_transaction_2(self): """ 5492a05f1edfbd29c525a3dbf45f654d0fc45a805ccd620d0a4dff47de63f90b :return: """ rawtransaction = ( "0100000001d488bf79a92feb869c984de9fc6be7cb5c5ac2e408d608e25460501c2aff2dac010000008a47304402200f" "185ac16694f3f3902fb058f1a3d96f2549db4311b038742fc315685c9e6a1f022018e6c2c8e0559d87988b48ba80d214" "d95ed3f06795e549d4568702cc2a9e2af301410463cd01a8f2b56fff4e9357ccedf014ca119d64c1dff8b576e2785f60" "3b3fd1a04e7ab451929ef5e4e2449a7999a1365db7bc08fccc19cdad16c4ce26d6ba9bf4ffffffff03008aa411000000" "001a76a91469d28eb9a311256338d281025a7437096149472c88ac610065cd1d000000001976a9145f8b65a4064ef5c0" "71c382d594b55d94bd31ec3a88ac00100000000000001976a9146300bf4c5c2a724c280b893807afb976ec78a92b88ac" "00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 2.95995904, "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 69d28eb9a311256338d281025a7437096149472c OP_EQUALVERIFY OP_CHECKSIG OP_NOP", "hex": "76a91469d28eb9a311256338d281025a7437096149472c88ac61", "type": "nonstandard", }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(sut, vout)
def sign(tx, i, priv, t="default", script="", hashcode=SIGHASH_ALL): i = int(i) #if (not is_python2 and isinstance(re, bytes)) or not re.match('^[0-9a-fA-F]*$', tx): if not re.match('^[0-9a-fA-F]*$', tx): return binascii.unhexlify( custom_sign(safe_hexlify(tx), i, priv, hashcode)) if len(priv) <= 33: priv = b.safe_hexlify(priv) pub = b.privkey_to_pubkey(priv) address = b.pubkey_to_address(pub) if t not in ["atomic_1", "atomic_2"]: script = b.mk_pubkey_script(address) if script == "": error() signing_tx = b.signature_form( tx, i, script, hashcode) #mk_pubkey_scrip needs to be our custom scriptn sig = b.ecdsa_tx_sign(signing_tx, priv, hashcode) txobj = b.deserialize(tx) if t == "atomic_1": txobj["ins"][i]["script"] = b.serialize_script([sig]) if t == "atomic_2": old_sig = txobj["ins"][i]["script"] txobj["ins"][i]["script"] = b.serialize_script([old_sig, sig, 1]) else: txobj["ins"][i]["script"] = b.serialize_script([sig, pub]) return b.serialize(txobj)
def test_native_P2WSH_SIGHASH_SINGLE_ANYONECANPAY(self): tx = TEST_CASES[2] deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) priv0 = self.append_compressed_flag_to_privkey(tx['ins'][1]['privkey']) partially_signed = segwit_sign(generated_tx, 0, priv0, int(0.16777215 * 10**8), hashcode=SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, script=tx['ins'][0]['txinwitness'][1]) signed = segwit_sign(partially_signed, 1, priv0, int(0.16777215 * 10 ** 8), hashcode=SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, script=tx['ins'][1]['txinwitness'][1], separator_index=tx['ins'][1]['separator']) self.assertEqual(signed, tx['signed']) print('[Native P2WSH] SIGHASH_SINGLE OK')
def list_purchases(obj): txs, heights = obj['txs'], obj['heights'] o = [] for h in txs: txhex = str(txs[h]) # print txhex txouts = b.deserialize(txhex)['outs'] if len(txouts) >= 2 and txouts[0]['value'] >= minimum - 30000: addr = b.script_to_address(txouts[0]['script']) if addr == exodus: v = txouts[0]['value'] + 30000 ht = heights[h] # We care about the timestamp of the previous # confirmed block before a transaction t = get_block_header_data(ht - 1)['timestamp'] o.append({ "tx": h, "addr": b.b58check_to_hex(b.script_to_address( txouts[1]['script'])), "value": v, "time": t }) if len(o) % 50 == 0: sys.stderr.write('Gathered outputs: %d\n' % len(o)) return o
def test_decode_nonstandard_transaction_4(self): """ b728387a3cf1dfcff1eef13706816327907f79f9366a7098ee48fc0c00ad2726 """ rawtransaction = ( "0100000001658d363400dac6f939da9065c853a77d07d7e62e60a3bb8c1063437fc0018cff000000008b483045" "022100e84437d13d6f316ee69e3328c77dba344a0da973fb40b4974a753e65cf8fae0c02205f3de940ad995e3f" "960523e9afa5f5cec71ed91ef16cb3dbd7a69a43fb8898a6014104e4411b8275776b110b3b06a7ac0d5927f08f" "95a476a97ab091436fe423de660fb9606ab64749ea360b7d624c9698d26d9965732017acd3da7e9ffc13daca0f" "26ffffffff02ee4d8a050000000043410467b7944809e4b3748d2cac0c388dad7ee3555b408a7892a8bf929e85" "6afa2da4d329a39cf2c28f85438ae8d98a4d0bfb107b914933168eb9b31fae845fe8f614ac0100000000000000" "4240f816b480f87144ec4de5862adf028ff66cc6964250325d53fd22bf8922824b6f1e1f2c881ae0608ec77ebf" "88a75c66d3099113a7343238f2f7a0ebb91a4ed335ac00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout1 = { "value": 0.00000001, "n": 1, "scriptPubKey": { "asm": "f816b480f87144ec4de5862adf028ff66cc6964250325d53fd22bf8922824b6f1e1f2c881ae0608ec77ebf88a75c66d3099113a7343238f2f7a0ebb91a4ed335 OP_CHECKSIG", "hex": "40f816b480f87144ec4de5862adf028ff66cc6964250325d53fd22bf8922824b6f1e1f2c881ae0608ec77ebf88a75c66d3099113a7343238f2f7a0ebb91a4ed335ac", "type": "pubkey", }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][1], 1, "main") vout = json.loads(json.dumps(bitcoind_json_vout1), parse_float=Decimal) self.assertEqual(sut, vout)
def test_Vin(self): rawtransaction = ( "01000000031091bb34c19754b689685bd5f84078b437653d08377d2d03d256b34f80eb219e010000008a4730440" "220476c26cdcecccf46fdd96fb87814661cb1044e103d1bcd5be339b9cbaceca47902201b2caafe5b36913ef475" "d4d33b9d62aa3316ece6f1ac3371a506906e61afd4510141048c632401521a105db6b62db0a2c393181b5538f2c" "56d461057611252baebc9c7794378c252c45b7393fc93ea3b8bc6d6db1c9b5506744d51d1ddd7a9acd27d81ffff" "ffffcc72f7a8acf77c1b1313d4ba229bff7db4f40e0a1b525a9b8a4dbc8ecc80b070000000008b4830450221009" "97b74ef85d3be61a96a4d8ecebfeb588979364276f54fa77571ff8fb7906e4202204390f9935695194362fbc221" "b00436b4811d01f645715105f9d081ad65977e2b014104fd579aa4983cece29365038ddbaf479af86bdf25afdca" "e67bbe8b30c268aecdac6cd8f923ef3f23ab694783f9243522f67886a46a43499e3fb3ed49623869d6fffffffff" "8ecdae566b8e8d709a32054175ce61fc2a9323e60023f62b23c342a7186beeea000000008b48304502200f95d4c" "d51bb5b867563700979ea23bf69921b1a0262ff5de3d7330bb992a713022100de58fa5822e7e62c8e6e4edbdece" "7913cb21f5a7b5a39d85fa9291874ce81a710141045f7f6eed56863bf527b8fd30cbe78038db311370da6c7054b" "eced527d60f47a65d6f1ce62278ba496f5da4a3d738eac0e2cb0f4ac38b113cbeabef59b685b16cffffffff0280" "c51b11010000000576a90088ac4cbdd397a90000001976a914d1121a58483d135c953e0f4e2cc6d126b5c6b0638" "8ac00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vin0 = { "txid": "9e21eb804fb356d2032d7d37083d6537b47840f8d55b6889b65497c134bb9110", "vout": 1, "scriptSig": { "asm": "30440220476c26cdcecccf46fdd96fb87814661cb1044e103d1bcd5be339b9cbaceca47902201b2caafe5b36913ef475d4d33b9d62aa3316ece6f1ac3371a506906e61afd45101 048c632401521a105db6b62db0a2c393181b5538f2c56d461057611252baebc9c7794378c252c45b7393fc93ea3b8bc6d6db1c9b5506744d51d1ddd7a9acd27d81", "hex": "4730440220476c26cdcecccf46fdd96fb87814661cb1044e103d1bcd5be339b9cbaceca47902201b2caafe5b36913ef475d4d33b9d62aa3316ece6f1ac3371a506906e61afd4510141048c632401521a105db6b62db0a2c393181b5538f2c56d461057611252baebc9c7794378c252c45b7393fc93ea3b8bc6d6db1c9b5506744d51d1ddd7a9acd27d81", }, "sequence": 4294967295, } sut = VINDecoder.decode(pybtcd_deserialized_transaction["ins"][0]) vin = json.loads(json.dumps(bitcoind_json_vin0), parse_float=Decimal) self.assertEqual(vin, sut)
def test_decode_nonostandard_9(self): """ 0f20c8dab4a8dfb50dd5cf4c276ba1fab1c79cae5b6641be2f67faaca838c1e6 """ rawtransaction = ( "0100000002919ce962176f35c28531389b386f98ea9ca418bfe50b2791bc680424638b6079010000006b48304" "5022100f1165ece65fc48f7b72e274b874924cece0f943ce5bc041bdcce23f7346218f0022079cf10cde06355" "11f465d18d16edab9321eac9055f5a66c320fc8ef364bb6c72012102b20dafdbe1f0da03bbe07eae16e07fe6a" "29cf3e3e564525ce4d5a9b687a1bd22ffffffffe109088d7f9ffeae98d356c535ca4d6e5893b561a299f71dfd" "2e6af1fdff7abf010000006c493046022100e058b2e7fd16e73841dcfbc58eb644d1ee84d055913e2858855e8" "2df35496598022100bc56a9b63f547d451b3d7a02a5e8d6fa94777c29dc84d1f2ecd5590da8f00c9e012102e3" "5cd7a41926b636db064133926c1834139dd58cb5fd968258d01b1b696c2da3ffffffff01e03cc80100000000a" "a512102953397b893148acec2a9da8341159e9e7fb3d32987c3563e8bdf22116213623441048da561da64584f" "b1457e906bc2840a1f963b401b632ab98761d12d74dd795bbf410c7b6d6fd39acf9d870cb9726578eaf8ba430" "bb296eac24957f3fb3395b8b042060466616fb675310aeb024f957b4387298dc28305bc7276bf1f7f662a6764" "bcdffb6a9740de596f89ad8000f8fa6741d65ff1338f53eb39e98179dd18c6e6be8e3953ae00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 0.29900000, "n": 0, "scriptPubKey": { "asm": "1 02953397b893148acec2a9da8341159e9e7fb3d32987c3563e8bdf221162136234 048da561da64584fb1457e906bc2840a1f963b401b632ab98761d12d74dd795bbf410c7b6d6fd39acf9d870cb9726578eaf8ba430bb296eac24957f3fb3395b8b0 060466616fb675310aeb024f957b4387298dc28305bc7276bf1f7f662a6764bcdffb6a9740de596f89ad8000f8fa6741d65ff1338f53eb39e98179dd18c6e6be8e39 3 OP_CHECKMULTISIG", "hex": "512102953397b893148acec2a9da8341159e9e7fb3d32987c3563e8bdf22116213623441048da561da64584fb1457e906bc2840a1f963b401b632ab98761d12d74dd795bbf410c7b6d6fd39acf9d870cb9726578eaf8ba430bb296eac24957f3fb3395b8b042060466616fb675310aeb024f957b4387298dc28305bc7276bf1f7f662a6764bcdffb6a9740de596f89ad8000f8fa6741d65ff1338f53eb39e98179dd18c6e6be8e3953ae", "type": "nonstandard", }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(sut, vout)
def test__decode_PayToPubKeyHash(self): """ OP_DUP OP_HASH160 OP_DATA_20 OP_EQUALVERIFY OP_CHECKSIG """ rawtransaction = ( "0100000002bc2ea135edf7fe4cbf907601a6dddcaa093c502791b476ebb756a2f63c72ae24000000" "008c4930460221009d4aa20d971b7c90143750227c905608e9dfe3546a02b25411b3005045e2ba60" "0221008c52ef6fe58ea64492ee1cde059bb22e0d7eeea2d7130f522c5dc02d598f7b2c0141040277" "a8116d60b32ddd8fe5e6215e10c39880888a7c7f125fa6815b06a0b51d934cc2b30a3c22e06ff179" "bca23c54652f233f7665cc54f8b7b1971e894482ea45ffffffffbc2ea135edf7fe4cbf907601a6dd" "dcaa093c502791b476ebb756a2f63c72ae24010000008c493046022100d4c00f143da46e733e5afe" "5f8babe61884d6b42250346f9e26f12d5821d70a7d022100b93ae61ab3792b4d2290c793b128a326" "c96234ac662793821063d887044e49f1014104f6e8c8581ee3dba51288e68386475fba780710c964" "dfb1aaabea06afb4fb0cd10282adf8bfed9fb94d959a089fcd19f691a0cc7b14b1f5aae5e132b39c" "c63efaffffffff0280d87407030000001976a914f5118746a4dce6ac146077f73fea49e10b1e908e" "88ac401c59c0020000001976a914c2a7a8f990252e6e048476b6a7a4433be10e9c3588ac00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 130.10000000, "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 f5118746a4dce6ac146077f73fea49e10b1e908e OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a914f5118746a4dce6ac146077f73fea49e10b1e908e88ac", "reqSigs": 1, "type": "pubkeyhash", "addresses": ["1PLoYttF6YdytJRzdnyubpEethhn5B8836"], }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(vout, sut)
def test_decode_nonstandard_8(self): rawtransaction = ( "0100000001b409333c7daee2ecb95e860ce7dc3376eff8aae437cad727cf9b624cf3354c00010000008a47304" "40220b5afdf9e538c59fd0604d43c7053cefeff20bbe434f7c0d71b8800c31e88c34b02209e0d55cc3bae16f8" "ba347213d0b565b915f25e401351c2d405edcec69af0508f01410441a99c4157ed26924cd410a1cd3d7524e3f" "4a1a5d4e764755b73abbd0c479d8a3e9c4b916e62d5603ac4514fffccaa4a27aa7d2cac403a6b872981e71acb" "9528ffffffff0400ca9a3b000000001976a9140cbc34efb7e6cde16940cc0283a5770c6627616c88ace0b85a0" "2000000001976a91403f024eb71ceafb36c67bc7ebdcfbd0e6b2a70d488ac00000000000000007b4c784d6573" "736167653a2057656c6c204920677565737320746861742773206f6e652077617920746f20646f2069742e205" "768792063616e27742074686520717420636c69656e742062652074686973206e6963653f20466f7220616e79" "6f6e6520737472696e67732d696e672074686520626c6f636b636861ac000000000000000023214120656c656" "374696f6e7320736f6f6e2e00000000000000000000000000000000ac00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vouts = [ { "value": 10.00000000, "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 0cbc34efb7e6cde16940cc0283a5770c6627616c OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a9140cbc34efb7e6cde16940cc0283a5770c6627616c88ac", "reqSigs": 1, "type": "pubkeyhash", "addresses": ["12ALa92sWLrXy5DSwL6Qs53AY4GP5e4GrX"], }, }, { "value": 0.39500000, "n": 1, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 03f024eb71ceafb36c67bc7ebdcfbd0e6b2a70d4 OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a91403f024eb71ceafb36c67bc7ebdcfbd0e6b2a70d488ac", "reqSigs": 1, "type": "pubkeyhash", "addresses": ["1Mpi67rzcwzmkcrzTAakUwtYnRcERSbhs"], }, }, { "value": 0.00000000, "n": 2, "scriptPubKey": { "asm": "4d6573736167653a2057656c6c204920677565737320746861742773206f6e652077617920746f20646f2069742e205768792063616e27742074686520717420636c69656e742062652074686973206e6963653f20466f7220616e796f6e6520737472696e67732d696e672074686520626c6f636b636861 OP_CHECKSIG", "hex": "4c784d6573736167653a2057656c6c204920677565737320746861742773206f6e652077617920746f20646f2069742e205768792063616e27742074686520717420636c69656e742062652074686973206e6963653f20466f7220616e796f6e6520737472696e67732d696e672074686520626c6f636b636861ac", "type": "nonstandard", }, }, { "value": 0.00000000, "n": 3, "scriptPubKey": { "asm": "4120656c656374696f6e7320736f6f6e2e00000000000000000000000000000000 OP_CHECKSIG", "hex": "214120656c656374696f6e7320736f6f6e2e00000000000000000000000000000000ac", "type": "pubkey", }, }, ] for x in bitcoind_json_vouts: sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][x["n"]], x["n"], "main") vout = json.loads(json.dumps(x), parse_float=Decimal) self.assertEqual(sut, vout)
def test_native_P2WSH_SIGHASH_SINGLE_ANYONECANPAY(self): tx = TEST_CASES[2] deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) priv0 = self.append_compressed_flag_to_privkey(tx['ins'][1]['privkey']) partially_signed = segwit_sign(generated_tx, 0, priv0, int(0.16777215 * 10**8), hashcode=SIGHASH_SINGLE | SIGHASH_ANYONECANPAY, script=tx['ins'][0]['txinwitness'][1]) signed = segwit_sign(partially_signed, 1, priv0, int(0.16777215 * 10**8), hashcode=SIGHASH_SINGLE | SIGHASH_ANYONECANPAY, script=tx['ins'][1]['txinwitness'][1], separator_index=tx['ins'][1]['separator']) self.assertEqual(signed, tx['signed']) print('[Native P2WSH] SIGHASH_SINGLE OK')
def test_decode_standard_pubkeyhash_op_drop_vin(self): """ 51874c4b26a92dacb256f0e60303daabf60a63681111c4c1948f0bba25d8df96 """ rawtransaction = ( "010000000135ae0d99ffc1aea8fe97944e01b7842cbcbb5e186ab993438def514a2153b5cd0000000003010075f" "fffffff01b01df505000000001976a914d994aabea310efb308baa96c044aeae1fe1c413188ac00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 0.99950000, "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 d994aabea310efb308baa96c044aeae1fe1c4131 OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a914d994aabea310efb308baa96c044aeae1fe1c413188ac", "reqSigs": 1, "type": "pubkeyhash", "addresses": ["1LqTjBzMRdXQqXpRQo1zDYRiUobAVS55Lo"], }, } bitcoind_json_vin0 = { "txid": "cdb553214a51ef8d4393b96a185ebbbc2c84b7014e9497fea8aec1ff990dae35", "vout": 0, "scriptSig": {"asm": "0 OP_DROP", "hex": "010075"}, "sequence": 4294967295, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") sut_in = VINDecoder.decode(pybtcd_deserialized_transaction["ins"][0]) vin = json.loads(json.dumps(bitcoind_json_vin0), parse_float=Decimal) vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(sut, vout) self.assertEqual(sut_in, vin)
def test__decode_PayToPubKey_33_bytes(self): """ OP_DATA_33 OP_CHECKSIG """ rawtransaction = ( "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3c049" "93c1c4f02b0002c4d4d3d3d7df37de04d7764c9945027b3d19e66a03ef56bdd230f36648ad8b4b0ce9e2a81" "0100000000000000062f503253482fffffffff0100f2052a010000002321024d57123256b2a84e6618bc12b" "08f81cd54ec79fcd7a55a129eee9402bac8d5f7ac00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 50.00000000, "n": 0, "scriptPubKey": { "asm": "024d57123256b2a84e6618bc12b08f81cd54ec79fcd7a55a129eee9402bac8d5f7 OP_CHECKSIG", "hex": "21024d57123256b2a84e6618bc12b08f81cd54ec79fcd7a55a129eee9402bac8d5f7ac", "reqSigs": 1, "type": "pubkey", "addresses": ["1PLDXZPhFEfGGxdXr54FxvWUvWcRCrjHEG"], }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(vout, sut)
def test_decode_nonstandard_transaction_9(self): """ 91c8b08f305d895d6bc8f43bbdd36dcbc7f1d998e3df5e8f13dd9cdeebf15cb5 """ rawtransaction = ( "0100000001a30562a1cd9e907a90d7367ceaf55e859417a53ffda6190086110b7f8a4b4d2201000000020151ffff" "ffff0130d397000000000017a91469d98314fbc4dbee037f86f51392a14c4c1d41da8700000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 0.09950000, "n": 0, "scriptPubKey": { "asm": "OP_HASH160 69d98314fbc4dbee037f86f51392a14c4c1d41da OP_EQUAL", "hex": "a91469d98314fbc4dbee037f86f51392a14c4c1d41da87", "reqSigs": 1, "type": "scripthash", "addresses": ["3BLhSgpY9xCFJv9Y6AyA9eSRZT6k3z6w4s"], }, } bitcoind_json_vin1 = { "txid": "224d4b8a7f0b11860019a6fd3fa51794855ef5ea7c36d7907a909ecda16205a3", "vout": 1, "scriptSig": {"asm": "81", "hex": "0151"}, "sequence": 4294967295, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") sut_in = VINDecoder.decode(pybtcd_deserialized_transaction["ins"][0]) vin = json.loads(json.dumps(bitcoind_json_vin1), parse_float=Decimal) vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(sut, vout) self.assertEqual(sut_in, vin)
def test__decode_OPRETURN_data(self): """ OP_RETURN OP_DATA """ rawtransaction = ( "0100000001c858ba5f607d762fe5be1dfe97ddc121827895c2562c4348d69d02b91dbb408e0100000" "08b4830450220446df4e6b875af246800c8c976de7cd6d7d95016c4a8f7bcdbba81679cbda2420221" "00c1ccfacfeb5e83087894aa8d9e37b11f5c054a75d030d5bfd94d17c5bc953d4a0141045901f6367" "ea950a5665335065342b952c5d5d60607b3cdc6c69a03df1a6b915aa02eb5e07095a2548a98dcdd84" "d875c6a3e130bafadfd45e694a3474e71405a4ffffffff020000000000000000156a13636861726c6" "579206c6f766573206865696469400d0300000000001976a914b8268ce4d481413c4e848ff353cd16" "104291c45b88ac00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 0.00000000, "n": 0, "scriptPubKey": { "asm": "OP_RETURN 636861726c6579206c6f766573206865696469", "hex": "6a13636861726c6579206c6f766573206865696469", "type": "nulldata", }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(vout, sut)
def test__decode_PayToPubKey_65_bytes(self): """ OP_DATA_65 OP_CHECKSIG """ rawtransaction = ( "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704f" "fff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a62" "7c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac0" "0000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 50.00000000, "n": 0, "scriptPubKey": { "asm": "0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee OP_CHECKSIG", "hex": "410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac", "reqSigs": 1, "type": "pubkey", "addresses": ["12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX"], }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(vout, sut)
def test__decode_P2SH(self): """ OP_HASH160 OP_DATA_20 OP_EQUAL """ rawtransaction = ( "0100000001323fcde8eb922407811af73ace8a621587f0e3756d9daa0306f43e9ee806701401000000fc" "004730440220385b914def508fe2e19e4db04eb3a242f9f2052ca4850e4d4ef47086c2ff0ca20220323c" "67b383d34731c3adcc231b3efbbd385a1ac1f9edbb03794361b0f8c39775014730440220663eb7920041" "7e448da1acfbf16543045ff42a8e2c64121589062f0e5311e879022010cb0965a9aa96bab8824778c2ae" "790ec14ed3bfaf4905478021152cbf78517f014c69522102d125ff449e4de303919ef232dafa0bc7528b" "266a576da91f6fd25a4709f98337210290418ccfa7e5ca60c01d5525be826dc791009e698519b4c090b4" "5e75ec8887d4210329ff00450d9756ecc26fc5446aebce88d4053f30cb08768e7cce3d172983d58f53ae" "ffffffff020b7e32000000000017a9146af7caf9b09224af8a171318f69d254c1756e54e87db8f0f2c00" "00000017a914fe9840ab09de0fa3d2f4c73da1d1fc49f0c0bb508700000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 0.03309067, "n": 0, "scriptPubKey": { "asm": "OP_HASH160 6af7caf9b09224af8a171318f69d254c1756e54e OP_EQUAL", "hex": "a9146af7caf9b09224af8a171318f69d254c1756e54e87", "reqSigs": 1, "type": "scripthash", "addresses": ["3BScPpzxa8LErVDWg7zfHC5wcGHQf8F5pi"], }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(vout, sut)
def list_purchases(obj): txs, heights = obj['txs'], obj['heights'] o = [] for h in txs: txhex = str(txs[h]) # print txhex txouts = b.deserialize(txhex)['outs'] if len(txouts) >= 2: addr = b.script_to_address(txouts[0]['script']) if addr == exodus: v = txouts[0][ 'value'] + 10000 # add 0.1 millibit for the fees paid transfering from koinify wallet to Factom multisig ht = heights[h] # We care about the timestamp of the previous # confirmed block before a transaction t = get_block_header_data(ht - 1)['timestamp'] o.append({ "tx": h, "addr": extract_pubkey(txouts[1]['script']), "value": v, "time": t }) if len(o) % 50 == 0: sys.stderr.write('Gathered outputs: %d\n' % len(o)) return o
def test__decode_CHECKMULTISIG_1_of_2(self): rawtransaction = ( "010000000123ba84a7ce8ab2785a838fa9ca50ad395bee25aba38dda28336cc337d08a599e000000006a4730" "440220320a58bf09ce578dd2ddf5381a34d80c3b659e2748c8fd8aa1b7ecc5b8c87665022019905d76a7bbc8" "3cbc3fb6d33e7e8aae903716206e9cf1fcb75518ce37baf69a01210312c50bdc21e06827c0bdd3ef1ff849e2" "4b17147f9a6f240c4af45bd235eb5819ffffffff0102000000000000004751210351efb6e91a31221652105d" "032a2508275f374cea63939ad72f1b1e02f477da782100f2b7816db49d55d24df7bdffdbc1e203b424e8cd39" "f5651ab938e5e4a193569e52ae00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 0.00000002, "n": 0, "scriptPubKey": { "asm": "1 0351efb6e91a31221652105d032a2508275f374cea63939ad72f1b1e02f477da78 00f2b7816db49d55d24df7bdffdbc1e203b424e8cd39f5651ab938e5e4a193569e 2 OP_CHECKMULTISIG", "hex": "51210351efb6e91a31221652105d032a2508275f374cea63939ad72f1b1e02f477da782100f2b7816db49d55d24df7bdffdbc1e203b424e8cd39f5651ab938e5e4a193569e52ae", "reqSigs": 1, "type": "multisig", "addresses": ["1NdB761LmTmrJixxp93nz7pEiCx5cKPW44"], }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(sut, vout)
def import_json( self, json_text ): try: importTxInfo = json.loads( json_text ) except: raise RuntimeError( "Invalid Input", "The input doesn't parse to valid json." ) try: if 'tx' not in importTxInfo: raise ValueError( "No transaction found in json" ) redeemScriptCanidate = None try: self.tx = bitcoin.deserialize( importTxInfo['tx'] ) sigScript = self.tx['ins'][0]['script'] if sigScript != "": sigScript = bitcoin.deserialize_script( sigScript ) redeemScriptCanidate = sigScript[-1] except Exception as e: raise ValueError( "tx could not be deserialized:" + str( e ) ) if 'input' in importTxInfo and 'redeemScript' in importTxInfo['input']: if redeemScriptCanidate is not None and redeemScriptCanidate.lower() != importTxInfo['input']['redeemScript'].lower(): raise ValueError( "redeemScript given in info doesn't match redeemScript from partial signature" ) redeemScriptCanidate = importTxInfo['input']['redeemScript'] if redeemScriptCanidate is not None: self.pubs, self.neededSigs = KeyHelper.parse_redeem_script( redeemScriptCanidate ) self.redeemScript = redeemScriptCanidate else: raise ValueError( "No redeemScript can be located." ) except ValueError as e: raise RuntimeError( "Invalid Input", str( e ) )
def test__decode_OPDATA_nonstandard(self): """ OP_DATA_32 OP_DATA_36 """ rawtransaction = ( "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2cfabe6d" "6dc4a1165ea4f5b251a55d0a5826282b4a9b3551a28d9ff0d9343a1bc942fa895e0100000000000000ffffffff" "0e00000000000000002120b7837f89bd7d3b262037ed0e31063c00d8e5f785b742ac467cef4e69d98a19bd5f71" "2300000000001976a91404b61d237655b3ceb6329ac474cd4eb16fa7318f88accf057b00000000001976a9147f" "92bc474f4d80ac06c8f02d57915bf550c8447b88aca16f850100000000434104ffd03de44a6e11b9917f3a29f9" "443283d9871c9d743ef30d5eddcd37094b64d1b3d8090496b53256786bf5c82932ec23c3b74d9f05a6f95a8b55" "29352656664bacb17fe203000000001976a9149fdc63fd4c87de443b5984d00b159a8340f64eb388acd88f4d04" "000000001976a91491ce910c7ca125114f2e38bf9a17f1130185ca7f88ac2fae2d0b000000001976a91426bad6" "b6f1079452cd954471d58a641dcd20abb888ac6ee2f50e000000001976a914761331627d4769d4e551762caa58" "f54fb65822a188ace92add0f000000001976a914984f8de73e491543c52a7cb23537706887247f8688acb1fc8f" "1f000000001976a9147522e01f331ef160bf609ddc321033a87529ccb688ac02767426000000001976a914bcf8" "2a713a320942ce47e073787b48e73ed21bc388ac3333752d000000001976a914155b7de88446ba2fb671df7e3e" "68def8646e1cda88ac331f893f0000000043410461c9f86eb47bda456cedc2e4bc45a51026b244db1f3fd4c2d2" "5713f517062b6c832f2e9231eba78e92eb77ce122498d99cea3007bdba9bed715e4525b92e8cc9ac79dfb64200" "0000001976a914af1ffe62761b0c8b83d96f06621eda34b1b0683288ac00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 0.00000000, "n": 0, "scriptPubKey": { "asm": "b7837f89bd7d3b262037ed0e31063c00d8e5f785b742ac467cef4e69d98a19bd", "hex": "20b7837f89bd7d3b262037ed0e31063c00d8e5f785b742ac467cef4e69d98a19bd", "type": "nonstandard", }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(sut, vout)
def test__decode_nonstandard_transaction(self): rawtransaction = ( "01000000031091bb34c19754b689685bd5f84078b437653d08377d2d03d256b34f80eb219e010000008a473044" "0220476c26cdcecccf46fdd96fb87814661cb1044e103d1bcd5be339b9cbaceca47902201b2caafe5b36913ef4" "75d4d33b9d62aa3316ece6f1ac3371a506906e61afd4510141048c632401521a105db6b62db0a2c393181b5538" "f2c56d461057611252baebc9c7794378c252c45b7393fc93ea3b8bc6d6db1c9b5506744d51d1ddd7a9acd27d81" "ffffffffcc72f7a8acf77c1b1313d4ba229bff7db4f40e0a1b525a9b8a4dbc8ecc80b070000000008b48304502" "2100997b74ef85d3be61a96a4d8ecebfeb588979364276f54fa77571ff8fb7906e4202204390f9935695194362" "fbc221b00436b4811d01f645715105f9d081ad65977e2b014104fd579aa4983cece29365038ddbaf479af86bdf" "25afdcae67bbe8b30c268aecdac6cd8f923ef3f23ab694783f9243522f67886a46a43499e3fb3ed49623869d6f" "ffffffff8ecdae566b8e8d709a32054175ce61fc2a9323e60023f62b23c342a7186beeea000000008b48304502" "200f95d4cd51bb5b867563700979ea23bf69921b1a0262ff5de3d7330bb992a713022100de58fa5822e7e62c8e" "6e4edbdece7913cb21f5a7b5a39d85fa9291874ce81a710141045f7f6eed56863bf527b8fd30cbe78038db3113" "70da6c7054beced527d60f47a65d6f1ce62278ba496f5da4a3d738eac0e2cb0f4ac38b113cbeabef59b685b16c" "ffffffff0280c51b11010000000576a90088ac4cbdd397a90000001976a914d1121a58483d135c953e0f4e2cc6" "d126b5c6b06388ac00000000" ) pybtcd_deserialized_transaction = deserialize(rawtransaction) bitcoind_json_vout0 = { "value": 45.82000000, "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 0 OP_EQUALVERIFY OP_CHECKSIG", "hex": "76a90088ac", "type": "nonstandard", }, } sut = VOUTDecoder.decode(pybtcd_deserialized_transaction["outs"][0], 0, "main") vout = json.loads(json.dumps(bitcoind_json_vout0), parse_float=Decimal) self.assertEqual(sut, vout)
def sign_donation_tx(tx, i, priv): from bitcoin.main import fast_multiply, decode_privkey, G, inv, N from bitcoin.transaction import der_encode_sig k = sign_k hashcode = btc.SIGHASH_ALL i = int(i) if len(priv) <= 33: priv = btc.safe_hexlify(priv) pub = btc.privkey_to_pubkey(priv) address = btc.pubkey_to_address(pub) signing_tx = btc.signature_form(tx, i, btc.mk_pubkey_script(address), hashcode) msghash = btc.bin_txhash(signing_tx, hashcode) z = btc.hash_to_int(msghash) # k = deterministic_generate_k(msghash, priv) r, y = fast_multiply(G, k) s = inv(k, N) * (z + r * decode_privkey(priv)) % N rawsig = 27 + (y % 2), r, s sig = der_encode_sig(*rawsig) + btc.encode(hashcode, 16, 2) # sig = ecdsa_tx_sign(signing_tx, priv, hashcode) txobj = btc.deserialize(tx) txobj["ins"][i]["script"] = btc.serialize_script([sig, pub]) return btc.serialize(txobj)
def segwit_signature_form(tx, i, script, amount, hashcode=SIGHASH_ALL): d = deserialize(tx) def parse_vout(o): return b''.join([struct.pack('<Q', o['value']), struct.pack('B', len(o['script']) // 2), binascii.unhexlify(o['script'])]) def parse_vin(inp): return b''.join([binascii.unhexlify(inp['outpoint']['hash'])[::-1], struct.pack('<I', (inp['outpoint']['index']))]) vin_outpoint = [binascii.unhexlify(d['ins'][i]['outpoint']['hash'])[::-1], struct.pack('<I', (d['ins'][i]['outpoint']['index']))] hashcode_strategy = get_hashcode_strategy(hashcode) outpoints = [parse_vin(inp) for inp in hashcode_strategy.get_inputs_for_sequences(d, i)] sequences = hashcode_strategy.get_sequences(d, i) outputs_to_sign = hashcode_strategy.get_outputs(d, i) outputs = [parse_vout(out) for out in outputs_to_sign] hash_outputs = hashlib.sha256(hashlib.sha256(b''.join(outputs)).digest()).digest() if outputs_to_sign else b'\x00'*32 hash_sequences = hashlib.sha256(hashlib.sha256(b''.join(sequences)).digest()).digest() if sequences else b'\x00'*32 hash_outpoints = hashlib.sha256(hashlib.sha256(b''.join(outpoints)).digest()).digest() if outpoints else b'\x00'*32 preimage = [struct.pack('<I', d['version']), hash_outpoints, hash_sequences, b''.join(vin_outpoint), struct.pack('B', len(script) // 2), binascii.unhexlify(script), struct.pack('<Q', amount), struct.pack('<I', d['ins'][i]['sequence']), hash_outputs, struct.pack('<I', d['locktime']), struct.pack('<I', hashcode)] return binascii.hexlify(b''.join(preimage)).decode('ascii')
def segwit_sign(tx, i, priv, amount, hashcode=SIGHASH_ALL, script=None, separator_index=None): i = int(i) txobj = tx if isinstance(tx, dict) else deserialize(tx) if not isinstance(tx, dict) and ((not is_python2 and isinstance(re, bytes)) or not re.match('^[0-9a-fA-F]*$', tx)): return binascii.unhexlify(sign(binascii.hexlify(tx), i, priv)) if len(priv) <= 33: priv = binascii.hexlify(priv) pub = privkey_to_pubkey(priv) address = pubkey_to_address(pub) wscript = mk_pubkey_script(address) if not script else script stripped_script = segwit_strip_script_separator(wscript, separator_index) signing_tx = segwit_signature_form(tx, i, stripped_script, amount, hashcode=hashcode) rawsig = ecdsa_raw_sign( hashlib.sha256( hashlib.sha256( binascii.unhexlify(signing_tx)).digest()).hexdigest(), priv) sig = der_encode_sig(*rawsig) + encode(hashcode, 16, 2) txobj['ins'][i]['txinwitness'] = [sig, pub if not script else script] return serialize(txobj)
def normalize_transaction(tx): _tx = deserialize(tx) _tx['segwit'] = True for i, vin in enumerate(_tx['ins']): if vin.get('txinwitness', '0' * 64) == '0' * 64: _tx['ins'][i]['txinwitness'] = '' return serialize(_tx)
def sign_donation_tx(tx, i, priv): from bitcoin.main import fast_multiply, decode_privkey, G, inv, N from bitcoin.transaction import der_encode_sig k = sign_k hashcode = btc.SIGHASH_ALL i = int(i) if len(priv) <= 33: priv = btc.safe_hexlify(priv) pub = btc.privkey_to_pubkey(priv) address = btc.pubkey_to_address(pub) signing_tx = btc.signature_form( tx, i, btc.mk_pubkey_script(address), hashcode) msghash = btc.bin_txhash(signing_tx, hashcode) z = btc.hash_to_int(msghash) # k = deterministic_generate_k(msghash, priv) r, y = fast_multiply(G, k) s = inv(k, N) * (z + r * decode_privkey(priv)) % N rawsig = 27 + (y % 2), r, s sig = der_encode_sig(*rawsig) + btc.encode(hashcode, 16, 2) # sig = ecdsa_tx_sign(signing_tx, priv, hashcode) txobj = btc.deserialize(tx) txobj["ins"][i]["script"] = btc.serialize_script([sig, pub]) return btc.serialize(txobj)
def main(): parser = OptionParser( usage= 'usage: %prog [options] utxo destaddr1 destaddr2 ..', description="For creating multiple utxos from one (for commitments in JM)." "Provide a utxo in form txid:N that has some unspent coins;" "Specify a list of destination addresses and the coins will" "be split equally between them (after bitcoin fees)." "You'll be prompted to enter the private key for the utxo" "during the run; it must be in WIF compressed format." "After the transaction is completed, the utxo strings for" "the new outputs will be shown." "Note that these utxos will not be ready for use as external" "commitments in Joinmarket until 5 confirmations have passed." " BE CAREFUL about handling private keys!" " Don't do this in insecure environments." " Also note this ONLY works for standard (p2pkh) utxos." ) parser.add_option( '-v', '--validate-utxos', action='store_true', dest='validate', help='validate the utxos and pubkeys provided against the blockchain', default=False ) parser.add_option( '-o', '--validate-only', action='store_true', dest='vonly', help='only validate the provided utxos (file or command line), not add', default=False ) (options, args) = parser.parse_args() load_program_config() if len(args) < 2: quit(parser, 'Invalid syntax') u = args[0] priv = raw_input( 'input private key for ' + u + ', in WIF compressed format : ') u, priv = get_utxo_info(','.join([u, priv])) if not u: quit(parser, "Failed to parse utxo info: " + u) destaddrs = args[1:] for d in destaddrs: if not validate_address(d): quit(parser, "Address was not valid; wrong network?: " + d) txsigned = sign(u, priv, destaddrs) log.debug("Got signed transaction:\n" + txsigned) log.debug("Deserialized:") log.debug(pformat(btc.deserialize(txsigned))) if raw_input('Would you like to push to the network? (y/n):')[0] != 'y': log.debug("You chose not to broadcast the transaction, quitting.") return jm_single().bc_interface.pushtx(txsigned)
def main(): locktime = args.locktime privkey = args.privkey address = args.address script = getRedeemScript(locktime, privkey) ins, balance = getBalance(scriptaddr(script, 50)) len_inputs = len(ins) tx = '' if balance > 0 and check_addr(address) and is_privkey(privkey): # Fee fee = round(base_fee + fee_per_input * len_inputs, 8) # Outputs out_value = int((balance - fee) * COIN) outs = [{'address' : address, 'value' : out_value}] # Make unsigned transaction tx = mktx(ins, outs) # Append nLockTime and reset nSequence unpacked = deserialize(tx) unpacked['locktime'] = locktime for i in range(len_inputs): unpacked['ins'][i]['sequence'] = 0 tx = serialize(unpacked) # get all signatures sigs = [] for i in range(len_inputs): sigs.append(multisign(tx, i, script, privkey)) # sign inputs unpacked = deserialize(tx) for i in range(len_inputs): unpacked['ins'][i]['script'] = getLen(sigs[i]) + sigs[i] unpacked['ins'][i]['script'] += getLen(script) + script tx = serialize(unpacked) print('> BALANCE (%s): %f' % (scriptaddr(script, 50), balance)) if len(tx) > 0: txid = broadcast(tx) print('> RESPONSE: %s' % txid.text)
def do_HEAD(self): pages = ('/walletnotify?', '/alertnotify?') if self.path.startswith('/walletnotify?'): txid = self.path[len(pages[0]):] if not re.match('^[0-9a-fA-F]*$', txid): log.debug('not a txid') return tx = self.btcinterface.rpc('getrawtransaction', [txid]) if not re.match('^[0-9a-fA-F]*$', tx): log.debug('not a txhex') return txd = btc.deserialize(tx) tx_output_set = set([(sv['script'], sv['value']) for sv in txd[ 'outs']]) unconfirmfun, confirmfun = None, None for tx_out, ucfun, cfun in self.btcinterface.txnotify_fun: if tx_out == tx_output_set: unconfirmfun = ucfun confirmfun = cfun break if unconfirmfun is None: log.debug('txid=' + txid + ' not being listened for') else: # on rare occasions people spend their output without waiting # for a confirm txdata = None for n in range(len(txd['outs'])): txdata = self.btcinterface.rpc('gettxout', [txid, n, True]) if txdata is not None: break assert txdata is not None if txdata['confirmations'] == 0: unconfirmfun(txd, txid) # TODO pass the total transfered amount value here somehow # wallet_name = self.get_wallet_name() # amount = # bitcoin-cli move wallet_name "" amount log.debug('ran unconfirmfun') else: confirmfun(txd, txid, txdata['confirmations']) self.btcinterface.txnotify_fun.remove( (tx_out, unconfirmfun, confirmfun)) log.debug('ran confirmfun') elif self.path.startswith('/alertnotify?'): jm_single().core_alert[0] = urllib.unquote(self.path[len(pages[1]):]) log.debug('Got an alert!\nMessage=' + jm_single().core_alert[0]) else: log.debug('ERROR: This is not a handled URL path. You may want to check your notify URL for typos.') os.system('curl -sI --connect-timeout 1 http://localhost:' + str( self.base_server.server_address[1] + 1) + self.path) self.send_response(200) # self.send_header('Connection', 'close') self.end_headers()
def self_sign(self): #now sign it ourselves tx = btc.serialize(self.latest_tx) for index, ins in enumerate(self.latest_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) if utxo not in self.input_utxos.keys(): continue addr = self.input_utxos[utxo]['address'] tx = self.sign_tx(tx, index, self.wallet.get_key_from_addr(addr)) self.latest_tx = btc.deserialize(tx)
def sign_tx(unsigned_raw_tx, privatekey): tx2 = unsigned_raw_tx detx = bitcoin.deserialize(tx2) input_length = len(detx['ins']) for i in range(0, input_length): tx2 = bitcoin.sign(tx2, i, privatekey) return tx2
def get_postings(): """ Retrive all books for sale in the mempool Returns: current_postings (list): list of current postings each element is tuple of (poster, isbn, price, quality) """ postings = [] canceled_postings = [] current_postings = [] txs = bitcoin.history(settings.MARKET_ADDRESS) for tx in txs: poster, isbn, price = None, None, None fetched = bitcoin.fetchtx(tx['output'].split(':')[0]) tx_outputs = bitcoin.deserialize(fetched)['outs'] tx_inputs = bitcoin.deserialize( bitcoin.fetchtx( bitcoin.deserialize(fetched)['ins'][0]['outpoint'] ['hash']))['outs'] for input in tx_inputs: if input['script'].startswith('76a914'): try: text = input['script'].lstrip('76a914').rstrip('88ac') poster = bitcoin.hex_to_b58check(text) except: pass for output in tx_outputs: if output['script'].startswith('6a'): text = str(binascii.unhexlify(output['script'][2:])) components = text.split('-') if len(components) == 3: isbn, price, quality = components isbn = isbn[-10:] if poster and isbn and price and quality: if price == '0': canceled_postings.append((poster, isbn)) else: postings.append((poster, isbn, price, quality)) for posting in postings: if (posting[0], posting[1]) not in canceled_postings: current_postings.append(posting) return list(set(current_postings))
def create_testing_cjtx(counterparty_list): msgchan_pushtx_count[0] = dict(zip(counterparty_list, [0]* len(counterparty_list))) self_pushtx_count[0] = 0 orders = zip(counterparty_list, [[]]*len(counterparty_list)) input_utxos = {'utxo-hex-here': {'value': 0, 'address': '1addr'}} cjtx = CoinJoinTX(DummyMessageChannel(), None, None, 0, orders, input_utxos , '1cjaddr', '1changeaddr', 0, None, None, dummy_commitment_creator) cjtx.latest_tx = btc.deserialize(sample_tx_hex) return cjtx
def self_sign(self): #now sign it ourselves tx = btc.serialize(self.latest_tx) for index, ins in enumerate(self.latest_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str( ins['outpoint']['index']) if utxo not in self.input_utxos.keys(): continue addr = self.input_utxos[utxo]['address'] tx = self.sign_tx(tx, index, self.wallet.get_key_from_addr(addr)) self.latest_tx = btc.deserialize(tx)
def create_testing_cjtx(counterparty_list): msgchan_pushtx_count[0] = dict(zip(counterparty_list, [0]* len(counterparty_list))) self_pushtx_count[0] = 0 orders = zip(counterparty_list, [[]]*len(counterparty_list)) input_utxos = {'utxo-hex-here': {'value': 0, 'address': '1addr'}} cjtx = CoinJoinTX(DummyMessageChannel(), None, None, 0, orders, input_utxos , '1cjaddr', '1changeaddr', 0, None, None, None) cjtx.latest_tx = btc.deserialize(sample_tx_hex) return cjtx
def get_txn_outputs(raw_tx_hex, output_addr_list, coin_symbol): ''' Used to verify a transaction hex does what's expected of it. Must supply a list of output addresses so that the library can try to convert from script to address using both pubkey and script. Returns a list of the following form: [{'value': 12345, 'address': '1abc...'}, ...] Uses @vbuterin's decoding methods. ''' # Defensive checks: err_msg = 'Library not able to parse %s transactions' % coin_symbol assert lib_can_deserialize_cs(coin_symbol), err_msg assert isinstance(output_addr_list, (list, tuple)) for output_addr in output_addr_list: assert is_valid_address_for_coinsymbol(output_addr, coin_symbol), output_addr output_addr_set = set(output_addr_list) # speed optimization outputs = [] deserialized_tx = deserialize(str(raw_tx_hex)) for out in deserialized_tx.get('outs', []): output = {'value': out['value']} # determine if the address is a pubkey address, script address, or op_return pubkey_addr = script_to_address( out['script'], vbyte=COIN_SYMBOL_MAPPINGS[coin_symbol]['vbyte_pubkey']) script_addr = script_to_address( out['script'], vbyte=COIN_SYMBOL_MAPPINGS[coin_symbol]['vbyte_script']) nulldata = out['script'] if out['script'][0:2] == '6a' else None if pubkey_addr in output_addr_set: address = pubkey_addr output['address'] = address elif script_addr in output_addr_set: address = script_addr output['address'] = address elif nulldata: output['script'] = nulldata output['script_type'] = 'null-data' else: raise Exception( 'Script %s Does Not Contain a Valid Output Address: %s' % ( out['script'], output_addr_set, )) outputs.append(output) return outputs
def test_native_P2WSH_SIGHASH_SINGLE(self): tx = TEST_CASES[1] deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) partially_signed = p2pk_sign(stripped_tx, 0, self.append_compressed_flag_to_privkey( tx['ins'][0]['privkey']), hashcode=SIGHASH_ALL) priv0 = self.append_compressed_flag_to_privkey( tx['ins'][1]['privkeys'][0]) priv1 = self.append_compressed_flag_to_privkey( tx['ins'][1]['privkeys'][1]) pub0 = privtopub(priv0) pub1 = privtopub(priv1) REDEEM_SCRIPT_STRUCTURE = { 'keys': [pub0, pub1], 'schema': [{ 'reqs': 1, 'keys': [0], }, { 'reqs': 1, 'keys': [1], }] } witness_script = mk_OPCS_multisig_script(REDEEM_SCRIPT_STRUCTURE) sign1 = segwit_multisign(partially_signed, 1, witness_script, priv0, 49 * 10**8, hashcode=SIGHASH_SINGLE) sign2 = segwit_multisign(partially_signed, 1, witness_script, priv1, 49 * 10**8, hashcode=SIGHASH_SINGLE, separator_index=1) signed = apply_segwit_multisignatures(partially_signed, 1, witness_script, [sign2, sign1], dummy=False) self.assertEqual(signed, tx['signed']) print('[Native P2WSH] SIGHASH_SINGLE OK')
def checkTransaction(transactiontext): try: transactiontext.strip() deserialized = bitcoin.deserialize(transactiontext) for item in deserialized['outs']: out = item['script'] subString = out[6:len(out) - 4] add = bitcoin.hex_to_b58check(subString, 111) if add == bitcoinAddress: return True return False except: return False
def segwit_signature_form(tx, i, script, amount, hashcode=SIGHASH_ALL): d = deserialize(tx) def parse_vout(o): return b''.join([ struct.pack('<Q', o['value']), struct.pack('B', len(o['script']) // 2), binascii.unhexlify(o['script']) ]) def parse_vin(inp): return b''.join([ binascii.unhexlify(inp['outpoint']['hash'])[::-1], struct.pack('<I', (inp['outpoint']['index'])) ]) vin_outpoint = [ binascii.unhexlify(d['ins'][i]['outpoint']['hash'])[::-1], struct.pack('<I', (d['ins'][i]['outpoint']['index'])) ] hashcode_strategy = get_hashcode_strategy(hashcode) outpoints = [ parse_vin(inp) for inp in hashcode_strategy.get_inputs_for_sequences(d, i) ] sequences = hashcode_strategy.get_sequences(d, i) outputs_to_sign = hashcode_strategy.get_outputs(d, i) outputs = [parse_vout(out) for out in outputs_to_sign] hash_outputs = hashlib.sha256(hashlib.sha256(b''.join( outputs)).digest()).digest() if outputs_to_sign else b'\x00' * 32 hash_sequences = hashlib.sha256( hashlib.sha256(b''.join( sequences)).digest()).digest() if sequences else b'\x00' * 32 hash_outpoints = hashlib.sha256( hashlib.sha256(b''.join( outpoints)).digest()).digest() if outpoints else b'\x00' * 32 preimage = [ struct.pack('<I', d['version']), hash_outpoints, hash_sequences, b''.join(vin_outpoint), struct.pack('B', len(script) // 2), binascii.unhexlify(script), struct.pack('<Q', amount), struct.pack('<I', d['ins'][i]['sequence']), hash_outputs, struct.pack('<I', d['locktime']), struct.pack('<I', hashcode) ] return binascii.hexlify(b''.join(preimage)).decode('ascii')
def get_messages(): """ Gets inbox messages from the mempool Returns: messages (dict): dict of messages {sender: {message_num: {submessage_num: message}}} """ messages = defaultdict(dict) priv, pub, addr = books.read_wallet() txs = bitcoin.history(addr) for tx in txs: sender, message_num, submessage_num, message = None, None, None, None fetched = bitcoin.fetchtx(tx['output'].split(':')[0]) tx_outputs = bitcoin.deserialize(fetched)['outs'] tx_inputs = bitcoin.deserialize( bitcoin.fetchtx( bitcoin.deserialize(fetched)['ins'][0]['outpoint'] ['hash']))['outs'] for output in tx_outputs: if output['script'].startswith('6a'): text = str(binascii.unhexlify(output['script'].lstrip('6a'))) message_num = text[1] submessage_num = text[2] message = text[3:] for input in tx_inputs: try: if input['script'].startswith('76a914'): text = input['script'].lstrip('76a914').rstrip('88ac') sender = bitcoin.hex_to_b58check(text) except: pass if sender and message: if sender != addr: if sender not in messages: messages[sender] = defaultdict(dict) messages[sender][message_num].update({submessage_num: message}) return messages
def apply_segwit_multisignatures(tx, i, witness_program, signatures, dummy=True, nested=False): txobj = deserialize(tx) signed = apply_segwit_multisignatures_deserialized_data(txobj, i, witness_program, signatures, dummy=dummy, nested=nested) return serialize(signed)
def apply_segwit_multisignatures(tx, i, witness_program, signatures, dummy=True, nested=False): o = [""] + signatures + [witness_program ] if dummy else signatures + [witness_program] txobj = deserialize(tx) txobj['ins'][i]['txinwitness'] = o if nested: redeem_script = hashlib.sha256( binascii.unhexlify(witness_program)).hexdigest() length = len(redeem_script) // 2 redeem_script = serialize_script([length + 2, None, redeem_script]) txobj["ins"][i]["script"] = redeem_script return serialize(txobj)
def list_purchases(obj): txs, heights = obj['txs'], obj['heights'] process_queue = [] for h in txs: txhex = str(txs[h]) txouts = b.deserialize(txhex)['outs'] if len(txouts) >= 2 and txouts[0]['value'] >= minimum - 30000: addr = b.script_to_address(txouts[0]['script']) if addr == exodus: v = txouts[0]['value'] + 30000 process_queue.append({ "tx": h, "addr": b.b58check_to_hex(b.script_to_address( txouts[1]['script'])), "value": v, "height": heights[h] }) else: sys.stderr.write( "Non-purchase tx found (not to exodus): %s\n" % h) elif len(txouts) == 1: sys.stderr.write("Non-purchase tx found (single output): %s\n" % h) else: sys.stderr.write( "Non-purchase tx found (insufficient value): %s\n" % h) sys.stderr.write('Gathered outputs, collecting block timestamps\n') # Determine the timestamp for every block height. We care about # the timestamp of the previous confirmed block before a transaction. # Save the results as a dictionary of transaction data o = [] for i in range(0, len(process_queue), 20): subpq = process_queue[i:i + 20] t = get_block_timestamp([x['height'] - 1 for x in subpq]) assert len(t) == len(subpq), [x['height'] - 1 for x in subpq] o.extend([{ "tx": _a["tx"], "addr": _a["addr"], "value": _a["value"], "time": _b } for _a, _b in zip(subpq, t)]) sys.stderr.write('Collected timestamps: %d\n' % len(o)) return o
def test_encode_decode(self): transaction = "010000000001019fa7fad392a29f74d124a8770d24e23f0fcc3e3007e756e4114e4b950a5cf37a0200000000f" \ "fffffff02402d0e20000000001976a914c0123fd352e7f53a9c4c0e512c490e1a6817dffa88acb19066000000" \ "0000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d040048304502210" \ "0f227d07b7ca8bef3b9d591fc46803b1fc6b41290b3b229064726eee5c3d6fc8b02206450b248d4d035a121e6" \ "92d7a0e1b720801e1fd30255f5d1f099dbca61eb92dc01483045022100966181ecf84d9a75be1c7654a29ce2a" \ "1cba32b2bfb9988d6564ae3bc7358420702200a5e54430e1a9c4537c84d9159243cbfe020fbac2fa7e09b8cd6" \ "efb08c984432016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c210" \ "3a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3" \ "e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000" expected_address = "bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej" decoded_expected_address = bech32decode(expected_address) deserialized = deserialize(transaction) assert decoded_expected_address == deserialized['outs'][1]['script'] re_encoded_address = bech32encode(deserialized['outs'][1]['script']) assert re_encoded_address == expected_address