def decode_spendables(address, results): spendables = [ Spendable(r['value'], ScriptPayToAddress(address), h2b_rev(r['tx_hash']), r['tx_pos']) for r in results['result'] ] return spendables
def make_bare_tx(candidate, change_address, rs_asm, version=1): # <Tx> components spendables = [] ins = [] outs = [] # estimate the final (signed) bytesize per input based on the redeemscript redeem_script = tools.compile(rs_asm) in_size = estimate_input_size(redeem_script) # initialize size and amount counters in_amount = Decimal(0) est_size = TX_COMPONENTS.version + TX_COMPONENTS.out_count + TX_COMPONENTS.in_count # add output size est_size += OUTSIZE * 2 # iterate over unspents for utxo in candidate.utxos: value = Decimal(utxo.amount) * COIN in_amount += value script = h2b(utxo.script) # for now: test if the in_script we figured we would need, actually matches the in script :D # reverse that tx hash prevtx = h2b_rev(utxo.hash) # output index outnum = utxo.outpoint # create "spendable" spdbl = Spendable(value, script, prevtx, outnum) spendables.append(spdbl) # also create this as input as_input = spdbl.tx_in() as_input.sigs = [] ins.append(as_input) # add the estimated size per input est_size += in_size # calc fee and out amount fee = (Decimal(math.ceil(est_size / 1000)) * COIN * NETWORK_FEE) + FEE_MARGIN change_amount = Decimal( math.floor(in_amount - (candidate.amount * COIN) - fee)) # create outputs outs.append( TxOut(int(candidate.amount * COIN), make_payto(candidate.address))) outs.append(TxOut(int(change_amount), make_payto_script(change_address))) # create bare tx without sigs tx = Tx(version, ins, outs, 0, spendables) return tx
def spendable_for_row(r): return Spendable(coin_value=r[2], script=h2b(r[3]), tx_hash=h2b_rev(r[0]), tx_out_index=r[1], block_index_available=r[4], does_seem_spent=r[5], block_index_spent=r[6])
def test_create_trx(self): tx_input = Spendable(200, '18eKkAWyU9kvRNHPKxnZb6wwtPMrNmRRRA', h2b('8443b07464c762d7fb404ea918a5ac9b3618d5cd6a0c5ea6e4dd5d7bbe28b154'), 0) tx_outs = [tx_utils.create_transaction_output('mgAqW5ZCnEp7fjvpj8RUL3WxsBy8rcDcCi', 0.0000275)] tx = tx_utils.create_trx('TEST'.encode('utf-8'), 3, 'mgAqW5ZCnEp7fjvpj8RUL3WxsBy8rcDcCi', tx_outs, tx_input) hextx = hexlify(tx.serialize()) self.assertEquals(hextx, '01000000018443b07464c762d7fb404ea918a5ac9b3618d5cd6a0c5ea6e4dd5d7bbe28b1540000000000ffffffff0300000000000000001976a914072a22e5913cd939904c46bbd0bc56755543384b88acc5000000000000001976a914072a22e5913cd939904c46bbd0bc56755543384b88ac0000000000000000066a045445535400000000')
def spendables_for_addresses(self, addresses): results = {} for address in addresses: if address == "mgMy4vmqChGT8XeKPb1zD6RURWsiNmoNvR": results[address] =\ [Spendable(coin_value=10000, script=ScriptPayToAddress(bitcoin_address_to_hash160_sec(address, address_prefix_for_netcode('XTN'))).script(), tx_out_index=0, tx_hash=b'2'*32)] return results
def op_return_this(privatekey, text, prefix = "KEYSTAMP:", bitcoin_fee = 10000): bitcoin_keyobj = get_key(privatekey) bitcoin_address = bitcoin_keyobj.bitcoin_address() ## Get the spendable outputs we are going to use to pay the fee all_spendables = get_spendables_blockcypher(bitcoin_address) spendables = [] value = 0 for unspent in all_spendables: while value < bitcoin_fee + 10000: coin_value = unspent.get("value") script = h2b(unspent.get("script_hex")) previous_hash = h2b_rev(unspent.get("tx_hash")) previous_index = unspent.get("index") spendables.append(Spendable(coin_value, script, previous_hash, previous_index)) value += coin_value bitcoin_sum = sum(spendable.coin_value for spendable in spendables) if(bitcoin_sum < bitcoin_fee): print "ERROR: not enough balance: available: %s - fee: %s" %(bitcoin_sum, bitcoin_fee) return False ## Create the inputs we are going to use inputs = [spendable.tx_in() for spendable in spendables] ## If we will have change left over create an output to send it back outputs = [] if (bitcoin_sum > bitcoin_fee): change_output_script = standard_tx_out_script(bitcoin_address) total_amout = bitcoin_sum - bitcoin_fee outputs.append(TxOut(total_amout, change_output_script)) # home_address = standard_tx_out_script(bitcoin_address) # #TODO: it needs some love and IQ on input mananagement stuff # outputs.append(TxOut((bitcoin_sum - bitcoin_fee), home_address)) ## Build the OP_RETURN output with our message if prefix is not None and (len(text) + len(prefix) <= 80): text = prefix + text message = hexlify(text.encode()).decode('utf8') op_return_output_script = tools.compile("OP_RETURN %s" % message) outputs.append(TxOut(0, op_return_output_script)) ## Create the transaction and sign it with the private key tx = Tx(version=1, txs_in=inputs, txs_out=outputs) # print tx.as_hex() # print spendables tx.set_unspents(spendables) sign_tx(tx, wifs=[privatekey]) print "singed_tx: %s" %tx.as_hex() #TODO: uncomment this when its ready to push data to blockchian tx_hash = broadcast_tx_blockr(tx.as_hex()) return tx_hash
def test_verify_transaction(self): tx_input = Spendable(200, '18eKkAWyU9kvRNHPKxnZb6wwtPMrNmRRRA', h2b('8443b07464c762d7fb404ea918a5ac9b3618d5cd6a0c5ea6e4dd5d7bbe28b154'), 0) tx_outs = [tx_utils.create_transaction_output('mgAqW5ZCnEp7fjvpj8RUL3WxsBy8rcDcCi', 0.0000275)] op_return_val = h2b('e9cee71ab932fde863338d08be4de9dfe39ea049bdafb342ce659ec5450b69ae') tx = tx_utils.create_trx(op_return_val, 3, 'mgAqW5ZCnEp7fjvpj8RUL3WxsBy8rcDcCi', tx_outs, tx_input) hextx = hexlify(tx.serialize()) tx_utils.verify_transaction(hextx, hexlify(op_return_val))
def spendables_for_address(self, address): if address == "1r1msgrPfqCMRAhg23cPBD9ZXH1UQ6jec": return [ Spendable( coin_value=10000, script=ScriptPayToAddress( bitcoin_address_to_hash160_sec(address)).script(), tx_out_index=0, tx_hash=b'2' * 32) ] else: return []
def spendables_for_address(self, bitcoin_address): URL = "%s/api/addr/%s/utxo" % (self.base_url, bitcoin_address) r = json.loads(urlopen(URL).read().decode("utf8")) spendables = [] for u in r: value = btc_to_satoshi(str(u.get("amount"))) script = h2b(u.get("scriptPubKey")) prev_hash = h2b_rev(u.get("txid")) prev_index = u.get("vout") spendable = Spendable(value, script, prev_hash, prev_index) spendables.append(spendable) return spendables
def spendable_for_hash_index(self, tx_hash, tx_out_index): tx_hash_hex = b2h_rev(tx_hash) SQL = ("select coin_value, script, block_index_available, " "does_seem_spent, block_index_spent from Spendable where " "tx_hash = ? and tx_out_index = ?") c = self._exec_sql(SQL, tx_hash_hex, tx_out_index) r = c.fetchone() if r is None: return r return Spendable(coin_value=r[0], script=h2b(r[1]), tx_hash=tx_hash, tx_out_index=tx_out_index, block_index_available=r[2], does_seem_spent=r[3], block_index_spent=r[4])
def spendables_for_address(self, address): if address == "32pQeKJ8KzRfb3ox9Me8EHn3ud8xo6mqAu": if address != payto_script.address(): raise ValueError() return [ Spendable(coin_value=10000, script=payto_script.script(), tx_out_index=0, tx_hash=b'2' * 32) ] else: return []
def spendables_for_address(self, bitcoin_address): url = "{0}/addr/{1}/utxo".format(self.base_url, bitcoin_address) result = json.loads(urlopen(url).read().decode("utf8")) spendables = [] for utxo in result: value = btc_to_satoshi(str(utxo["amount"])) prev_index = utxo["vout"] prev_hash = h2b_rev(utxo["txid"]) script = h2b(utxo["scriptPubKey"]) spendable = Spendable(value, script, prev_hash, prev_index) spendables.append(spendable) return spendables
def spendables_for_address(self, address): if address == "mgMy4vmqChGT8XeKPb1zD6RURWsiNmoNvR": script = ScriptPayToAddress( bitcoin_address_to_hash160_sec( address, address_prefix_for_netcode('XTN'))) return [ Spendable(coin_value=10000, script=script.script(), tx_out_index=0, tx_hash=b'2' * 32) ] else: return []
def spendables_for_address(self, bitcoin_address): """ Return a list of Spendable objects for the given bitcoin address. """ URL = "https://blockchain.info/unspent?active=%s" % bitcoin_address r = json.loads(urlopen(URL).read().decode("utf8")) spendables = [] for u in r["unspent_outputs"]: coin_value = u["value"] script = h2b(u["script"]) previous_hash = h2b(u["tx_hash"]) previous_index = u["tx_output_n"] spendables.append(Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def spendables_for_address(self, bitcoin_address): """ Return a list of Spendable objects for the given bitcoin address. """ URL = "%s/api/addr/%s/utxo" % (self.base_url, bitcoin_address) r = json.loads(urlopen(URL).read().decode("utf8")) spendables = [] for u in r: coin_value = btc_to_satoshi(u.get("amount")) script = h2b(u.get("scriptPubKey")) previous_hash = h2b_rev(u.get("txid")) previous_index = u.get("vout") spendables.append(Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def spendables_for_address(bitcoin_address): """ Return a list of Spendable objects for the given bitcoin address. """ URL = "http://btc.blockr.io/api/v1/address/unspent/%s" % bitcoin_address r = json.loads(urlopen(URL).read().decode("utf8")) spendables = [] for u in r.get("data", {}).get("unspent", []): coin_value = btc_to_satoshi(u.get("amount")) script = binascii.unhexlify(u.get("script")) previous_hash = h2b_rev(u.get("tx")) previous_index = u.get("n") spendables.append( Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def spendables_for_address(self, address): """ Return a list of Spendable objects for the given bitcoin address. """ spendables = [] url_append = "?unspentOnly=true&token=%s&includeScript=true" % self.api_key url = self.base_url("addrs/%s%s" % (address, url_append)) result = json.loads(urlopen(url).read().decode("utf8")) for txn in result.get("txrefs", []): coin_value = txn.get("value") script = h2b(txn.get("script")) previous_hash = h2b_rev(txn.get("tx_hash")) previous_index = txn.get("tx_output_n") spendables.append(Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def spendables_for_address(self, address): """ Return a list of Spendable objects for the given bitcoin address. """ url_append = "unspent/%s" % address URL = self.base_url("/address/%s" % url_append) r = json.loads(urlopen(URL).read().decode("utf8")) spendables = [] for u in r.get("data", {}).get("unspent", []): coin_value = btc_to_satoshi(u.get("amount")) script = h2b(u.get("script")) previous_hash = h2b_rev(u.get("tx")) previous_index = u.get("n") spendables.append(Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def spendables_for_address(bitcoin_address): """ Return a list of Spendable objects for the given bitcoin address. """ json_response = fetch_json("addresses/%s/unspent-outputs" % bitcoin_address) spendables = [] for tx_out_info in json_response.get("data", {}).get("outputs"): if tx_out_info.get("to_address") == bitcoin_address: coin_value = tx_out_info["value"] script = tools.compile(tx_out_info.get("script_pub_key")) previous_hash = h2b_rev(tx_out_info.get("transaction_hash")) previous_index = tx_out_info.get("transaction_index") spendables.append( Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def spendables_for_address(self, address): """ Converts to pycoin Spendable type :param address: :return: list of Spendables """ unspent_outputs = bitcoin.rpc.Proxy().listunspent(addrs=[address]) spendables = [] for unspent in unspent_outputs: coin_value = unspent.get('amount', 0) outpoint = unspent.get('outpoint') script = unspent.get('scriptPubKey') previous_hash = outpoint.hash previous_index = outpoint.n spendables.append( Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def spendables_for_address( _from, unused_utxo ): # Generate spendables without connecting to the Bitcoin network spendables = [] _script_p2pkh = PAYMENT_OBJ[_from][1] coin_value = unused_utxo.satoshis script = binascii.unhexlify(_script_p2pkh) previous_hash_big_endian = binascii.unhexlify(unused_utxo.txid) previous_hash_little_endian = previous_hash_big_endian[::-1] previous_index = unused_utxo.vout return [ Spendable(coin_value, script, previous_hash_little_endian, previous_index) ]
def unspents_for_addresses(self, address_iter): """ Return a list of Spendable objects for the given bitcoin address. """ address_list = ",".join(address_iter) URL = self.base_url() % ("addresses/%s/unspents" % address_list) r = json.loads(urlopen(URL).read().decode("utf8")) spendables = [] for u in r: coin_value = u["value"] script = h2b(u["script_hex"]) previous_hash = h2b(u["transaction_hash"]) previous_index = u["output_index"] spendables.append( Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def spendables_for_address(self, address): """ Return a list of Spendable objects for the given bitcoin address. """ spendables = [] r = json.loads( urlopen(self.base_url('get_tx_unspent', address)).read().decode("utf8")) for u in r['data']['txs']: coin_value = int(float(u['value']) * 100000000) script = h2b(u["script_hex"]) previous_hash = h2b_rev(u["txid"]) previous_index = u["output_no"] spendables.append( Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def spendables_for_addresses(self, bitcoin_addresses): """ Return a list of Spendable objects for the given bitcoin address. """ r = [] for i in xrange(0, len(bitcoin_addresses), CHUNK_SIZE): addresses = bitcoin_addresses[i:i + CHUNK_SIZE] url = "%s/api/addrs/%s/utxo" % (self.base_url, ",".join(addresses)) r.extend(json.loads(urlopen(url).read().decode("utf8"))) spendables = [] for u in r: coin_value = btc_to_satoshi(str(u.get("amount"))) script = h2b(u.get("scriptPubKey")) previous_hash = h2b_rev(u.get("txid")) previous_index = u.get("vout") spendables.append( Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def spendables_for_address(bitcoin_address): """ Return a list of Spendable objects for the given bitcoin address. """ URL = "https://api.biteasy.com/blockchain/v1/addresses/%s/unspent-outputs" % bitcoin_address r = Request(URL, headers={"content-type": "application/json", "accept": "*/*", "User-Agent": "curl/7.29.0"}) d = urlopen(r).read() json_response = json.loads(d.decode("utf8")) spendables = [] for tx_out_info in json_response.get("data", {}).get("outputs"): if tx_out_info.get("to_address") == bitcoin_address: coin_value = tx_out_info["value"] script = tools.compile(tx_out_info.get("script_pub_key")) previous_hash = h2b_rev(tx_out_info.get("transaction_hash")) previous_index = tx_out_info.get("transaction_index") spendables.append(Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def fake_sources_for_address(self, addr, num_sources, total_satoshi): """ Returns a fake list of funding sources for a bitcoin address. Note: total_satoshi will be split evenly by num_sources addr - bitcoin address to fund num_sources - number of sources to fund it with total_satoshi - total satoshis to fund 'addr' with Returns a list of Spendable objects """ spendables = [] satoshi_left = total_satoshi satoshi_per_tx = satoshi_left / num_sources satoshi_per_tx = int(satoshi_per_tx) # Create the output script for the input to fund script = standard_tx_out_script(addr) while satoshi_left > 0: if satoshi_left < satoshi_per_tx: satoshi_per_tx = satoshi_left # Create a random hash value rand_hash = bytes([random.randint(0, 0xFF) for _ in range(0, 32)]) # Create a random output index # This field is 32 bits, but typically transactions dont have that many, limit to 0xFF rand_output_index = random.randint(0, 0xFF) # Append the new fake source spend = Spendable(satoshi_per_tx, script, rand_hash, rand_output_index) spendables.append(spend) satoshi_left -= satoshi_per_tx assert satoshi_left == 0, "incorrect funding" return spendables
def make_bare_tx(network, from_address, to_address, redeem_script, version=1): # <Tx> components spendables = [] ins = [] outs = [] # estimate the final (signed) bytesize per input based on the redeemscript in_size = estimate_input_size(redeem_script) # initialize size and amount counters in_amount = Decimal(0) est_size = TX_COMPONENTS.version + TX_COMPONENTS.out_count + TX_COMPONENTS.in_count # add output size (we"ll only have 1) est_size += TX_COMPONENTS.out_scriptlen + TX_COMPONENTS.out_scriptsize + TX_COMPONENTS.out_scriptlen unspent_response = sochain_get_unspents(network, from_address) unspents = unspent_response.get("txs", []) # iterate over unspents for tx in unspents: value = Decimal(tx.get("value")) * Decimal(1e8) in_amount += value script = h2b(tx.get("script_hex")) # for now: test if the in_script we figured we would need, actually matches the in script :D # reverse that tx hash txhex = tx.get("txid") prevtx = h2b_rev(txhex) # output index outnum = tx.get("output_no") # create "spendable" spdbl = Spendable(value, script, prevtx, outnum) spendables.append(spdbl) # also create this as input as_input = spdbl.tx_in() as_input.sigs = [] ins.append(as_input) # add the estimated size per input est_size += in_size # calc fee and out amount fee = Decimal(math.ceil( est_size / 1000.0)) * Decimal(1e8) * NETWORK_FEES.get(network) out_amount = in_amount - fee if (is_p2sh(to_address)): outscript = make_payto_script(to_address) else: outscript = make_payto_address(to_address) # create output outs.append(TxOut(out_amount, outscript)) # create bare tx without sigs tx = Tx(version, ins, outs, 0, spendables) return tx
def create_spend(utxo): sp = Spendable(coin_value=utxo['amount'] * 10**6, script=unhexlify(utxo['scriptPubKey']), tx_hash=unhexlify(utxo['txid'])[::-1], tx_out_index=utxo['vout']) return sp
def test_sign(self, keynums_satoshi, out_addr, out_satoshi, change_keynum, change_satoshi, prevtx_keynums, prevtx_outputs, prevtx_inputs): """ Performs a tx signing test, comparing Polly's signed tx against the reference wallet. Basic tx signing parameters: keynums_satoshi - list of tuples (keynum, satoshis) with key indices and their unspent value to use as tx inputs. Funding above out_satoshi + change_satoshi will be fees. out_addr - output address in bitcoin address format. out_satoshi - output amount in satoshis. change_keynum - change key index in the wallet, use None for no change. change_satoshi - change amount in satoshis, use 0 for no change. Supporting (previous) txs will be created to fund keynums and are controlled by these parameters: prevtx_keynums - keynums will show up as outputs of previous txs. A number randomly picked from this list controls how many keynums are chosen to include per prev tx. prevtx_outputs - in addition to previous tx outputs funding keynums, other outputs may be present. A number randomly picked from this list controls how many ignored outputs are injected per keynum. prevtx_inputs - previous txs need inputs too. A number randomly picked from this list controls how many inputs are chosen per previous tx. """ total_in_satoshi = sum(satoshi for _, satoshi in keynums_satoshi) fee_satoshi = total_in_satoshi - out_satoshi - change_satoshi chain0 = self.wallet.subkey(0, is_hardened=True).subkey(0) chain1 = self.wallet.subkey(0, is_hardened=True).subkey(1) assert total_in_satoshi >= out_satoshi + change_satoshi assert len(keynums_satoshi) <= 32 # # Step 1: send the inputs and outputs to use in the signed tx # # Create the (key num, compressed public key) tuple, input keys assume an m/0h/0/keynum path for now. keys = [ (keynum, encoding.public_pair_to_sec(chain0.subkey(keynum).public_pair)) for (keynum, _) in keynums_satoshi ] # Convert base58 address to raw hex address out_addr_160 = encoding.bitcoin_address_to_hash160_sec(out_addr) print() print("Sign tx parameters:", "") for i, (keynum, satoshi) in enumerate(keynums_satoshi): print("{:<10}{:16.8f} btc < key {}".format( " inputs" if 0 == i else "", satoshi / 100000000, keynum)) print("{:<10}{:16.8f} btc > {}".format(" output", out_satoshi / 100000000, self.hexstr(out_addr_160))) print("{:<10}{:16.8f} btc > key {}".format(" change", change_satoshi / 100000000, change_keynum)) print("{:<10}{:16.8f} btc".format(" fee", fee_satoshi / 100000000)) print("{:<10}{:16.8f} btc".format(" total", total_in_satoshi / 100000000)) print() print(self.PAD.format("Send tx parameters"), end='') # ---> send to Polly self.polly.send_sign_tx(keys, out_addr_160, out_satoshi, change_keynum, change_satoshi) print(self.__outok()) # # Step 2: send previous txs to fund the inputs # print() cur = 0 prevtx_info = [] while cur < len(keynums_satoshi): prevtx_outputs_satoshi = [] # Calculate how many keynums will be associated with this prev tx end = min(cur + random.choice(prevtx_keynums), len(keynums_satoshi)) # Create the prev tx output list for keynum, satoshi in keynums_satoshi[cur:end]: # Inject a random number of outputs not associated with tx input keynums for _ in range(0, random.choice(prevtx_outputs)): prevtx_outputs_satoshi.append( (random.randint(0, 0x7FFFFFFF), random.randint(0, 2099999997690000))) # Add the outputs funding the tx input keynums prevtx_outputs_satoshi.append((keynum, satoshi)) # Create output script addr = chain0.subkey(keynum, as_private=True).bitcoin_address() script = standard_tx_out_script(addr) # Capture some info we'll use later to verify the signed tx prevtx_info.append(( keynum, satoshi, script, 0, # This is the hash and will be replaced later len(prevtx_outputs_satoshi) - 1)) # Index of the valid output print("{:30}{}".format( "Make prev tx for keys", " ".join( str(keynum) for (keynum, _, _, _, _) in prevtx_info[cur:]))) # Create the prev tx prevtx = self.create_prev_tx( win=Wallet.from_master_secret( bytes(0)), # create a dummy wallet in_keynum=list(range(0, random.choice(prevtx_inputs))), sources_per_input=1, wout=chain0, out_keynum_satoshi=prevtx_outputs_satoshi, fees_satoshi=random.randint(100, 1000)) # We have built the prev tx, calculate its hash (and reverse the bytes) prevtx_hash = encoding.double_sha256(prevtx)[::-1] # Update the hashes now that we have a full prev tx for i, (keynum, satoshi, script, _, outidx) in enumerate(prevtx_info[cur:]): prevtx_info[i + cur] = (keynum, satoshi, script, prevtx_hash, outidx) # Create the index table that matches a keynum index with an ouput index in this prev tx idx_table = [ (keynum_idx + cur, outidx) for keynum_idx, (_, _, _, _, outidx) in enumerate(prevtx_info[cur:]) ] print(self.PAD.format("Send prev tx "), end='') # ---> send to Polly self.polly.send_prev_tx(idx_table, prevtx) print(self.__outok()) cur = end # # Step 3: generate a signed tx with the reference wallet and compare against Polly's # spendables = [] wifs = [] # Make sure that the inputs add up correctly, and prep the input_sources for reference wallet signing for (keynum, satoshi, script, prevtx_hash, outidx) in prevtx_info: spendables.append(Spendable(satoshi, script, prevtx_hash, outidx)) wifs.append(chain0.subkey(keynum, as_private=True).wif()) change_addr = chain1.subkey(change_keynum).bitcoin_address() payables = [(out_addr, out_satoshi), (change_addr, change_satoshi)] print() print(self.PAD.format("Make reference signature")) signed_tx = create_signed_tx(spendables, payables, wifs, fee_satoshi) signed_tx = self.get_tx_bytes(signed_tx) print(self.PAD.format("Get signed tx"), end='', flush=True) # <--- get the signed tx from Polly polly_signed_tx = self.polly.send_get_signed_tx() #print(self.txstr(polly_signed_tx)) #print(self.txstr(signed_tx)) print(self.__outok()) # Compare reference wallet signed tx with polly's assert signed_tx == polly_signed_tx, "test_sign: signature mismatch\nExpected:\n" + self.hexstr( signed_tx) + "\n\nActual:\n" + self.hexstr(polly_signed_tx)