def tx_from_json_dict(r): version = r.get("version") lock_time = r.get("locktime") txs_in = [] for vin in r.get("vin"): if "coinbase" in vin: previous_hash = b'\0' * 32 script = h2b(vin.get("coinbase")) previous_index = 4294967295 else: previous_hash = h2b_rev(vin.get("txid")) scriptSig = vin.get("scriptSig") if "hex" in scriptSig: script = h2b(scriptSig.get("hex")) else: script = BitcoinScriptTools.compile(scriptSig.get("asm")) previous_index = vin.get("vout") sequence = vin.get("sequence") txs_in.append(Tx.TxIn(previous_hash, previous_index, script, sequence)) txs_out = [] for vout in r.get("vout"): coin_value = btc_to_satoshi(decimal.Decimal(vout.get("value"))) script = BitcoinScriptTools.compile(vout.get("scriptPubKey").get("asm")) txs_out.append(Tx.TxOut(coin_value, script)) tx = Tx(version, txs_in, txs_out, lock_time) bh = r.get("blockhash") if bh: bh = h2b_rev(bh) tx.confirmation_block_hash = bh return tx
def tx_from_json_dict(r): version = r.get("version") lock_time = r.get("locktime") txs_in = [] for vin in r.get("vin"): if "coinbase" in vin: previous_hash = b'\0' * 32 script = h2b(vin.get("coinbase")) previous_index = 4294967295 else: previous_hash = h2b_rev(vin.get("txid")) scriptSig = vin.get("scriptSig") if "hex" in scriptSig: script = h2b(scriptSig.get("hex")) else: script = BitcoinScriptTools.compile(scriptSig.get("asm")) previous_index = vin.get("vout") sequence = vin.get("sequence") txs_in.append(Tx.TxIn(previous_hash, previous_index, script, sequence)) txs_out = [] for vout in r.get("vout"): coin_value = btc_to_satoshi(decimal.Decimal(vout.get("value"))) script = BitcoinScriptTools.compile( vout.get("scriptPubKey").get("asm")) txs_out.append(Tx.TxOut(coin_value, script)) tx = Tx(version, txs_in, txs_out, lock_time) bh = r.get("blockhash") if bh: bh = h2b_rev(bh) tx.confirmation_block_hash = bh return tx
def parse_tx(tx_class, arg, parser, tx_db, network): # hex transaction id tx = None if TX_ID_RE.match(arg): if tx_db is None: tx_db = create_tx_db(network) tx = tx_db.get(h2b_rev(arg)) if not tx: parser.error("can't find Tx with id %s" % arg) return tx, tx_db # hex transaction data try: return tx_class.from_hex(arg), tx_db except Exception: pass if os.path.exists(arg): try: with open(arg, "rb") as f: if f.name.endswith("hex"): f = io.BytesIO(codecs.getreader("hex_codec")(f).read()) tx = tx_class.parse(f) tx.parse_unspents(f) except Exception: pass return tx, tx_db
def test_h2b(self): h = "000102" b = b"\x00\x01\x02" self.assertEqual(h2b(h), b) self.assertEqual(b2h(b), h) self.assertEqual(h2b_rev(h), b[::-1]) self.assertEqual(b2h_rev(b), "020100")
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)) script = network.contract.for_address(address) _un_spent.append(Spendable(balance, script, tx_id_b, idx)) _txs_out = [] for balance, receiver_address in tx_outs: _txs_out.append( TxOut(balance, network.contract.for_address(receiver_address))) 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], [secp256k1_generator]) tx.sign(solver, hash_type=SIGHASH_ALL) return tx.as_hex(), tx.id()
def spendable_for_row(r, spendable_class): return spendable_class(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 get_blockheader_with_transaction_hashes(self, block_hash): URL = "%s/block/%s" % (self.base_url, b2h_rev(block_hash)) r = json.loads(urlopen(URL).read().decode("utf8")) version = r.get("version") previous_block_hash = h2b_rev(r.get("previousblockhash")) merkle_root = h2b_rev(r.get("merkleroot")) timestamp = r.get("time") difficulty = int(r.get("bits"), 16) nonce = int(r.get("nonce")) tx_hashes = [h2b_rev(tx_hash) for tx_hash in r.get("tx")] blockheader = Block(version, previous_block_hash, merkle_root, timestamp, difficulty, nonce) if blockheader.hash() != block_hash: return None, None calculated_hash = merkle(tx_hashes, double_sha256) if calculated_hash != merkle_root: return None, None blockheader.height = r.get("height") return blockheader, tx_hashes
def _input_tx_to_spendable(self, tx: InputTransaction) -> Spendable: outs = tx.output.split(":") tx_hash = h2b_rev(outs[0]) output_n = int(outs[1]) return Spendable(coin_value=tx.value, script=self._network.ui.script_for_address( tx.address), tx_hash=tx_hash, tx_out_index=output_n)
def from_text(cls, text): the_tuple = (text.split("/") + [0, 0, 0])[:7] tx_hash_hex, tx_out_index_str, script_hex, coin_value, \ block_index_available, does_seem_spent, block_index_spent = the_tuple tx_hash = h2b_rev(tx_hash_hex) tx_out_index = int(tx_out_index_str) script = h2b(script_hex) coin_value = int(coin_value) return cls(coin_value, script, tx_hash, tx_out_index, int(block_index_available), int(does_seem_spent), int(block_index_spent))
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, network.contract.for_address(address), tx_id_b, idx)) _txs_out = [] for balance, receiver_address in tx_outs: _txs_out.append( TxOut(balance, network.contract.for_address(receiver_address))) 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( [network.parse.wif(wif_key).secret_exponent() for wif_key in wif_keys], [secp256k1_generator]) 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])]) r = BitcoinSolver(tx).solve(hash160_lookup, i, hash_type=SIGHASH_ALL, p2sh_lookup=p2sh_lookup) if isinstance(r, bytes): tx.txs_in[i].script = r else: tx.txs_in[i].script = r[0] tx.set_witness(i, r[1]) return tx.as_hex(), tx.id()
def tether_tx(tx_ins, in_keys, send_amount, receiver, change_address): """ simple usdt transaction 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 :param tx_ins: utxo from the sender :param in_keys: list of private keys in hex format corresponding to each input :param send_amount: (display amount) * (10 ** 8) :param receiver: address to receive usdt :param change_address: address to receive btc change """ _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, network.contract.for_address(address), tx_id_b, idx)) satoshi_per_byte = recommend_satoshi_per_byte() txn_fee = estimate_p2pkh_tx_bytes(len(tx_ins), 3) * satoshi_per_byte _txs_out = [ TxOut(total_bal - txn_fee - MIN_BTC_OUT, network.contract.for_address(change_address)), TxOut(0, binascii.unhexlify(omni_tether_script(send_amount))), TxOut(MIN_BTC_OUT, network.contract.for_address(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(pri_hex, 16) for pri_hex in in_keys], [secp256k1_generator]) signed_tx = tx.sign(solver, hash_type=SIGHASH_ALL) return signed_tx.as_hex(), signed_tx.id()
def txs_from_json(path): """ Read tests from ./data/tx_??valid.json Format is an array of arrays Inner arrays are either [ "comment" ] or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...], serializedTransaction, verifyFlags] ... where all scripts are stringified scripts. verifyFlags is a comma separated list of script verification flags to apply, or "NONE" """ comments = None with open(path, 'r') as f: for tvec in json.load(f): if len(tvec) == 1: comments = tvec[0] continue assert len(tvec) == 3 prevouts = tvec[0] for prevout in prevouts: assert len(prevout) in (3, 4) tx_hex = tvec[1] flag_mask = parse_flags(tvec[2]) try: tx = BitcoinMainnet.tx.from_hex(tx_hex) except Exception: print("Cannot parse tx_hex: %s" % tx_hex) raise spendable_db = {} blank_spendable = BitcoinMainnet.tx.Spendable( 0, b'', b'\0' * 32, 0) for prevout in prevouts: coin_value = 1000000 if len(prevout) == 4: coin_value = prevout[3] spendable = BitcoinMainnet.tx.Spendable( coin_value=coin_value, script=BitcoinMainnet.script_tools.compile(prevout[2]), tx_hash=h2b_rev(prevout[0]), tx_out_index=prevout[1]) spendable_db[(spendable.tx_hash, spendable.tx_out_index)] = spendable unspents = [ spendable_db.get((tx_in.previous_hash, tx_in.previous_index), blank_spendable) for tx_in in tx.txs_in ] tx.set_unspents(unspents) yield (tx, flag_mask, comments)
def validate_unspents(self, tx_db): """ Spendable objects returned from blockchain.info or similar services contain coin_value information that must be trusted on faith. Mistaken coin_value data can result in coins being wasted to fees. This function solves this problem by iterating over the incoming transactions, fetching them from the tx_db in full, and verifying that the coin_values are as expected. Returns the fee for this transaction. If any of the spendables set by tx.set_unspents do not match the authenticated transactions, a ValidationFailureError is raised. """ tx_hashes = set((tx_in.previous_hash for tx_in in self.txs_in)) # build a local copy of the DB tx_lookup = {} for h in tx_hashes: if h == ZERO32: continue the_tx = tx_db.get(h) if the_tx is None: raise KeyError("hash id %s not in tx_db" % b2h_rev(h)) if the_tx.hash() != h: raise KeyError( "attempt to load Tx %s yielded a Tx with id %s" % (h2b_rev(h), the_tx.id())) tx_lookup[h] = the_tx for idx, tx_in in enumerate(self.txs_in): if tx_in.previous_hash == ZERO32: continue txs_out = tx_lookup[tx_in.previous_hash].txs_out if tx_in.previous_index > len(txs_out): raise BadSpendableError( "tx_out index %d is too big for Tx %s" % (tx_in.previous_index, b2h_rev(tx_in.previous_hash))) tx_out1 = txs_out[tx_in.previous_index] tx_out2 = self.unspents[idx] if tx_out1.coin_value != tx_out2.coin_value: raise BadSpendableError( "unspents[%d] coin value mismatch (%d vs %d)" % (idx, tx_out1.coin_value, tx_out2.coin_value)) if tx_out1.script != tx_out2.script: raise BadSpendableError("unspents[%d] script mismatch!" % idx) return self.fee()
def spendables_for_address(self, address): """ Return a list of Spendable objects for the given bitcoin address. """ URL = "%s/addr/%s/utxo" % (self.base_url, address) r = 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(Tx.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(Tx.Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def get_spendables_for_address(self, address) -> List[Spendable]: """ Return a list of Spendable objects for the given bitcoin address. It needs to create transaction via pycoin library. """ spendables = [] r = self._request(f"{self._endpoint}get_tx_unspent/{self._network}/{address}") print(f"spendables_for_address: {r}") for u in r["data"]['txs']: coin_value = self._decimals_to_int(u['value']) 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_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(Tx.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 = "%s/addr/%s/utxo" % (self.base_url, address) r = 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( Tx.Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def validate_unspents(self, tx_db): """ Spendable objects returned from blockchain.info or similar services contain coin_value information that must be trusted on faith. Mistaken coin_value data can result in coins being wasted to fees. This function solves this problem by iterating over the incoming transactions, fetching them from the tx_db in full, and verifying that the coin_values are as expected. Returns the fee for this transaction. If any of the spendables set by tx.set_unspents do not match the authenticated transactions, a ValidationFailureError is raised. """ tx_hashes = set((tx_in.previous_hash for tx_in in self.txs_in)) # build a local copy of the DB tx_lookup = {} for h in tx_hashes: if h == ZERO32: continue the_tx = tx_db.get(h) if the_tx is None: raise KeyError("hash id %s not in tx_db" % b2h_rev(h)) if the_tx.hash() != h: raise KeyError("attempt to load Tx %s yielded a Tx with id %s" % (h2b_rev(h), the_tx.id())) tx_lookup[h] = the_tx for idx, tx_in in enumerate(self.txs_in): if tx_in.previous_hash == ZERO32: continue txs_out = tx_lookup[tx_in.previous_hash].txs_out if tx_in.previous_index > len(txs_out): raise BadSpendableError("tx_out index %d is too big for Tx %s" % (tx_in.previous_index, b2h_rev(tx_in.previous_hash))) tx_out1 = txs_out[tx_in.previous_index] tx_out2 = self.unspents[idx] if tx_out1.coin_value != tx_out2.coin_value: raise BadSpendableError( "unspents[%d] coin value mismatch (%d vs %d)" % ( idx, tx_out1.coin_value, tx_out2.coin_value)) if tx_out1.script != tx_out2.script: raise BadSpendableError("unspents[%d] script mismatch!" % idx) return self.fee()
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( Tx.Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def txs_from_json(path): """ Read tests from ./data/tx_??valid.json Format is an array of arrays Inner arrays are either [ "comment" ] or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...], serializedTransaction, verifyFlags] ... where all scripts are stringified scripts. verifyFlags is a comma separated list of script verification flags to apply, or "NONE" """ comments = None with open(path, 'r') as f: for tvec in json.load(f): if len(tvec) == 1: comments = tvec[0] continue assert len(tvec) == 3 prevouts = tvec[0] for prevout in prevouts: assert len(prevout) in (3, 4) tx_hex = tvec[1] flag_mask = parse_flags(tvec[2]) try: tx = network.tx.from_hex(tx_hex) except Exception: print("Cannot parse tx_hex: %s" % tx_hex) raise spendable_db = {} blank_spendable = network.tx.Spendable(0, b'', b'\0' * 32, 0) for prevout in prevouts: coin_value = 1000000 if len(prevout) == 4: coin_value = prevout[3] spendable = network.tx.Spendable( coin_value=coin_value, script=network.script.compile(prevout[2]), tx_hash=h2b_rev(prevout[0]), tx_out_index=prevout[1]) spendable_db[(spendable.tx_hash, spendable.tx_out_index)] = spendable unspents = [ spendable_db.get((tx_in.previous_hash, tx_in.previous_index), blank_spendable) for tx_in in tx.txs_in] tx.set_unspents(unspents) yield (tx, flag_mask, comments)
def get_spendables_for_address(self, address) -> List[Spendable]: """ Return a list of Spendable objects for the given bitcoin address. It needs to create transaction via pycoin library. """ unspent = self.get_unspent_tx(address) spendables = [] r = self._request(f"{self._endpoint}address/{address}/unspent") print(f"spendables_for_address: {r}") for utx in unspent: coin_value = utx["value"] script = self._network.ui.script_for_address(address) previous_hash = h2b_rev(utx["tx_hash"]) previous_index = utx["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. """ 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( Tx.Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def tether_tx_flush(tx_ins, private_key, send_amount, receiver): """ this is just a tool function that sends all btc and usdt fund to the same receiver address params are same with tether_tx """ _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, network.contract.for_address(address), tx_id_b, idx)) txn_fee = estimate_p2pkh_tx_bytes(len(tx_ins), 2) * recommend_satoshi_per_byte() _txs_out = [ TxOut(0, binascii.unhexlify(omni_tether_script(send_amount))), TxOut(total_bal - txn_fee, network.contract.for_address(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), [secp256k1_generator]) signed_tx = tx.sign(solver, hash_type=SIGHASH_ALL) return signed_tx.as_hex(), signed_tx.id()
def build_psbt(ctx, xfp, addrs, pubkey=None, xpubs=None, redeem=None): locals().update(ctx.obj) payout_address = ctx.obj['payout_address'] out_psbt = ctx.obj['output_psbt'] if pubkey: assert len(addrs) == 1 # can only be single addr in that case assert len(pubkey) == 33 spending = [] total = 0 psbt = BasicPSBT() for path, addr in addrs: print(f"addr: {path} => {addr} ... ", end='') rr = explora('address', addr, 'utxo') if not rr: print('nada') continue here = 0 for u in rr: here += u['value'] tt = TxIn(h2b_rev(u['txid']), u['vout']) spending.append(tt) #print(rr) pin = BasicPSBTInput(idx=len(psbt.inputs)) psbt.inputs.append(pin) pubkey = pubkey or calc_pubkey(xpubs, path) pin.bip32_paths[pubkey] = str2path(xfp, path) # fetch the UTXO for witness signging td = explora('tx', u['txid'], 'hex', is_json=False) #print(f"txis {u['txid']}:\b{td!r}") outpt = Tx.from_hex(td.decode('ascii')).txs_out[u['vout']] with BytesIO() as b: outpt.stream(b) pin.witness_utxo = b.getvalue() if redeem: pin.redeem_script = redeem print('%.8f BTC' % (here / 1E8)) total += here if len(spending) > 15: print("Reached practical limit on # of inputs. " "You'll need to repeat this process again later.") break assert total, "Sorry! Didn't find any UTXO" print("Found total: %.8f BTC" % (total / 1E8)) if payout_address: print("Planning to send to: %s" % payout_address) dest_scr = BTC.contract.for_address(payout_address) txn = Tx(2, spending, [TxOut(total, dest_scr)]) else: print("Output section of PSBT will be empty. Change downstream") txn = Tx(2, spending, []) fee = tx_fee.recommended_fee_for_tx(txn) # placeholder, single output that isn't change pout = BasicPSBTOutput(idx=0) psbt.outputs.append(pout) print("Guestimate fee: %.8f BTC" % (fee / 1E8)) if txn.txs_out: txn.txs_out[0].coin_value -= fee # write txn into PSBT with BytesIO() as b: txn.stream(b) psbt.txn = b.getvalue() out_psbt.write(psbt.as_bytes()) print("PSBT to be signed:\n\n\t" + out_psbt.name, end='\n\n')
def tether_tx_sh(tx_ins, wif_keys, send_amount, receiver, change_address): """ spend usdt having p2sh utxo WARNING!!! THIS FUNCTION IS NOT FULLY TESTED AS MY FUND WAS STOLEN BY A SON OF BITCH AFTER I BY ACCIDENT COMMITTED MY PRIVATE KEY!!! :param tx_ins: list with tuple(tx_id, idx, balance, address, redeem_script), redeem_script is required for p2sh utxo, set it None for p2pkh utxo :param wif_keys: private keys of the inputs :param send_amount: (display amount) * (10 ** 8) :param receiver: address to receive usdt :param change_address: address to receive btc change """ _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, network.contract.for_address(address), tx_id_b, idx)) txn_fee = estimate_p2pkh_tx_bytes(len(tx_ins), 3) * recommend_satoshi_per_byte() / 3 _txs_out = [ TxOut(total_bal - txn_fee - MIN_BTC_OUT, network.contract.for_address(change_address)), TxOut(0, binascii.unhexlify(omni_tether_script(send_amount))), TxOut(MIN_BTC_OUT, network.contract.for_address(receiver)) ] 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( [network.parse.wif(wif_key).secret_exponent() for wif_key in wif_keys], [secp256k1_generator]) for i in range(0, len(tx_ins)): if tx_ins[i][-1]: p2sh_lookup = build_p2sh_lookup( [binascii.unhexlify(tx_ins[i][-1])]) else: p2sh_lookup = None r = BitcoinSolver(tx).solve(hash160_lookup, i, hash_type=SIGHASH_ALL, p2sh_lookup=p2sh_lookup) if isinstance(r, bytes): tx.txs_in[i].script = r else: tx.txs_in[i].script = r[0] tx.set_witness(i, r[1]) return tx.as_hex(), tx.id()
def get_blockchain_tip(self): URL = "%s/status?q=getLastBlockHash" % self.base_url d = urlopen(URL).read().decode("utf8") r = json.loads(d) return h2b_rev(r.get("lastblockhash"))
def test_issue_39(self): """ See https://github.com/richardkiss/pycoin/issues/39 and https://github.com/richardkiss/pycoin/pull/40 There was a problem validating the following transactions: 315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f dbf38261224ebff0c455c405e2435cfc69adb6b8a42d7b10674d9a4eb0464dca de744408e4198c0a39310c8106d1830206e8d8a5392bcf715c9b5ec97d784edd This codes tests this. """ TX_B64_LIST = [ # some encoded transactions (the three listed above and the three # that they depend upon) ("AQAAAALcOOk1m9faO1g4YgThhtlAhoX0J/XlE2ZttzWqimshaQAAAABqRzBE" "AiBdj+6zEkeORo0LUU5j4ROVjXIU+lcqzYcHmn8MwCb8XAIgD6duoFvyQ69t" "D5F38kHK9gbQH8/V5i1r77yiTlaeXCcDIQIQChqcosGJMtZXfFjyJVgBhNDg" "gibUGVmHSslj48Gy/v/////cOOk1m9faO1g4YgThhtlAhoX0J/XlE2ZttzWq" "imshaQEAAABrSDBFAiAIft44cp5tNeT1FVBQGOZZIiAxJztzZpIPOT7jqxe8" "HgIhAMpDFkt1fRptEjXxMgDUtfdt2P2k7J/ChUay31sSEejfAyECdZg5E+YA" "k7dn6FWXypOX+y9Bjlf5mNavu8U2EWCFscv/////AUCJlQAAAAAAGXapFPzJ" "s204z1XX1bTuTd22ssF2EvSMiKwAAAAA"), ("AQAAAAEtUf3HWib/PGE4Ag4am7QPH6tuOc6W/q4yGMmuA14AqwEAAABrSDBF" "AiEA5PGlIZB+UPxE0zEy7pjJcVpk350sKGDj4EdMUhq4U34CIDCvjTUGpTUu" "KwVkRazYVaQtNycOlKYpp7KLIYcOxtdhASEDgIxJPwYZkNK+AB5A8EiuiHAy" "C3SJXOLZZS88HHPNbyz/////AvCHSwAAAAAAGXapFPzJs204z1XX1bTuTd22" "ssF2EvSMiKzwh0sAAAAAABl2qRQzzvYXSdEboq3wkaXgRWeBd/46bYisAAAA" "AA=="), ("AQAAAAJa+fLO2OCiRk98qhSvobvRyPsY3qrl0QEZa1jcIn70rgAAAABqRzBE" "AiANKFITbLHEu93eBOx29YHRsyockZFIyF+8D9BWXTWK8wIgNvKqF87Ind6w" "A3aigYv3KMRHmSgLnyBExWkad7Dc2WwDIQIQChqcosGJMtZXfFjyJVgBhNDg" "gibUGVmHSslj48Gy/v////9a+fLO2OCiRk98qhSvobvRyPsY3qrl0QEZa1jc" "In70rgEAAABrSDBFAiEA9APIYMTjztPlIyyzWCXnk3It+vCsLwGWGpN4K0kG" "qWMCIGLdifJz5mvPrW8FqLDNJrp7Bma+/Qw9pF2feVcX2lBKAyECdZg5E+YA" "k7dn6FWXypOX+y9Bjlf5mNavu8U2EWCFscv/////AaAClAAAAAAAGXapFOUK" "XY2jOZUbBAutBFPXxAz9dNPciKwAAAAA"), ("AQAAAAGfYeIRrb5mi2ycUPFoaEqbONlRKDXMKYFmaW3C1MdaMQAAAABsSTBG" "AiEAhIisrGQ/6Sa7DAJtv+pa9nMiHuBTLNAkxlyzDjYvGEQCIQCFH27K+zjJ" "ItZHnrCORpOhrBnHvPnUX8mqXy1pGB/4ngEhAhAKGpyiwYky1ld8WPIlWAGE" "0OCCJtQZWYdKyWPjwbL+/////wKgxEoAAAAAABl2qRT8ybNtOM9V19W07k3d" "trLBdhL0jIisoMRKAAAAAAAZdqkUM872F0nRG6Kt8JGl4EVngXf+Om2IrAAA" "AAA="), ("AQAAAALCBkSoNGHOnUgtcCy8I87ODdMmW1WL56GNNOIWvaccAAAAAABrSDBF" "AiAxKffbGKLs4sDhPFwLZvQlHX+Q20uxr0hFzQqtnSQZQAIhAImY0R1z7HrT" "Tt4hR0R/3n3eS8LXk14G94/O8Pc7LDlmAyECE2UQ39BTBuo0mCvz395yuOSd" "QyqYBb9kUtOZTnkvnRn/////yRF9O6xy+bn8PWf3KNM1uywKHCYWOL0bgEe1" "Zd1jGaIAAAAAakcwRAIgRQ7h/BpT6uurhfpEmEE/Xx5OAZdUohj+Euzr3Zg8" "mbkCIDxIakZ02TMLAtt5OHKyy0VQw7uywxjyis6540zeNZdJAyED78tvrsro" "6386Jta3YJd/I64guTuYS8oof9K4PDGZeHD/////AeD9HAAAAAAAGXapFB0x" "6lo758/yr1vtc3EOtvXV9n1wiKwAAAAA"), ("AQAAAAKerCh2TFeXmFaXU1qdQUucoCL5WRFVNZdvNt1FZgp5XQAAAACMSTBG" "AiEAvLz97Qz/zSlKSDrllLRwj73G2B7RfaiR1ZspOG5Ae3kCIQD5ATZgiNvH" "X8Tn8Ib8RohgW0HGbPRi00XUcvxCTmybGgFBBCsXId9LDBz91gENMCmVXxRE" "ZI+E6QOSkToVTtny7tiOJhmHy/jci4KzQmucvUBotsK5r4CiwjhjOkAAXRD6" "SWD/////6864dM1/4fxjvltUc0HJ1da9agsSw4LV3KYhGR7FJ+MBAAAAi0gw" "RQIhAJIopjUy7dPOHa+LGTvgM4jfZ8pA522/Jx3+uFC4Lz5IAiBzLNoxejaa" "dw1CXwOUuzI4rMl0xsuYC5XQaxZNT2TFzwFBBBPpriULEjb9VdVoC8v3E4is" "RMmfQByPCJYadSwK/ZZg9TTFGyDXUwW+dQ9tScDzhMWfdLK9DyV4iAbnYh/S" "2cr/////A0BCDwAAAAAAGXapFFzGycfh13x6rrUPhNJNj2ViE7xbiKwACT0A" "AAAAABl2qRQhQVEH8cwnc3//rGPcfvakBANJxIistBcsAAAAAAAZdqkUMQV+" "QpfDgBAsCQ+ixaUK5Kgl0kOIrAAAAAA="), ("AQAAAAO1CFlm1mEB3fjCtilQEH+6TbR3UzdJyqafj3mab9Mc6gAAAACKRzBE" "AiA8rWZ4BB8YYJp3xtx8jAZdrfQ6B0zjYRdgTS7I5LZF7gIgabCjn9iu9L3n" "YvKrdXFJJygtbg6V8iMTLrPh8ghdGvwBQQQrFyHfSwwc/dYBDTAplV8URGSP" "hOkDkpE6FU7Z8u7YjiYZh8v43IuCs0JrnL1AaLbCua+AosI4YzpAAF0Q+klg" "/////8IGRKg0Yc6dSC1wLLwjzs4N0yZbVYvnoY004ha9pxwAAQAAAItIMEUC" "IDNZYWLuCV0nJL6CCGgUfQfNoh0oAACd2lMZn+zJdJCDAiEAqZafa18G1K1x" "/6yOvj8h1uAGSM8UjSJJ6479li5sos4BQQTswrqYR5m+x0vFTzgGrrM2k+Gx" "gX+hDBAvN8Kq9RRuWdqC4jVNGhGdFD63Ev1TQYXMqvp6b9ztbAZ3ED8i6sFo" "/////0Vf19DzvUs2DvFwlVW9viTF+YlXCNYNMD6yUXK9I9RBAgAAAItIMEUC" "IQCKbaQY2eH1fsXZFksstrP4B+uxPBwGRe2Wxl7rW5sYGwIgVvVEPdnJNvVj" "rh0XZdhqnOAA0Sw39Upqkejrm+yXWnwBQQQ1hDJBuzoTc1ZJ8zyVQjEfRcjW" "o8rq3lE+3x3rYZ3Q/9xBEBtsnkFAzps/N8n6C5cK2QAmRGxeGFmbYaGFT5RP" "/////wNAQg8AAAAAABl2qRSU70Qwi2d2bI+nKnCP19XGsbSnWoisVEkwAAAA" "AAAZdqkUgroT7ai54LzKPXVnWJsPoV6lJ0yIrHjrFQAAAAAAGXapFEFyZV9I" "izJXnWmTivO2n9OKDWCdiKwAAAAA"), ("AQAAAAHBHumhtHyFj2ma501AFchO/RrrfkY1sYTKsJiYe6i5pAEAAADaAEcw" "RAIgJQsMj5xe4yyGSQOseNBu7zuQNbdwYRpmu4tyOeVrDhoCIHTRJ5lHr5OH" "JsmDYl4nTEMhT2TeEN8tMNtrt/rFLMaHAUgwRQIhAObKZ2o5NubR2aoXKP7q" "oNMI3sv4u33Hnxcu1NBCilhoAiAH5OaEGAC5snVQDIWgXXVWICosFmTHHjXg" "y5fNwAO5gAFHUiECzr9qtYCUjRRrfMdx2OZGl0NJ09exHz4DKH0Jl6R307kh" "A3umUUhbeiyyIhketkpVkm5iu6v+m17SqUiKrVR7IEKCUq7/////An1KDwAA" "AAAAGXapFNxnIa33YyARGtMFwzhMdn1LmeGViKxllyYPAAAAABepFNsSg3N8" "2T68HrEpjWRKeEbFWm2WhwAAAAA="), ("AQAAAAHZI2Rm7Gvz7UMEKi20P7AIT5AOxlhwW29S0uFz9EPz1QEAAADaAEgw" "RQIhAIX1NZuYzrKUHFAxUNYI6yWMUuzCEapuZOUY6TdCspWaAiAchzgPP6if" "WNh0cmVkyW1UpygM/eVa1XrtHepCMhvArAFHMEQCIGLJtKtbyJEaH6iQS+hK" "xUlGrWwmqdJScz/JfSZ1Qln6AiBNRC+gswEEMjTNR5uVetqCGJkNL2m6fDfk" "DyICU/otoQFHUiECzr9qtYCUjRRrfMdx2OZGl0NJ09exHz4DKH0Jl6R307kh" "A3umUUhbeiyyIhketkpVkm5iu6v+m17SqUiKrVR7IEKCUq7/////Aux5CAAA" "AAAAGXapFDIKbLrYWAn/2ZTB7ToisbIaZ5DoiKzL5TUPAAAAABepFNsSg3N8" "2T68HrEpjWRKeEbFWm2WhwAAAAA="), ( # 837dea37ddc8b1e3ce646f1a656e79bbd8cc7f558ac56a169626d649ebe2a3ba "AQAAAAGsp/O0VlTCMOCIalf7mIwwRO9ej385cm0wXGHV6BiQPAAAAAD9XQEAS" "DBFAiABh6+Sjp0VXEsaycHJEYFTI5q6dndPd118H5w+EG/zPAIhAIgisPZY7e" "wiJ00LauneEOvy2gaxu9qrpOUOsHjznj14AUcwRAIgeV8PT1lBp3rgMuy54zd" "TeI1+tcsMeNgFV11rAKHZv+0CID4fStkzLRQWrgHicDjpRbydtZxzJyijg6bx" "7S+5naekAUzJUkEEkbuiUQkSpb032h+1sWcwEOQ9LG2BLFFOkb+p8usSnhwYM" "ynbVb2GjiCarC+8Assz2Y/nS/I/DCNdYSax2DNPhkEEhlxAKTpoDLnAIOex4Q" "bYwZFtPO+ZqkMaVtJT5pJW2sCe8SKxqYaBiny2JFMvBiwdH4ciCEhhxcMpHM/" "+9OxodEEEjSRV0kA+CHCPwfVWAC8bbNg/mS0IUJf5l0qwiiiDjweJb7qwjzlJ" "XhX6b61u2/sedU41+hx4RMQfMioYY9RiE1Ou/////wFAQg8AAAAAABl2qRSuV" "rTbE1VNMhxALbOWEYeu0bvtW4isAAAAAA=="), ( # 3c9018e8d5615c306d72397f8f5eef44308c98fb576a88e030c25456b4f3a7ac # input of # 837dea37ddc8b1e3ce646f1a656e79bbd8cc7f558ac56a169626d649ebe2a3ba "AQAAAAGJYyhI+ZcikVcnxcddqNstvxlDQqBCmCj2b/iPqyr31gAAAACLSDBFA" "iEAq7yKc/4gVEgL2j8ygdotDFHihBORq9TAn0+QiiA0wY0CIFvJ5NaOr7kY8+" "lmIzhkekQZwN4aZQq4mD8dIW4qMdjjAUEEb1XXre/2ARx+rClP5UDFeDC+gOk" "1XIOGnJJgpLi/R2ema6y9cLgE3GPVvusUGAKSrX87CDNysdAtejfdl/9cnv//" "//8BQEIPAAAAAAAXqRT4FbA22bu85enyoAq9G/PckelVEIcAAAAA") ] TX_LIST = [ Tx.from_hex(b2h(binascii.a2b_base64(b64.encode("utf8")))) for b64 in TX_B64_LIST ] TX_DB = dict((tx.hash(), tx) for tx in TX_LIST) for h in [ "315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f", "dbf38261224ebff0c455c405e2435cfc69adb6b8a42d7b10674d9a4eb0464dca", "de744408e4198c0a39310c8106d1830206e8d8a5392bcf715c9b5ec97d784edd", "485716e53b422aca0fe5b1ded21360695ce5f49255d80e10db56458ed6962ff3", "837dea37ddc8b1e3ce646f1a656e79bbd8cc7f558ac56a169626d649ebe2a3ba" ]: tx = TX_DB.get(h2b_rev(h)) self.assertNotEqual(tx, None) tx.unspents_from_db(TX_DB) for idx, tx_in in enumerate(tx.txs_in): self.assertTrue(tx.is_solution_ok(tx_in_idx=idx))
def from_dict(cls, d): return cls(d["coin_value"], h2b(d["script_hex"]), h2b_rev(d["tx_hash_hex"]), d["tx_out_index"], d.get("block_index_available", 0), d.get("does_seem_spent", 0), d.get("block_index_spent", 0))
def test_issue_39(self): """ See https://github.com/richardkiss/pycoin/issues/39 and https://github.com/richardkiss/pycoin/pull/40 There was a problem validating the following transactions: 315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f dbf38261224ebff0c455c405e2435cfc69adb6b8a42d7b10674d9a4eb0464dca de744408e4198c0a39310c8106d1830206e8d8a5392bcf715c9b5ec97d784edd This codes tests this. """ TX_B64_LIST = [ # some encoded transactions (the three listed above and the three # that they depend upon) ( "AQAAAALcOOk1m9faO1g4YgThhtlAhoX0J/XlE2ZttzWqimshaQAAAABqRzBE" "AiBdj+6zEkeORo0LUU5j4ROVjXIU+lcqzYcHmn8MwCb8XAIgD6duoFvyQ69t" "D5F38kHK9gbQH8/V5i1r77yiTlaeXCcDIQIQChqcosGJMtZXfFjyJVgBhNDg" "gibUGVmHSslj48Gy/v/////cOOk1m9faO1g4YgThhtlAhoX0J/XlE2ZttzWq" "imshaQEAAABrSDBFAiAIft44cp5tNeT1FVBQGOZZIiAxJztzZpIPOT7jqxe8" "HgIhAMpDFkt1fRptEjXxMgDUtfdt2P2k7J/ChUay31sSEejfAyECdZg5E+YA" "k7dn6FWXypOX+y9Bjlf5mNavu8U2EWCFscv/////AUCJlQAAAAAAGXapFPzJ" "s204z1XX1bTuTd22ssF2EvSMiKwAAAAA" ), ( "AQAAAAEtUf3HWib/PGE4Ag4am7QPH6tuOc6W/q4yGMmuA14AqwEAAABrSDBF" "AiEA5PGlIZB+UPxE0zEy7pjJcVpk350sKGDj4EdMUhq4U34CIDCvjTUGpTUu" "KwVkRazYVaQtNycOlKYpp7KLIYcOxtdhASEDgIxJPwYZkNK+AB5A8EiuiHAy" "C3SJXOLZZS88HHPNbyz/////AvCHSwAAAAAAGXapFPzJs204z1XX1bTuTd22" "ssF2EvSMiKzwh0sAAAAAABl2qRQzzvYXSdEboq3wkaXgRWeBd/46bYisAAAA" "AA==" ), ( "AQAAAAJa+fLO2OCiRk98qhSvobvRyPsY3qrl0QEZa1jcIn70rgAAAABqRzBE" "AiANKFITbLHEu93eBOx29YHRsyockZFIyF+8D9BWXTWK8wIgNvKqF87Ind6w" "A3aigYv3KMRHmSgLnyBExWkad7Dc2WwDIQIQChqcosGJMtZXfFjyJVgBhNDg" "gibUGVmHSslj48Gy/v////9a+fLO2OCiRk98qhSvobvRyPsY3qrl0QEZa1jc" "In70rgEAAABrSDBFAiEA9APIYMTjztPlIyyzWCXnk3It+vCsLwGWGpN4K0kG" "qWMCIGLdifJz5mvPrW8FqLDNJrp7Bma+/Qw9pF2feVcX2lBKAyECdZg5E+YA" "k7dn6FWXypOX+y9Bjlf5mNavu8U2EWCFscv/////AaAClAAAAAAAGXapFOUK" "XY2jOZUbBAutBFPXxAz9dNPciKwAAAAA" ), ( "AQAAAAGfYeIRrb5mi2ycUPFoaEqbONlRKDXMKYFmaW3C1MdaMQAAAABsSTBG" "AiEAhIisrGQ/6Sa7DAJtv+pa9nMiHuBTLNAkxlyzDjYvGEQCIQCFH27K+zjJ" "ItZHnrCORpOhrBnHvPnUX8mqXy1pGB/4ngEhAhAKGpyiwYky1ld8WPIlWAGE" "0OCCJtQZWYdKyWPjwbL+/////wKgxEoAAAAAABl2qRT8ybNtOM9V19W07k3d" "trLBdhL0jIisoMRKAAAAAAAZdqkUM872F0nRG6Kt8JGl4EVngXf+Om2IrAAA" "AAA=" ), ( "AQAAAALCBkSoNGHOnUgtcCy8I87ODdMmW1WL56GNNOIWvaccAAAAAABrSDBF" "AiAxKffbGKLs4sDhPFwLZvQlHX+Q20uxr0hFzQqtnSQZQAIhAImY0R1z7HrT" "Tt4hR0R/3n3eS8LXk14G94/O8Pc7LDlmAyECE2UQ39BTBuo0mCvz395yuOSd" "QyqYBb9kUtOZTnkvnRn/////yRF9O6xy+bn8PWf3KNM1uywKHCYWOL0bgEe1" "Zd1jGaIAAAAAakcwRAIgRQ7h/BpT6uurhfpEmEE/Xx5OAZdUohj+Euzr3Zg8" "mbkCIDxIakZ02TMLAtt5OHKyy0VQw7uywxjyis6540zeNZdJAyED78tvrsro" "6386Jta3YJd/I64guTuYS8oof9K4PDGZeHD/////AeD9HAAAAAAAGXapFB0x" "6lo758/yr1vtc3EOtvXV9n1wiKwAAAAA" ), ( "AQAAAAKerCh2TFeXmFaXU1qdQUucoCL5WRFVNZdvNt1FZgp5XQAAAACMSTBG" "AiEAvLz97Qz/zSlKSDrllLRwj73G2B7RfaiR1ZspOG5Ae3kCIQD5ATZgiNvH" "X8Tn8Ib8RohgW0HGbPRi00XUcvxCTmybGgFBBCsXId9LDBz91gENMCmVXxRE" "ZI+E6QOSkToVTtny7tiOJhmHy/jci4KzQmucvUBotsK5r4CiwjhjOkAAXRD6" "SWD/////6864dM1/4fxjvltUc0HJ1da9agsSw4LV3KYhGR7FJ+MBAAAAi0gw" "RQIhAJIopjUy7dPOHa+LGTvgM4jfZ8pA522/Jx3+uFC4Lz5IAiBzLNoxejaa" "dw1CXwOUuzI4rMl0xsuYC5XQaxZNT2TFzwFBBBPpriULEjb9VdVoC8v3E4is" "RMmfQByPCJYadSwK/ZZg9TTFGyDXUwW+dQ9tScDzhMWfdLK9DyV4iAbnYh/S" "2cr/////A0BCDwAAAAAAGXapFFzGycfh13x6rrUPhNJNj2ViE7xbiKwACT0A" "AAAAABl2qRQhQVEH8cwnc3//rGPcfvakBANJxIistBcsAAAAAAAZdqkUMQV+" "QpfDgBAsCQ+ixaUK5Kgl0kOIrAAAAAA=" ), ( "AQAAAAO1CFlm1mEB3fjCtilQEH+6TbR3UzdJyqafj3mab9Mc6gAAAACKRzBE" "AiA8rWZ4BB8YYJp3xtx8jAZdrfQ6B0zjYRdgTS7I5LZF7gIgabCjn9iu9L3n" "YvKrdXFJJygtbg6V8iMTLrPh8ghdGvwBQQQrFyHfSwwc/dYBDTAplV8URGSP" "hOkDkpE6FU7Z8u7YjiYZh8v43IuCs0JrnL1AaLbCua+AosI4YzpAAF0Q+klg" "/////8IGRKg0Yc6dSC1wLLwjzs4N0yZbVYvnoY004ha9pxwAAQAAAItIMEUC" "IDNZYWLuCV0nJL6CCGgUfQfNoh0oAACd2lMZn+zJdJCDAiEAqZafa18G1K1x" "/6yOvj8h1uAGSM8UjSJJ6479li5sos4BQQTswrqYR5m+x0vFTzgGrrM2k+Gx" "gX+hDBAvN8Kq9RRuWdqC4jVNGhGdFD63Ev1TQYXMqvp6b9ztbAZ3ED8i6sFo" "/////0Vf19DzvUs2DvFwlVW9viTF+YlXCNYNMD6yUXK9I9RBAgAAAItIMEUC" "IQCKbaQY2eH1fsXZFksstrP4B+uxPBwGRe2Wxl7rW5sYGwIgVvVEPdnJNvVj" "rh0XZdhqnOAA0Sw39Upqkejrm+yXWnwBQQQ1hDJBuzoTc1ZJ8zyVQjEfRcjW" "o8rq3lE+3x3rYZ3Q/9xBEBtsnkFAzps/N8n6C5cK2QAmRGxeGFmbYaGFT5RP" "/////wNAQg8AAAAAABl2qRSU70Qwi2d2bI+nKnCP19XGsbSnWoisVEkwAAAA" "AAAZdqkUgroT7ai54LzKPXVnWJsPoV6lJ0yIrHjrFQAAAAAAGXapFEFyZV9I" "izJXnWmTivO2n9OKDWCdiKwAAAAA" ), ( "AQAAAAHBHumhtHyFj2ma501AFchO/RrrfkY1sYTKsJiYe6i5pAEAAADaAEcw" "RAIgJQsMj5xe4yyGSQOseNBu7zuQNbdwYRpmu4tyOeVrDhoCIHTRJ5lHr5OH" "JsmDYl4nTEMhT2TeEN8tMNtrt/rFLMaHAUgwRQIhAObKZ2o5NubR2aoXKP7q" "oNMI3sv4u33Hnxcu1NBCilhoAiAH5OaEGAC5snVQDIWgXXVWICosFmTHHjXg" "y5fNwAO5gAFHUiECzr9qtYCUjRRrfMdx2OZGl0NJ09exHz4DKH0Jl6R307kh" "A3umUUhbeiyyIhketkpVkm5iu6v+m17SqUiKrVR7IEKCUq7/////An1KDwAA" "AAAAGXapFNxnIa33YyARGtMFwzhMdn1LmeGViKxllyYPAAAAABepFNsSg3N8" "2T68HrEpjWRKeEbFWm2WhwAAAAA=" ), ( "AQAAAAHZI2Rm7Gvz7UMEKi20P7AIT5AOxlhwW29S0uFz9EPz1QEAAADaAEgw" "RQIhAIX1NZuYzrKUHFAxUNYI6yWMUuzCEapuZOUY6TdCspWaAiAchzgPP6if" "WNh0cmVkyW1UpygM/eVa1XrtHepCMhvArAFHMEQCIGLJtKtbyJEaH6iQS+hK" "xUlGrWwmqdJScz/JfSZ1Qln6AiBNRC+gswEEMjTNR5uVetqCGJkNL2m6fDfk" "DyICU/otoQFHUiECzr9qtYCUjRRrfMdx2OZGl0NJ09exHz4DKH0Jl6R307kh" "A3umUUhbeiyyIhketkpVkm5iu6v+m17SqUiKrVR7IEKCUq7/////Aux5CAAA" "AAAAGXapFDIKbLrYWAn/2ZTB7ToisbIaZ5DoiKzL5TUPAAAAABepFNsSg3N8" "2T68HrEpjWRKeEbFWm2WhwAAAAA=" ), ( # 837dea37ddc8b1e3ce646f1a656e79bbd8cc7f558ac56a169626d649ebe2a3ba "AQAAAAGsp/O0VlTCMOCIalf7mIwwRO9ej385cm0wXGHV6BiQPAAAAAD9XQEAS" "DBFAiABh6+Sjp0VXEsaycHJEYFTI5q6dndPd118H5w+EG/zPAIhAIgisPZY7e" "wiJ00LauneEOvy2gaxu9qrpOUOsHjznj14AUcwRAIgeV8PT1lBp3rgMuy54zd" "TeI1+tcsMeNgFV11rAKHZv+0CID4fStkzLRQWrgHicDjpRbydtZxzJyijg6bx" "7S+5naekAUzJUkEEkbuiUQkSpb032h+1sWcwEOQ9LG2BLFFOkb+p8usSnhwYM" "ynbVb2GjiCarC+8Assz2Y/nS/I/DCNdYSax2DNPhkEEhlxAKTpoDLnAIOex4Q" "bYwZFtPO+ZqkMaVtJT5pJW2sCe8SKxqYaBiny2JFMvBiwdH4ciCEhhxcMpHM/" "+9OxodEEEjSRV0kA+CHCPwfVWAC8bbNg/mS0IUJf5l0qwiiiDjweJb7qwjzlJ" "XhX6b61u2/sedU41+hx4RMQfMioYY9RiE1Ou/////wFAQg8AAAAAABl2qRSuV" "rTbE1VNMhxALbOWEYeu0bvtW4isAAAAAA==" ), ( # 3c9018e8d5615c306d72397f8f5eef44308c98fb576a88e030c25456b4f3a7ac # input of # 837dea37ddc8b1e3ce646f1a656e79bbd8cc7f558ac56a169626d649ebe2a3ba "AQAAAAGJYyhI+ZcikVcnxcddqNstvxlDQqBCmCj2b/iPqyr31gAAAACLSDBFA" "iEAq7yKc/4gVEgL2j8ygdotDFHihBORq9TAn0+QiiA0wY0CIFvJ5NaOr7kY8+" "lmIzhkekQZwN4aZQq4mD8dIW4qMdjjAUEEb1XXre/2ARx+rClP5UDFeDC+gOk" "1XIOGnJJgpLi/R2ema6y9cLgE3GPVvusUGAKSrX87CDNysdAtejfdl/9cnv//" "//8BQEIPAAAAAAAXqRT4FbA22bu85enyoAq9G/PckelVEIcAAAAA" ) ] TX_LIST = [Tx.from_hex(b2h(binascii.a2b_base64(b64.encode("utf8")))) for b64 in TX_B64_LIST] TX_DB = dict((tx.hash(), tx) for tx in TX_LIST) for h in ["315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f", "dbf38261224ebff0c455c405e2435cfc69adb6b8a42d7b10674d9a4eb0464dca", "de744408e4198c0a39310c8106d1830206e8d8a5392bcf715c9b5ec97d784edd", "485716e53b422aca0fe5b1ded21360695ce5f49255d80e10db56458ed6962ff3", "837dea37ddc8b1e3ce646f1a656e79bbd8cc7f558ac56a169626d649ebe2a3ba"]: tx = TX_DB.get(h2b_rev(h)) self.assertNotEqual(tx, None) tx.unspents_from_db(TX_DB) for idx, tx_in in enumerate(tx.txs_in): self.assertTrue(tx.is_signature_ok(tx_in_idx=idx))
import threading import unittest from pycoin.encoding.hexbytes import h2b_rev from pycoin.services import providers from pycoin.services.blockchain_info import BlockchainInfoProvider from pycoin.services.blockcypher import BlockcypherProvider from pycoin.services.blockexplorer import BlockExplorerProvider from pycoin.services.chain_so import ChainSoProvider from pycoin.services.insight import InsightProvider BLOCK_0_HASH = h2b_rev("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") BLOCK_1_HASH = h2b_rev("00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048") tx_id_for_net = { "BTC": ["b958e4a3ccd5bc8fe0ff6fafd635199313e347b88a8102040c05dd123f32a4f3", "d1ef46055a84fd02ee82580d691064780def18614d98646371c3448ca20019ac", "69916297f7adde13457b8244e2d704966097e9519ec8fd6f2e7af8c2a60f70f2", "c586389e5e4b3acb9d6c8be1c19ae8ab2795397633176f5a6442a261bbdefc3a"], "XTN": ["4586e67ee5adcdbc97ed3d2a026ee8703df2ed3553854c186c216e90cd761b69"], "DOGE": ["ed7df4e7506ac8447b6983c8ad79da1af86cddda0ff012f7db83e664f61ef6cf"], "XDT": ["19dd5c3423e606b5b5dd30b070688bdf9af27fa736e8f3aeb2b68d92a50e67ef"], } class ServicesTest(unittest.TestCase): def test_env(self): CS = "blockchain.info blockexplorer.com chain.so insight:https://hostname/url"
def check_provider_tx_for_tx_hash(self, p, networks): for net in networks: b = p(net) for tx_id in tx_id_for_net[net]: tx = b.tx_for_tx_hash(h2b_rev(tx_id)) self.assertEqual(tx.id(), tx_id)